From 10c8a1df7a7ae8d7a02615d8555df627b8a8bda3 Mon Sep 17 00:00:00 2001 From: Jon Lund Steffensen Date: Tue, 4 Nov 2014 20:07:52 -0500 Subject: [PATCH] Initial import of QSopt_ex 2.5.10 --- Doxyfile | 1201 +++++++++ License.txt | 674 +++++ Makefile | 39 + Makefile.common | 213 ++ Makefile.library | 123 + Makefile.template | 226 ++ README | 65 + configure.ac | 851 +++++++ make.conf.in | 84 + src/allocrus.c | 284 +++ src/allocrus.h | 242 ++ src/basicdefs.h | 386 +++ src/basis.c | 1548 ++++++++++++ src/basis.h | 107 + src/bgetopt.c | 131 + src/bgetopt.h | 43 + src/binary.c | 1763 +++++++++++++ src/binary.h | 36 + src/demo_qs.c | 265 ++ src/dheaps_i.c | 343 +++ src/dheaps_i.h | 69 + src/dstruct.c | 494 ++++ src/dstruct.h | 133 + src/editor.c | 780 ++++++ src/editor.h | 35 + src/eg_exact.h | 41 + src/eg_exutil.c | 483 ++++ src/eg_exutil.h | 311 +++ src/eg_sloan.c | 234 ++ src/eg_sloan.h | 9 + src/esolver.c | 379 +++ src/exact.c | 1848 ++++++++++++++ src/exact.h | 485 ++++ src/except.c | 60 + src/except.h | 167 ++ src/factor.c | 5659 ++++++++++++++++++++++++++++++++++++++++++ src/factor.h | 206 ++ src/fct.c | 2488 +++++++++++++++++++ src/fct.h | 246 ++ src/format.c | 220 ++ src/format.h | 136 + src/ftest.c | 303 +++ src/ftest.h | 21 + src/iqsutil.h | 30 + src/lib.c | 4343 ++++++++++++++++++++++++++++++++ src/lib.h | 151 ++ src/lp.c | 1268 ++++++++++ src/lp.h | 75 + src/lpdata.c | 724 ++++++ src/lpdata.h | 302 +++ src/lpdefs.h | 329 +++ src/machdefs.h | 218 ++ src/mps.c | 1335 ++++++++++ src/mps.h | 53 + src/names.c | 97 + src/names.h | 35 + src/presolve.c | 2677 ++++++++++++++++++++ src/presolve.h | 21 + src/price.c | 1631 ++++++++++++ src/price.h | 222 ++ src/priority.c | 255 ++ src/priority.h | 75 + src/qs_config.h | 180 ++ src/qsopt.c | 3921 +++++++++++++++++++++++++++++ src/qsopt.h | 353 +++ src/qstruct.h | 46 + src/ratio.c | 1290 ++++++++++ src/ratio.h | 73 + src/rawlp.c | 1760 +++++++++++++ src/rawlp.h | 256 ++ src/read_lp.c | 826 ++++++ src/read_lp.h | 145 ++ src/read_mps.c | 516 ++++ src/read_mps.h | 95 + src/reader.c | 284 +++ src/reader.h | 34 + src/readline.c | 56 + src/readline.h | 64 + src/reporter.c | 89 + src/reporter.h | 57 + src/simplex.c | 3045 +++++++++++++++++++++++ src/simplex.h | 88 + src/solver.c | 361 +++ src/solver.h | 33 + src/sortrus.c | 285 +++ src/sortrus.h | 43 + src/sortrus_common.c | 423 ++++ src/sortrus_common.h | 62 + src/stddefs.h | 34 + src/symtab.c | 965 +++++++ src/symtab.h | 138 + src/trace.h | 41 + src/urandom.c | 174 ++ src/urandom.h | 59 + src/util.c | 284 +++ src/util.h | 156 ++ src/write_lp.c | 253 ++ src/write_lp.h | 71 + src/zeit.c | 292 +++ src/zeit.h | 65 + 100 files changed, 54189 insertions(+) create mode 100644 Doxyfile create mode 100644 License.txt create mode 100644 Makefile create mode 100644 Makefile.common create mode 100644 Makefile.library create mode 100644 Makefile.template create mode 100644 README create mode 100644 configure.ac create mode 100644 make.conf.in create mode 100644 src/allocrus.c create mode 100644 src/allocrus.h create mode 100644 src/basicdefs.h create mode 100644 src/basis.c create mode 100644 src/basis.h create mode 100644 src/bgetopt.c create mode 100644 src/bgetopt.h create mode 100644 src/binary.c create mode 100644 src/binary.h create mode 100644 src/demo_qs.c create mode 100644 src/dheaps_i.c create mode 100644 src/dheaps_i.h create mode 100644 src/dstruct.c create mode 100644 src/dstruct.h create mode 100644 src/editor.c create mode 100644 src/editor.h create mode 100644 src/eg_exact.h create mode 100644 src/eg_exutil.c create mode 100644 src/eg_exutil.h create mode 100644 src/eg_sloan.c create mode 100644 src/eg_sloan.h create mode 100644 src/esolver.c create mode 100644 src/exact.c create mode 100644 src/exact.h create mode 100644 src/except.c create mode 100644 src/except.h create mode 100644 src/factor.c create mode 100644 src/factor.h create mode 100644 src/fct.c create mode 100644 src/fct.h create mode 100644 src/format.c create mode 100644 src/format.h create mode 100644 src/ftest.c create mode 100644 src/ftest.h create mode 100644 src/iqsutil.h create mode 100644 src/lib.c create mode 100644 src/lib.h create mode 100644 src/lp.c create mode 100644 src/lp.h create mode 100644 src/lpdata.c create mode 100644 src/lpdata.h create mode 100644 src/lpdefs.h create mode 100644 src/machdefs.h create mode 100644 src/mps.c create mode 100644 src/mps.h create mode 100644 src/names.c create mode 100644 src/names.h create mode 100644 src/presolve.c create mode 100644 src/presolve.h create mode 100644 src/price.c create mode 100644 src/price.h create mode 100644 src/priority.c create mode 100644 src/priority.h create mode 100644 src/qs_config.h create mode 100644 src/qsopt.c create mode 100644 src/qsopt.h create mode 100644 src/qstruct.h create mode 100644 src/ratio.c create mode 100644 src/ratio.h create mode 100644 src/rawlp.c create mode 100644 src/rawlp.h create mode 100644 src/read_lp.c create mode 100644 src/read_lp.h create mode 100644 src/read_mps.c create mode 100644 src/read_mps.h create mode 100644 src/reader.c create mode 100644 src/reader.h create mode 100644 src/readline.c create mode 100644 src/readline.h create mode 100644 src/reporter.c create mode 100644 src/reporter.h create mode 100644 src/simplex.c create mode 100644 src/simplex.h create mode 100644 src/solver.c create mode 100644 src/solver.h create mode 100644 src/sortrus.c create mode 100644 src/sortrus.h create mode 100644 src/sortrus_common.c create mode 100644 src/sortrus_common.h create mode 100644 src/stddefs.h create mode 100644 src/symtab.c create mode 100644 src/symtab.h create mode 100644 src/trace.h create mode 100644 src/urandom.c create mode 100644 src/urandom.h create mode 100644 src/util.c create mode 100644 src/util.h create mode 100644 src/write_lp.c create mode 100644 src/write_lp.h create mode 100644 src/zeit.c create mode 100644 src/zeit.h diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..6c9ddee --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1201 @@ +# Doxyfile 1.4.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = QSopt_ex + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 050502 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = YES + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 300 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. + +SHOW_DIRECTORIES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the progam writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = doxygen.log + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = *.c \ + *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = EGlib + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = . EGlib + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = YES + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = YES + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = YES + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 150 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = yes + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = YES + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = pst-all amsmath amssymb algorithmic + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = /home/daespino/man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .9 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = NO + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = EGlib/EGlib_Doxygen_Tags=http://www.dii.uchile.cl/~daespino/EGlib_doc + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = ESolver_Doxygen_Tags + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = YES + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = gif + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/License.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3be457b --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +# ============================================================================= +# This is the Makefile of EGlib +# Revision 2003-4-14 +# - 2007-12-27 +# - Separate Makefile into multiple files +# - 2005-08-17 +# - Update EGlib.so rule +# - 2005-08-01 +# - Update to generate templates, and compute dependencies on the +# fly +# - 2003-11-18 +# - Update to automatic dependency generation +# ============================================================================= + +.PHONY: indent doc clean default template library +DEFAULT := template library +default = $(DEFAULT) + +#============================================================================== +# Default rules for each type of file + +library: template + @$(MAKE) -f Makefile.library + +template: + @$(MAKE) -f Makefile.template + +doc: template + @$(MAKE) -f Makefile.library doc + +clean: + @$(MAKE) -f Makefile.library clean + @$(MAKE) -f Makefile.template clean + +indent: template + @$(MAKE) -f Makefile.library indent + +# end of Makefile +# ============================================================================= diff --git a/Makefile.common b/Makefile.common new file mode 100644 index 0000000..5edbf03 --- /dev/null +++ b/Makefile.common @@ -0,0 +1,213 @@ +# ============================================================================= +# This is the Makefile.common from EGlib +# - 2007-12-27 +# - Separate template and library creation +# - 2007-12-20 +# - Update to create a full .h and improve support for x86_64 +# and mac OSX, and to generate a unified library interface +# - 2005-08-17 +# - Update EGlib.so rule +# - 2005-08-01 +# - Update to generate templates, and compute dependencies on the +# fly +# - 2003-11-18 +# - Update to automatic dependency generation +# ============================================================================= + +# ============================================================================= +# Here we read some configurations, you should edit this file instead +# of this makefile +include make.conf +# ============================================================================= +# if no working long double present, disable long double compilation +ifeq ($(HAVE_LONG_DOUBLE),0) +ENABLE_LONG_DOUBLE := 0 +endif +# ============================================================================= +# Here we define the source files (not need to put the prefix) that will +# generate objective files. DO NOT INCLUDE files that don't generate objective +# files here, they will be automagically computed +# ============================================================================= +# Main files without template +MAIN_SFILE := esolver.c eg_sloan.c demo_qs.c +# regular source files +SOURCE_FILE := allocrus.c bgetopt.c except.c urandom.c zeit.c \ + names.c symtab.c util.c exact.c reporter.c eg_exutil.c basicdefs.h \ + sortrus_common.c sortrus_common.h +# ============================================================================= +# Template main files +TEMPLATE_MAIN_SFILE := solver.c +# Template source files +TEMPLATE_SFILE := rawlp.c mps.c read_mps.c lp.c write_lp.c read_lp.c \ + readline.c lpdata.c presolve.c factor.c basis.c price.c \ + dstruct.c simplex.c fct.c ratio.c lib.c binary.c qsopt.c sortrus.c \ + dheaps_i.c priority.c editor.c format.c basis.h dheaps_i.h dstruct.h \ + factor.h format.h lpdata.h lpdefs.h mps.h price.h priority.h qsopt.h \ + qstruct.h ratio.h rawlp.h readline.h read_lp.h read_mps.h simplex.h \ + write_lp.h lib.h editor.h sortrus.h solver.h iqsutil.h binary.h fct.h \ + util.h util.c lp.h + +# ============================================================================= +# Basic programs used, if no in the PATH variable, put the full path to the +# utilites +# ============================================================================= +CTAGS := ctags +#CTAGS := ctags-exuberant +CUT := cut +UNIQ := uniq + +# ============================================================================= +# Path for each kind of file +# ============================================================================= +SOURCE_DIR := src +INCLUDE_DIR := src . include +BIN_DIR := bin +OBJ_DIR := obj +DEP_DIR := dep +LIB_DIR := lib +ALT_DIR := TEmplate +SOURCE_DIR += $(ALT_DIR) +INCLUDE_DIR += $(ALT_DIR) +# ============================================================================= +# You shoudn't edit bellow this point. Other configuration is found in +# 'make.conf', see that file for more details. +# ============================================================================= +# types of templates to be used +BASES_BASE := dbl fp20 +BASES_GMP := mpq mpf +BASES_LONG_DOUBLE := ldbl +BASES_SOFTFLOAT := float128 +BASES = $(BASES_BASE) +ifeq ($(ENABLE_SOFTFLOAT),1) +BASES += $(BASES_SOFTFLOAT) +endif +ifeq ($(ENABLE_LONG_DOUBLE),1) +BASES += $(BASES_LONG_DOUBLE) +endif +ifeq ($(ENABLE_LIBGMP),1) +BASES += $(BASES_GMP) +endif + +# ============================================================================= +# Define any extra includes/libraries needed by extra dependencies +LIB_FILES := + +#============================================================================== +# Default search paths for each type of file +vpath %.c $(SOURCE_DIR) +vpath %.h $(INCLUDE_DIR) $(EXTRA_INCLUDE_DIR) +vpath %.o $(OBJ_DIR) +vpath %.d $(DEP_DIR) +vpath %.a $(LIB_DIR) $(EXTRA_LIBS_DIR) $(LD_LIBRARY_PATH) +vpath %.so $(LIB_DIR) $(EXTRA_LIBS_DIR) $(LD_LIBRARY_PATH) + + +# computed files +# ============================================================================= +# General Files +ALL_TFILE := $(TEMPLATE_MAIN_SFILE) $(TEMPLATE_SFILE) +MAIN_SFILE += $(foreach base,$(BASES),$(addprefix $(base)_,$(TEMPLATE_MAIN_SFILE))) +SOURCE_FILE += $(foreach base,$(BASES),$(addprefix $(base)_,$(TEMPLATE_SFILE))) +ALL_FILE_TEMPLATE += $(addprefix $(ALT_DIR)/,$(foreach base,$(BASES),$(addprefix $(base)_,$(TEMPLATE_MAIN_SFILE) $(TEMPLATE_SFILE)))) +DEP_FILE := $(addsuffix .d,$(addprefix $(DEP_DIR)/,$(notdir $(SOURCE_FILE) $(MAIN_SFILE)))) + +# ============================================================================= +# GMP-related files +MAIN_SFILE_GMP += $(foreach base,$(BASES_GMP),$(addprefix $(base)_,$(TEMPLATE_MAIN_SFILE))) +SOURCE_FILE_GMP += $(foreach base,$(BASES_GMP),$(addprefix $(base)_,$(TEMPLATE_SFILE))) +ifneq ($(ENABLE_LIBGMP),1) +DEP_FILE += $(addsuffix .d,$(addprefix $(DEP_DIR)/,$(notdir $(SOURCE_FILE_GMP) $(MAIN_SFILE_GMP)))) +endif +ALL_FILE_TEMPLATE += $(addprefix $(ALT_DIR)/,$(foreach base,$(BASES_GMP),$(addprefix $(base)_,$(TEMPLATE_MAIN_SFILE) $(TEMPLATE_SFILE)))) + +# ============================================================================= +# Long Double-related files +MAIN_SFILE_LONG_DOUBLE += $(foreach base,$(BASES_LONG_DOUBLE),$(addprefix $(base)_,$(TEMPLATE_MAIN_SFILE))) +SOURCE_FILE_LONG_DOUBLE += $(foreach base,$(BASES_LONG_DOUBLE),$(addprefix $(base)_,$(TEMPLATE_SFILE))) +ifneq ($(ENABLE_LONG_DOUBLE),1) +DEP_FILE += $(addsuffix .d,$(addprefix $(DEP_DIR)/,$(notdir $(SOURCE_FILE_LONG_DOUBLE) $(MAIN_SFILE_LONG_DOUBLE)))) +endif +ALL_FILE_TEMPLATE += $(addprefix $(ALT_DIR)/,$(foreach base,$(BASES_LONG_DOUBLE),$(addprefix $(base)_,$(TEMPLATE_MAIN_SFILE) $(TEMPLATE_SFILE)))) + +# ============================================================================= +# Softfloat-related files +MAIN_SFILE_SOFTFLOAT += $(foreach base,$(BASES_SOFTFLOAT),$(addprefix $(base)_,$(TEMPLATE_MAIN_SFILE))) +SOURCE_FILE_SOFTFLOAT += $(foreach base,$(BASES_SOFTFLOAT),$(addprefix $(base)_,$(TEMPLATE_SFILE))) +ifneq ($(ENABLE_SOFTFLOAT),1) +DEP_FILE += $(addsuffix .d,$(addprefix $(DEP_DIR)/,$(notdir $(SOURCE_FILE_SOFTFLOAT) $(MAIN_SFILE_SOFTFLOAT)))) +endif +ALL_FILE_TEMPLATE += $(addprefix $(ALT_DIR)/,$(foreach base,$(BASES_SOFTFLOAT),$(addprefix $(base)_,$(TEMPLATE_MAIN_SFILE) $(TEMPLATE_SFILE)))) $(ALT_DIR)/base_$(PACKAGE_NAME).h + +# ============================================================================= +# objective files ============================================================= +OBJ_FILE := $(addprefix $(OBJ_DIR)/,$(notdir $(patsubst %.c,%.o,$(filter %c,$(SOURCE_FILE))))) $(OBJ_DIR)/$(PACKAGE_NAME)_version.o +MAIN_OFILE := $(addprefix $(OBJ_DIR)/,$(MAIN_SFILE:.c=.o)) + +# ============================================================================= +# main configuration options, the definition of _XOPEN_SOURCE is needed to use +# posix_memalign, now given by configure +SVNVERSION:=$(shell svnversion) +MAINOPT += -DSVNVERSION=\"$(SVNVERSION)\" + +# ============================================================================= +# Optimization Flags +SW += $(FLAG_STD_GNU89) +ifdef ENABLE_DEBUG +ifeq ($(ENABLE_DEBUG),1) +SW += $(FLAG_GGDB3) $(FLAG_WALL) $(FLAG_WBAD_FUNCTION_CAST) $(FLAG_WCAST_EQUAL) $(FLAG_WDECLARATION_AFTER_STATEMENT) $(FLAG_WEXTRA) $(FLAG_WINLINE) $(FLAG_WNESTED_EXTERNS) $(FLAG_WNO_EMPTY_BODY) $(FLAG_WNO_FORMAT_ZERO_LENGTH) $(FLAG_WNO_POINTER_SIGN) $(FLAG_WNO_UNINITIALIZED) $(FLAG_WPOINTER_ARITH) $(FLAG_WSHADOW) $(FLAG_WSIGN_COMPARE) $(FLAG_WSTRICT_PROTOTYPES) $(FLAG_WUNDEF) $(FLAG_WUNUSED_FUNCTION) $(FLAG_WUNUSED_LABEL) $(FLAG_WUNUSED_VALUE) $(FLAG_WUNUSED_VARIABLE) $(FLAG_WUNUSED_PARAMETER) $(FLAG_WWRITE_STRINGS) #-Wconversion +endif +endif +ifdef ENABLE_OPTIMIZE +ifeq ($(ENABLE_OPTIMIZE),1) +SW += $(FLAG_FFORCE_ADDR) $(FLAG_FINLINE_LIMIT) $(FLAG_FRERUN_CSE_AFTER_LOOP) $(FLAG_FRERUN_LOOP_OPT) $(FLAG_FUNROLL_LOOPS) $(FLAG_O3) $(FLAG_M3DNOW) $(FLAG_MARCH) $(FLAG_MFPMATH_SSE) $(FLAG_MMMX) $(FLAG_MPREFERRED_STACK_BOUNDARY) $(FLAG_MSSE) $(FLAG_MSSE2) $(FLAG_MSSE3) $(FLAG_MSSE4) $(FLAG_MTUNE) $(FLAG_WUNINITIALIZED) +endif +endif +# Add extra compilation flags and add source paths for include files +SW += $(CFLAGS) $(foreach dir,$(INCLUDE_DIR),$(addprefix -I,$(dir))) +# ============================================================================= +# Libraries flags +LIB_FLAGS += $(LIBS) $(LIBGMP) + +#============================================================================== +# Path rules for CC +CCFLAGS += $(patsubst %,-I%,$(subst :, ,$(INCLUDE_DIR) $(EXTRA_INCLUDE_DIR))) +CCFLAGS += $(patsubst %,-L%,$(subst :, ,$(LIB_DIR) $(EXTRA_LIBS_DIR))) + +#============================================================================== +#ifeq ($(OS),$(OSXMAC)) +#SHARED_FLAG := -dynamiclib +#endif +#ifeq ($(OS),$(LINUX)) +#SHARED_FLAG := -shared +#endif +#ifeq ($(OS),$(OSXMAC)) +#LD_ALL_OPTION := -Wl,-all_load +#LD_NOALL_OPTION := +#else +#LD_ALL_OPTION := -Wl,--whole-archive +#LD_NOALL_OPTION := -Wl,-no-whole-archive +#endif + +# ============================================================================= +# now we create the system includes to include in $(PACKAGE_NAME).h +TEMPLATE_HEADER := qstruct.h editor.h dstruct.h factor.h lpdefs.h readline.h lpdata.h basis.h dheaps_i.h \ + qsopt.h format.h rawlp.h mps.h price.h priority.h \ + ratio.h read_lp.h read_mps.h simplex.h write_lp.h \ + lib.h +HEADER_FILE := basicdefs.h urandom.h symtab.h reporter.h allocrus.h bgetopt.h zeit.h except.h qs_config.h +HEADER_FILE += $(foreach base,$(BASES),$(addprefix $(base)_,$(TEMPLATE_HEADER))) +HEADER_FILE += $(foreach base, $(BASES_GMP),$(addprefix $(base)_,$(TEMPLATE_HEADER))) +HEADER_FILE += $(foreach base, $(BASES_SOFTFLOAT),$(addprefix $(base)_,$(TEMPLATE_HEADER))) +HEADER_FILE += $(foreach base, $(BASES_LONG_DOUBLE),$(addprefix $(base)_,$(TEMPLATE_HEADER))) +HEADER_FILE += exact.h eg_exutil.h + +# ============================================================================= +# COnfiguration-dependant executables and objective files +ALL_FILE := $(SOURCE_FILE) $(MAIN_SFILE) $(HEADER_FILE) +ALL_OFILE := $(patsubst %.c,%.o,$(filter %c,$(addprefix $(OBJ_DIR)/,$(ALL_FILE)))) $(OBJ_DIR)/$(PACKAGE_NAME)_version.o +MAIN_PROG := $(addprefix $(BIN_DIR)/, $(notdir $(MAIN_SFILE:.c=))) +MAIN_PROG_DYN := $(addsuffix _dyn, $(MAIN_PROG)) +MAIN_PROG_ST := $(addsuffix _st, $(MAIN_PROG)) + +# end of Makefile.common +# ============================================================================= diff --git a/Makefile.library b/Makefile.library new file mode 100644 index 0000000..c311b16 --- /dev/null +++ b/Makefile.library @@ -0,0 +1,123 @@ +# ============================================================================= +# This is the Makefile.library of EGlib +# - 2007-12-27 +# - Separate template and library creation +# - 2007-12-20 +# - Update to create a full .h and improve support for x86_64 +# and mac OSX, and to generate a unified library interface +# - 2005-08-17 +# - Update EGlib.so rule +# - 2005-08-01 +# - Update to generate templates, and compute dependencies on the +# fly +# - 2003-11-18 +# - Update to automatic dependency generation +# ============================================================================= + +# ============================================================================= +# Here we read some configurations, you should edit this file instead +# of this makefile +include Makefile.common + +#============================================================================== +# Default targets to do +.PHONY: indent doc clean selftest default +DEFAULT += selftest $(LIB_DIR)/lib$(PACKAGE_NAME).a include/$(PACKAGE_NAME).h $(MAIN_PROG) +default: $(DEFAULT) +make.conf: ; +Makefile.library : ; + +#============================================================================== +# Some extra dependencies +$(OBJ_FILE): make.conf +$(MAIN_OFILE): make.conf + +#============================================================================== +# Rules for objective files +$(ALL_OFILE): $(OBJ_DIR)/%.o : %.c + @echo Compiling $< + @$(CC) $(SW) $(CCFLAGS) $(MAINOPT) -c $< -o $@ + +#============================================================================== +# check some stuff in here +selftest: + @if [ ! -d $(LIB_DIR) ]; then mkdir -p $(LIB_DIR); fi + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + @if [ ! -d $(DEP_DIR) ]; then mkdir -p $(DEP_DIR); fi + @if [ ! -d $(ALT_DIR) ]; then mkdir -p $(ALT_DIR); fi + @if [ ! -d $(BIN_DIR) ]; then mkdir -p $(BIN_DIR); fi + +# rule to force an action +FORCE: + +# ============================================================================= +# we should re-compile the version to correctly print the package version +# $(OBJ_DIR)/$(PACKAGE_NAME)_version.o: FORCE $(PACKAGE_NAME)_version.c +$(OBJ_DIR)/$(PACKAGE_NAME)_version.o : FORCE + +#============================================================================== +# include files for dependencies +include $(DEP_FILE) + +#============================================================================== +# Targets to be done + +doc: $(INC_FILE) $(SOURCE_FILE) $(DEP_FILE) Doxyfile + @echo "Generating Documentation..." && doxygen + +#ifeq ($(OS),$(OSXMAC)) +#SHARED_FLAG := -dynamiclib +#endif +#ifeq ($(OS),$(LINUX)) +#SHARED_FLAG := -shared +#endif + +$(LIB_DIR)/$(PACKAGE_NAME).so: $(OBJ_FILE) include/$(PACKAGE_NAME).h make.conf + @echo Linking $@ + @rm -f $@ + @$(CC) $(SW) -o $@ $(SHARED_FLAG) $(filter %.o,$^) $(CCFLAGS) + +$(LIB_DIR)/lib$(PACKAGE_NAME).a: $(OBJ_FILE) include/$(PACKAGE_NAME).h make.conf + @echo Linking $@ + @rm -f $@ $(LIB_DIR)/$(PACKAGE_NAME).a + @$(AR) cq $@ $(filter %.o,$^) + @$(RANLIB) $@ + @ln $@ $(LIB_DIR)/$(PACKAGE_NAME).a + +clean: + -@rm -Rf doc/* + -@rm -f $(ALL_OFILE) $(MAIN_PROG) $(MAIN_PROG_DYN) $(MAIN_PROG_ST) $(LIB_DIR)/lib$(PACKAGE_NAME).a $(LIB_DIR)/$(PACKAGE_NAME).so + -@rm -f include/$(PACKAGE_NAME).h + +IDENTFLAGS := -bli0 -i2 -lc79 -lps -sc -cdw -bfda -psl -nbc -npsl \ + -ut -ts2 -bad -bap -bl -l80 + +indent: + -@for j in $(SOURCE_DIR); do for i in $$j/*.c; do indent $$i -o _ind_ $(IDENTFLAGS) && mv _ind_ $$i && echo "Indenting $$i"; done ; done + -@for j in $(INCLUDE_DIR); do for i in $$j/*.h; do indent $$i -o _ind_ $(IDENTFLAGS) && mv _ind_ $$i && echo "Indenting $$i"; done; done + +$(MAIN_PROG): $(BIN_DIR)/% : %.o lib$(PACKAGE_NAME).a $(addsuffix .a,$(LIB_FILES)) + @echo Linking $@ + @$(CC) $(SW) $(INCLUDEDIR) $(MAINOPT) $< $(filter %.a,$^) $(CCFLAGS) $(LIB_FLAGS) $(LD_ALL_OPTION) $(LD_NOALL_OPTION) -o $@ + +$(MAIN_PROG_ST): $(BIN_DIR)/%_st : %.o lib$(PACKAGE_NAME).a $(addsuffix .a,$(LIB_FILES)) + @echo Linking $@ + @$(CC) -static -static-libgcc $(SW) $(INCLUDEDIR) $(MAINOPT) $< $(filter %.a,$^) $(LD_ALL_OPTION) $(filter %.so,$^) $(LIB_FLAGS) $(LD_NOALL_OPTION) $(CCFLAGS) -o $@ + +$(MAIN_PROG_DYN): $(BIN_DIR)/%_dyn : %.o lib$(PACKAGE_NAME).so $(addsuffix .so,$(LIB_FILES)) tags + @echo Linking $@ + @$(CC) $(SW) $(INCLUDEDIR) $(MAINOPT) $< $(filter %.so,$^) $(CCFLAGS) $(LIB_FLAGS) -o $@ + +include/$(PACKAGE_NAME).h: $(ALT_DIR)/base_$(PACKAGE_NAME).h make.conf $(CONFIG_HEADER) + @echo Building $@ + @rm -f $@ + @echo "/* ========================================================================== */" >> $@ + @echo "#ifndef __$(PACKAGE_NAME)__" >> $@ + @echo "#define __$(PACKAGE_NAME)__" >> $@ + @cat $(CONFIG_HEADER) >> $@ + @cat $(ALT_DIR)/base_$(PACKAGE_NAME).h >> $@ + @echo "/* ========================================================================== */" >> $@ + @echo "#endif" >> $@ + +# end of Makefile.library +# ============================================================================= diff --git a/Makefile.template b/Makefile.template new file mode 100644 index 0000000..ccbe511 --- /dev/null +++ b/Makefile.template @@ -0,0 +1,226 @@ +# ============================================================================= +# This is the Makefile.template from EGlib +# - 2007-12-27 +# - Separate template generation part +# - 2007-12-20 +# - Update to create a full .h and improve support for x86_64 +# and mac OSX, and to generate a unified library interface +# - 2005-08-17 +# - Update (PACKAGE_NAME).so rule +# - 2005-08-01 +# - Update to generate templates, and compute dependencies on the +# fly +# - 2003-11-18 +# - Update to automatic dependency generation +# ============================================================================= + +# ============================================================================= +# Here we read some configurations, you should edit this file instead +# of this makefile +include Makefile.common + +#============================================================================== +# Default targets to do +.PHONY: selftest default +DEFAULT += selftest +ifneq ($(REUSE_DEP),1) +DEFAULT += $(ALL_FILE_TEMPLATE) $(DEP_FILE) tags $(ALT_DIR)/$(PACKAGE_NAME)_version.c +endif +default: $(DEFAULT) + +# check some stuff in here +selftest: + @if [ ! -d $(LIB_DIR) ]; then mkdir -p $(LIB_DIR); fi + @if [ ! -d $(BIN_DIR) ]; then mkdir -p $(BIN_DIR); fi + @if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi + @if [ ! -d $(DEP_DIR) ]; then mkdir -p $(DEP_DIR); fi + @if [ ! -d $(ALT_DIR) ]; then mkdir -p $(ALT_DIR); fi + +# rule to force an action +FORCE: + +ifneq ($(REUSE_DEP),1) +# ============================================================================= +# This is a list of tags whose name shoud be changed while compiling +# different versions of template files +DO_CHANGE := MaxLpNum MinLpNum epsLpNum EGlpNumGetStr EGlpNumReadStr EGlpNumCeil EGlpNumFloor \ + EGlpNumInv zeroLpNum oneLpNum EGlpNumSet EGlpNumIsEqual EGlpNumIsEqqual \ + EGlpNumIsNeq EGlpNumIsNeqq EGlpNumIsNeqZero EGlpNumIsNeqqZero EGlpNumIsLess \ + EGlpNumIsSumLess EGlpNumIsDiffLess EGlpNumIsLessDbl EGlpNnumIsGreaDbl \ + EGlpNumIsLeq EGlpNumCopyDiffRatio EGlpNumCopyDiff EGlpNumCopySum EGlpNumCopy \ + EGlpNumSetToMaxAbs EGlpNumSetToMinAbs EGlpNumCopySqrOver EGlpNumCopyAbs \ + EGlpNumCopyNeg EGlpNumCopyFrac EGlpNumCopyArray EGlpNumSubInnProdTo \ + EGlpNumAddInnProdTo EGlpNumSubUiTo EGlpNumAddUiTo EGlpNumAddTo EGlpNumSubTo \ + EGlpNumMultTo EGlpNumDivTo EGlpNumDivUiTo EGlpNumMultUiTo EGlpNumZero \ + EGlpNumOne EGlpNumSign EGlpNumToLf EGlpNumAllocArray EGlpNumInitVar \ + EGlpNumInitVar EGlpNumClearVar EGlpNumReallocArray EGlpNumFreeArray \ + EGlpNumIsGreaDbl EGlpNumIsLessDbl EGutilPermSort EGlpNumInnProd \ + EGlpNumIsLessZero EGlpNumIsGreatZero + +# ============================================================================= +# This is a list of functions whose name shoudn't be changed while compiling +# different versions of templates +NO_CHANGE := main sscanf sprintf fprintf fprint ungetc perror parseargs \ + memset listen fscanf fflush fclose TRACE connect bind accept \ + time printf getrusage strcasecmp strncasecmp \ + NULL ILL_PTRWORLD_ROUTINES DEBUG ILL_IFTRACE itcnt_t + + +#============================================================================== +# This is to help simplify the makefile for the templates (I hope), note that +# TYPE_NUMBER should match the corresponding EGLPNUM_TYPE definition. +int32_% $(OBJ_DIR)/int32_% $(ALT_DIR)/int32_% $(DEP_DIR)/int32_% %.int32 : TYPE_AFFIX = int32 +int32_% $(OBJ_DIR)/int32_% $(ALT_DIR)/int32_% $(DEP_DIR)/int32_% %.int32 : TYPE_NAME = "int32_t" +int32_% $(OBJ_DIR)/int32_% $(ALT_DIR)/int32_% $(DEP_DIR)/int32_% %.int32 : TYPE_NUMBER = 14 +int_% $(OBJ_DIR)/int_% $(ALT_DIR)/int_% $(DEP_DIR)/int_% %.int : TYPE_AFFIX = int +int_% $(OBJ_DIR)/int_% $(ALT_DIR)/int_% $(DEP_DIR)/int_% %.int : TYPE_NAME = "int" +int_% $(OBJ_DIR)/int_% $(ALT_DIR)/int_% $(DEP_DIR)/int_% %.int : TYPE_NUMBER = 2 +dbl_% $(OBJ_DIR)/dbl_% $(ALT_DIR)/dbl_% $(DEP_DIR)/dbl_% %.dbl : TYPE_AFFIX = dbl +dbl_% $(OBJ_DIR)/dbl_% $(ALT_DIR)/dbl_% $(DEP_DIR)/dbl_% %.dbl : TYPE_NAME = "double" +dbl_% $(OBJ_DIR)/dbl_% $(ALT_DIR)/dbl_% $(DEP_DIR)/dbl_% %.dbl : TYPE_NUMBER = 0 +mpq_% $(OBJ_DIR)/mpq_% $(ALT_DIR)/mpq_% $(DEP_DIR)/mpq_% %.mpq : TYPE_AFFIX = mpq +mpq_% $(OBJ_DIR)/mpq_% $(ALT_DIR)/mpq_% $(DEP_DIR)/mpq_% %.mpq : TYPE_NAME = "mpq_t" +mpq_% $(OBJ_DIR)/mpq_% $(ALT_DIR)/mpq_% $(DEP_DIR)/mpq_% %.mpq : TYPE_NUMBER = 9 +mpf_% $(OBJ_DIR)/mpf_% $(ALT_DIR)/mpf_% $(DEP_DIR)/mpf_% %.mpf : TYPE_AFFIX = mpf +mpf_% $(OBJ_DIR)/mpf_% $(ALT_DIR)/mpf_% $(DEP_DIR)/mpf_% %.mpf : TYPE_NAME = "mpf_t" +mpf_% $(OBJ_DIR)/mpf_% $(ALT_DIR)/mpf_% $(DEP_DIR)/mpf_% %.mpf : TYPE_NUMBER = 10 +fp20_% $(OBJ_DIR)/fp20_% $(ALT_DIR)/fp20_% $(DEP_DIR)/fp20_% %.fp20 : TYPE_AFFIX = fp20 +fp20_% $(OBJ_DIR)/fp20_% $(ALT_DIR)/fp20_% $(DEP_DIR)/fp20_% %.fp20 : TYPE_NAME = "EGfp20_t" +fp20_% $(OBJ_DIR)/fp20_% $(ALT_DIR)/fp20_% $(DEP_DIR)/fp20_% %.fp20 : TYPE_NUMBER = 4 +ldbl_% $(OBJ_DIR)/ldbl_% $(ALT_DIR)/ldbl_% $(DEP_DIR)/ldbl_% %.ldbl : TYPE_AFFIX = ldbl +ldbl_% $(OBJ_DIR)/ldbl_% $(ALT_DIR)/ldbl_% $(DEP_DIR)/ldbl_% %.ldbl : TYPE_NAME = "long double" +ldbl_% $(OBJ_DIR)/ldbl_% $(ALT_DIR)/ldbl_% $(DEP_DIR)/ldbl_% %.ldbl : TYPE_NUMBER = 11 +float128_% $(OBJ_DIR)/float128_% $(ALT_DIR)/float128_% $(DEP_DIR)/float128_% %.float128 : TYPE_AFFIX = float128 +float128_% $(OBJ_DIR)/float128_% $(ALT_DIR)/float128_% $(DEP_DIR)/float128_% %.float128 : TYPE_NAME = "float128" +float128_% $(OBJ_DIR)/float128_% $(ALT_DIR)/float128_% $(DEP_DIR)/float128_% %.float128 : TYPE_NUMBER = 13 + +tags: $(ALL_FILE) $(TEMPLATE_SFILE) $(TEMPLATE_MAIN_SFILE) $(HEADER_FILE) $(CONFIG_HEADER) + @echo Building vi $@ + @$(CTAGS) $^ + +$(ALT_DIR)/$(PACKAGE_NAME)_version.c: $(CONFIG_HEADER) + @echo Creating $@ + @echo "#include \"qs_config.h\"" > $@ + @echo "#ifndef SVNVERSION" >> $@ + @echo "const char svn_$(PACKAGE_NAME)[]=\"release\";" >> $@ + @echo "#else" >> $@ + @echo "const char svn_$(PACKAGE_NAME)[]=SVNVERSION;" >> $@ + @echo "#endif" >> $@ + @echo "const char string_$(PACKAGE_NAME)[1024] = \"$(PACKAGE_VERSION)\";" >> $@ + @echo "const char date_$(PACKAGE_NAME)[1024] = __DATE__\"-\"__TIME__;" >> $@ + @echo "void $(PACKAGE_NAME)_version(void) __attribute__ ((constructor));" >> $@ + @echo "static int $(PACKAGE_NAME)_int = 0;" >> $@ + @echo "void $(PACKAGE_NAME)_version(void){if($(PACKAGE_NAME)_int == 0)fprintf(stderr,\"Using %s (SVN-version %s:%s, built %s)%s\",\"$(PACKAGE_NAME)\",string_$(PACKAGE_NAME),svn_$(PACKAGE_NAME),date_$(PACKAGE_NAME),EG_NEWLINE);$(PACKAGE_NAME)_int=1;}" >> $@ + +#============================================================================== +# Rules for dependencies files +# rule to make .d files +$(DEP_FILE): $(DEP_DIR)/%.d : % + @echo Making Dependencies for $< + @$(CC) -MG -MM -MF $@ -MT $@ -MT $(OBJ_DIR)/$(patsubst %.c.d,%.o,$(notdir $@)) \ + -MT tags $(SW) $(CPPFLAGS) $(MAINOPT) $< + +$(ALT_DIR)/int32_% : % tag.int32 + @echo Building $@ + @$(AWK) -f tag.int32 $< > $@ + +$(ALT_DIR)/int_% : % tag.int + @echo Building $@ + @$(AWK) -f tag.int $< > $@ + +$(ALT_DIR)/dbl_% : % tag.dbl + @echo Building $@ + @$(AWK) -f tag.dbl $< > $@ + +$(ALT_DIR)/fp20_% : % tag.fp20 + @echo Building $@ + @$(AWK) -f tag.fp20 $< > $@ + +$(ALT_DIR)/ldbl_%.h : %.h tag.ldbl + @echo Building $@ + @echo "#include \"qs_config.h\"" > $@ + @echo "#ifdef HAVE_LONG_DOUBLE" >> $@ + @echo "#if HAVE_LONG_DOUBLE" >> $@ + @$(AWK) -f tag.ldbl $< >> $@ + @echo "#endif" >> $@ + @echo "#endif" >> $@ + +$(ALT_DIR)/ldbl_%.c : %.c tag.ldbl + @echo Building $@ + @$(AWK) -f tag.ldbl $< > $@ + +$(ALT_DIR)/mpf_%.h : %.h tag.mpf + @echo Building $@ + @echo "#include \"qs_config.h\"" > $@ + @echo "#ifdef HAVE_LIBGMP" >> $@ + @echo "#if HAVE_LIBGMP" >> $@ + @$(AWK) -f tag.mpf $< >> $@ + @echo "#endif" >> $@ + @echo "#endif" >> $@ + +$(ALT_DIR)/mpf_%.c : %.c tag.mpf + @echo Building $@ + @$(AWK) -f tag.mpf $< > $@ + +$(ALT_DIR)/mpq_%.h : %.h tag.mpq + @echo Building $@ + @echo "#include \"qs_config.h\"" > $@ + @echo "#ifdef HAVE_LIBGMP" >> $@ + @echo "#if HAVE_LIBGMP" >> $@ + @$(AWK) -f tag.mpq $< >> $@ + @echo "#endif" >> $@ + @echo "#endif" >> $@ + +$(ALT_DIR)/mpq_%.c : %.c tag.mpq + @echo Building $@ + @$(AWK) -f tag.mpq $< > $@ + +$(ALT_DIR)/float128_%.h : %.h tag.float128 + @echo Building $@ + @echo "#include \"qs_config.h\"" > $@ + @echo "#ifdef HAVE_SOFTFLOAT" >> $@ + @echo "#if HAVE_SOFTFLOAT" >> $@ + @$(AWK) -f tag.float128 $< >> $@ + @echo "#endif" >> $@ + @echo "#endif" >> $@ + +$(ALT_DIR)/float128_%.c : %.c tag.float128 + @echo Building $@ + @$(AWK) -f tag.float128 $< > $@ + +$(ALT_DIR)/base_$(PACKAGE_NAME).h: $(HEADER_FILE) + @rm -f $@ + @echo Building $@ + @for i in $(filter %h,$^); do $(AWK) '{if($$1 != "#include") print $$0;}' $$i >> $@ ; done + +tag: $(ALL_TFILE) + @echo Making $@ + @$(CTAGS) -x --c-kinds=+xp-m --c++-kinds=+xp-m $^ | $(CUT) -d \ -f 1 | \ + $(UNIQ) > $@2; for j in $(NO_CHANGE); do $(GREP) -v -w $$j $@2 > $@3; \ + mv $@3 $@2; done; if [ ! -f $@ ]; then mv $@2 $@; else \ + val=`diff tag2 tag|wc -l`; if [ $$val -ne 0 ]; then mv $@2 $@; else rm $@2; \ + fi; fi + +$(foreach base,$(BASES_BASE),tag.$(base)) $(foreach base,$(BASES_GMP),tag.$(base)) $(foreach base,$(BASES_LONG_DOUBLE),tag.$(base)) $(foreach base,$(BASES_SOFTFLOAT),tag.$(base)): tag + @echo Making Awk preprocessor $@ + @rm -f $@; for i in `cat $<`; do \ + echo "/\<$$i\>/ {gsub(/\<$$i\>/,\"$(TYPE_AFFIX)_$$i\")};" >> $@; done;\ + for i in $(DO_CHANGE); do \ + echo "/\<$$i\>/ {gsub(/\<$$i\>/,\"$(TYPE_AFFIX)_$$i\")};" >> $@; done; \ + for i in $(ALL_TFILE); do \ + echo "/\<$$i\>/ {gsub(/\<$$i\>/,\"$(TYPE_AFFIX)_$$i\")};" >> $@; done; \ + echo "/\/ {gsub(/\/,\"$(TYPE_NAME)\")};">> $@; \ + echo "{print};" >> $@ + +clean: + -@rm -Rf $(ALL_FILE_TEMPLATE) tag $(foreach base,$(BASES),tag.$(base)) $(foreach base,$(BASES_GMP),tag.$(base)) $(foreach base,$(BASES_LONG_DOUBLE),tag.$(base)) $(foreach base,$(BASES_SOFTFLOAT),tag.$(base)) + -@rm -f $(DEP_FILE) tags $(ALT_DIR)/$(PACKAGE_NAME)_version.c $(ALT_DIR)/base_$(PACKAGE_NAME).h +else +clean: + + +endif + +# end of Makefile.template +# ============================================================================= + diff --git a/README b/README new file mode 100644 index 0000000..f40b7fb --- /dev/null +++ b/README @@ -0,0 +1,65 @@ + +NEEDED SOFTWARE: + +- GCC c compiler (gcc), porting to other C compilers have not been attempted + (if you succeed with other compilers please let me know). +- gawk (other versions of awk don't work, be advised), it has been tested with + GNU awk version 3.1.6 +- exuberant ctags (regular ctags don't work), it has been tested with + Exuberant Ctags 5.6, Copyright (C) 1996-2004 Darren Hiebert + Addresses: , http://ctags.sourceforge.net +- GNU MP (we have tested the 4.x.x and with 5.0.x version series without problem ), be aware + that you should compile and install a version using option + --enable-alloca=malloc-reentrant + to ensure no memory overwriting problems. +- EGlib you will need version 2.6.20 or later, and is available as a + subversion repository in + https://conexo.dii.uchile.cl/SVN/EGlib/EGlib2/tags/EGlib-2.6.20/ + or you can get the bleading edge version at + https://conexo.dii.uchile.cl/SVN/EGlib/EGlib2/trunk + or you can get the full source at + http://www.dii.uchile.cl/~daespino/ + Under EGlib, note that you should have installed before the previous programs, + and you should ensure that Makefile.common uses gawk and exuberant-ctags, also + you should edit make.conf and enable GMP support and SoftFloat support. +- libz to read/write gz-compresed files +- libbz2 to read/write bz2-compresed files + +INSTALLING + + After installing all pre-requisites, ensure that Makefile.common uses + gawk and exuberant-ctags, also you should edit make.conf to ensure that + proper paths are suplied, an example make.conf.default is provided. + + Set-up path and locations of needed software (see --help for options) + + ./configure + + Then just type + + make + you will generate several executables. The main solver + is named esolver or esolver_dyn (depending on compilation options), to force + the generation of a static binary type + make -f Makefile.library esolver + +USING IT AS A LIBRARY + To see an example of how to use this software as a C library, see the file + src/esolver.c or the file SLoan_LPs/eg_sloan.h, the library is provided in + shared and static form, they are mamed lib/QSopt_ex.so and lib/QSopt_ex.a + and the main include file is called include/QSopt_ex.h + A simple example showing the basic functions and details of using mpq_t types + is shown in src/demo_qs.c + +NOTES + You could use the release version that is MUCH simpler to compile, se the + webpage and https://conexo.dii.uchile.cl/SVN/ESolver/tags/QSopt_ex-2.5.8 + +COMMENTS + + As usual, no waranties are made about the software, see the LICNECE file. + For comments or questions send an e-mail to daespino __at__ gmail __dot__ com + +ISSUES/KNOWN BUGS + + It seems that reading LPs with maximizing objective functions is broken, check if that is the case for your problem diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..832204a --- /dev/null +++ b/configure.ac @@ -0,0 +1,851 @@ +AC_PREREQ(2.61) +# define a svn version string to use in the package versioning +# define([svnversion], esyscmd([sh -c "svnversion|tr -d '\n'"]))dnl +AC_INIT([[QSopt_ex]], [2.5.10], [daespino@gmail.com]) +# by default, don't set any flag for the compiler +: ${CFLAGS=""} +#AC_DEFINE(SVN_REVISION, "svnversion", [SVN Revision]) +AC_DEFINE([_XOPEN_SOURCE],[600],[Required for correct definition of functions like exp2]) + +AC_CONFIG_HEADER([config.h]) +AC_CONFIG_FILES([make.conf]) +AC_USE_SYSTEM_EXTENSIONS +# ====================================================================== +# Checks for programs. +AC_PROG_AWK +AC_PROG_CC +AC_PROG_RANLIB +AC_PROG_GREP +AC_LANG(C) + +# ====================================================================== +# optional packages to use +# ====================================================================== +AC_ARG_WITH( + [EGlib-lib-dir], + [AS_HELP_STRING([--with-EGlib-lib-dir=DIR],[specify where to look for @<:@EGLIB_NAME@:>@.a])], + [ AC_SUBST([EXTRA_LIBS_DIR],["$EXTRA_LIBS_DIR $with_EGlib_lib_dir"]) + AC_SUBST([LDFLAGS],["$LDFLAGS -L $with_EGlib_lib_dir"])]) +AC_ARG_WITH( + [EGlib-include-dir], + [AS_HELP_STRING([--with-EGlib-include-dir=DIR],[specify where to look for @<:@EGLIB_NAME@:>@.h])], + [ AC_SUBST([CPPFLAGS],["$CPPFLAGS -I $with_EGlib_include_dir"]) + AC_SUBST([EXTRA_INCLUDE_DIR],["$EXTRA_INCLUDE_DIR $with_EGlib_include_dir"])]) +AC_ARG_WITH( + [EGlib-name], + [AS_HELP_STRING([--with-EGlib-name],[specify base name for EGlib @<:@default=EGlib@:>@ ])], + [],[with_EGlib_name=EGlib]) +AC_SUBST([EGLIB_NAME],["$with_EGlib_name"]) +# ====================================================================== +AC_ARG_WITH( + [gmp-lib-dir], + [AS_HELP_STRING([--with-gmp-lib-dir],[specify where to look for -lgmp])], + [ AC_SUBST([LDFLAGS],["$LDFLAGS -L $with_gmp_lib_dir"]) + AC_SUBST([EXTRA_LIBS_DIR],["$EXTRA_LIBS_DIR $with_gmp_lib_dir"])]) +AC_ARG_WITH( + [gmp-include-dir], + [AS_HELP_STRING([--with-gmp-include-dir],[specify where to look for gmp.h])], + [ AC_SUBST([CPPFLAGS],["$CPPFLAGS -I $with_gmp_include_dir"]) + AC_SUBST([EXTRA_INCLUDE_DIR],["$EXTRA_INCLUDE_DIR $with_gmp_include_dir"])]) +AC_ARG_WITH( [gmp], [AS_HELP_STRING( [--with-gmp], [support gnump templates @<:@defaukt=check@:>@]) ], [], [with_gmp=check]) +AS_IF( + [test "x$with_gmp" != xno], + [AC_CHECK_LIB( + [gmp], + [__gmpz_add], + [AC_SUBST( [LIBGMP], ["-lgmp"]) + AC_SUBST([ENABLE_LIBGMP],[1]) + AC_DEFINE( [HAVE_LIBGMP], [1], [Define if you have libgmp]) + ],[ + AC_SUBST([ENABLE_LIBGMP],[0]) + if test "x$with_gmp" != xcheck; then + AC_MSG_FAILURE([--with-gmp was given, but test for gmp failed]) fi ], ["-lgmp"])]) +# ====================================================================== +# gcc-based debug flags +AC_ARG_ENABLE([debug],[AS_HELP_STRING([--enable-debug],[use GCC debug comilation flags and support -ggdb3 @<:@default=yes@:>@])],[enable_debug=$enableval],[enable_debug=yes]) +AS_IF( + [test "x$enable_debug" != xno], + [AC_SUBST([ENABLE_DEBUG],[1])], + [AC_SUBST([ENABLE_DEBUG],[0])]) +# ====================================================================== +# compilation-time debug level +AC_ARG_ENABLE([debug-level],[AS_HELP_STRING([--enable-debug-level],[fix debug-level for compile-time routines @<:@default=1@:>@])],[enable_debug_level=$enableval],[enable_debug_level=1]) +AC_DEFINE_UNQUOTED([DEBUG],[$enable_debug_level],[Compilation-time debug level]) +# ====================================================================== +# check for long double support +AC_ARG_ENABLE([long-double],[AS_HELP_STRING([--enable-long-double],[support long double (if present in the system) @<:@default=yes@:>@])],[],[enable_long_double=yes]) +AS_IF( + [test "x$enable_long_double" != xno], + [AC_DEFINE([ENABLE_LONG_DOUBLE],[1],[Define to one if yiu want long double support (if present in the system)]) + AC_SUBST([ENABLE_LONG_DOUBLE],[1])], + [AC_SUBST([ENABLE_LONG_DOUBLE],[0])]) +# ====================================================================== +# gcc-based optimization flags +AC_ARG_ENABLE([optimize],[AS_HELP_STRING([--enable-optimize],[use GCC optimization comilation flags @<:@default=yes@:>@])],[],[enable_optimize=yes]) +AS_IF( + [test "x$enable_optimize" != xno], + [AC_SUBST([ENABLE_OPTIMIZE],[1])], + [AC_SUBST([ENABLE_OPTIMIZE],[0])]) +# ====================================================================== +# define if re-use pre-generated dependencies +AC_ARG_ENABLE([reuse-dep],[AS_HELP_STRING([--enable-reuse-dep],[Enable re-using reviously generated dependencies (recomended) @<:@default=yes@:>@])],[],[enable_reuse_dep=yes]) +AS_IF( + [test "x$enable_reuse_dep" != "xno"], + [AC_SUBST([REUSE_DEP],[1])], + [AC_SUBST([REUSE_DEP],[0])]) +# ====================================================================== +# check for softfloat support +AC_ARG_ENABLE([softfloat],[AS_HELP_STRING([--enable-softfloat],[support software-based 128-bit floating point numbers @<:@default=no@:>@])],[],[enable_softfloat=no]) +AS_IF( + [test "x$enable_softfloat" != xno], + [AC_DEFINE([HAVE_SOFTFLOAT],[1],[Define to one if you want software-based 128-bit floating point numbers]) + AC_SUBST([ENABLE_SOFTFLOAT],[1])], + [AC_SUBST([ENABLE_SOFTFLOAT],[0])]) +# ====================================================================== +# compilation-time verbose level +AC_ARG_ENABLE([verbose-level],[AS_HELP_STRING([--enable-verbose-level],[fix verbose-level for compile-time routines @<:@default=100@:>@])],[],[enable_verbose_level=100]) +AC_DEFINE_UNQUOTED([VERBOSE_LEVEL],[$enable_verbose_level],[Compilation-time verbose level]) +# ====================================================================== +# Checks for libraries. +AC_CHECK_LIB(z, gzopen, [], AC_MSG_NOTICE([Compiling without libz.]), []) +AC_CHECK_LIB(bz2, BZ2_bzopen, [], AC_MSG_NOTICE([Compiling without libbz2.]), []) +# find math library +AC_CHECK_LIB([m], [pow]) +# +AC_CHECK_LIB([nsl], [y_bind]) +# thread library +AC_CHECK_LIB([pthread], [pthread_mutex_lock]) +# resolve library +AC_CHECK_LIB([resolv], [_gethtbyname]) +AC_CHECK_LIB([$with_EGlib_name],[EGlib_version],[AC_SUBST([LIBS],["$LIBS -l$with_EGlib_name"])],[AC_MSG_ERROR([Could not find -l$wih_EGlib_name, please specify base-name and library path])]) + +# ====================================================================== +# Checking for supported compiler flags (taken from valgrind 3.5.0) +# ====================================================================== +# does this compiler support -fforce-addr ? +AC_MSG_CHECKING([if gcc accepts -fforce-addr]) +safe_CFLAGS=$CFLAGS +CFLAGS="-fforce-addr" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_FFORCE_ADDR="-fforce-addr"; AC_MSG_RESULT([yes]) ], + [ FLAG_FFORCE_ADDR=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_FFORCE_ADDR) + +# ====================================================================== +# does this compiler support -finline-limit=1000000 ? +AC_MSG_CHECKING([if gcc accepts -finline-limit=1000000]) +safe_CFLAGS=$CFLAGS +CFLAGS="-finline-limit=1000000" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_FINLINE_LIMIT="-finline-limit=1000000"; AC_MSG_RESULT([yes]) ], + [ FLAG_FINLINE_LIMIT=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_FINLINE_LIMIT) + +# ====================================================================== +# does this compiler support -frerun-cse-after-loop ? +AC_MSG_CHECKING([if gcc accepts -frerun-cse-after-loop]) +safe_CFLAGS=$CFLAGS +CFLAGS="-frerun-cse-after-loop" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_FRERUN_CSE_AFTER_LOOP="-frerun-cse-after-loop"; AC_MSG_RESULT([yes]) ], + [ FLAG_FRERUN_CSE_AFTER_LOOP=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_FRERUN_CSE_AFTER_LOOP) + +# ====================================================================== +# does this compiler support -frerun-loop-opt ? +AC_MSG_CHECKING([if gcc accepts -frerun-loop-opt]) +safe_CFLAGS=$CFLAGS +CFLAGS="-frerun-loop-opt" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_FRERUN_LOOP_OPT="-frerun-loop-opt"; AC_MSG_RESULT([yes]) ], + [ FLAG_FRERUN_LOOP_OPT=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_FRERUN_LOOP_OPT) + +# ====================================================================== +# does this compiler support -funroll-loops ? +AC_MSG_CHECKING([if gcc accepts -funroll-loops]) +safe_CFLAGS=$CFLAGS +CFLAGS="-funroll-loops" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_FUNROLL_LOOPS="-funroll-loops"; AC_MSG_RESULT([yes]) ], + [ FLAG_FUNROLL_LOOPS=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_FUNROLL_LOOPS) + +# ====================================================================== +# does this compiler support -ggdb3 ? +AC_MSG_CHECKING([if gcc accepts -ggdb3 -ggdb or -g]) +safe_CFLAGS=$CFLAGS +CFLAGS="-ggdb3" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_GGDB3="-ggdb3"; AC_MSG_RESULT([-ggdb3]) ], + [ CFLAGS="-ggdb" + AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_GGDB3="-ggdb"; AC_MSG_RESULT([-ggdb])], + [ CFLAGS="-g" + AC_TRY_COMPILE(, + [ return 0;], + [ FLAG_GGDB3="-g"; AC_MSG_RESULT([-g])], + [ FLAG_GGDB3=""; AC_MSG_RESULT([not supported])]) + ]) + ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_GGDB3) + +# ====================================================================== +# does this compiler support -m32 ? +AC_MSG_CHECKING([if gcc accepts -m32]) +safe_CFLAGS=$CFLAGS +CFLAGS="-m32" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_M32="-m32"; AC_MSG_RESULT([yes]) ], + [ FLAG_M32=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_M32) + +# ====================================================================== +# does this compiler support -m3dnow ? +AC_MSG_CHECKING([if gcc accepts -m3dnow]) +safe_CFLAGS=$CFLAGS +CFLAGS="-m3dnow" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_M3DNOW="-m3dnow"; AC_MSG_RESULT([yes]) ], + [ FLAG_M3DNOW=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_M3DNOW) + +# ====================================================================== +# does this compiler support -maix32 ? +AC_MSG_CHECKING([if gcc accepts -maix32]) +safe_CFLAGS=$CFLAGS +CFLAGS="-maix32" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MAIX32="-maix32"; AC_MSG_RESULT([yes]) ], + [ FLAG_MAIX32=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MAIX32) + +# ====================================================================== +# does this compiler support -m64 ? +AC_MSG_CHECKING([if gcc accepts -m64]) +safe_CFLAGS=$CFLAGS +CFLAGS="-m64" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_M64="-m64"; AC_MSG_RESULT([yes]) ], + [ FLAG_M64=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_M64) + +# ====================================================================== +# does this compiler support -maix64 ? +AC_MSG_CHECKING([if gcc accepts -maix64]) +safe_CFLAGS=$CFLAGS +CFLAGS="-maix64" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MAIX64="-maix64"; AC_MSG_RESULT([yes]) ], + [ FLAG_MAIX64=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MAIX64) + +# ====================================================================== +# does this compiler support -march=native ? +AC_MSG_CHECKING([if gcc accepts -march=native]) +safe_CFLAGS=$CFLAGS +CFLAGS="-march=native" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MARCH="-march=native"; AC_MSG_RESULT([yes]) ], + [ FLAG_MARCH=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MARCH) + +# ====================================================================== +# does this compiler support -mfpmath=sse ? +AC_MSG_CHECKING([if gcc accepts -mfpmath=sse]) +safe_CFLAGS=$CFLAGS +CFLAGS="-mfpmath=sse" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MFPMATH_SSE="-mfpmath=sse"; AC_MSG_RESULT([yes]) ], + [ FLAG_MFPMATH_SSE=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MFPMATH_SSE) + +# ====================================================================== +# does this compiler support -mmmx ? +AC_MSG_CHECKING([if gcc accepts -mmmx]) +safe_CFLAGS=$CFLAGS +CFLAGS="-mmmx" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MMMX="-mmmx"; AC_MSG_RESULT([yes]) ], + [ FLAG_MMMX=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MMMX) + +# ====================================================================== +# does this compiler support -mpreferred-stack-boundary=4 ? +AC_MSG_CHECKING([if gcc accepts -mpreferred-stack-boundary]) +safe_CFLAGS=$CFLAGS +CFLAGS="-mpreferred-stack-boundary=4" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MPREFERRED_STACK_BOUNDARY="-mpreferred-stack-boundary=4"; + AC_MSG_RESULT([yes]) ], + [ FLAG_MPREFERRED_STACK_BOUNDARY=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MPREFERRED_STACK_BOUNDARY) + +# ====================================================================== +# does this compiler support -msse ? +AC_MSG_CHECKING([if gcc accepts -msse]) +safe_CFLAGS=$CFLAGS +CFLAGS="-msse" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MSSE="-msse"; AC_MSG_RESULT([yes]) ], + [ FLAG_MSSE=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MSSE) + +# ====================================================================== +# does this compiler support -msse2 ? +AC_MSG_CHECKING([if gcc accepts -msse2]) +safe_CFLAGS=$CFLAGS +CFLAGS="-msse2" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MSSE2="-msse2"; AC_MSG_RESULT([yes]) ], + [ FLAG_MSSE2=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MSSE2) + +# ====================================================================== +# does this compiler support -msse3 ? +AC_MSG_CHECKING([if gcc accepts -msse3]) +safe_CFLAGS=$CFLAGS +CFLAGS="-msse3" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MSSE3="-msse3"; AC_MSG_RESULT([yes]) ], + [ FLAG_MSSE3=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MSSE3) + +# ====================================================================== +# does this compiler support -msse4 ? +AC_MSG_CHECKING([if gcc accepts -msse4]) +safe_CFLAGS=$CFLAGS +CFLAGS="-msse4" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MSSE4="-msse4"; AC_MSG_RESULT([yes]) ], + [ FLAG_MSSE4=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MSSE4) + +# ====================================================================== +# does this compiler support -mtune ? +AC_MSG_CHECKING([if gcc accepts -mtune=native]) +safe_CFLAGS=$CFLAGS +CFLAGS="-mtune=native" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_MTUNE="-mtune=native"; AC_MSG_RESULT([yes]) ], + [ FLAG_MTUNE=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_MTUNE) + +# ====================================================================== +# does this compiler support -O3 ? +AC_MSG_CHECKING([if gcc accepts -O3]) +safe_CFLAGS=$CFLAGS +CFLAGS="-O3" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_O3="-O3"; + AC_MSG_RESULT([yes]) ], + [ FLAG_O3=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_O3) +# ====================================================================== +# does this compiler support -std=gnu89 ? +AC_MSG_CHECKING([if gcc accepts -std=gnu89]) +safe_CFLAGS=$CFLAGS +CFLAGS="-std=gnu89" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_STD_GNU89="-std=gnu89"; + AC_MSG_RESULT([yes]) ], + [ FLAG_STD_GNU89=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_STD_GNU89) + +# ====================================================================== +# does this compiler support -Wall ? +AC_MSG_CHECKING([if gcc accepts -Wall]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wall" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WALL="-Wall"; AC_MSG_RESULT([yes]) ], + [ FLAG_WALL=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WALL) + +# ====================================================================== +# does this compiler support -Wbad-function-cast ? +AC_MSG_CHECKING([if gcc accepts -Wbad-function-cast]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wbad-function-cast" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WBAD_FUNCTION_CAST="-Wbad-function-cast"; AC_MSG_RESULT([yes]) ], + [ FLAG_WBAD_FUNCTION_CAST=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WBAD_FUNCTION_CAST) + +# ====================================================================== +# does this compiler support -Wcast-equal ? +AC_MSG_CHECKING([if gcc accepts -Wcast-equal]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wcast-equal" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WCAST_EQUAL="-Wundef"; AC_MSG_RESULT([yes]) ], + [ FLAG_WCAST_EQUAL=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WCAST_EQUAL) + +# ====================================================================== +# does this compiler support -Wdeclaration-after-statement ? +AC_MSG_CHECKING([if gcc accepts -Wdeclaration-after-statement]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wdeclaration-after-statement" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WDECLARATION_AFTER_STATEMENT="-Wdeclaration-after-statement"; AC_MSG_RESULT([yes]) ], + [ FLAG_WDECLARATION_AFTER_STATEMENT=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WDECLARATION_AFTER_STATEMENT) + +# ====================================================================== +# does this compiler support -Wextra or the older -W ? +AC_MSG_CHECKING([if gcc accepts -Wextra or -W]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wextra" +AC_TRY_COMPILE(, + [ return 0; ], + [ AC_SUBST([FLAG_WEXTRA], [-Wextra]) + AC_MSG_RESULT([-Wextra]) ], + [ CFLAGS="-W" + AC_TRY_COMPILE(, + [ return 0; ], + [ AC_SUBST([FLAG_WEXTRA], [-W]) + AC_MSG_RESULT([-W]) ], + [ AC_SUBST([FLAG_WEXTRA], []) + AC_MSG_RESULT([not supported]) ]) + ]) +CFLAGS=$safe_CFLAGS + +# ====================================================================== +# does this compiler support -Wfloat-equal ? +AC_MSG_CHECKING([if gcc accepts -Wfloat-equal]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wfloat-equal" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WFLOAT_EQUAL="-Wfloat-equal"; AC_MSG_RESULT([yes]) ], + [ FLAG_WFLOAT_EQUAL=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WFLOAT_EQUAL) + +# ====================================================================== +# does this compiler support -Winline ? +AC_MSG_CHECKING([if gcc accepts -Winline]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Winline" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WINLINE="-Winline"; AC_MSG_RESULT([yes]) ], + [ FLAG_WINLINE=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WINLINE) + +# ====================================================================== +# does this compiler support -Wnexted-externs ? +AC_MSG_CHECKING([if gcc accepts -Wnexted-externs]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wnexted-externs" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WNESTED_EXTERNS="-Wnexted-externs"; AC_MSG_RESULT([yes]) ], + [ FLAG_WNESTED_EXTERNS=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WNESTED_EXTERNS) + +# ====================================================================== +# does this compiler support -Wno-empty-body ? +AC_MSG_CHECKING([if gcc accepts -Wno-empty-body]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wno-empty-body" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WNO_EMPTY_BODY="-Wno-empty-body"; AC_MSG_RESULT([yes]) ], + [ FLAG_WNO_EMPTY_BODY=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WNO_EMPTY_BODY) + +# ====================================================================== +# does this compiler support -Wno-pointer-sign ? +AC_MSG_CHECKING([if gcc accepts -Wno-pointer-sign]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wno-pointer-sign" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WNO_POINTER_SIGN="-Wno-pointer-sign"; AC_MSG_RESULT([yes]) ], + [ FLAG_WNO_POINTER_SIGN=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WNO_POINTER_SIGN) + +# ====================================================================== +# does this compiler support -Wno-format-zero-length ? +AC_MSG_CHECKING([if gcc accepts -Wno-format-zero-length]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wno-format-zero-length" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WNO_FORMAT_ZERO_LENGTH="-Wno-format-zero-length"; AC_MSG_RESULT([yes]) ], + [ FLAG_WNO_FORMAT_ZERO_LENGTH=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WNO_FORMAT_ZERO_LENGTH) + +# ====================================================================== +# does this compiler support -Wno-uninitialized ? +AC_MSG_CHECKING([if gcc accepts -Wno-uninitialized]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wno-uninitialized" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WNO_UNINITIALIZED="-Wno-uninitialized"; AC_MSG_RESULT([yes]) ], + [ FLAG_WNO_UNINITIALIZED=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WNO_UNINITIALIZED) + +# ====================================================================== +# does this compiler support -Wpointer-arith ? +AC_MSG_CHECKING([if gcc accepts -Wpointer-arith]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wpointer-arith" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WPOINTER_ARITH="-Wpointer-arith"; AC_MSG_RESULT([yes]) ], + [ FLAG_WPOINTER_ARITH=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WPOINTER_ARITH) + +# ====================================================================== +# does this compiler support -Wshadow ? +AC_MSG_CHECKING([if gcc accepts -Wshadow]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wshadow" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WSHADOW="-Wshadow"; AC_MSG_RESULT([yes]) ], + [ FLAG_WSHADOW=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WSHADOW) + +# ====================================================================== +# does this compiler support -Wsign-compare ? +AC_MSG_CHECKING([if gcc accepts -Wsign-compare]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wsign-compare" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WSIGN_COMPARE="-Wsign-compare"; AC_MSG_RESULT([yes]) ], + [ FLAG_WSIGN_COMPARE=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WSIGN_COMPARE) + +# ====================================================================== +# does this compiler support -Wstrict-prototypes ? +AC_MSG_CHECKING([if gcc accepts -Wstrict-prototypes]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wstrict-prototypes" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WSTRICT_PROTOTYPES="-Wstrict-prototypes"; AC_MSG_RESULT([yes]) ], + [ FLAG_WSTRICT_PROTOTYPES=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WSTRICT_PROTOTYPES) + +# ====================================================================== +# does this compiler support -Wundef ? +AC_MSG_CHECKING([if gcc accepts -Wundef]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wundef" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WUNDEF="-Wundef"; AC_MSG_RESULT([yes]) ], + [ FLAG_WUNDEF=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WUNDEF) + +# ====================================================================== +# does this compiler support -Wuninitialized ? +AC_MSG_CHECKING([if gcc accepts -Wuninitialized]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wuninitialized" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WUNINITIALIZED="-Wuninitialized"; AC_MSG_RESULT([yes]) ], + [ FLAG_WUNINITIALIZED=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WUNINITIALIZED) + +# ====================================================================== +# does this compiler support -Wunused-function ? +AC_MSG_CHECKING([if gcc accepts -Wunused-function]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wunused-function" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WUNUSED_FUNCTION="-Wunused-function"; AC_MSG_RESULT([yes]) ], + [ FLAG_WUNUSED_FUNCTION=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WUNUSED_FUNCTION) + +# ====================================================================== +# does this compiler support -Wunused-label ? +AC_MSG_CHECKING([if gcc accepts -Wunused-label]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wunused-label" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WUNUSED_LABEL="-Wunused-label"; AC_MSG_RESULT([yes]) ], + [ FLAG_WUNUSED_LABEL=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WUNUSED_LABEL) + +# ====================================================================== +# does this compiler support -Wunused-value ? +AC_MSG_CHECKING([if gcc accepts -Wunused-value]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wunused-value" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WUNUSED_VALUE="-Wunused-value"; AC_MSG_RESULT([yes]) ], + [ FLAG_WUNUSED_VALUE=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WUNUSED_VALUE) + +# ====================================================================== +# does this compiler support -Wunused-variable ? +AC_MSG_CHECKING([if gcc accepts -Wunused-variable]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wunused-variable" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WUNUSED_VARIABLE="-Wunused-variable"; AC_MSG_RESULT([yes]) ], + [ FLAG_WUNUSED_VARIABLE=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WUNUSED_VARIABLE) + +# ====================================================================== +# does this compiler support -Wunused-parameter ? +AC_MSG_CHECKING([if gcc accepts -Wunused-parameter]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wunused-parameter" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WUNUSED_PARAMETER="-Wunused-parameter"; AC_MSG_RESULT([yes]) ], + [ FLAG_WUNUSED_PARAMETER=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WUNUSED_PARAMETER) + +# ====================================================================== +# does this compiler support -Wwrite-strings ? +AC_MSG_CHECKING([if gcc accepts -Wwrite-strings]) +safe_CFLAGS=$CFLAGS +CFLAGS="-Wwrite-strings" +AC_TRY_COMPILE(, + [ return 0; ], + [ FLAG_WWRITE_STRINGS="-Wwrite-strings"; AC_MSG_RESULT([yes]) ], + [ FLAG_WWRITE_STRINGS=""; AC_MSG_RESULT([no]) ]) +CFLAGS=$safe_CFLAGS +AC_SUBST(FLAG_WWRITE_STRINGS) + +# ====================================================================== +# Checks for header files. +AC_HEADER_STDC +AC_HEADER_TIME +AC_CHECK_HEADERS(sys/time.h time.h stdio.h sys/types.h sys/stat.h stdlib.h stddef.h string.h strings.h inttypes.h stdint.h unistd.h limits.h errno.h assert.h malloc.h fcntl.h signal.h sys/socket.h netinet/in.h netdb.h sys/resource.h sys/param.h sys/times.h float.h zlib.h bzlib.h stdarg.h gmp.h math.h sys/utsname.h EGlib.h setjmp.h) +AC_DEFUN([EG_INCLUDES],[ + #define _XOPEN_SOURCE 600 + #ifdef TIME_WITH_SYS_TIME + # include + # include + #else + # ifdef HAVE_SYS_TIME_H + # include + # else + # include + # endif + #endif + #ifdef HAVE_STDIO_H + #include + #endif + #ifdef HAVE_SYS_TYPES_H + # include + #endif + #ifdef HAVE_SYS_STAT_H + # include + #endif + #ifdef STDC_HEADERS + # include + # include + #else + # ifdef HAVE_STDLIB_H + # include + # endif + # ifdef HAVE_STDDEF_H + # include + #endif + #endif + #ifdef HAVE_STRING_H + # if !defined STDC_HEADERS && defined HAVE_MEMORY_H + # include + # endif + # include + #endif + #ifdef HAVE_STRINGS_H + # include + #endif + #ifdef HAVE_INTTYPES_H + # include + #endif + #ifdef HAVE_STDINT_H + # include + #endif + #ifdef HAVE_UNISTD_H + # include + #endif + #ifdef HAVE_LIMITS_H + # include + #endif + #ifdef HAVE_ERRNO_H + # include + #endif + #ifdef HAVE_ASSERT_H + # include + #endif + #ifdef HAVE_MALLOC_H + # include + #endif + #ifdef HAVE_FCNTL_H + # include + #endif + #ifdef HAVE_SIGNAL_H + # include + #endif + #ifdef HAVE_SYS_SOCKET_H + # include + #endif + #ifdef HAVE_NETINET_IN_H + # include + #endif + #ifdef HAVE_NETDB_H + # include + #endif + #ifdef HAVE_SYS_RESOURCE_H + # include + #endif + #ifdef HAVE_SYS_PARAM_H + # include + #endif + #ifdef HAVE_SYS_TIMES_H + # include + #endif + #ifdef HAVE_FLOAT_H + # include + #endif + #ifdef HAVE_ZLIB_H + # include + #endif + #ifdef HAVE_BZLIB_H + # include + #endif + #ifdef HAVE_STDARG_H + # include + #endif + #ifdef HAVE_GMP_H + # include + #endif + #ifdef HAVE_MATH_H + # include + #endif + #ifdef HAVE_SYS_UTSNAME_H + # include + #endif + #ifdef HAVE_SETJMP_H + # include + #endif + ]) +# ====================================================================== +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_C_VOLATILE +AC_C_RESTRICT +AC_C_TYPEOF +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_INT8_T +AC_TYPE_PID_T +AC_TYPE_SIGNAL +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T +AC_TYPE_LONG_DOUBLE +AS_IF([test "x$ac_cv_type_long_double" != xno],[AC_SUBST([HAVE_LONG_DOUBLE],[1])],[AC_SUBST([HAVE_LONG_DOUBLE],[0])]) +AC_CHECK_TYPES([gzFile, BZFILE*],[],[],[EG_INCLUDES]) +# ====================================================================== +# check declaration of some functions +AC_CHECK_DECLS([gzopen, gzeof, gzerror, gzclose, gzgets, gzwrite],[],[],[EG_INCLUDES]) +AC_CHECK_DECLS([BZ2_bzopen, BZ2_bzerror, BZ2_bzclose, BZ2_bzread, BZ2_bzwrite],[],[],[EG_INCLUDES]) +# ====================================================================== +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_FUNC_REALLOC +AC_FUNC_STRTOD +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([floor gethostbyname memset pow socket sqrt strdup strerror uname posix_memalign sleep getrusage times clock sigaction signal]) +# ====================================================================== +# test for +AS_IF([test \(\("x$with_gmp" = xyes\) -a \("x$ac_cv_have_header_gmp_h" != xyes\)\)],[AC_ERROR([You need gmp.h (usually in gmp-dev package) in order to compile gmp support for EGlib, or specify the correct include path])]) +# ====================================================================== +# print output files +AS_IF([test "x$ac_cv_header_EGlib_h" != xyes],[AC_MSG_ERROR([We need EGlib.h to compile])],[AC_MSG_NOTICE([Using EGlib.h])]) +AC_OUTPUT diff --git a/make.conf.in b/make.conf.in new file mode 100644 index 0000000..2282ad0 --- /dev/null +++ b/make.conf.in @@ -0,0 +1,84 @@ +# ====================================================================== +# base make.conf.in file for EGlib +# ====================================================================== +CONFIG_HEADER = config.h +EGLIB_NAME = @EGLIB_NAME@ +AWK = @AWK@ +GREP = @GREP@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXTRA_INCLUDE_DIR = @EXTRA_INCLUDE_DIR@ +EXTRA_LIBS_DIR = @EXTRA_LIBS_DIR@ +FLAG_FFORCE_ADDR = @FLAG_FFORCE_ADDR@ +FLAG_FINLINE_LIMIT = @FLAG_FINLINE_LIMIT@ +FLAG_FRERUN_CSE_AFTER_LOOP = @FLAG_FRERUN_CSE_AFTER_LOOP@ +FLAG_FRERUN_LOOP_OPT = @FLAG_FRERUN_LOOP_OPT@ +FLAG_FUNROLL_LOOPS = @FLAG_FUNROLL_LOOPS@ +FLAG_GGDB3 = @FLAG_GGDB3@ +FLAG_M32 = @FLAG_M32@ +FLAG_M3DNOW = @FLAG_M3DNOW@ +FLAG_M64 = @FLAG_M64@ +FLAG_MAIX32 = @FLAG_MAIX32@ +FLAG_MAIX64 = @FLAG_MAIX64@ +FLAG_MARCH = @FLAG_MARCH@ +FLAG_MFPMATH_SSE = @FLAG_MFPMATH_SSE@ +FLAG_MMMX = @FLAG_MMMX@ +FLAG_MPREFERRED_STACK_BOUNDAR= @FLAG_MPREFERRED_STACK_BOUNDARY@ +FLAG_MSSE = @FLAG_MSSE@ +FLAG_MSSE2 = @FLAG_MSSE2@ +FLAG_MSSE3 = @FLAG_MSSE3@ +FLAG_MSSE4 = @FLAG_MSSE4@ +FLAG_MTUNE = @FLAG_MTUNE@ +FLAG_O3 = @FLAG_O3@ +FLAG_STD_GNU89 = @FLAG_STD_GNU89@ +FLAG_WALL = @FLAG_WALL@ +FLAG_WBAD_FUNCTION_CAST = @FLAG_WBAD_FUNCTION_CAST@ +FLAG_WCAST_EQUAL = @FLAG_WCAST_EQUAL@ +FLAG_WDECLARATION_AFTER_STATEMENT = @FLAG_WDECLARATION_AFTER_STATEMENT@ +FLAG_WEXTRA = @FLAG_WEXTRA@ +FLAG_WFLOAT_EQUAL = @FLAG_WFLOAT_EQUAL@ +FLAG_WINLINE = @FLAG_WINLINE@ +FLAG_WNESTED_EXTERNS = @FLAG_WNESTED_EXTERNS@ +FLAG_WNO_EMPTY_BODY = @FLAG_WNO_EMPTY_BODY@ +FLAG_WNO_FORMAT_ZERO_LENGTH = @FLAG_WNO_FORMAT_ZERO_LENGTH@ +FLAG_WNO_POINTER_SIGN = @FLAG_WNO_POINTER_SIGN@ +FLAG_WNO_UNINITIALIZED = @FLAG_WNO_UNINITIALIZED@ +FLAG_WPOINTER_ARITH = @FLAG_WPOINTER_ARITH@ +FLAG_WSHADOW = @FLAG_WSHADOW@ +FLAG_WSIGN_COMPARE = @FLAG_WSIGN_COMPARE@ +FLAG_WSTRICT_PROTOTYPES = @FLAG_WSTRICT_PROTOTYPES@ +FLAG_WUNDEF = @FLAG_WUNDEF@ +FLAG_WUNINITIALIZED = @FLAG_WUNINITIALIZED@ +FLAG_WUNUSED_FUNCTION = @FLAG_WUNUSED_FUNCTION@ +FLAG_WUNUSED_LABEL = @FLAG_WUNUSED_LABEL@ +FLAG_WUNUSED_VALUE = @FLAG_WUNUSED_VALUE@ +FLAG_WUNUSED_VARIABLE = @FLAG_WUNUSED_VARIABLE@ +FLAG_WUNUSED_PARAMETER = @FLAG_WUNUSED_PARAMETER@ +FLAG_WWRITE_STRINGS = @FLAG_WWRITE_STRINGS@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +OBJEXT = @OBJEXT@ +LIBGMP = @LIBGMP@ +ENABLE_LIBGMP = @ENABLE_LIBGMP@ +HAVE_LONG_DOUBLE = @HAVE_LONG_DOUBLE@ +ENABLE_LONG_DOUBLE = @ENABLE_LONG_DOUBLE@ +ENABLE_SOFTFLOAT = @ENABLE_SOFTFLOAT@ +ENABLE_DEBUG = @ENABLE_DEBUG@ +ENABLE_OPTIMIZE = @ENABLE_OPTIMIZE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +REUSE_DEP = @REUSE_DEP@ diff --git a/src/allocrus.c b/src/allocrus.c new file mode 100644 index 0000000..ff71905 --- /dev/null +++ b/src/allocrus.c @@ -0,0 +1,284 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: allocrus.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* MEMORY ALLOCATION MACROS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 2, 1995 (cofeb16) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void *ILLutil_allocrus (size_t size) */ +/* RETURNS a pointer to an allocated block of "size" memory. */ +/* */ +/* void ILLutil_freerus (void *ptr) */ +/* FREES ptr. */ +/* */ +/* void *ILLutil_reallocrus (void *ptr, size_t size) */ +/* REALLOCS ptr to size bytes. */ +/* */ +/* int ILLutil_reallocrus_scale (void **pptr, int *pnnum, int count, */ +/* double scale, size_t size) */ +/* void **pptr (a reference to the pointer to the allocated space) */ +/* int *pnnum (a reference to the number of objects in the */ +/* allocated space) */ +/* int count (a minimum value for the new nnum) */ +/* double scale (a scale factor to apply to nnum) */ +/* int size (the size of objects to be realloced) */ +/* RETURNS 0 if *pptr was successfully changed to point to at */ +/* least max(*pnnum*scale, *pnnum+1000, count) objects. */ +/* *pnnum is changed to the new object count. */ +/* Otherwise, prints an error message, leaves *pptr and */ +/* *pnnum alone, and returns nonzero. */ +/* */ +/* int ILLutil_reallocrus_count (void **pptr, int count, */ +/* size_t size) */ +/* void **pptr (a reference to the pointer to the allocated space) */ +/* int count (number of objects to be realloced) */ +/* int size (the size of the objects to be realloced) */ +/* RETURNS 0 is successful, and 1 if the realloc failed. */ +/* */ +/* ILLbigchunkptr *ILLutil_bigchunkalloc (void) */ +/* RETURNS a ILLbigchunkptr with the "this_one" field loaded with a */ +/* a pointer to a bigchunk of memory. */ +/* NOTES: */ +/* The idea is to use bigchunks (the size of a bigchunk is defined */ +/* by ILL_BIGCHUNK in util.h) to supply local routines with memory */ +/* for ptrs, so the memory can be shared with other */ +/* local routines. */ +/* */ +/* ILLutil_bigchunkfree (ILLbigchunkptr *bp) */ +/* ACTION: Frees a ILLbigchunkptr. */ +/* */ +/* void ILLptrworld_init (ILLptrworld *world) */ +/* initialize a ILLptrworld with 1 reference */ +/* */ +/* void ILLptrworld_add (ILLptrworld *world) */ +/* add a reference to a ILLptrworld */ +/* */ +/* void ILLptrworld_delete (ILLptrworld *world) */ +/* delete a reference to a ptrworld, and free if no more references */ +/* */ +/****************************************************************************/ + +#include "machdefs.h" +#include "except.h" +#include "util.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +int ILLTRACE_MALLOC = 0; + +typedef struct ILLbigchunk +{ + char space[ILL_BIGCHUNK]; + ILLbigchunkptr ptr; +} +ILLbigchunk; + +void *ILLutil_allocrus ( + size_t size) +{ + void *mem = (void *) NULL; + + if (size == 0) + { + //fprintf (stderr, "Warning: 0 bytes allocated\n"); + } + + mem = (void *) malloc (size); + if (mem == (void *) NULL) + { + fprintf (stderr, "Out of memory. Asked for %d bytes\n", (int) size); + } + return mem; +} + +void ILLutil_freerus ( + void *p) +{ + if (!p) + { + //fprintf (stderr, "Warning: null pointer freed\n"); + return; + } + + free (p); +} + +void *ILLutil_reallocrus ( + void *ptr, + size_t size) +{ + void *newptr; + + if (!ptr) + { + return ILLutil_allocrus (size); + } + else + { + newptr = (void *) realloc (ptr, size); + if (!newptr) + { + fprintf (stderr, "Out of memory. Tried to grow to %d bytes\n", + (int) size); + } + return newptr; + } +} + +int ILLutil_reallocrus_scale ( + void **pptr, + int *pnnum, + int count, + double scale, + size_t size) +{ + int rval = 0; + int newsize = (int) (((double) *pnnum) * scale); + void *p; + + if (newsize < *pnnum + 1000) + newsize = *pnnum + 1000; + if (newsize < count) + newsize = count; + p = ILLutil_reallocrus (*pptr, newsize * size); + if (!p) + { + rval = ILL_GENERAL_ERROR; + ILL_REPRT ("ILLutil_reallocrus_scale failed\n"); + ILL_CLEANUP; + } + else + { + *pptr = p; + *pnnum = newsize; + } +CLEANUP: + return rval; +} + +int ILLutil_reallocrus_count ( + void **pptr, + int count, + size_t size) +{ + int rval = 0; + void *p = ILLutil_reallocrus (*pptr, count * size); + + if (!p) + { + rval = ILL_GENERAL_ERROR; + ILL_REPRT ("ILLutil_reallocrus_count failed\n"); + ILL_CLEANUP; + } + else + { + *pptr = p; + } +CLEANUP: + return rval; +} + + +ILLbigchunkptr *ILLutil_bigchunkalloc ( + void) +{ + ILLbigchunk *p; + + ILL_NEW_no_rval (p, ILLbigchunk); + + p->ptr.this_chunk = p; + p->ptr.this_one = (void *) p->space; +CLEANUP: + if (p == (ILLbigchunk *) NULL) + { + return (ILLbigchunkptr *) NULL; + } + return &(p->ptr); +} + +void ILLutil_bigchunkfree ( + ILLbigchunkptr * bp) +{ + /* This copy is necessary since ILL_FREE zeros its first argument */ + ILLbigchunk *p = bp->this_chunk; + + ILL_IFFREE (p, ILLbigchunk); +} + +void ILLptrworld_init ( + ILLptrworld * world) +{ + world->refcount = 1; + world->freelist = (void *) NULL; + world->chunklist = (ILLbigchunkptr *) NULL; +} + +void ILLptrworld_add ( + ILLptrworld * world) +{ + world->refcount++; +} + +void ILLptrworld_delete ( + ILLptrworld * world) +{ + world->refcount--; + if (world->refcount <= 0) + { + ILLbigchunkptr *bp, *bpnext; + + for (bp = world->chunklist; bp; bp = bpnext) + { + bpnext = bp->next; + ILLutil_bigchunkfree (bp); + } + world->chunklist = (ILLbigchunkptr *) NULL; + world->freelist = (void *) NULL; + world->refcount = 0; + } +} diff --git a/src/allocrus.h b/src/allocrus.h new file mode 100644 index 0000000..50ba822 --- /dev/null +++ b/src/allocrus.h @@ -0,0 +1,242 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __ALLOCRUS_H__ +#define __ALLOCRUS_H__ +/****************************************************************************/ +/* */ +/* allocrus.c */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* MEMORY ALLOCATION MACROS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 24, 1995 (cofeb24) */ +/* see allocrus.c */ +/* */ +/****************************************************************************/ + +extern int ILLTRACE_MALLOC; + +#ifndef USEDMALLOC +#define ILL_UTIL_SAFE_MALLOC(nnum,type,varname) \ + (((ILLTRACE_MALLOC) ? printf("%s.%d: %s: ILL_UTIL_SAFE_MALLOC: %s = %d * %s\n", __FILE__, __LINE__, __DEV_FUNCTION__, #varname, nnum, #type) : 0), \ + (type *) ILLutil_allocrus (((size_t) (nnum)) * sizeof (type))) +#else +#define ILL_UTIL_SAFE_MALLOC(nnum,type,varname) \ + (((ILLTRACE_MALLOC) ? printf("%s.%d: %s: ILL_UTIL_SAFE_MALLOC: %s = %d * %s\n", __FILE__, __LINE__, __DEV_FUNCTION__, #varname, nnum, #type) : 0), \ + (type *) malloc (((size_t) (nnum)) * sizeof (type))) +#endif + +#define ILL_IFFREE(object,type) { \ + if ((object)) { \ + ILLutil_freerus ((void *) (object)); \ + object = (type *) NULL; \ + }} + +#define ILL_PTRWORLD_ALLOC_ROUTINE(type, ptr_alloc_r, ptr_bulkalloc_r) \ + \ +static int ptr_bulkalloc_r (ILLptrworld *world, int nalloc) \ +{ \ + ILLbigchunkptr *bp; \ + int i; \ + int count = ILL_BIGCHUNK / sizeof ( type ); \ + type *p; \ + \ + while (nalloc > 0) { \ + bp = ILLutil_bigchunkalloc (); \ + if (bp == (ILLbigchunkptr *) NULL) { \ + fprintf (stderr, "ptr alloc failed\n"); \ + return 1; \ + } \ + bp->next = world->chunklist ; \ + world->chunklist = bp; \ + \ + p = ( type * ) bp->this_one; \ + for (i=count-2; i>=0; i--) { \ + p[i].next = &p[i+1]; \ + } \ + p[count - 1].next = (type *) world->freelist; \ + world->freelist = (void *) p; \ + nalloc -= count; \ + } \ + return 0; \ +} \ + \ +static type *ptr_alloc_r (ILLptrworld *world) \ +{ \ + type *p; \ + \ + if (world->freelist == (void *) NULL) { \ + if (ptr_bulkalloc_r (world, 1)) { \ + fprintf (stderr, "ptr alloc failed\n"); \ + return ( type * ) NULL; \ + } \ + } \ + p = (type *) world->freelist ; \ + world->freelist = (void *) p->next; \ + \ + return p; \ +} + +#define ILL_PTRWORLD_FREE_ROUTINE(type, ptr_free_r) \ + \ +static void ptr_free_r (ILLptrworld *world, type *p) \ +{ \ + p->next = (type *) world->freelist ; \ + world->freelist = (void *) p; \ +} + +#define ILL_PTRWORLD_LISTADD_ROUTINE(type, entrytype, ptr_listadd_r, ptr_alloc_r) \ + \ +static int ptr_listadd_r (type **list, entrytype x, ILLptrworld *world) \ +{ \ + if (list != (type **) NULL) { \ + type *p = ptr_alloc_r (world); \ + \ + if (p == (type *) NULL) { \ + fprintf (stderr, "ptr list add failed\n"); \ + return 1; \ + } \ + p->this = x; \ + p->next = *list; \ + *list = p; \ + } \ + return 0; \ +} + +#define ILL_PTRWORLD_LISTFREE_ROUTINE(type, ptr_listfree_r, ptr_free_r) \ + \ +static void ptr_listfree_r (ILLptrworld *world, type *p) \ +{ \ + type *next; \ + \ + while (p != (type *) NULL) { \ + next = p->next; \ + ptr_free_r (world, p); \ + p = next; \ + } \ +} + +#define ILL_PTRWORLD_LEAKS_ROUTINE(type, ptr_leaks_r, field, fieldtype) \ + \ +static int ptr_leaks_r (ILLptrworld *world, int *total, int *onlist) \ +{ \ + int count = ILL_BIGCHUNK / sizeof ( type ); \ + int duplicates = 0; \ + type * p; \ + ILLbigchunkptr *bp; \ + \ + *total = 0; \ + *onlist = 0; \ + \ + for (bp = world->chunklist ; bp; bp = bp->next) \ + (*total) += count; \ + \ + for (p = (type *) world->freelist ; p; p = p->next) { \ + (*onlist)++; \ + p-> field = ( fieldtype ) 0; \ + } \ + for (p = (type *) world->freelist ; p; p = p->next) { \ + if ((unsigned long) p-> field == (unsigned long) (size_t) 1) \ + duplicates++; \ + else \ + p-> field = ( fieldtype ) (size_t) 1; \ + } \ + if (duplicates) { \ + fprintf (stderr, "WARNING: %d duplicates on ptr free list \n", \ + duplicates); \ + } \ + return *total - *onlist; \ +} + +#define ILL_PTRWORLD_ROUTINES(type, ptr_alloc_r, ptr_bulkalloc_r, ptr_free_r) \ +ILL_PTRWORLD_ALLOC_ROUTINE (type, ptr_alloc_r, ptr_bulkalloc_r) \ +ILL_PTRWORLD_FREE_ROUTINE (type, ptr_free_r) + +#define ILL_PTRWORLD_LIST_ROUTINES(type, entrytype, ptr_alloc_r, ptr_bulkalloc_r, ptr_free_r, ptr_listadd_r, ptr_listfree_r) \ +ILL_PTRWORLD_ROUTINES (type, ptr_alloc_r, ptr_bulkalloc_r, ptr_free_r) \ +ILL_PTRWORLD_LISTADD_ROUTINE (type, entrytype, ptr_listadd_r, ptr_alloc_r) \ +ILL_PTRWORLD_LISTFREE_ROUTINE (type, ptr_listfree_r, ptr_free_r) + +#define ILL_BIGCHUNK ((int) ((1<<16) - sizeof (ILLbigchunkptr) - 16)) + +struct ILLbigchunk; + +typedef struct ILLbigchunkptr +{ + void *this_one; + struct ILLbigchunk *this_chunk; + struct ILLbigchunkptr *next; +} +ILLbigchunkptr; + + +typedef struct ILLptrworld +{ + int refcount; + void *freelist; + ILLbigchunkptr *chunklist; +} +ILLptrworld; + + + +void *ILLutil_allocrus ( + size_t size), + *ILLutil_reallocrus ( + void *ptr, + size_t size), + ILLutil_freerus ( + void *p), + ILLutil_bigchunkfree ( + ILLbigchunkptr * bp), + ILLptrworld_init ( + ILLptrworld * world), + ILLptrworld_add ( + ILLptrworld * world), + ILLptrworld_delete ( + ILLptrworld * world); + +int ILLutil_reallocrus_scale ( + void **pptr, + int *pnnum, + int count, + double scale, + size_t size), + ILLutil_reallocrus_count ( + void **pptr, + int count, + size_t size); + +ILLbigchunkptr *ILLutil_bigchunkalloc ( + void); + + + +#endif diff --git a/src/basicdefs.h b/src/basicdefs.h new file mode 100644 index 0000000..1b8c01f --- /dev/null +++ b/src/basicdefs.h @@ -0,0 +1,386 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ +#ifndef __BASICDEFS__ +#define __BASICDEFS__ + +/* storage type */ +#define DENSE 0 +#define SPARSE 1 + +/* type of vector */ +#define ROW_SOLVE 1 +#define COLUMN_SOLVE 2 + +/* direction of change in non-basic var */ +#define VINCREASE 1 +#define VDECREASE 2 + +/* status of variables */ +#define STAT_BASIC 1 +#define STAT_UPPER 2 +#define STAT_LOWER 3 +#define STAT_ZERO 4 + +#define BOUND_LOWER 1 +#define BOUND_UPPER 2 + +/* type of variables */ +#define VARTIFICIAL 1 +#define VFIXED 2 +#define VFREE 4 +#define VUPPER 8 +#define VLOWER 16 +#define VBOUNDED 32 + +/* class of variables */ +#define CLASS_STRUCT 0 +#define CLASS_LOGICAL 1 + +/* algo */ +#define PRIMAL_SIMPLEX 1 +#define DUAL_SIMPLEX 2 +#define PRIMAL_OR_DUAL 3 + +/* phase */ +#define PRIMAL_PHASEI 1 +#define PRIMAL_PHASEII 2 +#define DUAL_PHASEI 3 +#define DUAL_PHASEII 4 + +/* number of phases */ +#define PHASEI 1 +#define PHASEII 2 + +/* type of pricing (all vars or some) */ +#define COMPLETE_PRICING 1 +#define PARTIAL_PRICING 2 +#define MULTI_PART_PRICING 3 + +/* default pricing */ + +#define QS_DEFAULT_PRICE_PI QS_PRICE_PSTEEP +#define QS_DEFAULT_PRICE_PII QS_PRICE_PSTEEP +#define QS_DEFAULT_PRICE_DI QS_PRICE_DSTEEP +#define QS_DEFAULT_PRICE_DII QS_PRICE_DSTEEP + +/* lp sol status */ +#define ILL_LP_SOLVED 1 +#define ILL_LP_UNSOLVED 2 +#define ILL_MAX_ITER 3 +#define ILL_MAX_TIME 4 +#define ILL_BND_REACHED 5 +#define ILL_PPHASEI_ERROR 6 +#define ILL_PPHASEII_ERROR 7 +#define ILL_DPHASEI_ERROR 8 +#define ILL_DPHASEII_ERROR 9 +#define ILL_LP_ABORTED 10 + +/* basis status */ +#define OPTIMAL 1 +#define NONOPTIMAL 2 +#define PRIMAL_FEASIBLE 3 +#define PRIMAL_INFEASIBLE 4 +#define PRIMAL_UNBOUNDED 5 +#define DUAL_FEASIBLE 7 +#define DUAL_INFEASIBLE 8 +#define DUAL_UNBOUNDED 9 + +/* type of ratio test */ +#define RATIOTEST_NORMAL 1 +#define RATIOTEST_HARRIS 2 + +/* control parameters */ +#define PARAM_PRATIOTESTS 10 +#define PARAM_DRATIOTESTS 20 +#define PARAM_PRIMAL_REFACTORGAP 50 +#define PARAM_PRIMAL_RESOLVEGAP 25 +#define PARAM_DUAL_REFACTORGAP 100 +#define PARAM_DUAL_RESOLVEGAP 25 +#define PARAM_MAX_NOSOLVE 500 +#define PARAM_MAX_NOPROG 300 +#define PARAM_NOPROG_FACTOR 15 + +/* numerical parameters */ +#define PARAM_BSHIFT 10 +#define PARAM_CSHIFT 10 + +/* general constants */ +#define PARAM_HEAP_UTRIGGER 10 +#define PARAM_HEAP_RATIO 4.0 + +/* errors */ +#define E_GENERAL_ERROR 1 +#define E_INV_LINSOLVE_OPTION 2 +#define E_NO_MEMORY 3 +#define E_INVALID_OPTION 4 +#define E_NULL_ARGUMENT 5 +#define E_SIMPLEX_ERROR 6 +#define E_BASIS_SINGULAR 7 + +#ifndef __QS_BASIS__ +#define __QS_BASIS__ +typedef struct qsbasis +{ + int nstruct; + int nrows; + char *cstat; + char *rstat; +} +QSbasis; +#endif + +typedef struct itcnt_t +{ + int pI_iter; + int pII_iter; + int dI_iter; + int dII_iter; + int tot_iter; +} itcnt_t; + +#ifndef QS_DEFINITIONS +#define QS_DEFINITIONS +#define QS_MIN (1) +#define QS_MAX (-1) + +/****************************************************************************/ +/* */ +/* PARAMETERS THAT CAN BE SET BY setparam */ +/* */ +/****************************************************************************/ + + +#define QS_PARAM_PRIMAL_PRICING 0 +#define QS_PARAM_DUAL_PRICING 2 +#define QS_PARAM_SIMPLEX_DISPLAY 4 +#define QS_PARAM_SIMPLEX_MAX_ITERATIONS 5 +#define QS_PARAM_SIMPLEX_MAX_TIME 6 +#define QS_PARAM_SIMPLEX_SCALING 7 +#define QS_PARAM_OBJULIM 8 +#define QS_PARAM_OBJLLIM 9 + + +/****************************************************************************/ +/* */ +/* VALUES FOR PRICING PARAMETERS */ +/* */ +/****************************************************************************/ + +#define QS_PRICE_PDANTZIG 1 +#define QS_PRICE_PDEVEX 2 +#define QS_PRICE_PSTEEP 3 +#define QS_PRICE_PMULTPARTIAL 4 + +#define QS_PRICE_DDANTZIG 6 +#define QS_PRICE_DSTEEP 7 +#define QS_PRICE_DMULTPARTIAL 8 +#define QS_PRICE_DDEVEX 9 + + +/****************************************************************************/ +/* */ +/* VALUES FOR BASIS STATUS */ +/* */ +/****************************************************************************/ + + +#define QS_COL_BSTAT_LOWER '0' +#define QS_COL_BSTAT_BASIC '1' +#define QS_COL_BSTAT_UPPER '2' +#define QS_COL_BSTAT_FREE '3' + +#define QS_ROW_BSTAT_LOWER '0' +#define QS_ROW_BSTAT_BASIC '1' +#define QS_ROW_BSTAT_UPPER '2' + + +/****************************************************************************/ +/* */ +/* Return Status for dbl_QSopt_primal, dbl_QSopt_dual, dbl_QSget_status */ +/* */ +/****************************************************************************/ + +#define QS_LP_OPTIMAL 1 +#define QS_LP_INFEASIBLE 2 +#define QS_LP_UNBOUNDED 3 +#define QS_LP_ITER_LIMIT 4 +#define QS_LP_TIME_LIMIT 5 +#define QS_LP_UNSOLVED 6 +#define QS_LP_ABORTED 7 +#define QS_LP_NUMERR 8 +#define QS_LP_OBJ_LIMIT 9 +#define QS_LP_MODIFIED 100 +#define QS_LP_CHANGE_PREC 1024 +#endif + + + +/** @brief If set to one, them we allow to re-start the simplex algorithm due to + * numerical issues */ +#define DO_NUMER 0 +/** @brief If set to one, then we allow to re-start simplex due to singular + * basis */ +#define DO_SINGULAR 0 + +/** @brief Factor for wich we change tolerances each time we have to resume + * simplex */ +#define SIMPLEX_FACTOR 5U +#define DENSE_PI 0 +#define DENSE_PIIPI 0 +#define DENSE_NORM 0 +#define SIMPLEX_DEBUG 0 + + +/* possible values of nextstep */ +#define SIMPLEX_CONTINUE 1 +#define SIMPLEX_TERMINATE 2 +#define SIMPLEX_RESUME 3 + +/* reason for resuming simplex */ +#define SIMPLEX_RESUME_SING 1 +#define SIMPLEX_RESUME_UNSHIFT 2 +#define SIMPLEX_RESUME_NUMER 3 + +/* values for newphase */ +#define SIMPLEX_PHASE_RECOMP 1 +#define SIMPLEX_PHASE_NEW 2 + +#define SIMPLEX_PIVOTINROW 1 +#define SIMPLEX_PIVOTINCOL 2 +#define SIMPLEX_MAX_RESTART 4 +#define SIMPLEX_MAX_PIVOT_FAIL 300 + + +#define FALSE 0 +#define TRUE 1 +#define QS_FACTOR_MAX_K 1 +#define QS_FACTOR_P 2 +#define QS_FACTOR_ETAMAX 3 +#define QS_FACTOR_FZERO_TOL 4 +#define QS_FACTOR_SZERO_TOL 5 +#define QS_FACTOR_PARTIAL_TOL 6 +#define QS_FACTOR_UR_SPACE_MUL 7 +#define QS_FACTOR_UC_SPACE_MUL 8 +#define QS_FACTOR_LC_SPACE_MUL 9 +#define QS_FACTOR_LR_SPACE_MUL 10 +#define QS_FACTOR_ER_SPACE_MUL 11 +#define QS_FACTOR_GROW_MUL 12 +#define QS_FACTOR_MAXMULT 13 +#define QS_FACTOR_MINMULT 14 +#define QS_FACTOR_UPDMAXMULT 15 +#define QS_FACTOR_DENSE_FRACT 16 +#define QS_FACTOR_DENSE_MIN 17 +#define E_CHECK_FAILED 6 +#define E_NO_PIVOT 7 +#define E_FACTOR_BLOWUP 8 +#define E_UPDATE_NOSPACE 9 +#define E_UPDATE_SINGULAR_ROW 10 +#define E_UPDATE_SINGULAR_COL 11 +#define E_SING_NO_DATA 12 +#define E_SINGULAR_INTERNAL 13 +#define SPARSE_FACTOR 0.05 +#define CNT_YNZ 1 /* nz in entering columns */ +#define CNT_ZNZ 2 /* nz in ith row of B^{-1}, ie z_i */ +#define CNT_ZANZ 3 /* nz in ith row of B^{-1}, ie z_i */ +#define CNT_PINZ 4 /* nz in phase II pi (solve) */ +#define CNT_P1PINZ 5 /* nz in phase I pi (solve) */ +#define CNT_UPNZ 6 /* nz in ftran_updates */ +#define CNT_PPHASE1ITER 7 /* primal phase I iterations */ +#define CNT_PPHASE2ITER 8 +#define CNT_DPHASE1ITER 9 /* dual phase I iterations */ +#define CNT_DPHASE2ITER 10 +#define CNT_PIPIV 11 +#define CNT_PIIPIV 12 +#define CNT_DIPIV 13 +#define CNT_DIIPIV 14 +#define CNT_YRAVG 15 +#define CNT_ZARAVG 16 + +#define ROW_PIVOT 0 +#define COL_PIVOT 1 + +#define ILL_LP_OPTIMAL 1 +#define ILL_LP_NONOPTIMAL 2 +#define ILL_LP_PRIMAL_FEASIBLE 3 +#define ILL_LP_PRIMAL_INFEASIBLE 4 +#define ILL_LP_PRIMAL_UNBOUNDED 5 +#define ILL_LP_DUAL_FEASIBLE 6 +#define ILL_LP_DUAL_INFEASIBLE 7 +#define ILL_LP_DUAL_UNBOUNDED 8 + +typedef enum +{ ILL_MPS_NAME, ILL_MPS_OBJSENSE, ILL_MPS_OBJNAME, + ILL_MPS_ROWS, ILL_MPS_COLS, ILL_MPS_RHS, ILL_MPS_RANGES, + ILL_MPS_BOUNDS, ILL_MPS_REFROW, ILL_MPS_ENDATA, + ILL_MPS_NONE +} +ILLmps_section; + +#define ILL_MPS_N_SECTIONS ILL_MPS_NONE + +/*define as > 0 if heap is to be used */ +#define USEHEAP 1 + +/*result of pricing */ +#define PRICE_OPTIMAL 1 +#define PRICE_NONOPTIMAL 2 + +/*type of pricing */ +#define ROW_PRICING 1 +#define COL_PRICING 2 + + +/**************************************************************************** + * error collection + */ +#define QS_DATA_ERROR 0 +#define QS_DATA_WARN 1 +#define QS_MPS_FORMAT_ERROR 2 +#define QS_MPS_FORMAT_WARN 3 +#define QS_LP_FORMAT_ERROR 4 +#define QS_LP_FORMAT_WARN 5 +#define QS_INPUT_NERROR 8 + +/* defs for phase I ratio test */ +#define BBOUND 1 +#define BATOLOWER 2 +#define BATOUPPER 3 +#define BBTOLOWER 4 +#define BBTOUPPER 5 +#define BSKIP 6 + +/* result of ratio test */ +#define RATIO_UNBOUNDED 1 +#define RATIO_NOBCHANGE 2 +#define RATIO_BCHANGE 3 +#define RATIO_FAILED 4 +#define RATIO_NEGATIVE 5 + +/* warning level */ +#define QSE_WLVL 10000 + + + + + + +#endif diff --git a/src/basis.c b/src/basis.c new file mode 100644 index 0000000..5cbb1b4 --- /dev/null +++ b/src/basis.c @@ -0,0 +1,1548 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: basis.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +static int TRACE = 0; + +#include +#include +#include +#include "qs_config.h" +#include "config.h" +#include "sortrus.h" +#include "iqsutil.h" +#include "lpdefs.h" +#include "qstruct.h" +#include "qsopt.h" +#include "basis.h" +#include "fct.h" +#include "lp.h" +#include "lib.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +//#define DJZERO_TOLER PFEAS_TOLER +#define BASIS_STATS 0 +//#define BASIS_DEBUG 10 +#define BASIS_DEBUG 0 + +void ILLbasis_init_vardata ( + var_data * vd) +{ + memset (vd, 0, sizeof (var_data)); + EGlpNumInitVar (vd->cmax); +} + +void ILLbasis_clear_vardata ( + var_data * vd) +{ + EGlpNumClearVar (vd->cmax); + memset (vd, 0, sizeof (var_data)); +} + +static void get_var_info ( + lpinfo * lp, + var_data * v); + +static int init_slack_basis ( + lpinfo * lp, + int *vstat, + int *irow, + int *rrow, + int *unitcol, + int *icol, + int *rcol), + get_initial_basis1 ( + lpinfo * lp, + int *vstat), + get_initial_basis2 ( + lpinfo * lp, + int *vstat), + set_basis_indices ( + lpinfo * lp, + int *vstat), + choose_basis ( + int algorithm, + EGlpNum_t pinf1, + EGlpNum_t dinf1, + EGlpNum_t pinf2, + EGlpNum_t dinf2); + +void ILLbasis_init_basisinfo ( + lpinfo * lp) +{ + lp->baz = 0; + lp->nbaz = 0; + lp->vstat = 0; + lp->vindex = 0; + lp->f = 0; +} + +void ILLbasis_free_basisinfo ( + lpinfo * lp) +{ + ILL_IFFREE (lp->baz, int); + ILL_IFFREE (lp->nbaz, int); + ILL_IFFREE (lp->vstat, int); + ILL_IFFREE (lp->vindex, int); + + if (lp->f) + { + ILLfactor_free_factor_work (lp->f); + EGlpNumClearVar (lp->f->fzero_tol); + EGlpNumClearVar (lp->f->szero_tol); + EGlpNumClearVar (lp->f->partial_tol); + EGlpNumClearVar (lp->f->maxelem_orig); + EGlpNumClearVar (lp->f->maxelem_factor); + EGlpNumClearVar (lp->f->maxelem_cur); + EGlpNumClearVar (lp->f->partial_cur); + ILL_IFFREE (lp->f, factor_work); + } +} + +int ILLbasis_build_basisinfo ( + lpinfo * lp) +{ + int rval = 0; + + ILL_SAFE_MALLOC (lp->baz, lp->O->nrows, int); + ILL_SAFE_MALLOC (lp->nbaz, lp->O->ncols, int); + ILL_SAFE_MALLOC (lp->vstat, lp->O->ncols, int); + ILL_SAFE_MALLOC (lp->vindex, lp->O->ncols, int); + + lp->fbasisid = -1; + +CLEANUP: + if (rval) + ILLbasis_free_basisinfo (lp); + EG_RETURN (rval); +} + +int ILLbasis_load ( + lpinfo * lp, + ILLlp_basis * B) +{ + int rval = 0; + char *cstat = B->cstat; + char *rstat = B->rstat; + int *structmap = lp->O->structmap; + int *rowmap = lp->O->rowmap; + char *sense = lp->O->sense; + int i, j, ncols = lp->O->ncols, nrows = lp->O->nrows, nstruct = lp->O->nstruct; + int basic = 0, nonbasic = 0; + + ILLbasis_free_basisinfo (lp); + ILLbasis_init_basisinfo (lp); + rval = ILLbasis_build_basisinfo (lp); + CHECKRVALG (rval, CLEANUP); + + for (i = 0; i < nstruct; i++) + { + j = structmap[i]; + if (cstat[i] == QS_COL_BSTAT_BASIC) + { + lp->vstat[j] = STAT_BASIC; + lp->baz[basic] = j; + lp->vindex[j] = basic; + basic++; + } + else + { + lp->nbaz[nonbasic] = j; + lp->vindex[j] = nonbasic; + nonbasic++; + switch (cstat[i]) + { + case QS_COL_BSTAT_LOWER: + lp->vstat[j] = STAT_LOWER; + break; + case QS_COL_BSTAT_UPPER: + lp->vstat[j] = STAT_UPPER; + break; + case QS_COL_BSTAT_FREE: + lp->vstat[j] = STAT_ZERO; + break; + default: + fprintf (stderr, "unknown col basis stat 1: %c\n", cstat[i]); + rval = 1; + goto CLEANUP; + } + } + } + + for (i = 0; i < nrows; i++) + { + j = rowmap[i]; + if (sense[i] == 'R') + { + if (rstat[i] == QS_ROW_BSTAT_BASIC) + { + lp->vstat[j] = STAT_BASIC; + lp->baz[basic] = j; + lp->vindex[j] = basic; + basic++; + } + else + { + lp->nbaz[nonbasic] = j; + lp->vindex[j] = nonbasic; + nonbasic++; + switch (rstat[i]) + { + case QS_ROW_BSTAT_LOWER: + lp->vstat[j] = STAT_LOWER; + break; + case QS_ROW_BSTAT_UPPER: + lp->vstat[j] = STAT_UPPER; + break; + default: + fprintf (stderr, "unknown range basis stat 2\n"); + rval = 1; + goto CLEANUP; + } + } + } + else + { + switch (rstat[i]) + { + case QS_ROW_BSTAT_BASIC: + lp->vstat[j] = STAT_BASIC; + lp->baz[basic] = j; + lp->vindex[j] = basic; + basic++; + break; + case QS_ROW_BSTAT_LOWER: + lp->vstat[j] = STAT_LOWER; + lp->nbaz[nonbasic] = j; + lp->vindex[j] = nonbasic; + nonbasic++; + break; + default: + fprintf (stderr, "unknown row basis stat 3\n"); + rval = 1; + goto CLEANUP; + } + } + } + + if (basic + nonbasic != ncols) + { + fprintf (stderr, "error in counts in ILLopt_load_basis\n"); + rval = 1; + goto CLEANUP; + } + + if (lp->fbasisid != 0) + lp->basisid = 0; + else + lp->basisid = 1; + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLbasis_tableau_row ( + lpinfo * lp, + int row, + EGlpNum_t * brow, + EGlpNum_t * trow, + EGlpNum_t * rhs, + int strict) +{ + int rval = 0; + int i; + int singular = 0; + int indx; + EGlpNum_t coef; + EGlpNum_t sum; + svector z, zA; + + EGlpNumInitVar (coef); + EGlpNumInitVar (sum); + EGlpNumZero (sum); + + ILLsvector_init (&z); + ILLsvector_init (&zA); + + if (lp->basisid == -1) + { + fprintf (stderr, "ILLbasis_tableau_row: no basis\n"); + rval = E_GENERAL_ERROR; + ILL_CLEANUP; + } + if (lp->fbasisid != lp->basisid) + { /* Needs to be changed */ + rval = ILLbasis_factor (lp, &singular); + CHECKRVALG (rval, CLEANUP); + if (singular) + { + MESSAGE (__QS_SB_VERB, "Singular Basis found!"); + rval = E_BASIS_SINGULAR; + ILL_CLEANUP; + } + } + if (brow == NULL) + { + fprintf (stderr, "No array for basis inverse row\n"); + rval = E_GENERAL_ERROR; + ILL_CLEANUP; + } + + rval = ILLsvector_alloc (&z, lp->nrows); + CHECKRVALG (rval, CLEANUP); + ILLfct_compute_zz (lp, &z, row); + + for (i = 0; i < lp->O->nrows; i++) + EGlpNumZero (brow[i]); + for (i = 0; i < z.nzcnt; i++) + { + indx = z.indx[i]; + EGlpNumCopy (coef, z.coef[i]); + EGlpNumCopy (brow[indx], coef); + EGlpNumAddInnProdTo (sum, coef, lp->bz[indx]); + } + + if (rhs != NULL) + EGlpNumCopy (*rhs, sum); + if (trow != NULL) + { + if (!strict) + { + rval = ILLsvector_alloc (&zA, lp->ncols); + if (rval) + ILL_CLEANUP; + ILL_IFTRACE ("%s:\n", __func__); + rval = ILLfct_compute_zA (lp, &z, &zA); + CHECKRVALG (rval, CLEANUP); + + for (i = 0; i < lp->ncols; i++) + EGlpNumZero (trow[i]); + for (i = 0; i < zA.nzcnt; i++) + EGlpNumCopy (trow[lp->nbaz[zA.indx[i]]], zA.coef[i]); + EGlpNumOne (trow[lp->baz[row]]); + } + else + { + ILLfct_compute_vA (lp, &z, trow); + } + } + +#if BASIS_DEBUG > 0 + if (rhs != NULL && trow != NULL) + { + EGlpNum_t *tr = NULL; + + EGlpNumZero (sum); + if (strict) + tr = trow; + else + { + tr = EGlpNumAllocArray (lp->ncols); + ILLfct_compute_vA (lp, &z, tr); + } + for (i = 0; i < lp->nrows; i++) + if (EGlpNumIsGreatZero (tr[lp->baz[i]])) + EGlpNumAddTo (sum, tr[lp->baz[i]]); + else + EGlpNumSubTo (sum, tr[lp->baz[i]]); + EGlpNumCopy (coef, oneLpNum); + EGlpNumSubTo (coef, sum); + if (EGlpNumIsLessZero (coef)) + EGlpNumSign (coef); + if (EGlpNumIsLess (PIVZ_TOLER, coef)) + fprintf (stderr, "tableau: bas computed = %.12f\n", EGlpNumToLf (sum)); + if (!strict) + EGlpNumFreeArray (tr); +#if BASIS_DEBUG > 1 + EGlpNumZero (sum); + for (i = 0; i < lp->ncols; i++) + { + if (lp->vstat[i] == STAT_BASIC) + EGlpNumAddInnProdTo (sum, lp->xbz[lp->vindex[i]], trow[i]); + else if (lp->vstat[i] == STAT_UPPER) + EGlpNumAddInnProdTo (sum, lp->uz[i], trow[i]); + else if (lp->vstat[i] == STAT_LOWER) + EGlpNumAddInnProdTo (sum, lp->lz[i], trow[i]); + } + EGlpNumSet (coef, 1e-10); + if (EGlpNumIsNeq (sum, *rhs, coef)) + fprintf (stderr, "tableau rhs = %.9f, computed = %.9f\n", + EGlpNumToLf (*rhs), EGlpNumToLf (sum)); +#endif + } +#endif + +CLEANUP: + ILLsvector_free (&z); + ILLsvector_free (&zA); + EGlpNumClearVar (coef); + EGlpNumClearVar (sum); + return rval; +} + +static void get_var_info ( + lpinfo * lp, + var_data * v) +{ + int i = 0; + + v->nartif = 0; + v->nslacks = 0; + v->nfree = 0; + v->nbndone = 0; + v->nbounded = 0; + v->nfixed = 0; + EGlpNumCopy (v->cmax, NINFTY); + + for (i = 0; i < lp->ncols; i++) + { + switch (lp->vtype[i]) + { + case VARTIFICIAL: + v->nartif++; + break; + case VFREE: + v->nfree++; + break; + case VLOWER: + case VUPPER: + if (lp->vclass[i] == CLASS_LOGICAL) + v->nslacks++; + else + v->nbndone++; + break; + + case VFIXED: + v->nfixed++; + case VBOUNDED: + if (lp->vclass[i] == CLASS_LOGICAL) + v->nslacks++; + else + v->nbounded++; + break; + } + EGlpNumSetToMaxAbs (v->cmax, lp->cz[i]); + } + +#if BASIS_STATS > 0 + printf ("cols = %d, acols = %d, total = %d, nrows = %d, nlog = %d\n", + lp->ncols, lp->ncols - lp->nrows, + v->nartif + v->nfree + v->nslacks + v->nbndone + v->nbounded, + lp->nrows, v->nartif + v->nslacks); +#endif +} + +static int init_slack_basis ( + lpinfo * lp, + int *vstat, + int *irow, + int *rrow, + int *unitcol, + int *icol, + int *rcol) +{ + int j, r, vt; + int nslacks = 0; + + for (j = 0; j < lp->ncols; j++) + { + r = lp->matind[lp->matbeg[j]]; + vt = lp->vtype[j]; + + if ((vt == VUPPER || vt == VLOWER || vt == VBOUNDED || vt == VFIXED) && + lp->vclass[j] == CLASS_LOGICAL) + { + + vstat[j] = STAT_BASIC; + irow[r] = 1; + rrow[r] = 1; + unitcol[r] = j; + if (icol != NULL) + { + icol[j] = 1; + rcol[j] = 1; + } + nslacks++; + } + else if (vt == VARTIFICIAL) + { + unitcol[r] = j; + vstat[j] = STAT_UPPER; + } + else if (vt == VFREE) + vstat[j] = STAT_ZERO; + else if (vt == VFIXED || vt == VUPPER) + vstat[j] = STAT_UPPER; + else if (vt == VLOWER) + vstat[j] = STAT_LOWER; + else if (vt == VBOUNDED) + { + if (fabs (EGlpNumToLf (lp->lz[j])) < fabs (EGlpNumToLf (lp->uz[j]))) + vstat[j] = STAT_LOWER; + else + vstat[j] = STAT_UPPER; + } + } + return nslacks; +} + +static int primal_col_select ( + lpinfo * lp, + int *vstat, + int *irow, + int *rrow, + int *unitcol, + EGlpNum_t * v, + int *perm, + int *porder, + int nbelem, + int pcols) +{ + int i, j, k, tr, r = 0; + int mcnt, mbeg; + int *matbeg = lp->matbeg; + int *matcnt = lp->matcnt; + int *matind = lp->matind; + EGlpNum_t *matval = lp->matval; + EGlpNum_t alpha, val, maxelem; + + EGlpNumInitVar (alpha); + EGlpNumInitVar (val); + EGlpNumInitVar (maxelem); + + for (k = 0; k < pcols; k++) + { + j = porder[perm[k]]; + mcnt = matcnt[j]; + mbeg = matbeg[j]; + + EGlpNumCopy (alpha, NINFTY); + EGlpNumCopy (maxelem, NINFTY); + + for (i = 0; i < mcnt; i++) + { + EGlpNumCopyAbs (val, matval[mbeg + i]); + if (EGlpNumIsLess (maxelem, val)) + EGlpNumCopy (maxelem, val); + if (rrow[matind[mbeg + i]] == 0 && EGlpNumIsLess (alpha, val)) + { + EGlpNumCopy (alpha, val); + r = matind[mbeg + i]; + } + } + EGlpNumCopy (val, maxelem); + EGlpNumMultTo (val, PARAM_IBASIS_RPIVOT); + if (EGlpNumIsLess (val, alpha)) + { + vstat[j] = STAT_BASIC; + nbelem++; + irow[r] = 1; + EGlpNumCopy (v[r], alpha); + for (i = 0; i < mcnt; i++) + if (EGlpNumIsNeqqZero (matval[mbeg + i])) + rrow[matind[mbeg + i]]++; + } + else + { + EGlpNumCopy (alpha, NINFTY); + for (i = 0; i < mcnt; i++) + { + tr = matind[mbeg + i]; + EGlpNumCopyAbs (val, matval[mbeg + i]); + EGlpNumDivTo (val, PARAM_IBASIS_RTRIANG); + if (EGlpNumIsNeqq (v[tr], INFTY) && EGlpNumIsLess (v[tr], val)) + { + EGlpNumZero (alpha); + break; + } + EGlpNumCopyAbs (val, matval[mbeg + i]); + if (irow[tr] == 0 && EGlpNumIsLess (alpha, val)) + { + EGlpNumCopy (alpha, val); + r = tr; + } + } + if (EGlpNumIsNeqqZero (alpha) && EGlpNumIsNeqq (alpha, NINFTY)) + { + vstat[j] = STAT_BASIC; + nbelem++; + irow[r] = 1; + EGlpNumCopy (v[r], alpha); + for (i = 0; i < mcnt; i++) + if (EGlpNumIsNeqqZero (matval[mbeg + i])) + rrow[matind[mbeg + i]]++; + } + } + } +#if BASIS_STATS > 0 + printf ("nartifs = %d\n", lp->nrows - nbelem); +#endif + + if (nbelem < lp->nrows) + { + for (i = 0; i < lp->nrows; i++) + { + if (irow[i] == 0) + { + if (unitcol[i] != -1) + { + vstat[unitcol[i]] = STAT_BASIC; + nbelem++; + } + else + { + fprintf (stderr, "Error: Not enough artificials\n"); + return -1; + } + } + } + } + EGlpNumClearVar (alpha); + EGlpNumClearVar (val); + EGlpNumClearVar (maxelem); + return nbelem; +} + +/* This is an implementation of the initial basis procedure + in: "Implementing the simplex method: the initial basis", by + Bob Bixby. + Goals: choose initial variables to go into basis which satisfy: + 1) vars are slacks, 2) vars have freedom to move + 3) initial submatrix is nonsingular, 4) low objective function + contribution. +*/ +static int get_initial_basis1 ( + lpinfo * lp, + int *vstat) +{ + int rval = 0; + int i, j, tot1 = 0, tot2 = 0; + int nbelem = 0, nslacks = 0; + int tfree = 0, tbndone = 0; + int tbounded = 0; + int *irow = NULL, *rrow = NULL; + int *perm = NULL, *porder = NULL; + int *unitcol = NULL; + EGlpNum_t cmax; + EGlpNum_t *v = NULL; + EGlpNum_t *qpenalty = NULL; + var_data vd; + + ILLbasis_init_vardata (&vd); + EGlpNumInitVar (cmax); + + get_var_info (lp, &vd); + if (!EGlpNumIsNeqqZero (vd.cmax)) + EGlpNumOne (cmax); + else + { + EGlpNumCopy (cmax, vd.cmax); + EGlpNumMultUiTo (cmax, 1000); + } + + ILL_SAFE_MALLOC (irow, lp->nrows, int); + ILL_SAFE_MALLOC (rrow, lp->nrows, int); + + v = EGlpNumAllocArray (lp->nrows); + ILL_SAFE_MALLOC (unitcol, lp->nrows, int); + + for (i = 0; i < lp->nrows; i++) + { + unitcol[i] = -1; + EGlpNumCopy (v[i], INFTY); + irow[i] = 0; + rrow[i] = 0; + } + + nslacks = init_slack_basis (lp, vstat, irow, rrow, unitcol, NULL, NULL); + if (nslacks != vd.nslacks) + { + printf ("complain: incorrect basis info(slacks)\n"); + rval = E_SIMPLEX_ERROR; + ILL_CLEANUP; + } + if (nslacks == lp->nrows) + ILL_CLEANUP; + nbelem = nslacks; + if (nbelem < lp->nrows) + { + for (i = 0; i < lp->nrows; i++) + { + if (irow[i] == 0) + { + if (unitcol[i] != -1) + { + vstat[unitcol[i]] = STAT_BASIC; + nbelem++; + } + else + { + fprintf (stderr, "Error: Not enough artificials\n"); + return -1; + } + } + } + } + ILL_CLEANUP; + + tot1 = vd.nfree + vd.nbndone; + tot2 = vd.nfree + vd.nbndone + vd.nbounded; + ILL_SAFE_MALLOC (perm, tot2, int); + ILL_SAFE_MALLOC (porder, tot2, int); + + qpenalty = EGlpNumAllocArray (tot2); + + for (j = 0; j < lp->ncols; j++) + { + if (vstat[j] == STAT_BASIC) + continue; + + switch (lp->vtype[j]) + { + case VFREE: + porder[tfree] = j; + perm[tfree] = tfree; + EGlpNumCopyFrac (qpenalty[tfree], lp->cz[j], cmax); + tfree++; + break; + + case VLOWER: + case VUPPER: + porder[vd.nfree + tbndone] = j; + perm[vd.nfree + tbndone] = tbndone; + EGlpNumCopyFrac (qpenalty[vd.nfree + tbndone], lp->cz[j], cmax); + if (lp->vtype[j] == VLOWER) + EGlpNumAddTo (qpenalty[vd.nfree + tbndone], lp->lz[j]); + else + EGlpNumSubTo (qpenalty[vd.nfree + tbndone], lp->uz[j]); + tbndone++; + break; + + case VFIXED: + case VBOUNDED: + porder[tot1 + tbounded] = j; + perm[tot1 + tbounded] = tbounded; + EGlpNumCopyFrac (qpenalty[tot1 + tbndone], lp->cz[j], cmax); + EGlpNumAddTo (qpenalty[tot1 + tbndone], lp->lz[j]); + EGlpNumSubTo (qpenalty[tot1 + tbndone], lp->uz[j]); + tbounded++; + break; + } + } + if (tfree != vd.nfree || tbndone != vd.nbndone || tbounded != vd.nbounded) + { + printf ("complain: incorrect basis info \n"); + rval = E_SIMPLEX_ERROR; + ILL_CLEANUP; + } + + ILLutil_EGlpNum_perm_quicksort (perm, qpenalty, vd.nfree); + ILLutil_EGlpNum_perm_quicksort (perm + vd.nfree, qpenalty + vd.nfree, + vd.nbndone); + ILLutil_EGlpNum_perm_quicksort (perm + tot1, qpenalty + tot1, vd.nbounded); + + for (i = 0; i < vd.nbndone; i++) + perm[vd.nfree + i] += vd.nfree; + for (i = 0; i < vd.nbounded; i++) + perm[tot1 + i] += tot1; + + nbelem = + primal_col_select (lp, vstat, irow, rrow, unitcol, v, perm, porder, nbelem, + tot2); + if (nbelem != lp->nrows) + { + printf ("complain: incorrect final basis size\n"); + rval = E_SIMPLEX_ERROR; + ILL_CLEANUP; + } + +CLEANUP: + EGlpNumClearVar (cmax); + if (rval) + ILLbasis_free_basisinfo (lp); + ILL_IFFREE (irow, int); + ILL_IFFREE (rrow, int); + + EGlpNumFreeArray (v); + ILL_IFFREE (perm, int); + ILL_IFFREE (porder, int); + ILL_IFFREE (unitcol, int); + + EGlpNumFreeArray (qpenalty); + ILLbasis_clear_vardata (&vd); + EG_RETURN (rval); +} + +static int get_initial_basis2 ( + lpinfo * lp, + int *vstat) +{ + int rval = 0; + int i, j, k, tot1, tot2; + int rbeg, rcnt, mcnt; + int nbelem = 0, nslacks = 0; + int tfree = 0, tbndone = 0; + int tbounded = 0; + int *irow = NULL, *rrow = NULL; + int *perm = NULL, *porder = NULL; + int *unitcol = NULL; + EGlpNum_t *v = NULL; + EGlpNum_t *qpenalty = NULL; + int col = 0, s_i = 0, selc = 0; + int *icol = NULL, *rcol = NULL; + int *plen = NULL; + EGlpNum_t *dj = NULL; + var_data vd; + EGlpNum_t seldj; + EGlpNum_t selv; + EGlpNum_t c_dj; + EGlpNum_t cmax; + + EGlpNumInitVar (seldj); + EGlpNumInitVar (selv); + EGlpNumInitVar (c_dj); + EGlpNumInitVar (cmax); + EGlpNumZero (c_dj); + EGlpNumZero (selv); + EGlpNumZero (seldj); + ILLbasis_init_vardata (&vd); + + get_var_info (lp, &vd); + + ILL_SAFE_MALLOC (irow, lp->nrows, int); + ILL_SAFE_MALLOC (rrow, lp->nrows, int); + + v = EGlpNumAllocArray (lp->nrows); + ILL_SAFE_MALLOC (unitcol, lp->nrows, int); + ILL_SAFE_MALLOC (icol, lp->ncols, int); + ILL_SAFE_MALLOC (rcol, lp->ncols, int); + + dj = EGlpNumAllocArray (lp->ncols); + + for (i = 0; i < lp->nrows; i++) + { + unitcol[i] = -1; + EGlpNumCopy (v[i], INFTY); + irow[i] = 0; + rrow[i] = 0; + } + /* assign all d_j */ + for (i = 0; i < lp->ncols; i++) + { + icol[i] = 0; + rcol[i] = 0; + EGlpNumCopy (dj[i], lp->cz[i]); + } + + nslacks = init_slack_basis (lp, vstat, irow, rrow, unitcol, icol, rcol); + if (nslacks != vd.nslacks) + { + printf ("complain: incorrect basis info\n"); + rval = E_SIMPLEX_ERROR; + ILL_CLEANUP; + } + if (nslacks == lp->nrows) + ILL_CLEANUP; + nbelem = nslacks; + + /* allocate maximum required space for perm etc. */ + ILL_SAFE_MALLOC (perm, lp->ncols, int); + ILL_SAFE_MALLOC (porder, lp->ncols, int); + ILL_SAFE_MALLOC (plen, lp->nrows, int); + + qpenalty = EGlpNumAllocArray (lp->ncols); + + /* find all unit rows and record lengths */ + for (i = 0; i < lp->nrows; i++) + { + if (irow[i] != 1) + { + rbeg = lp->rowbeg[i]; + rcnt = lp->rowcnt[i]; + for (j = 0; j < rcnt; j++) + { + EGlpNumCopyAbs (cmax, lp->rowval[rbeg + j]); + if (EGlpNumIsNeqq (cmax, oneLpNum)) + break; + } + if (j == rcnt) + { + perm[s_i] = s_i; + porder[s_i] = i; + plen[s_i] = rcnt; + s_i++; + } + } + } + + /*sort all unit rows */ + ILLutil_int_perm_quicksort (perm, plen, s_i); + + /* now go through the unit rows */ + for (k = 0; k < s_i; k++) + { + i = porder[perm[k]]; + rbeg = lp->rowbeg[i]; + rcnt = lp->rowcnt[i]; + selc = -1; + EGlpNumCopy (seldj, INFTY); + EGlpNumZero (selv); + + /* for every row s_i, compute min {d_j : d_j <0 , j is u or l or fr} */ + for (j = 0; j < rcnt; j++) + { + col = lp->rowind[rbeg + j]; + if (rcol[col] == 1) + break; + if (EGlpNumIsLessZero (dj[col])) + { + if (EGlpNumIsLess (dj[col], seldj)) + { + selc = col; + EGlpNumCopy (seldj, dj[col]); + EGlpNumCopy (selv, lp->rowval[rbeg + j]); + } + } + } + /* select pivot element and update all d_j's */ + if (selc != -1) + { + nbelem++; + irow[i] = 1; + rrow[i] = 1; + icol[selc] = 1; + EGlpNumCopyFrac (c_dj, dj[selc], selv); + vstat[selc] = STAT_BASIC; + for (j = 0; j < rcnt; j++) + { + col = lp->rowind[rbeg + j]; + EGlpNumSubInnProdTo (dj[col], lp->rowval[rbeg + j], c_dj); + rcol[col] = 1; + } + } + } +#if BASIS_STATS > 0 + printf ("unit rows = %d\n", s_i); + printf ("nslacks %d, unit rows selected = %d\n", nslacks, nbelem - nslacks); +#endif + /* now go through remaining cols with dj = 0 */ + tot1 = vd.nfree + vd.nbndone; + + if (!EGlpNumIsNeqqZero (vd.cmax)) + EGlpNumOne (cmax); + else + { + EGlpNumCopy (cmax, vd.cmax); + EGlpNumMultUiTo (cmax, 1000); + } + for (j = 0; j < lp->ncols; j++) + { + if (vstat[j] == STAT_BASIC) + continue; + if (icol[j] == 1 || EGlpNumIsNeqZero (dj[j], BD_TOLER)) + continue; + mcnt = lp->matcnt[j]; + + EGlpNumSet (c_dj, (double) mcnt); + switch (lp->vtype[j]) + { + case VFREE: + porder[tfree] = j; + perm[tfree] = tfree; + EGlpNumCopyFrac (qpenalty[tfree], lp->cz[j], cmax); + EGlpNumAddTo (qpenalty[tfree], c_dj); + tfree++; + break; + + case VLOWER: + case VUPPER: + porder[vd.nfree + tbndone] = j; + perm[vd.nfree + tbndone] = tbndone; + EGlpNumCopyFrac (qpenalty[vd.nfree + tbndone], lp->cz[j], cmax); + EGlpNumAddTo (qpenalty[vd.nfree + tbndone], c_dj); + if (lp->vtype[j] == VLOWER) + EGlpNumAddTo (qpenalty[vd.nfree + tbndone], lp->lz[j]); + else + EGlpNumSubTo (qpenalty[vd.nfree + tbndone], lp->uz[j]); + tbndone++; + break; + + case VFIXED: + case VBOUNDED: + porder[tot1 + tbounded] = j; + perm[tot1 + tbounded] = tbounded; + EGlpNumCopyFrac (qpenalty[tot1 + tbounded], lp->cz[j], cmax); + EGlpNumAddTo (qpenalty[tot1 + tbounded], lp->lz[j]); + EGlpNumSubTo (qpenalty[tot1 + tbounded], lp->uz[j]); + EGlpNumAddTo (qpenalty[tot1 + tbounded], c_dj); + tbounded++; + break; + } + } +#if BASIS_STATS > 0 + printf ("bfree %d, bone %d, bbnd %d\n", tfree, tbndone, tbounded); +#endif + + ILLutil_EGlpNum_perm_quicksort (perm, qpenalty, tfree); + ILLutil_EGlpNum_perm_quicksort (perm + vd.nfree, qpenalty + vd.nfree, + tbndone); + ILLutil_EGlpNum_perm_quicksort (perm + tot1, qpenalty + tot1, tbounded); + + tot2 = tfree + tbndone; + for (i = 0; i < tbndone; i++) + { + perm[tfree + i] = perm[vd.nfree + i] + tfree; + porder[tfree + i] = porder[vd.nfree + i]; + } + for (i = 0; i < tbounded; i++) + { + perm[tot2 + i] = perm[tot1 + i] + tot2; + porder[tot2 + i] = porder[tot1 + i]; + } + tot2 += tbounded; + + nbelem = + primal_col_select (lp, vstat, irow, rrow, unitcol, v, perm, porder, nbelem, + tot2); + if (nbelem != lp->nrows) + { + printf ("complain: incorrect final basis size\n"); + rval = E_SIMPLEX_ERROR; + ILL_CLEANUP; + } + +CLEANUP: + if (rval) + ILLbasis_free_basisinfo (lp); + + ILL_IFFREE (irow, int); + ILL_IFFREE (rrow, int); + + EGlpNumFreeArray (v); + ILL_IFFREE (unitcol, int); + ILL_IFFREE (icol, int); + ILL_IFFREE (rcol, int); + + EGlpNumFreeArray (dj); + ILL_IFFREE (perm, int); + ILL_IFFREE (porder, int); + ILL_IFFREE (plen, int); + + EGlpNumFreeArray (qpenalty); + EGlpNumClearVar (seldj); + EGlpNumClearVar (selv); + EGlpNumClearVar (c_dj); + EGlpNumClearVar (cmax); + ILLbasis_clear_vardata (&vd); + EG_RETURN (rval); +} + +static int set_basis_indices ( + lpinfo * lp, + int *vstat) +{ + int i, b = 0, nb = 0; + int vs; + + for (i = 0; i < lp->ncols; i++) + { + vs = vstat[i]; + lp->vstat[i] = vs; + + if (vs == STAT_BASIC) + { + lp->baz[b] = i; + lp->vindex[i] = b; + b++; + } + else if (vs == STAT_UPPER || vs == STAT_LOWER || vs == STAT_ZERO) + { + lp->nbaz[nb] = i; + lp->vindex[i] = nb; + nb++; + } + else + { + fprintf (stderr, "Error in basis creation\n"); + return E_SIMPLEX_ERROR; + } + } + if (b != lp->nrows) + { + fprintf (stderr, "Error 2 in basis creation\n"); + return E_SIMPLEX_ERROR; + } + else if (nb != lp->nnbasic) + { + fprintf (stderr, "Error 3 in basis creation\n"); + return E_SIMPLEX_ERROR; + } + return 0; +} + +int ILLbasis_get_initial ( + lpinfo * lp, + int algorithm) +{ + int rval = 0; + int *vstat = NULL; + + ILLbasis_free_basisinfo (lp); + ILLbasis_init_basisinfo (lp); + rval = ILLbasis_build_basisinfo (lp); + CHECKRVALG (rval, CLEANUP); + + ILL_SAFE_MALLOC (vstat, lp->ncols, int); + + if (algorithm == PRIMAL_SIMPLEX) + rval = get_initial_basis1 (lp, vstat); + else + rval = get_initial_basis2 (lp, vstat); + + if (rval == E_SIMPLEX_ERROR) + { + #ifdef HAVE_ZLIB_H + EGioFile_t *f = EGioOpen ("bad.lp.gz", "w"); + #else + #ifdef HAVE_BZLIB_H + EGioFile_t *f = EGioOpen ("bad.lp.bz2", "w"); + #else + EGioFile_t *f = EGioOpen ("bad.lp", "w"); + #endif + #endif + int tval = ILLwrite_lp_file (lp->O, f, NULL); + if (tval) + { + fprintf (stderr, "Error writing bad lp\n"); + } + if (f != NULL) + EGioClose (f); + } + CHECKRVALG (rval, CLEANUP); + + rval = set_basis_indices (lp, vstat); + CHECKRVALG (rval, CLEANUP); + lp->basisid = 0; + +CLEANUP: + ILL_IFFREE (vstat, int); + + EG_RETURN (rval); +} + +static int choose_basis ( + int algorithm, + EGlpNum_t pinf1, + EGlpNum_t dinf1, + EGlpNum_t pinf2, + EGlpNum_t dinf2) +{ +/* We changed the constant definitions outside here, the actual numbers are + * asigned in lpdata.c. the values are as follows: + * CB_EPS = 0.001; + * CB_PRI_RLIMIT = 0.25; + * CB_INF_RATIO = 10.0; + * */ + int choice = 1; + EGlpNum_t rp, rd; + + if (algorithm == PRIMAL_SIMPLEX) + { + EGlpNumInitVar (rp); + EGlpNumInitVar (rd); + EGlpNumCopyDiff (rp, pinf1, pinf2); + EGlpNumCopyDiff (rd, dinf1, dinf2); + if (EGlpNumIsLeq (rp, CB_EPS) && EGlpNumIsLeq (rd, CB_EPS)) + choice = 1; + else + { + EGlpNumSign (rp); + EGlpNumSign (rd); + if (EGlpNumIsLeq (rp, CB_EPS) && EGlpNumIsLeq (rd, CB_EPS)) + choice = 2; + else if (EGlpNumIsLess (pinf1, pinf2) && EGlpNumIsLess (dinf2, dinf1)) + { + choice = 1; + EGlpNumCopyFrac (rp, pinf1, pinf2); + EGlpNumCopyFrac (rd, dinf2, dinf1); + EGlpNumMultTo (rd, CB_INF_RATIO); + if (EGlpNumIsLess (CB_PRI_RLIMIT, rp) && (EGlpNumIsLess (rd, rp))) + choice = 2; + } + else if (EGlpNumIsLess (pinf2, pinf1) && EGlpNumIsLess (dinf1, dinf2)) + { + choice = 2; + EGlpNumCopyFrac (rp, pinf2, pinf1); + EGlpNumCopyFrac (rd, dinf1, dinf2); + EGlpNumMultTo (rd, CB_INF_RATIO); + if (EGlpNumIsLess (CB_PRI_RLIMIT, rp) && EGlpNumIsLess (rd, rp)) + choice = 1; + } + else + choice = 1; + } + EGlpNumClearVar (rp); + EGlpNumClearVar (rd); + } + ILL_IFTRACE ("%s:%d\n", __func__, choice); + return choice; +} + +int ILLbasis_get_cinitial ( + lpinfo * lp, + int algorithm) +{ + int rval = 0; + int *vstat1 = NULL; + int *vstat2 = NULL; + int singular; + int choice = 0; + +#if BASIS_STATS > 0 + int i, nz1 = 0, nz2 = 0; +#endif + EGlpNum_t pinf1, pinf2, dinf1, dinf2; + feas_info fi; + + EGlpNumInitVar (pinf1); + EGlpNumInitVar (pinf2); + EGlpNumInitVar (dinf1); + EGlpNumInitVar (dinf2); + EGlpNumInitVar (fi.totinfeas); + + ILLbasis_free_basisinfo (lp); + ILLbasis_init_basisinfo (lp); + rval = ILLbasis_build_basisinfo (lp); + CHECKRVALG (rval, CLEANUP); + + ILL_SAFE_MALLOC (vstat1, lp->ncols, int); + ILL_SAFE_MALLOC (vstat2, lp->ncols, int); + + if (algorithm != PRIMAL_SIMPLEX) + { + rval = get_initial_basis2 (lp, vstat2); + CHECKRVALG (rval, CLEANUP); + rval = set_basis_indices (lp, vstat2); + lp->basisid = 0; + ILL_CLEANUP; + } + + rval = get_initial_basis1 (lp, vstat1); + CHECKRVALG (rval, CLEANUP); + rval = get_initial_basis2 (lp, vstat2); + CHECKRVALG (rval, CLEANUP); + lp->basisid = 0; + + /* handle first basis */ + rval = set_basis_indices (lp, vstat1); + CHECKRVALG (rval, CLEANUP); +#if BASIS_STATS > 0 + for (i = 0; i < lp->nrows; i++) + nz1 += lp->matcnt[lp->baz[i]]; +#endif + rval = ILLbasis_factor (lp, &singular); + if (singular) + MESSAGE (__QS_SB_VERB, "Singular Basis found!"); + CHECKRVALG (rval, CLEANUP); + + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + ILLfct_dual_adjust (lp, zeroLpNum); + ILLfct_compute_xbz (lp); + + ILLfct_check_pfeasible (lp, &fi, lp->tol->pfeas_tol); + ILLfct_check_dfeasible (lp, &fi, lp->tol->dfeas_tol); + EGlpNumCopy (pinf1, lp->pinfeas); + EGlpNumCopy (dinf1, lp->dinfeas); + /* + * ILLfct_compute_pobj (lp); obj1p = lp->objval; + * ILLfct_compute_dobj (lp); obj1d = lp->objval; + */ + + /* handle second basis */ + rval = set_basis_indices (lp, vstat2); + CHECKRVALG (rval, CLEANUP); +#if BASIS_STATS > 0 + for (i = 0; i < lp->nrows; i++) + nz2 += lp->matcnt[lp->baz[i]]; +#endif + rval = ILLbasis_factor (lp, &singular); + if (singular) + MESSAGE (__QS_SB_VERB, "Singular Basis found!"); + CHECKRVALG (rval, CLEANUP); + + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + ILLfct_dual_adjust (lp, zeroLpNum); + ILLfct_compute_xbz (lp); + + ILLfct_check_pfeasible (lp, &fi, lp->tol->pfeas_tol); + ILLfct_check_dfeasible (lp, &fi, lp->tol->dfeas_tol); + EGlpNumCopy (pinf2, lp->pinfeas); + EGlpNumCopy (dinf2, lp->dinfeas); + +#if BASIS_STATS > 0 + printf ("b1: nz %d pinf %.2f dinf %.2f\n", nz1, EGlpNumToLf (pinf1), + EGlpNumToLf (dinf1)); + printf ("b2: nz %d pinf %.2f dinf %.2f\n", nz2, EGlpNumToLf (pinf2), + EGlpNumToLf (dinf2)); +#endif + choice = choose_basis (algorithm, pinf1, dinf1, pinf2, dinf2); + if (choice == 1) + { + lp->fbasisid = -1; + rval = set_basis_indices (lp, vstat1); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + if (rval == E_SIMPLEX_ERROR) + { + #ifdef HAVE_ZLIB_H + EGioFile_t *fil = EGioOpen ("bad.lp.gz", "w"); + #else + #ifdef HAVE_BZLIB_H + EGioFile_t *fil = EGioOpen ("bad.lp.bz2", "w"); + #else + EGioFile_t *fil = EGioOpen ("bad.lp", "w"); + #endif + #endif + int tval = ILLwrite_lp_file (lp->O, fil, NULL); + + if (tval) + { + fprintf (stderr, "Error writing bad lp\n"); + } + if (fil != NULL) + EGioClose (fil); + } + ILL_IFFREE (vstat1, int); + ILL_IFFREE (vstat2, int); + + EGlpNumClearVar (pinf1); + EGlpNumClearVar (pinf2); + EGlpNumClearVar (dinf1); + EGlpNumClearVar (dinf2); + EGlpNumClearVar (fi.totinfeas); + EG_RETURN (rval); +} + +int ILLbasis_factor ( + lpinfo * lp, + int *singular) +{ + int rval = 0; + int i; + int eindex; + int lindex; + int ltype; + int lvstat; + int nsing = 0; + int *singr = 0; + int *singc = 0; + + *singular = 0; + do + { + if (lp->f) + { + ILLfactor_free_factor_work (lp->f); + } + else + { + ILL_SAFE_MALLOC (lp->f, 1, factor_work); + EGlpNumInitVar (lp->f->fzero_tol); + EGlpNumInitVar (lp->f->szero_tol); + EGlpNumInitVar (lp->f->partial_tol); + EGlpNumInitVar (lp->f->maxelem_orig); + EGlpNumInitVar (lp->f->maxelem_factor); + EGlpNumInitVar (lp->f->maxelem_cur); + EGlpNumInitVar (lp->f->partial_cur); + ILLfactor_init_factor_work (lp->f); + } + rval = ILLfactor_create_factor_work (lp->f, lp->O->nrows); + CHECKRVALG (rval, CLEANUP); + + rval = ILLfactor (lp->f, lp->baz, lp->matbeg, lp->matcnt, + lp->matind, lp->matval, &nsing, &singr, &singc); + CHECKRVALG (rval, CLEANUP); + + if (nsing != 0) + { + *singular = 1; + MESSAGE (__QS_SB_VERB, "Found singular basis!"); + for (i = 0; i < nsing; i++) + { + eindex = lp->vindex[lp->O->rowmap[singr[i]]]; + lindex = singc[i]; + ltype = lp->vtype[lp->baz[lindex]]; + + if (ltype == VBOUNDED || ltype == VLOWER || ltype == VARTIFICIAL) + lvstat = STAT_LOWER; + else if (ltype == VUPPER) + lvstat = STAT_UPPER; + else + lvstat = STAT_ZERO; + + ILLfct_update_basis_info (lp, eindex, lindex, lvstat); + lp->basisid++; + } + ILL_IFFREE (singr, int); + ILL_IFFREE (singc, int); + } + + } while (nsing != 0); + + lp->fbasisid = lp->basisid; + +CLEANUP: + ILL_IFFREE (singr, int); + ILL_IFFREE (singc, int); + + if (rval) + fprintf (stderr, "Error: unknown in %s\n", __func__); + EG_RETURN (rval); +} + +int ILLbasis_refactor ( + lpinfo * lp) +{ + int sing = 0; + int rval = 0; + + rval = ILLbasis_factor (lp, &sing); + if (sing) + { + MESSAGE (__QS_SB_VERB, "Singular Basis found!"); + rval = QS_LP_CHANGE_PREC; + return rval; + } + EG_RETURN (rval); +} + +void ILLbasis_column_solve ( + lpinfo * lp, + svector * rhs, + svector * soln) +{ + ILLfactor_ftran (lp->f, rhs, soln); +} + +void ILLbasis_column_solve_update ( + lpinfo * lp, + svector * rhs, + svector * upd, + svector * soln) +{ + ILLfactor_ftran_update (lp->f, rhs, upd, soln); +} + +void ILLbasis_row_solve ( + lpinfo * lp, + svector * rhs, + svector * soln) +{ + ILLfactor_btran (lp->f, rhs, soln); +} + +int ILLbasis_update ( + lpinfo * lp, + svector * y, + int lindex, + int *refactor, + int *singular) +{ +#if 0 /* To always refactor, change 0 to 1 */ + *refactor = 1; + return ILLbasis_factor (lp, singular); +#else + + int rval = 0; + + *refactor = 0; + rval = ILLfactor_update (lp->f, y, lindex, refactor); + if (rval == E_FACTOR_BLOWUP || rval == E_UPDATE_SINGULAR_ROW + || rval == E_UPDATE_SINGULAR_COL) + { +/* Bico - comment out for dist + fprintf(stderr, "Warning: numerically bad basis in ILLfactor_update\n"); +*/ + *refactor = 1; + rval = 0; + } + if (rval == E_UPDATE_NOSPACE) + { + *refactor = 1; + rval = 0; + } + + if (*refactor) + { + rval = ILLbasis_factor (lp, singular); + if (*singular) + MESSAGE (__QS_SB_VERB, "Singular Basis found!"); + } + if (rval) + { + EGioFile_t *eout = 0; + int tval; + + printf ("write bad lp to factor.lp\n"); + fflush (stdout); + #ifdef HAVE_ZLIB_H + eout = EGioOpen ("factor.lp.gz", "w"); + #else + #ifdef HAVE_BZLIB_H + eout = EGioOpen ("factor.lp.bz2", "w"); + #else + eout = EGioOpen ("factor.lp", "w"); + #endif + #endif + if (!eout) + { + fprintf (stderr, "could not open file to write bad factor lp\n"); + } + else + { + tval = ILLwrite_lp_file (lp->O, eout, NULL); + if (tval) + { + fprintf (stderr, "error while writing bad factor lp\n"); + } + EGioClose (eout); + } + + printf ("write bad basis to factor.bas\n"); + fflush (stdout); + tval = ILLlib_writebasis (lp, 0, "factor.bas"); + if (tval) + { + fprintf (stderr, "error while writing factor basis\n"); + } + } + + EG_RETURN (rval); +#endif +} diff --git a/src/basis.h b/src/basis.h new file mode 100644 index 0000000..120dbad --- /dev/null +++ b/src/basis.h @@ -0,0 +1,107 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: basis.h,v 1.3 2003/11/05 16:57:39 meven Exp $ */ +#ifndef __BASIS_H +#define __BASIS_H + +#include "config.h" +#include "dstruct.h" +#include "lpdefs.h" +#include "lpdata.h" + +#if 0 +#if EGLPNUM_TYPE != DBL_TYPE && EGLPNUM_TYPE != LDBL_TYPE +extern EGlpNum_t CB_PRI_RLIMIT; /* = 0.25 */ +extern EGlpNum_t CB_INF_RATIO; /* = 10.0 */ +extern EGlpNum_t CB_EPS; /* = 0.001 */ +#endif +#endif + +typedef struct var_data +{ + int nartif; + int nslacks; + int nfree; + int nbndone; + int nbounded; + int nfixed; + EGlpNum_t cmax; +} +var_data; + +void ILLbasis_init_vardata ( + var_data * vd); +void ILLbasis_clear_vardata ( + var_data * vd); + +int ILLbasis_build_basisinfo ( + lpinfo * lp), + ILLbasis_get_initial ( + lpinfo * lp, + int algorithm), + ILLbasis_get_cinitial ( + lpinfo * lp, + int algorithm), + ILLbasis_load ( + lpinfo * lp, + ILLlp_basis * B), + ILLbasis_tableau_row ( + lpinfo * lp, + int row, + EGlpNum_t * brow, + EGlpNum_t * trow, + EGlpNum_t * rhs, + int strict), + ILLbasis_factor ( + lpinfo * lp, + int *singular), + ILLbasis_refactor ( + lpinfo * lp), + ILLbasis_update ( + lpinfo * lp, + svector * y, + int lindex, + int *refactor, + int *singular); + +void ILLbasis_column_solve ( + lpinfo * lp, + svector * rhs, + svector * soln), + ILLbasis_column_solve_update ( + lpinfo * lp, + svector * rhs, + svector * upd, + svector * soln), + ILLbasis_row_solve ( + lpinfo * lp, + svector * rhs, + svector * soln), + ILLbasis_free_basisinfo ( + lpinfo * lp), + ILLbasis_free_fbasisinfo ( + lpinfo * lp), + ILLbasis_init_basisinfo ( + lpinfo * lp); + +#endif /* __BASIS_H */ diff --git a/src/bgetopt.c b/src/bgetopt.c new file mode 100644 index 0000000..4843e46 --- /dev/null +++ b/src/bgetopt.c @@ -0,0 +1,131 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: bgetopt.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* PORTABLE GETOPT */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: 1993 (?) (fmfeb02) */ +/* Modified: 15 February 1995 (bico) - added warning */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int ILLutil_bix_getopt (int argc, char **argv, const char *def, */ +/* int *p_optind, char **p_optarg) */ +/* parse an argument list */ +/* */ +/****************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +int ILLutil_bix_getopt ( + int ac, + char **av, + const char *def, + int *p_optind, + char **p_optarg) +{ + int c; + char *sp = av[*p_optind]; + char bwarn[2]; + + if (*p_optind < 1 || *p_optind >= ac) + { + *p_optind = ac; + return (EOF); + } + if ((int) *sp != (int) '-') + return (EOF); + if ((int) *(sp + 1) == (int) '-') + { + (*p_optind)++; + return (EOF); + } + (av[*p_optind])++; + sp++; + while ((int) *sp != (int) *def && (int) *def != (int) '\0') + def++; + if ((int) *def == (int) '\0') + { + *p_optind = ac; + bwarn[0] = *sp; /* Bico: February 8, 1995 */ + bwarn[1] = '\0'; + printf ("Illegal option: -%s\n", bwarn); + return ILL_BIX_GETOPT_UNKNOWN; + } + if ((int) *(def + 1) != (int) ':') + { + c = *sp; + if ((int) *(sp + 1) != (int) '\0') + *sp = '-'; + else + (*p_optind)++; + return (c); + } + else + { + if ((int) *(sp + 1) != (int) '\0') + { + *p_optarg = sp + 1; + c = *sp; + (*p_optind)++; + return (c); + } + else if (*p_optind >= ac - 1) + { + *p_optind = ac; + return (EOF); + } + else + { + *p_optarg = av[*p_optind + 1]; + c = *sp; + *p_optind += 2; + return (c); + } + } +} diff --git a/src/bgetopt.h b/src/bgetopt.h new file mode 100644 index 0000000..6ec0cf0 --- /dev/null +++ b/src/bgetopt.h @@ -0,0 +1,43 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __BGETOPT_H__ +#define __BGETOPT_H__ + +/****************************************************************************/ +/* */ +/* bgetopt.c */ +/* */ +/****************************************************************************/ +int ILLutil_bix_getopt ( + int argc, + char **argv, + const char *def, + int *p_optind, + char **p_optarg); + + +#define ILL_BIX_GETOPT_UNKNOWN -3038 + + + +#endif diff --git a/src/binary.c b/src/binary.c new file mode 100644 index 0000000..c1c13db --- /dev/null +++ b/src/binary.c @@ -0,0 +1,1763 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: binary.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +static int TRACE = 0; + +/****************************************************************************/ +/* */ +/* Simple MIP Code to test LP Solver */ +/* */ +/* EXPORTED FUNCTIONS */ +/* */ +/* int ILLmip_bfs (lpinfo *lp, double *val, double *x) */ +/* */ +/* NOTES */ +/* */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "priority.h" +#include "sortrus.h" +#include "iqsutil.h" +#include "lpdata.h" +#include "lpdefs.h" +#include "simplex.h" +#include "binary.h" +#include "price.h" +#include "lib.h" +#include "qstruct.h" +#include "qsopt.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +/*#define ILL_INTTOL (0.000001)*/ +#define ILL_INTTOL PFEAS_TOLER + +#define STRONG_PIVOTS (50) +#define STRONG_CANDIDATES (10) + +#define ILL_BRANCH_STRONG_WEIGHT (10) +#define ILL_BRANCH_STRONG_VAL(v0,v1) \ + (((v0) < (v1) ? (ILL_BRANCH_STRONG_WEIGHT * (v0) + (v1)) \ + : (ILL_BRANCH_STRONG_WEIGHT * (v1) + (v0))) \ + / (ILL_BRANCH_STRONG_WEIGHT + 1.0)) + +#define ILL_BRANCH_PENALTY_WEIGHT (2) +#define ILL_BRANCH_PENALTY_VAL(v0,v1,f) \ + (((v0)*(f) < (v1)*(1.0-(f)) ? \ + (ILL_BRANCH_PENALTY_WEIGHT * (v0)*(f) + (v1)*(1.0-(f))) \ + : (ILL_BRANCH_PENALTY_WEIGHT * (v1)*(1.0-(f)) + (v0)*(f))) \ + / (ILL_BRANCH_PENALTY_WEIGHT + 1.0)) + + + +#define FIRSTBRANCH 1 +#define MIDDLEBRANCH 2 +#define STRONGBRANCH 3 +#define PENALTYBRANCH 4 + + +typedef struct bbnode +{ + struct bbnode *next; + struct bbnode *prev; + int id; + int depth; + int handle; + EGlpNum_t bound; + char *cstat; + char *rstat; + EGlpNum_t *rownorms; + int rownorms_size; + int bound_cnt; + int *bound_indx; + char *lu; + EGlpNum_t *bounds; + int bounds_size; +} +bbnode; + +typedef struct mipinfo +{ + int branching_rule; + int watch; + int depth; + int totalnodes; + int activenodes; + int totalpivots; + int lastpivots; + int objsense; + EGlpNum_t objectivebound; + EGlpNum_t value; + EGlpNum_t *downpen; + EGlpNum_t *uppen; + EGlpNum_t *x; + EGlpNum_t *bestx; + EGlpNum_t *orig_lower; + EGlpNum_t *orig_upper; + EGlpNum_t *lower; + EGlpNum_t *upper; + int nstruct; /* size of all EGlpNum_t arrays */ + lpinfo *lp; + price_info *pinf; + bbnode head_bbnode; + ILLpriority *que; + ILLptrworld ptrworld; +} +mipinfo; + + +ILL_PTRWORLD_ROUTINES (bbnode, bbnodealloc, bbnode_bulkalloc, bbnodefree) +ILL_PTRWORLD_LISTFREE_ROUTINE (bbnode, bbnode_listfree, bbnodefree) +ILL_PTRWORLD_LEAKS_ROUTINE (bbnode, bbnode_check_leaks, depth, int) +static void cleanup_mip ( mipinfo * minf), + choose_initial_price ( price_info * pinf), + best_bbnode ( mipinfo * minf, bbnode ** best), + put_bbnode ( mipinfo * minf, bbnode * b), + remove_bbnode ( bbnode * b), + find_first_branch ( lpinfo * lp, EGlpNum_t * x, int *bvar), + find_middle_branch ( lpinfo * lp, EGlpNum_t * x, int *bvar), + check_integral ( lpinfo * lp, EGlpNum_t * x, int *yesno), + copy_x ( int nstruct, EGlpNum_t * from_x, EGlpNum_t * to_x), + init_mipinfo ( mipinfo * minf), + free_mipinfo ( mipinfo * minf), + init_bbnode ( bbnode * b), + free_bbnode ( bbnode * b); + +static int startup_mip ( mipinfo * minf, lpinfo * lp, price_info * pinf, + EGlpNum_t * lpval, itcnt_t*itcnt), + run_bfs ( mipinfo * minf, itcnt_t*itcnt), + process_bfs_bbnode ( mipinfo * minf, bbnode * b, itcnt_t*itcnt), + child_work ( mipinfo * minf, bbnode * active, int bvar, int bdir, + EGlpNum_t * cval, int *cp, itcnt_t*itcnt), + fix_variables ( lpinfo * lp, EGlpNum_t * bestval, bbnode * b, + EGlpNum_t * wupper, EGlpNum_t * wlower, int *hit), + find_branch ( mipinfo * minf, EGlpNum_t * x, EGlpNum_t * lpval, + int *bvar, itcnt_t*itcnt), + find_penalty_branch ( lpinfo * lp, price_info * pinf, EGlpNum_t * x, + EGlpNum_t * downpen, EGlpNum_t * uppen, EGlpNum_t * lpval, int *bvar, + itcnt_t*itcnt), + find_strong_branch ( lpinfo * lp, price_info * pinf, EGlpNum_t * x, + int *bvar, itcnt_t*itcnt), + plunge ( mipinfo * minf, itcnt_t*itcnt), + plunge_work ( mipinfo * minf, int depth, itcnt_t*itcnt), + round_variables ( mipinfo * minf, int *count, EGlpNum_t * tol); + +static void choose_initial_price ( price_info * pinf) +{ + pinf->pI_price = QS_PRICE_PSTEEP; + pinf->pII_price = QS_PRICE_PSTEEP; + pinf->dI_price = QS_PRICE_DSTEEP; + pinf->dII_price = QS_PRICE_DSTEEP; +} + +int ILLmip_bfs ( + lpinfo * lp, + EGlpNum_t * val, + EGlpNum_t * x, + itcnt_t*itcnt) +{ + int tval, rval = 0; + price_info pinf; + mipinfo minf; + bbnode *b; + EGlpNum_t lpval; + double szeit = ILLutil_zeit (); + + EGlpNumInitVar (lpval); + EGlpNumInitVar (pinf.htrigger); + + ILLprice_init_pricing_info (&pinf); + init_mipinfo (&minf); + + if (!lp) + { + fprintf (stderr, "ILLmip_bfs called without an LP\n"); + rval = 1; + goto CLEANUP; + } + + rval = startup_mip (&minf, lp, &pinf, &lpval, itcnt); + ILL_CLEANUP_IF (rval); + + ILL_SAFE_MALLOC (minf.que, 1, ILLpriority); + rval = ILLutil_priority_init (minf.que, lp->O->nstruct + 1); + ILL_CLEANUP_IF (rval); + + b = bbnodealloc (&minf.ptrworld); + init_bbnode (b); + b->depth = 0; + b->id = minf.totalnodes++; + EGlpNumCopy (b->bound, lpval); + ILL_SAFE_MALLOC (b->cstat, lp->O->nstruct, char); + ILL_SAFE_MALLOC (b->rstat, lp->nrows, char); + + rval = ILLlib_getbasis (lp, b->cstat, b->rstat); + ILL_CLEANUP_IF (rval); + + if (pinf.dII_price == QS_PRICE_DSTEEP) + { + b->rownorms = EGlpNumAllocArray (lp->nrows); + tval = ILLlib_getrownorms (lp, &pinf, b->rownorms); + if (tval) + { + printf ("Row norms not available\n"); + fflush (stdout); + EGlpNumFreeArray (b->rownorms); + } + } + + rval = ILLutil_priority_insert (minf.que, (void *) b, &lpval, &(b->handle)); + ILL_CLEANUP_IF (rval); + + b->prev = &(minf.head_bbnode); + b->next = 0; + minf.head_bbnode.next = b; + minf.activenodes++; + + minf.branching_rule = PENALTYBRANCH; + + rval = run_bfs (&minf, itcnt); + ILL_CLEANUP_IF (rval); + + printf ("Total Number of Nodes: %d\n", minf.totalnodes); + printf ("Total Number of Pivots: %d\n", minf.totalpivots); + printf ("BFS MIP Runing Time: %.2f seconds\n", ILLutil_zeit () - szeit); + fflush (stdout); + + EGlpNumCopy (*val, minf.value); + if (minf.objsense == ILL_MAX) + EGlpNumSign (*val); + + if (x && EGlpNumIsNeqq (minf.value, ILL_MAXDOUBLE)) + { + copy_x (lp->O->nstruct, minf.bestx, x); + } + +CLEANUP: + + if (minf.que) + { + ILLutil_priority_free (minf.que); + ILL_IFFREE (minf.que, ILLpriority); + } + cleanup_mip (&minf); + free_mipinfo (&minf); + ILLprice_free_pricing_info (&pinf); + EGlpNumClearVar (lpval); + EGlpNumClearVar (pinf.htrigger); + ILL_RETURN (rval, "ILLmip_bfs"); +} + +static int startup_mip ( + mipinfo * minf, + lpinfo * lp, + price_info * pinf, + EGlpNum_t * lpval, + itcnt_t*itcnt) +{ + int rval = 0; + int i, col, status, intcount = 0; + EGlpNum_t val; + ILLlpdata *qlp; + + EGlpNumInitVar (val); + + choose_initial_price (pinf); + + qlp = lp->O; + + rval = ILLlib_optimize (lp, 0, pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + + minf->totalpivots += ILLlib_iter (lp); + + rval = ILLlib_objval (lp, 0, &val); + ILL_CLEANUP_IF (rval); + + printf ("LP Value: %.6f\n", EGlpNumToLf (val)); + fflush (stdout); + if (lpval) + EGlpNumCopy (*lpval, val); + + if (qlp->intmarker) + { + for (i = 0; i < qlp->nstruct; i++) + { + if (qlp->intmarker[i]) + { + col = qlp->structmap[i]; + intcount++; + if (EGlpNumIsEqqual (qlp->lower[col], ILL_MINDOUBLE) + || EGlpNumIsEqqual (qlp->upper[col], ILL_MAXDOUBLE)) + { + printf ("Instance has unbounded integer variable\n"); + fflush (stdout); + rval = 1; + goto CLEANUP; + } + } + } + } + + if (intcount == 0) + { + printf ("No integer variables\n"); + fflush (stdout); + rval = 1; + goto CLEANUP; + } + else + { + printf ("%d integer variables\n", intcount); + fflush (stdout); + } + + if (qlp->sinfo) + { /* Free the presolve LP and work with orginal */ + ILLlp_sinfo_free (qlp->sinfo); + ILL_IFFREE (qlp->sinfo, ILLlp_sinfo); + } + + + minf->lp = lp; + minf->pinf = pinf; + minf->objsense = qlp->objsense; + if (qlp->objsense == ILL_MAX) + { /* MIP codes work with min */ + for (i = 0; i < lp->ncols; i++) + { + EGlpNumCopyNeg (qlp->obj[i], qlp->obj[i]); + } + qlp->objsense = ILL_MIN; + } + + minf->x = EGlpNumAllocArray (qlp->nstruct); + minf->bestx = EGlpNumAllocArray (qlp->nstruct); + minf->lower = EGlpNumAllocArray (qlp->nstruct); + minf->upper = EGlpNumAllocArray (qlp->nstruct); + minf->orig_lower = EGlpNumAllocArray (qlp->nstruct); + minf->orig_upper = EGlpNumAllocArray (qlp->nstruct); + minf->downpen = EGlpNumAllocArray (qlp->nstruct); + minf->uppen = EGlpNumAllocArray (qlp->nstruct); + minf->nstruct = qlp->nstruct; + + rval = ILLlib_get_x (lp, 0, minf->x); + ILL_CLEANUP_IF (rval); + + for (i = 0; i < qlp->nstruct; i++) + { + EGlpNumCopy (minf->lower[i], qlp->lower[i]); + EGlpNumCopy (minf->upper[i], qlp->upper[i]); + EGlpNumCopy (minf->orig_lower[i], qlp->lower[i]); + EGlpNumCopy (minf->orig_upper[i], qlp->upper[i]); + EGlpNumOne (minf->downpen[i]); + EGlpNumOne (minf->uppen[i]); + EGlpNumSign (minf->downpen[i]); + EGlpNumSign (minf->uppen[i]); + } + + +CLEANUP: + + EGlpNumClearVar (val); + ILL_RETURN (rval, "startup_mip"); +} + +static void cleanup_mip ( + mipinfo * minf) +{ + int i; + ILLlpdata *qslp; + + if (minf && minf->lp) + { + qslp = minf->lp->O; + if (minf->objsense == ILL_MAX) + { + for (i = 0; i < minf->lp->ncols; i++) + { + EGlpNumSign (qslp->obj[i]); + } + qslp->objsense = ILL_MIN; + } + } +} + +static int run_bfs ( + mipinfo * minf, + itcnt_t*itcnt) +{ + int rval = 0; + bbnode *b; + + while (minf->head_bbnode.next) + { + best_bbnode (minf, &b); + rval = process_bfs_bbnode (minf, b, itcnt); + ILL_CLEANUP_IF (rval); + remove_bbnode (b); + free_bbnode (b); + bbnodefree (&minf->ptrworld, b); + minf->activenodes--; + } + +CLEANUP: + + ILL_RETURN (rval, "run_bfs"); +} + +static int process_bfs_bbnode ( + mipinfo * minf, + bbnode * active, + itcnt_t*itcnt) +{ + lpinfo *lp = minf->lp; + ILLlp_basis B; + int status, bvar = 0; + int i, j, hit, dnp = 0, upp = 0; + int nstruct = lp->O->nstruct; + EGlpNum_t t, lpval, dnval, upval; + EGlpNum_t *wupper = 0; + EGlpNum_t *wlower = 0; + int rval = 0; + + EGlpNumInitVar (t); + EGlpNumInitVar (lpval); + EGlpNumInitVar (dnval); + EGlpNumInitVar (upval); + + ILLlp_basis_init (&B); + + if (minf->watch > 1) + { + printf ("Node %4d: %.3f", active->id, EGlpNumToLf (active->bound)); + if (EGlpNumIsNeqq (minf->value, ILL_MAXDOUBLE)) + printf (" %.3f", EGlpNumToLf (minf->value)); + else + printf (" None"); + printf (", Active %d ", minf->activenodes); + fflush (stdout); + } + else if (minf->watch == 1) + { + if (minf->lastpivots > 1000) + { + minf->lastpivots = 0; + printf ("Pivots %d, Active Nodes %d, Bound %.3f, Soln ", + minf->totalpivots, minf->activenodes, + EGlpNumToLf (active->bound)); + if (!EGlpNumIsLess (minf->value, ILL_MAXDOUBLE)) + printf ("%.3f", EGlpNumToLf (minf->value)); + else + printf ("None\n"); + } + } + + if (EGlpNumIsLeq (minf->objectivebound, active->bound)) + { + if (minf->watch > 1) + { + printf (" Node can be purged\n"); + fflush (stdout); + } + goto CLEANUP; + } + + /* Set the LP bounds for the node. */ + + wlower = EGlpNumAllocArray (nstruct); + wupper = EGlpNumAllocArray (nstruct); + + for (i = 0; i < nstruct; i++) + { + EGlpNumCopy (wlower[i], minf->orig_lower[i]); + EGlpNumCopy (wupper[i], minf->orig_upper[i]); + } + for (i = 0; i < active->bound_cnt; i++) + { + j = active->bound_indx[i]; + if (active->lu[i] == 'L') + EGlpNumCopy (wlower[j], active->bounds[i]); + else + EGlpNumCopy (wupper[j], active->bounds[i]); + } + + if (active->bound_cnt > 0) + { + rval = ILLlib_chgbnds (lp, active->bound_cnt, active->bound_indx, + active->lu, active->bounds); + ILL_CLEANUP_IF (rval); + } + + /* Solve the LP. */ + + rval = ILLlib_loadbasis (&B, nstruct, lp->nrows, active->cstat, + active->rstat); + ILL_CLEANUP_IF (rval); + if (active->rownorms) + { + B.rownorms = EGlpNumAllocArray (lp->nrows); + for (i = 0; i < lp->nrows; i++) + { + EGlpNumCopy (B.rownorms[i], active->rownorms[i]); + } + } + + rval = ILLlib_optimize (lp, &B, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + + minf->totalpivots += ILLlib_iter (lp); + minf->lastpivots += ILLlib_iter (lp); + + if (status == QS_LP_UNSOLVED) + { + printf ("Simplex did not solve the LP\n"); + fflush (stdout); + rval = 1; + ILL_CLEANUP; + } + + if (status == QS_LP_INFEASIBLE) + { + printf (" Infeasible LP, should have been purged earlier\n"); + fflush (stdout); + rval = 1; + ILL_CLEANUP; + } + + if (active->depth < 0) + { + for (i = 0; i < nstruct; i++) + { + EGlpNumCopy (minf->lower[i], wlower[i]); + EGlpNumCopy (minf->upper[i], wupper[i]); + } + rval = plunge (minf, itcnt); + ILL_CLEANUP_IF (rval); + } + + /* Fix variables. */ + + if (EGlpNumIsLess (minf->value, ILL_MAXDOUBLE)) + { + rval = fix_variables (lp, &(minf->value), active, wupper, wlower, &hit); + ILL_CLEANUP_IF (rval); + + if (hit) + { + rval = ILLlib_optimize (lp, &B, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + + minf->totalpivots += ILLlib_iter (lp); + minf->lastpivots += ILLlib_iter (lp); + + if (status == QS_LP_UNSOLVED) + { + printf ("Simplex did not solve the LP\n"); + fflush (stdout); + rval = 1; + ILL_CLEANUP; + } + + if (status == QS_LP_INFEASIBLE) + { + printf (" Infeasible LP after fixing\n"); + fflush (stdout); + rval = 1; + ILL_CLEANUP; + } + } + } + + + /* Branch. */ + + rval = ILLlib_get_x (lp, 0, minf->x); + ILL_CLEANUP_IF (rval); + + rval = ILLlib_objval (lp, 0, &lpval); + ILL_CLEANUP_IF (rval); + + rval = find_branch (minf, minf->x, &lpval, &bvar, itcnt); + ILL_CLEANUP_IF (rval); + + if (bvar == -1) + { + printf ("Found integral solution: %f\n", EGlpNumToLf (lpval)); + if (EGlpNumIsLess (lpval, minf->value)) + { + EGlpNumCopy (minf->value, lpval); + EGlpNumCopy (minf->objectivebound, lpval); + EGlpNumSubTo (minf->objectivebound, ILL_INTTOL); + copy_x (nstruct, minf->x, minf->bestx); + } + } + else + { + /* Create down child */ + + rval = child_work (minf, active, bvar, 'D', &dnval, &dnp, itcnt); + ILL_CLEANUP_IF (rval); + + /* Restore parent basis */ + + rval = ILLlib_loadbasis (&B, nstruct, lp->nrows, active->cstat, + active->rstat); + ILL_CLEANUP_IF (rval); + if (active->rownorms) + { + B.rownorms = EGlpNumAllocArray (lp->nrows); + for (i = 0; i < lp->nrows; i++) + { + EGlpNumCopy (B.rownorms[i], active->rownorms[i]); + } + } + + /* Create up child */ + + rval = child_work (minf, active, bvar, 'U', &upval, &upp, itcnt); + ILL_CLEANUP_IF (rval); + + if (minf->watch > 1) + { + if (EGlpNumIsEqqual (dnval, ILL_MAXDOUBLE)) + { + printf ("DN->XXX"); + } + else + { + printf ("DN->%.3f%c", EGlpNumToLf (dnval), dnp ? 'X' : ' '); + } + if (EGlpNumIsEqqual (upval, ILL_MAXDOUBLE)) + { + printf ("UP->XXX\n"); + } + else + { + printf ("UP->%.3f%c\n", EGlpNumToLf (upval), upp ? 'X' : ' '); + } + fflush (stdout); + } + } + + /* Set the LP bounds back to original values */ + + for (i = 0; i < active->bound_cnt; i++) + { + if (active->lu[i] == 'L') + EGlpNumCopy (t, minf->orig_lower[active->bound_indx[i]]); + else + EGlpNumCopy (t, minf->orig_upper[active->bound_indx[i]]); + + rval = ILLlib_chgbnd (lp, active->bound_indx[i], active->lu[i], t); + ILL_CLEANUP_IF (rval); + } + +CLEANUP: + + EGlpNumFreeArray (wlower); + EGlpNumFreeArray (wupper); + ILLlp_basis_free (&B); + EGlpNumClearVar (t); + EGlpNumClearVar (lpval); + EGlpNumClearVar (dnval); + EGlpNumClearVar (upval); + ILL_RETURN (rval, "process_bfs_bbnode"); +} + +static int child_work ( + mipinfo * minf, + bbnode * active, + int bvar, + int bdir, + EGlpNum_t * cval, + int *cp, + itcnt_t*itcnt) +{ + int tval, rval = 0; + int i, status, intsol; + EGlpNum_t t, oldt, lpval; + EGlpNum_t *xi = &(minf->x[bvar]); + lpinfo *lp = minf->lp; + bbnode *b; + + EGlpNumInitVar (t); + EGlpNumInitVar (lpval); + EGlpNumInitVar (oldt); + + *cp = 0; + + if (bdir == 'D') + { + rval = ILLlib_getbnd (lp, bvar, 'U', &oldt); + ILL_CLEANUP_IF (rval); + EGlpNumFloor (t, *xi); + rval = ILLlib_chgbnd (lp, bvar, 'U', t); + ILL_CLEANUP_IF (rval); + } + else + { + rval = ILLlib_getbnd (lp, bvar, 'L', &oldt); + ILL_CLEANUP_IF (rval); + EGlpNumCeil (t, *xi); + rval = ILLlib_chgbnd (lp, bvar, 'L', t); + ILL_CLEANUP_IF (rval); + } + + rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + + minf->totalpivots += ILLlib_iter (lp); + minf->lastpivots += ILLlib_iter (lp); + + if (status == QS_LP_UNSOLVED) + { + printf ("Simplex did not solve Child LP\n"); + fflush (stdout); + rval = 1; + ILL_CLEANUP; + } + + if (status == QS_LP_INFEASIBLE) + { + EGlpNumCopy (*cval, ILL_MAXDOUBLE); + *cp = 1; + } + else + { + rval = ILLlib_objval (lp, 0, &lpval); + ILL_CLEANUP_IF (rval); + EGlpNumCopy (*cval, lpval); + + /* What about the x vector? Bico - 020531 */ + + check_integral (lp, minf->x, &intsol); + if (intsol) + { + if (EGlpNumIsLess (lpval, minf->value)) + { + printf ("Found integral solution: %f\n", EGlpNumToLf (lpval)); + EGlpNumCopy (minf->value, lpval); + EGlpNumCopy (minf->objectivebound, lpval); + EGlpNumSubTo (minf->objectivebound, ILL_INTTOL); + copy_x (lp->O->nstruct, minf->x, minf->bestx); + } + } + + if (EGlpNumIsLeq (minf->objectivebound, lpval)) + { + *cp = 1; + } + else + { + b = bbnodealloc (&minf->ptrworld); + init_bbnode (b); + b->depth = active->depth + 1; + b->id = minf->totalnodes; + EGlpNumCopy (b->bound, lpval); + ILL_SAFE_MALLOC (b->cstat, lp->O->nstruct, char); + ILL_SAFE_MALLOC (b->rstat, lp->nrows, char); + + rval = ILLlib_getbasis (lp, b->cstat, b->rstat); + ILL_CLEANUP_IF (rval); + if (minf->pinf->dII_price == QS_PRICE_DSTEEP) + { + b->rownorms = EGlpNumAllocArray (lp->nrows); + tval = ILLlib_getrownorms (lp, minf->pinf, b->rownorms); + if (tval) + { + printf ("Row norms not available\n"); + fflush (stdout); + printf ("A\n"); + exit (1); + EGlpNumFreeArray (b->rownorms); + } + } + ILL_SAFE_MALLOC (b->bound_indx, active->bound_cnt + 1, int); + ILL_SAFE_MALLOC (b->lu, active->bound_cnt + 1, char); + + b->bounds = EGlpNumAllocArray (active->bound_cnt + 1); + for (i = 0; i < active->bound_cnt; i++) + { + b->bound_indx[i] = active->bound_indx[i]; + b->lu[i] = active->lu[i]; + EGlpNumCopy (b->bounds[i], active->bounds[i]); + } + b->bound_indx[active->bound_cnt] = bvar; + if (bdir == 'D') + b->lu[active->bound_cnt] = 'U'; + else + b->lu[active->bound_cnt] = 'L'; + EGlpNumCopy (b->bounds[active->bound_cnt], t); + b->bound_cnt = active->bound_cnt + 1; + + rval = ILLutil_priority_insert (minf->que, (void *) b, &lpval, + &(b->handle)); + ILL_CLEANUP_IF (rval); + + put_bbnode (minf, b); + minf->activenodes++; + } + } + minf->totalnodes++; + + if (bdir == 'D') + { + rval = ILLlib_chgbnd (lp, bvar, 'U', oldt); + ILL_CLEANUP_IF (rval); + } + else + { + rval = ILLlib_chgbnd (lp, bvar, 'L', oldt); + ILL_CLEANUP_IF (rval); + } + +CLEANUP: + + EGlpNumClearVar (t); + EGlpNumClearVar (lpval); + EGlpNumClearVar (oldt); + return rval; +} + +static int fix_variables ( + lpinfo * lp, + EGlpNum_t * bestval, + bbnode * b, + EGlpNum_t * wupper, + EGlpNum_t * wlower, + int *hit) +{ + int rval = 0; + int i, nnew = 0; + int nstruct = lp->O->nstruct; + EGlpNum_t delta, lpval; + int *new_indx = 0; + char *new_lu = 0; + EGlpNum_t *new_bounds = 0; + EGlpNum_t *dj = 0; + + EGlpNumInitVar (delta); + EGlpNumInitVar (lpval); + + *hit = 0; + + if (EGlpNumIsLess (*bestval, ILL_MAXDOUBLE)) + { + rval = ILLlib_objval (lp, 0, &lpval); + ILL_CLEANUP_IF (rval); + //delta = bestval - lpval + ILL_INTTOL; + EGlpNumCopy (delta, *bestval); + EGlpNumSubTo (delta, lpval); + EGlpNumAddTo (delta, ILL_INTTOL); + + ILL_SAFE_MALLOC (new_indx, nstruct, int); + ILL_SAFE_MALLOC (new_lu, nstruct, char); + + dj = EGlpNumAllocArray (nstruct); + new_bounds = EGlpNumAllocArray (nstruct); + + rval = ILLlib_solution (lp, 0, 0, 0, 0, 0, dj); + ILL_CLEANUP_IF (rval); + + for (i = 0; i < nstruct; i++) + { + if (lp->O->intmarker[i]) + { + if (EGlpNumIsNeqq (wlower[i], wupper[i])) + { + if (EGlpNumIsLess (delta, dj[i])) + { + EGlpNumSubTo (wupper[i], oneLpNum); + rval = ILLlib_chgbnd (lp, i, 'U', wupper[i]); + ILL_CLEANUP_IF (rval); + new_indx[nnew] = i; + new_lu[nnew] = 'U'; + EGlpNumCopy (new_bounds[nnew], wupper[i]); + nnew++; + } + /*if (-dj[i] > delta) */ + EGlpNumSign (delta); + if (EGlpNumIsLess (delta, dj[i])) + { + EGlpNumAddTo (wlower[i], oneLpNum); + rval = ILLlib_chgbnd (lp, i, 'L', wlower[i]); + ILL_CLEANUP_IF (rval); + new_indx[nnew] = i; + new_lu[nnew] = 'L'; + EGlpNumCopy (new_bounds[nnew], wlower[i]); + nnew++; + } + EGlpNumSign (delta); + } + } + } + + if (nnew) + { + b->bound_indx = + EGrealloc (b->bound_indx, sizeof (int) * (b->bound_cnt + nnew)); + //rval = ILLutil_reallocrus_count ((void **) &(b->bound_indx), + // b->bound_cnt + nnew, sizeof (int)); + //ILL_CLEANUP_IF (rval); + b->lu = EGrealloc (b->lu, sizeof (char) * (b->bound_cnt + nnew)); + //rval = ILLutil_reallocrus_count ((void **) &(b->lu), + // b->bound_cnt + nnew, sizeof (char)); + //ILL_CLEANUP_IF (rval); + EGlpNumReallocArray (&(b->bounds), b->bound_cnt + nnew); + for (i = 0; i < nnew; i++) + { + b->bound_indx[b->bound_cnt + i] = new_indx[i]; + b->lu[b->bound_cnt + i] = new_lu[i]; + EGlpNumCopy (b->bounds[b->bound_cnt + i], new_bounds[i]); + } + b->bound_cnt += nnew; + } + } + + *hit = nnew; + +CLEANUP: + + ILL_IFFREE (new_indx, int); + ILL_IFFREE (new_lu, char); + + EGlpNumFreeArray (dj); + EGlpNumFreeArray (new_bounds); + EGlpNumClearVar (delta); + EGlpNumClearVar (lpval); + return rval; +} + +static void best_bbnode ( + mipinfo * minf, + bbnode ** best) +{ +#if 0 + bbnode *b; + double bestval = ILL_MAXDOUBLE; + + for (b = minf->head_bbnode.next; b; b = b->next) + { + if (b->bound < bestval) + { + *best = b; + bestval = b->bound; + } + } +#endif + + EGlpNum_t val; + + EGlpNumInitVar (val); + ILLutil_priority_deletemin (minf->que, &val, (void **) best); + EGlpNumClearVar (val); +} + +static void put_bbnode ( + mipinfo * minf, + bbnode * b) +{ + b->next = minf->head_bbnode.next; + b->prev = &(minf->head_bbnode); + if (b->next) + b->next->prev = b; + minf->head_bbnode.next = b; +} + +static void remove_bbnode ( + bbnode * b) +{ + b->prev->next = b->next; + if (b->next) + b->next->prev = b->prev; +} + +static int find_branch ( + mipinfo * minf, + EGlpNum_t * x, + EGlpNum_t * lpval, + int *bvar, + itcnt_t*itcnt) +{ + lpinfo *lp = minf->lp; + int rval = 0; + + switch (minf->branching_rule) + { + case PENALTYBRANCH: + rval = find_penalty_branch (lp, minf->pinf, x, minf->downpen, + minf->uppen, lpval, bvar, itcnt); + ILL_CLEANUP_IF (rval); + break; + case FIRSTBRANCH: + find_first_branch (lp, x, bvar); + break; + case MIDDLEBRANCH: + find_middle_branch (lp, x, bvar); + break; + case STRONGBRANCH: + rval = find_strong_branch (lp, minf->pinf, x, bvar, itcnt); + ILL_CLEANUP_IF (rval); + break; + default: + fprintf (stderr, "Unknown branching rule.\n"); + rval = 1; + goto CLEANUP; + } + +CLEANUP: + + ILL_RETURN (rval, "find_branch"); +} + +static void find_first_branch ( + lpinfo * lp, + EGlpNum_t * x, + int *bvar) +{ + int i, ibest = -1; + ILLlpdata *qslp = lp->O; + EGlpNum_t t; + + EGlpNumInitVar (t); + + for (i = 0; i < qslp->nstruct; i++) + { + if (qslp->intmarker[i]) + { + /*t = ILLutil_our_frac (x[i]); */ + EGlpNumFloor (t, x[i]); + EGlpNumSubTo (t, x[i]); + EGlpNumSign (t); + if ((EGlpNumIsNeqZero (t, ILL_INTTOL)) && + (EGlpNumIsNeq (t, oneLpNum, ILL_INTTOL))) + { + ibest = i; + break; + } + } + } + *bvar = ibest; + EGlpNumClearVar (t); +} + +static void find_middle_branch ( + lpinfo * lp, + EGlpNum_t * x, + int *bvar) +{ + int i, ibest = -1; + EGlpNum_t t, tbest; + ILLlpdata *qlp = lp->O; + + EGlpNumInitVar (t); + EGlpNumInitVar (tbest); + EGlpNumSet (tbest, 0.5); + + for (i = 0; i < qlp->nstruct; i++) + { + if (qlp->intmarker[i]) + { + /*t = ILLutil_our_frac (x[i]) - 0.5; + * if (t < 0.0) + * t = -t; */ + EGlpNumFloor (t, x[i]); + EGlpNumMultUiTo (t, 2); + EGlpNumSubTo (t, oneLpNum); + EGlpNumDivUiTo (t, 2); + if (EGlpNumIsLessZero (t)) + EGlpNumSign (t); + /*if (t < tbest) */ + if (EGlpNumIsLess (t, tbest)) + { + EGlpNumCopy (tbest, t); + ibest = i; + } + } + } + + /*if (tbest < (0.5 - ILL_INTTOL)) */ + EGlpNumAddTo (tbest, ILL_INTTOL); + if (EGlpNumIsLessDbl (tbest, 0.5)) + { + *bvar = ibest; + } + else + { + *bvar = -1; + } + EGlpNumClearVar (t); + EGlpNumClearVar (tbest); +} + +static int find_penalty_branch ( + lpinfo * lp, + price_info * pinf, + EGlpNum_t * x, + EGlpNum_t * downpen, + EGlpNum_t * uppen, + EGlpNum_t * lpval, + int *bvar, + itcnt_t*itcnt) +{ + int rval = 0; + int i, k, ibest = -1, ncand = 0, nneed = 0; + ILLlpdata *qslp = lp->O; + int *candidatelist = 0; + int *needlist = 0; + EGlpNum_t *fval = 0; + EGlpNum_t *xlist = 0; + EGlpNum_t *newdown = 0; + EGlpNum_t *newup = 0; + EGlpNum_t a, t, tbest; + + EGlpNumInitVar (a); + EGlpNumInitVar (t); + EGlpNumInitVar (tbest); + EGlpNumCopy (tbest, ILL_MINDOUBLE); + + ILL_SAFE_MALLOC (candidatelist, qslp->nstruct, int); + ILL_SAFE_MALLOC (needlist, qslp->nstruct, int); + + fval = EGlpNumAllocArray (qslp->nstruct); + xlist = EGlpNumAllocArray (qslp->nstruct); + for (i = 0; i < qslp->nstruct; i++) + { + if (qslp->intmarker[i]) + { + /*fval[i] = x[i] - floor(x[i]); */ + EGlpNumFloor (fval[i], x[i]); + EGlpNumSubTo (fval[i], x[i]); + EGlpNumSign (fval[i]); + if ((EGlpNumIsNeqZero (fval[i], ILL_INTTOL)) && + (EGlpNumIsNeq (fval[i], oneLpNum, ILL_INTTOL))) + { + candidatelist[ncand++] = i; + /*if (downpen[i] == -1.0) */ + EGlpNumSign (downpen[i]); + if (EGlpNumIsEqqual (downpen[i], oneLpNum)) + { + EGlpNumCopy (xlist[nneed], x[i]); + needlist[nneed++] = i; + } + EGlpNumSign (downpen[i]); + } + } + } + + if (nneed > 0) + { + newdown = EGlpNumAllocArray (nneed); + newup = EGlpNumAllocArray (nneed); + rval = ILLlib_strongbranch (lp, pinf, needlist, nneed, + 0, newdown, newup, + 5 * STRONG_PIVOTS, ILL_MAXDOUBLE, itcnt); + ILL_CLEANUP_IF (rval); + + for (i = 0; i < nneed; i++) + { + k = needlist[i]; + /*uppen[k] = (newup[i] - lpval) / (1.0 - fval[k]); */ + EGlpNumCopyDiff (uppen[k], newup[i], *lpval); + EGlpNumCopyDiff (downpen[k], oneLpNum, fval[k]); + EGlpNumDivTo (uppen[k], downpen[k]); + /*downpen[k] = (newdown[i] - lpval) / fval[k]; */ + EGlpNumCopyDiffRatio (downpen[k], newdown[i], *lpval, fval[k]); + + } + } + + for (i = 0; i < ncand; i++) + { + k = candidatelist[i]; + /*t = ILL_BRANCH_PENALTY_VAL (downpen[k], uppen[k], fval[k]); */ + EGlpNumCopy (t, downpen[k]); + EGlpNumMultTo (t, fval[k]); + EGlpNumCopyDiff (a, oneLpNum, fval[k]); + EGlpNumMultTo (a, uppen[k]); + if (EGlpNumIsLess (t, a)) + { + EGlpNumMultUiTo (t, ILL_BRANCH_PENALTY_WEIGHT); + EGlpNumAddTo (t, a); + } + else + { + EGlpNumMultUiTo (a, ILL_BRANCH_PENALTY_WEIGHT); + EGlpNumAddTo (t, a); + } + EGlpNumDivUiTo (t, ILL_BRANCH_PENALTY_WEIGHT + 1); + + if (EGlpNumIsLess (tbest, t)) + { + EGlpNumCopy (tbest, t); + ibest = k; + } + } + + *bvar = ibest; + +CLEANUP: + + EGlpNumClearVar (a); + EGlpNumClearVar (t); + EGlpNumClearVar (tbest); + EGlpNumFreeArray (newdown); + EGlpNumFreeArray (newup); + EGlpNumFreeArray (fval); + EGlpNumFreeArray (xlist); + ILL_IFFREE (candidatelist, int); + ILL_IFFREE (needlist, int); + + return rval; +} + +static int find_strong_branch ( + lpinfo * lp, + price_info * pinf, + EGlpNum_t * x, + int *bvar, + itcnt_t*itcnt) +{ + int rval = 0; + int i, ibest = -1, ncand = 0; + int maxtrys = STRONG_CANDIDATES; + EGlpNum_t t, tbest; + ILLlpdata *qlp = lp->O; + int *candidatelist = 0; + int *newlist = 0; + int *perm = 0; + EGlpNum_t *tval = 0; + EGlpNum_t *xlist = 0; + EGlpNum_t *downpen = 0; + EGlpNum_t *uppen = 0; + ILLrandstate rstate; + + EGlpNumInitVar (t); + EGlpNumInitVar (tbest); + EGlpNumCopy (tbest, ILL_MINDOUBLE); + + ILLutil_sprand (999, &rstate); + ILL_SAFE_MALLOC (candidatelist, qlp->nstruct, int); + + tval = EGlpNumAllocArray (qlp->nstruct); + + for (i = 0; i < qlp->nstruct; i++) + { + if (qlp->intmarker[i]) + { + /*t = ILLutil_our_frac (x[i]) - 0.5; + * if (t < 0.0) + * t = -t; */ + EGlpNumFloor (t, x[i]); + EGlpNumSubTo (t, x[i]); + EGlpNumSign (t); + EGlpNumMultUiTo (t, 2); + EGlpNumSubTo (t, oneLpNum); + if (EGlpNumIsLessZero (t)) + EGlpNumSign (t); + /*if (t < (0.5 - ILL_INTTOL)) */ + if (EGlpNumIsNeq (t, oneLpNum, ILL_INTTOL)) + { + candidatelist[ncand] = i; + EGlpNumDivUiTo (t, 2); + EGlpNumCopy (tval[ncand++], t); + } + } + } + + if (ncand > 0) + { + if (ncand > maxtrys) + { + ILL_SAFE_MALLOC (perm, ncand, int); + + for (i = 0; i < ncand; i++) + { + perm[i] = i; + } + ILLutil_EGlpNum_rselect (perm, 0, ncand - 1, maxtrys, tval, &rstate); + + ILL_SAFE_MALLOC (newlist, maxtrys, int); + + for (i = 0; i < maxtrys; i++) + { + newlist[i] = candidatelist[perm[i]]; + } + ILL_IFFREE (candidatelist, int); + + candidatelist = newlist; + newlist = 0; + ncand = maxtrys; + } + + downpen = EGlpNumAllocArray (ncand); + uppen = EGlpNumAllocArray (ncand); + xlist = EGlpNumAllocArray (ncand); + + for (i = 0; i < ncand; i++) + { + EGlpNumCopy (xlist[i], x[candidatelist[i]]); + } + + rval = ILLlib_strongbranch (lp, pinf, candidatelist, ncand, + 0, downpen, uppen, STRONG_PIVOTS, + ILL_MAXDOUBLE, itcnt); + ILL_CLEANUP_IF (rval); + + for (i = 0; i < ncand; i++) + { + /*t = ILL_BRANCH_STRONG_VAL (downpen[i], uppen[i]); */ + if (EGlpNumIsLess (downpen[i], uppen[i])) + { + EGlpNumCopy (t, downpen[i]); + EGlpNumMultUiTo (t, ILL_BRANCH_STRONG_WEIGHT); + EGlpNumAddTo (t, uppen[i]); + } + else + { + EGlpNumCopy (t, uppen[i]); + EGlpNumMultUiTo (t, ILL_BRANCH_STRONG_WEIGHT); + EGlpNumAddTo (t, downpen[i]); + } + EGlpNumDivUiTo (t, ILL_BRANCH_STRONG_WEIGHT + 1); + if (EGlpNumIsLess (tbest, t)) + { + EGlpNumCopy (tbest, t); + ibest = candidatelist[i]; + } + } + } + + *bvar = ibest; + + +CLEANUP: + + EGlpNumClearVar (t); + EGlpNumClearVar (tbest); + EGlpNumFreeArray (tval); + EGlpNumFreeArray (xlist); + EGlpNumFreeArray (uppen); + EGlpNumFreeArray (downpen); + ILL_IFFREE (candidatelist, int); + ILL_IFFREE (newlist, int); + ILL_IFFREE (perm, int); + + ILL_RETURN (rval, "find_strong_branch"); +} + +static void check_integral ( + lpinfo * lp, + EGlpNum_t * x, + int *yesno) +{ + int i; + EGlpNum_t t; + ILLlpdata *qlp = lp->O; + + EGlpNumInitVar (t); + + for (i = 0; i < qlp->nstruct; i++) + { + if (qlp->intmarker[i]) + { + /*t = ILLutil_our_frac (x[i]); */ + EGlpNumFloor (t, x[i]); + EGlpNumSubTo (t, x[i]); + EGlpNumSign (t); + /*if (t > ILL_INTTOL && t < 1.0 - ILL_INTTOL) */ + if ((EGlpNumIsNeqZero (t, ILL_INTTOL)) && + (EGlpNumIsNeq (t, oneLpNum, ILL_INTTOL))) + { + *yesno = 0; + EGlpNumClearVar (t); + return; + } + } + } + + *yesno = 1; + EGlpNumClearVar (t); +} + +static int plunge ( + mipinfo * minf, + itcnt_t*itcnt) +{ + int rval = 0; + int i, status; + lpinfo *lp = minf->lp; + ILLlpdata *qlp = minf->lp->O; + EGlpNum_t *oldlower = 0; + EGlpNum_t *oldupper = 0; + + if (minf->watch) + { + printf ("Plunging ...\n"); + fflush (stdout); + } + + oldlower = EGlpNumAllocArray (qlp->nstruct); + oldupper = EGlpNumAllocArray (qlp->nstruct); + + for (i = 0; i < qlp->nstruct; i++) + { + EGlpNumCopy (oldlower[i], minf->lower[i]); + EGlpNumCopy (oldupper[i], minf->upper[i]); + } + + rval = plunge_work (minf, 0, itcnt); + ILL_CLEANUP_IF (rval); + + for (i = 0; i < qlp->nstruct; i++) + { + rval = ILLlib_chgbnd (lp, i, 'L', oldlower[i]); + ILL_CLEANUP_IF (rval); + rval = ILLlib_chgbnd (lp, i, 'U', oldupper[i]); + ILL_CLEANUP_IF (rval); + EGlpNumCopy (minf->lower[i], oldlower[i]); + EGlpNumCopy (minf->upper[i], oldupper[i]); + } + + rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + + +CLEANUP: + + EGlpNumFreeArray (oldlower); + EGlpNumFreeArray (oldupper); + + ILL_RETURN (rval, "plunge"); +} + +static int plunge_work ( + mipinfo * minf, + int depth, + itcnt_t*itcnt) +{ + int rval = 0; + int bvar, status, count; + EGlpNum_t lpval, val0, val1, int_tol; + lpinfo *lp = minf->lp; + + EGlpNumInitVar (lpval); + EGlpNumInitVar (val0); + EGlpNumInitVar (val1); + EGlpNumInitVar (int_tol); + EGlpNumSet (int_tol, 0.001); + + rval = ILLlib_get_x (lp, 0, minf->x); + ILL_CLEANUP_IF (rval); + + rval = round_variables (minf, &count, &int_tol /* 0.001 */ ); + ILL_CLEANUP_IF (rval); + if (count) + { + rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + if (status != QS_LP_OPTIMAL) + { + goto CLEANUP; + } + rval = ILLlib_get_x (lp, 0, minf->x); + ILL_CLEANUP_IF (rval); + } + + find_middle_branch (lp, minf->x, &bvar); + if (bvar == -1) + { + rval = ILLlib_objval (lp, 0, &lpval); + ILL_CLEANUP_IF (rval); + + if (EGlpNumIsLess (lpval, minf->value)) + { + printf ("Plunge Integral Solution: %.6f (Depth: %d)\n", + EGlpNumToLf (lpval), depth); + fflush (stdout); + + EGlpNumCopy (minf->value, lpval); + EGlpNumCopyDiff (minf->objectivebound, lpval, ILL_INTTOL); + copy_x (lp->O->nstruct, minf->x, minf->bestx); + } + goto CLEANUP; + } + + EGlpNumOne (minf->lower[bvar]); + rval = ILLlib_chgbnd (lp, bvar, 'L', oneLpNum); + ILL_CLEANUP_IF (rval); + rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + + if (status == QS_LP_UNSOLVED) + { + printf ("Simplex did not solve the plunge LP\n"); + fflush (stdout); + rval = 1; + ILL_CLEANUP; + } + else if (status == QS_LP_INFEASIBLE) + { + EGlpNumCopy (val1, ILL_MAXDOUBLE); + } + else if (status == QS_LP_OPTIMAL) + { + rval = ILLlib_objval (lp, 0, &val1); + ILL_CLEANUP_IF (rval); + } + else + { + ILL_CLEANUP; + } + + rval = ILLlib_chgbnd (lp, bvar, 'L', zeroLpNum); + ILL_CLEANUP_IF (rval); + EGlpNumZero (minf->lower[bvar]); + + EGlpNumZero (minf->upper[bvar]); + rval = ILLlib_chgbnd (lp, bvar, 'U', zeroLpNum); + ILL_CLEANUP_IF (rval); + rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + + if (status == QS_LP_UNSOLVED) + { + printf ("Simplex did not solve the plunge LP\n"); + fflush (stdout); + rval = 1; + ILL_CLEANUP; + } + else if (status == QS_LP_INFEASIBLE) + { + EGlpNumCopy (val0, ILL_MAXDOUBLE); + } + else if (status == QS_LP_OPTIMAL) + { + rval = ILLlib_objval (lp, 0, &val0); + ILL_CLEANUP_IF (rval); + } + else + { + ILL_CLEANUP; + } + + rval = ILLlib_chgbnd (lp, bvar, 'U', oneLpNum); + ILL_CLEANUP_IF (rval); + EGlpNumCopy (minf->upper[bvar], oneLpNum); + + if (EGlpNumIsEqqual (val0, ILL_MAXDOUBLE) && + EGlpNumIsEqqual (val1, ILL_MAXDOUBLE)) + { + ILL_CLEANUP; + } + + if (EGlpNumIsLess (val0, val1)) + { + EGlpNumZero (minf->upper[bvar]); + rval = ILLlib_chgbnd (lp, bvar, 'U', zeroLpNum); + ILL_CLEANUP_IF (rval); + rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + rval = plunge_work (minf, depth + 1, itcnt); + ILL_CLEANUP_IF (rval); + rval = ILLlib_chgbnd (lp, bvar, 'U', oneLpNum); + ILL_CLEANUP_IF (rval); + EGlpNumOne (minf->upper[bvar]); + } + else + { + EGlpNumOne (minf->lower[bvar]); + rval = ILLlib_chgbnd (lp, bvar, 'L', oneLpNum); + ILL_CLEANUP_IF (rval); + rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt); + ILL_CLEANUP_IF (rval); + rval = plunge_work (minf, depth + 1, itcnt); + ILL_CLEANUP_IF (rval); + rval = ILLlib_chgbnd (lp, bvar, 'L', zeroLpNum); + ILL_CLEANUP_IF (rval); + EGlpNumZero (minf->lower[bvar]); + } + +CLEANUP: + + EGlpNumClearVar (lpval); + EGlpNumClearVar (val0); + EGlpNumClearVar (val1); + EGlpNumClearVar (int_tol); + ILL_RETURN (rval, "plunge_work"); +} + +static int round_variables ( + mipinfo * minf, + int *count, + EGlpNum_t * tol) +{ + int rval = 0; + int i, hit = 0; + lpinfo *lp = minf->lp; + ILLlpdata *qlp = lp->O; + + *count = 0; + + for (i = 0; i < qlp->nstruct; i++) + { + if (qlp->intmarker[i]) + { + if (EGlpNumIsNeqq (minf->lower[i], minf->upper[i])) + { + if (EGlpNumIsLess (minf->x[i], *tol)) + { + EGlpNumZero (minf->upper[i]); + rval = ILLlib_chgbnd (lp, i, 'U', zeroLpNum); + ILL_CLEANUP_IF (rval); + hit++; + } + else if (EGlpNumIsEqual (minf->x[i], oneLpNum, *tol)) + { + EGlpNumOne (minf->lower[i]); + rval = ILLlib_chgbnd (lp, i, 'L', oneLpNum); + ILL_CLEANUP_IF (rval); + hit++; + } + } + } + } + *count = hit; + +CLEANUP: + + ILL_RETURN (rval, "round_variables"); +} + +static void copy_x ( + int nstruct, + EGlpNum_t * from_x, + EGlpNum_t * to_x) +{ + int j; + + for (j = 0; j < nstruct; j++) + { + EGlpNumCopy (to_x[j], from_x[j]); + } +} + +static void init_mipinfo ( + mipinfo * minf) +{ + if (minf) + { + minf->depth = 0; + minf->totalnodes = 0; + minf->activenodes = 0; + minf->totalpivots = 0; + minf->lastpivots = 0; + minf->downpen = 0; + minf->uppen = 0; + minf->x = 0; + minf->bestx = 0; + minf->lower = 0; + minf->upper = 0; + minf->lp = 0; + minf->pinf = 0; + minf->head_bbnode.prev = 0; + minf->head_bbnode.next = 0; + minf->que = 0; + minf->branching_rule = /* MIDDLEBRANCH */ STRONGBRANCH; + minf->watch = 1; + EGlpNumInitVar (minf->objectivebound); + EGlpNumInitVar (minf->value); + EGlpNumCopy (minf->objectivebound, ILL_MAXDOUBLE); + EGlpNumCopy (minf->value, ILL_MAXDOUBLE); + ILLptrworld_init (&minf->ptrworld); + } +} + +static void free_mipinfo ( + mipinfo * minf) +{ + int total, onlist; + + if (minf) + { + EGlpNumFreeArray (minf->downpen); + EGlpNumFreeArray (minf->uppen); + EGlpNumFreeArray (minf->x); + EGlpNumFreeArray (minf->bestx); + EGlpNumFreeArray (minf->lower); + EGlpNumFreeArray (minf->upper); + bbnode_listfree (&minf->ptrworld, minf->head_bbnode.next); + if (bbnode_check_leaks (&minf->ptrworld, &total, &onlist)) + { + fprintf (stderr, "WARNING: %d outstanding bbnodes\n", total - onlist); + } + ILLptrworld_delete (&minf->ptrworld); + EGlpNumClearVar ((minf->objectivebound)); + EGlpNumClearVar ((minf->value)); + memset (minf, 0, sizeof (mipinfo)); + //init_mipinfo (minf); + } +} + +static void init_bbnode ( + bbnode * b) +{ + if (b) + { + b->next = 0; + b->prev = 0; + b->id = 0; + b->depth = 0; + b->handle = 0; + b->cstat = 0; + b->rstat = 0; + b->rownorms = 0; + b->bound_cnt = 0; + b->bound_indx = 0; + b->lu = 0; + b->bounds = 0; + EGlpNumInitVar ((b->bound)); + EGlpNumCopy (b->bound, ILL_MINDOUBLE); + } +} + +static void free_bbnode ( + bbnode * b) +{ + if (b) + { + EGlpNumFreeArray (b->rownorms); + EGlpNumFreeArray (b->bounds); + ILL_IFFREE (b->cstat, char); + ILL_IFFREE (b->rstat, char); + ILL_IFFREE (b->bound_indx, int); + ILL_IFFREE (b->lu, char); + + EGlpNumClearVar ((b->bound)); + memset (b, 0, sizeof (bbnode)); + } +} diff --git a/src/binary.h b/src/binary.h new file mode 100644 index 0000000..1a362ce --- /dev/null +++ b/src/binary.h @@ -0,0 +1,36 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: binary.h,v 1.3 2003/11/05 16:57:39 meven Exp $ */ +/****************************************************************************/ +/* */ +/* binary.c */ +/* */ +/****************************************************************************/ + +struct itcnt_t; + +int ILLmip_bfs ( + lpinfo * lp, + EGlpNum_t * val, + EGlpNum_t * x, + struct itcnt_t*itcnt); diff --git a/src/demo_qs.c b/src/demo_qs.c new file mode 100644 index 0000000..7f5c4f8 --- /dev/null +++ b/src/demo_qs.c @@ -0,0 +1,265 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + + +#include +#include +#include "EGlib.h" +#include "QSopt_ex.h" + +static int load_test (mpq_QSprob *p); + +int main (int ac, char **av) +{ + int rval = 0, status = 0; + int i, nrows = 0, ncols = 0; + mpq_t value; + mpq_t *x = (mpq_t *) NULL; + mpq_t *y = (mpq_t *) NULL; + mpq_QSprob p = (mpq_QSprob) NULL; + char **colnames = (char **) NULL; + char **rownames = (char **) NULL; + EGlib_version(); + QSopt_ex_version(); + QSexactStart(); + + mpq_init (value); + + if (ac > 1) { + printf ("Usage: %s\n", *av); + goto CLEANUP; + } + + /* Must call QSexact_set_precision before any other QS function */ + /* Cannot use mpq_ILL_MAXDOUBLE or mpq_ILL_MINDOUBLE before this call */ + + QSexact_set_precision (128); + + rval = load_test (&p); + if (rval) { + fprintf (stderr, "Unable to load the LP\n"); + goto CLEANUP; + } + + /* CPXgetnumrows */ + + nrows = mpq_QSget_rowcount (p); + printf ("Number of constraints: %d\n", nrows); + + /* CPXgetnumcols */ + + ncols = mpq_QSget_colcount (p); + printf ("Number of variables: %d\n", ncols); + + /* CPXlpopt */ + + rval = QSexact_solver (p, NULL, NULL, NULL, DUAL_SIMPLEX, &status); + if (rval) { + fprintf (stderr, "QSexact_solver failed\n"); + goto CLEANUP; + } + if (status != QS_LP_OPTIMAL) { + fprintf (stderr, "Did not find an optimal solution.\n"); + goto CLEANUP; + } + + /* CPXsolninfo */ + + rval = mpq_QSget_status (p, &status); + switch (status) { + case QS_LP_OPTIMAL: + printf ("An optimal solution is available\n"); + break; + case QS_LP_INFEASIBLE: + printf ("The LP has no feasible solution\n"); + break; + case QS_LP_UNBOUNDED: + printf ("The LP has unbounded objective value\n"); + break; + case QS_LP_UNSOLVED: + printf ("The optimizer could not solve the LP\n"); + break; + case QS_LP_MODIFIED: + printf ("The LP was modified since last optimization call\n"); + break; + default: + printf ("Unknown solution status: %d\n", status); + break; + } + + /* CPXgetobjval */ + + rval = mpq_QSget_objval (p, &value); + if (rval) { + fprintf (stderr, "Could not get obj value, error code %d\n", rval); + } else { + printf ("Objective Value = "); + mpq_out_str (stdout, 10, value); + printf ("\n"); + printf ("Objective Value (rounded to double) = %.6f\n", + mpq_get_d (value)); + } + + /* CPXgetx */ + + x = (mpq_t *) malloc (ncols * sizeof (mpq_t)); + for (i = 0; i < ncols; i++) mpq_init (x[i]); + rval = mpq_QSget_x_array (p, x); + if (rval) { + fprintf (stderr, "Could not get x-vector, error code %d\n", rval); + } else { + printf ("Primal Solution:\n"); + colnames = (char **) malloc (ncols * sizeof (char *)); + mpq_QSget_colnames (p, colnames); + for (i = 0; i < ncols; i++) { + printf ("%s = ", colnames[i]); + mpq_out_str (stdout, 10, x[i]); + printf ("\n"); + } + } + + /* CPXgetpi */ + + y = (mpq_t *) malloc (nrows * sizeof (mpq_t)); + for (i = 0; i < nrows; i++) mpq_init (y[i]); + rval = mpq_QSget_pi_array (p, y); + if (rval) { + fprintf (stderr, "Could not get dual values, error code %d\n", rval); + } else { + printf ("Dual Solution:\n"); + rownames = (char **) malloc (nrows * sizeof (char *)); + mpq_QSget_rownames (p, rownames); + for (i = 0; i < nrows; i++) { + printf ("%s = ", rownames[i]); + mpq_out_str (stdout, 10, y[i]); + printf ("\n"); + } + } + + /* CPXwriteprob */ + + rval = mpq_QSwrite_prob (p, "name.lp", "LP"); + if (rval) { + fprintf (stdout, "Could not write the LP, error code %d\n", rval); + } else { + printf ("LP written to name.lp\n"); + } + +CLEANUP: + + if (p) mpq_QSfree_prob (p); /* CPXfreeprob */ + + mpq_clear (value); + if (x) { + for (i = 0; i < ncols; i++) mpq_clear (x[i]); + free (x); + } + if (y) { + for (i = 0; i < nrows; i++) mpq_clear (y[i]); + free (y); + } + if (rownames) { + for (i = 0; i < nrows; i++) if (rownames[i]) free (rownames[i]); + free (rownames); + } + if (colnames) { + for (i = 0; i < ncols; i++) if (colnames[i]) free (colnames[i]); + free (colnames); + } + + QSexactClear(); + return rval; +} + +/* */ +/* Using QSload_prob to load the following LP problem */ +/* Maximize 3.0x + 2.0y + 4.0z */ +/* Subject to */ +/* 3.0x + 2.0y + 1.0z <= 12.0 */ +/* 5.0x + 1.0y = 10.0 */ +/* x >= 2.0 */ +/* y free */ +/* 1.0 <= z <= 10.0 */ +/* */ + +static int load_test (mpq_QSprob *p) +{ + int i, rval = 0; + int cmatcnt[3] = { 2, 2, 1 }; + int cmatbeg[3] = { 0, 2, 4 }; + int cmatind[5] = { 0, 1, 0, 1, 0 }; + char sense[2] = { 'L', 'E' }; + const char *colnames[3] = { "x", "y", "z" }; + const char *rownames[2] = { "c1", "c2"}; + mpq_t cmatval[5]; + mpq_t obj[3]; + mpq_t rhs[2]; + mpq_t lower[3]; + mpq_t upper[3]; + + for (i = 0; i < 5; i++) mpq_init (cmatval[i]); + mpq_set_d (cmatval[0], 3.0); + mpq_set_d (cmatval[1], 5.0); + mpq_set_d (cmatval[2], 2.0); + mpq_set_d (cmatval[3], 1.0); + mpq_set_d (cmatval[4], 1.0); + + for (i = 0; i < 3; i++) mpq_init (obj[i]); + mpq_set_d (obj[0], 3.0); + mpq_set_d (obj[1], 2.0); + mpq_set_d (obj[2], 4.0); + + for (i = 0; i < 2; i++) mpq_init (rhs[i]); + mpq_set_d (rhs[0], 12.0); + mpq_set_d (rhs[1], 10.0); + + for (i = 0; i < 3; i++) mpq_init (lower[i]); + mpq_set_d (lower[0], 2.0); + mpq_set (lower[1], mpq_ILL_MINDOUBLE); + mpq_set_d (lower[2], 1.0); + + for (i = 0; i < 3; i++) mpq_init (upper[i]); + mpq_set (upper[0], mpq_ILL_MAXDOUBLE); + mpq_set (upper[1], mpq_ILL_MAXDOUBLE); + mpq_set_d (upper[2], 10.0); + + /* CPXcopylpwnames */ + + *p = mpq_QSload_prob ("small", 3, 2, cmatcnt, cmatbeg, cmatind, cmatval, + QS_MAX, obj, rhs, sense, lower, upper, colnames, + rownames); + + if (*p == (mpq_QSprob) NULL) { + fprintf (stderr, "Unable to load the LP problem\n"); + rval = 1; goto CLEANUP; + } + +CLEANUP: + + for (i = 0; i < 5; i++) mpq_clear (cmatval[i]); + for (i = 0; i < 3; i++) mpq_clear (obj[i]); + for (i = 0; i < 2; i++) mpq_clear (rhs[i]); + for (i = 0; i < 3; i++) mpq_clear (lower[i]); + for (i = 0; i < 3; i++) mpq_clear (upper[i]); + + return rval; +} diff --git a/src/dheaps_i.c b/src/dheaps_i.c new file mode 100644 index 0000000..41df6d7 --- /dev/null +++ b/src/dheaps_i.c @@ -0,0 +1,343 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: dheaps_i.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* DHEAP ROUTINES */ +/* */ +/* */ +/* TSP CODE */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 9, 1995 */ +/* March 11, 2002 - Cook (Modifed for QS) */ +/* Reference: R.E. Tarjan, Data Structures and Network Algorithms */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int ILLutil_dheap_init (ILLdheap *h, int k) */ +/* -h should point to a ILLdheap struct. */ +/* -k the max number of elements in the dheap. */ +/* */ +/* void ILLutil_dheap_free (ILLdheap *h) */ +/* -frees the spaces allocated by ILLutil_dheap_init */ +/* */ +/* int ILLutil_dheap_resize (ILLdheap *h, int newsize) */ +/* -REALLOCs h so it can contain newsize elements. */ +/* -returns -1 if it can't resize the heap. */ +/* */ +/* void ILLutil_dheap_findmin (ILLdheap *h, int *i) */ +/* -sets i to the index of the element with min value h->key[i] */ +/* -sets i to -1 if no elements in heap. */ +/* */ +/* int ILLutil_dheap_insert (ILLdheap *h, int i) */ +/* -inserts the element with index i (so its key should be loaded */ +/* beforehand in h->key[i]). */ +/* */ +/* void ILLutil_dheap_delete (ILLdheap *h, int i) */ +/* -deletes the element with index i. */ +/* */ +/* void ILLutil_dheap_deletemin (ILLdheap *h, int *i) */ +/* -sets i to the min element in the heap, and deletes the min element */ +/* -sets i to -1 if no elements in heap. */ +/* */ +/* void ILLutil_dheap_changekey (ILLdheap *h, int i, EGlpNum_t* newkey) */ +/* -changes the key of the element with index i to newkey. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* NOTES: */ +/* A k-element heap will malloc 16k bytes of memory. If memory is */ +/* tight, using integer keys (instead of doubles), brings it down to */ +/* 12k bytes, and if arbitrary deletions are not required, with a little */ +/* rewriting, the h->loc field can be eliminated, bring the space down */ +/* to 8k bytes. */ +/* These routines work with indices into the h->key array, so in */ +/* some cases, you will need to maintain a separate names array to know */ +/* what element belongs to index i. For an example, see the k_nearest */ +/* code in kdnear.c. */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "dheaps_i.h" +#include "allocrus.h" +#include "machdefs.h" +#include "except.h" +#include "trace.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +static int TRACE = 0; + +#define HEAP_D 3 +#define HEAP_UP(x) (((x)-1)/HEAP_D) +#define HEAP_DOWN(x) (((x)*HEAP_D)+1) + + +static void dheap_siftup ( + ILLdheap * h, + int i, + int x), + dheap_siftdown ( + ILLdheap * h, + int i, + int x); + +static int dheap_minchild ( + int x, + ILLdheap * h); + + +int ILLutil_dheap_init ( + ILLdheap * h, + int k) +{ + int rval = 0; + + h->entry = (int *) NULL; + h->loc = (int *) NULL; + h->key = 0; + + + ILL_SAFE_MALLOC (h->entry, k, int); + ILL_SAFE_MALLOC (h->loc, k, int); + + h->key = EGlpNumAllocArray (k); + h->size = 0; + h->total_space = k; + +CLEANUP: + + if (rval) + { + ILLutil_dheap_free (h); + } + + ILL_RETURN (rval, "ILLutil_dheap_init"); +} + +void ILLutil_dheap_free ( + ILLdheap * h) +{ + ILL_IFFREE (h->entry, int); + ILL_IFFREE (h->loc, int); + + EGlpNumFreeArray (h->key); +} + +int ILLutil_dheap_resize ( + ILLdheap * h, + int newsize) +{ + int rval = 0; + + if (newsize < h->size || newsize < h->total_space) + { + ILL_CLEANUP; + } + + h->key = EGrealloc (h->key, sizeof (double) * newsize); + //rval = ILLutil_reallocrus_count ((void **) &(h->key), newsize, + // sizeof (double)); + //ILL_CLEANUP_IF (rval); + h->entry = EGrealloc (h->entry, sizeof (int) * newsize); + //rval = ILLutil_reallocrus_count ((void **) &(h->entry), newsize, + // sizeof (int)); + //ILL_CLEANUP_IF (rval); + h->loc = EGrealloc (h->loc, sizeof (int) * newsize); + //rval = ILLutil_reallocrus_count ((void **) &(h->loc), newsize, sizeof (int)); + //ILL_CLEANUP_IF (rval); + h->total_space = newsize; + +CLEANUP: + + ILL_RETURN (rval, "ILLutil_dheap_resize"); +} + +void ILLutil_dheap_findmin ( + ILLdheap * h, + int *i) +{ + if (h->size == 0) + *i = -1; + else + *i = h->entry[0]; +} + +int ILLutil_dheap_insert ( + ILLdheap * h, + int i) +{ + if (h->size >= h->total_space) + { + fprintf (stderr, "Error - heap already full\n"); + return 1; + } + h->size++; + dheap_siftup (h, i, h->size - 1); + + return 0; +} + +void ILLutil_dheap_delete ( + ILLdheap * h, + int i) +{ + int j; + + h->size--; + j = h->entry[h->size]; + h->entry[h->size] = -1; + + if (j != i) + { + if (EGlpNumIsLeq (h->key[j], h->key[i])) + { + dheap_siftup (h, j, h->loc[i]); + } + else + { + dheap_siftdown (h, j, h->loc[i]); + } + } +} + +void ILLutil_dheap_deletemin ( + ILLdheap * h, + int *i) +{ + int j; + + if (h->size == 0) + *i = -1; + else + { + j = h->entry[0]; + ILLutil_dheap_delete (h, j); + *i = j; + } +} + +void ILLutil_dheap_changekey ( + ILLdheap * h, + int i, + EGlpNum_t * newkey) +{ + if (EGlpNumIsLess (*newkey, h->key[i])) + { + EGlpNumCopy (h->key[i], *newkey); + dheap_siftup (h, i, h->loc[i]); + } + else if (EGlpNumIsLess (h->key[i], *newkey)) + { + EGlpNumCopy (h->key[i], *newkey); + dheap_siftdown (h, i, h->loc[i]); + } +} + +static void dheap_siftup ( + ILLdheap * h, + int i, + int x) +{ + int p; + + p = HEAP_UP (x); + while (x && EGlpNumIsLess (h->key[i], h->key[h->entry[p]])) + { + h->entry[x] = h->entry[p]; + h->loc[h->entry[p]] = x; + x = p; + p = HEAP_UP (p); + } + h->entry[x] = i; + h->loc[i] = x; +} + +static void dheap_siftdown ( + ILLdheap * h, + int i, + int x) +{ + int c; + + c = dheap_minchild (x, h); + + while (c >= 0 && EGlpNumIsLess (h->key[h->entry[c]], h->key[i])) + { + h->entry[x] = h->entry[c]; + h->loc[h->entry[c]] = x; + x = c; + c = dheap_minchild (c, h); + } + h->entry[x] = i; + h->loc[i] = x; +} + +static int dheap_minchild ( + int x, + ILLdheap * h) +{ + int c = HEAP_DOWN (x); + int cend; + EGlpNum_t minval; + int minloc; + + if (c >= h->size) + return -1; + + EGlpNumInitVar (minval); + EGlpNumCopy (minval, h->key[h->entry[c]]); + minloc = c; + cend = c + HEAP_D; + if (h->size < cend) + cend = h->size; + for (c++; c < cend; c++) + { + if (EGlpNumIsLess (h->key[h->entry[c]], minval)) + { + EGlpNumCopy (minval, h->key[h->entry[c]]); + minloc = c; + } + } + EGlpNumClearVar (minval); + return minloc; +} diff --git a/src/dheaps_i.h b/src/dheaps_i.h new file mode 100644 index 0000000..3b88f63 --- /dev/null +++ b/src/dheaps_i.h @@ -0,0 +1,69 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __DHEAPS_I_H__ +#define __DHEAPS_I_H__ +/****************************************************************************/ +/* */ +/* dheaps_i.c */ +/* */ +/****************************************************************************/ + +typedef struct ILLdheap +{ + EGlpNum_t *key; + int *entry; + int *loc; + int total_space; + int size; +} +ILLdheap; + +void ILLutil_dheap_free ( + ILLdheap * h), + ILLutil_dheap_delete ( + ILLdheap * h, + int i), + ILLutil_dheap_changekey ( + ILLdheap * h, + int i, + EGlpNum_t * newkey), + ILLutil_dheap_findmin ( + ILLdheap * h, + int *i), + ILLutil_dheap_deletemin ( + ILLdheap * h, + int *i); + +int ILLutil_dheap_init ( + ILLdheap * h, + int k), + ILLutil_dheap_resize ( + ILLdheap * h, + int newsize), + ILLutil_dheap_insert ( + ILLdheap * h, + int i); + + + +#endif diff --git a/src/dstruct.c b/src/dstruct.c new file mode 100644 index 0000000..126fd60 --- /dev/null +++ b/src/dstruct.c @@ -0,0 +1,494 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: dstruct.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +static int TRACE = 0; + +#include "config.h" +#include "iqsutil.h" +#include "dstruct.h" +#include "qsopt.h" +#include "lpdefs.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +/****************************************************************************/ +/* */ +/* svector */ +/* */ +/* Written by: Applegate, Cook, Dash */ +/* Date: */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/****************************************************************************/ + +void ILLsvector_init ( + svector * s) +{ + s->nzcnt = 0; + s->indx = 0; + s->coef = 0; +} + +void ILLsvector_free ( + svector * s) +{ + ILL_IFFREE (s->indx, int); + + EGlpNumFreeArray (s->coef); + s->nzcnt = 0; +} + +int ILLsvector_alloc ( + svector * s, + int nzcnt) +{ + int rval = 0; + + s->nzcnt = nzcnt; + if (nzcnt == 0) + { + s->indx = 0; + s->coef = 0; + } + else + { + ILL_SAFE_MALLOC (s->indx, nzcnt, int); + + s->coef = EGlpNumAllocArray (nzcnt); + } + return 0; +CLEANUP: + ILL_IFFREE (s->indx, int); + EGlpNumFreeArray (s->coef); + ILL_RETURN (rval, "ILLsvector_alloc"); +} + +int ILLsvector_copy ( + const svector * s_in, + svector * s_out) +{ + int i; + int nzcnt = s_in->nzcnt; + int rval = 0; + + rval = ILLsvector_alloc (s_out, nzcnt); + ILL_CLEANUP_IF (rval); + for (i = 0; i < nzcnt; i++) + { + s_out->indx[i] = s_in->indx[i]; + EGlpNumCopy (s_out->coef[i], s_in->coef[i]); + } + +CLEANUP: + ILL_RETURN (rval, "ILLsvector_copy"); +} + +/****************************************************************************/ +/* */ +/* heap */ +/* */ +/* Written by: Applegate, Cook, Dash */ +/* Date: */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/****************************************************************************/ + +#define DEBUG_HEAP 0 + +#define HEAP_D 3 +#define HEAP_UP(x) (((x)-1)/HEAP_D) +#define HEAP_DOWN(x) (((x)*HEAP_D)+1) + +static int siftup ( + heap * h, + int hloc, + int ix), + siftdown ( + heap * h, + int hloc, + int ix), + maxchild ( + heap * h, + int hloc); + +static int siftup ( + heap * h, + int hloc, + int ix) +{ + int i = hloc; + int p = HEAP_UP (i); + EGlpNum_t val; + + EGlpNumInitVar (val); + EGlpNumCopy (val, h->key[ix]); + + while (i > 0 && EGlpNumIsLess (h->key[h->entry[p]], val)) + { + h->entry[i] = h->entry[p]; + h->loc[h->entry[i]] = i; + i = p; + p = HEAP_UP (p); + } + h->entry[i] = ix; + h->loc[ix] = i; + ILL_IFTRACE2 ("%s:%la:%d:%d:%d\n", __func__, EGlpNumToLf (val), hloc, ix, i); + EGlpNumClearVar (val); + return i; +} + +static int siftdown ( + heap * h, + int hloc, + int ix) +{ + int i = hloc; + int c = maxchild (h, i); + EGlpNum_t val; + + EGlpNumInitVar (val); + EGlpNumCopy (val, h->key[ix]); + ILL_IFTRACE2 ("%s:%d:%d:%d:%la", __func__, hloc, ix, c, EGlpNumToLf (val)); + + while (c != -1 && EGlpNumIsLess (val, h->key[h->entry[c]])) + { + h->entry[i] = h->entry[c]; + h->loc[h->entry[i]] = i; + i = c; + c = maxchild (h, c); + } + h->entry[i] = ix; + h->loc[ix] = i; + EGlpNumClearVar (val); + ILL_IFTRACE2 ("%s:%d:%d\n", __func__, ix, i); + return i; +} + +//extern EGlpNum_t ILL_MINDOUBLE; +static int maxchild ( + heap * h, + int hloc) +{ + int i; + int mc = -1; + int hmin = HEAP_D * hloc + 1; + int hmax = HEAP_D * hloc + HEAP_D; + EGlpNum_t val; + + EGlpNumInitVar (val); + EGlpNumCopy (val, ILL_MINDOUBLE); + ILL_IFTRACE2 (" %s:%d", __func__, hloc); + + for (i = hmin; i <= hmax && i < h->size; i++) + if (EGlpNumIsLess (val, h->key[h->entry[i]])) + { + EGlpNumCopy (val, h->key[h->entry[i]]); + mc = i; + ILL_IFTRACE2 (":%d:%la", mc, EGlpNumToLf (val)); + } + EGlpNumClearVar (val); + ILL_IFTRACE2 ("\n"); + return mc; +} + +#if DEBUG_HEAP > 0 + +static void printheap ( + heap * h) +{ + int i; + + printf ("entry (%d): ", h->size); + for (i = 0; i < h->size; i++) + printf ("%d ", h->entry[i]); + printf ("\n loc: "); + for (i = 0; i < h->maxsize; i++) + printf ("%d ", h->loc[i]); + printf ("\n key: "); + for (i = 0; i < h->maxsize; i++) + printf ("%la ", EGlpNumToLf (h->key[i])); + printf ("\n key(sorted): "); + for (i = 0; i < h->size; i++) + printf ("%la ", EGlpNumToLf (h->key[h->entry[i]])); + printf ("\n"); +} + +static void heapcheck ( + heap * h) +{ + int i, tcnt = 0; + + for (i = 0; i < h->maxsize; i++) + { + if (h->loc[i] < -1) + printf ("error in heap\n"); + else if (h->loc[i] > -1) + tcnt++; + } + if (tcnt != h->size) + printf ("error 3 in heap\n"); + + for (i = 0; i < h->size; i++) + { + if (h->loc[h->entry[i]] != i) + printf ("error 1 in heap\n"); + if (!EGlpNumIsNeqqZero (h->key[h->entry[i]])) + printf ("error 2 in heap\n"); + if (EGlpNumIsLess (h->key[h->entry[HEAP_UP (i)]], h->key[h->entry[i]])) + printf ("error 4 in heap\n"); + } +} + +#endif + +void ILLheap_insert ( + heap * const h, + int const ix) +{ + int i = h->size; + + ILL_IFTRACE ("%s:%d:%la\n", __func__, ix, EGlpNumToLf (h->key[ix])); + + i = siftup (h, i, ix); + h->size++; + +#if DEBUG_HEAP > 0 + heapcheck (h); +#endif +#if DEBUG_HEAP > 1 + printheap (h); +#endif +} + +void ILLheap_modify ( + heap * const h, + int const ix) +{ + int i = h->loc[ix]; + int pi = i; + + ILL_IFTRACE ("%s:%d\n", __func__, ix); + + if (h->loc[ix] == -1) + return; + i = siftup (h, i, ix); + if (pi == i) + i = siftdown (h, i, ix); + +#if DEBUG_HEAP > 0 + heapcheck (h); +#endif +#if DEBUG_HEAP > 1 + printheap (h); +#endif +} + +void ILLheap_delete ( + heap * const h, + int const ix) +{ + int i = h->loc[ix]; + int pi = i; + int nix = h->entry[h->size - 1]; + + ILL_IFTRACE ("%s:%d:%d:%d\n", __func__, ix, nix, pi); + + h->loc[ix] = -1; + h->size--; + if (nix == ix) + { +#if DEBUG_HEAP > 0 + heapcheck (h); +#endif +#if DEBUG_HEAP > 1 + printheap (h); +#endif + return; + } + + h->entry[i] = nix; + h->loc[nix] = i; + + i = siftup (h, i, nix); + ILL_IFTRACE ("%s:%d:%d:%d:%d\n", __func__, ix, nix, pi, i); + if (pi == i) + siftdown (h, i, nix); + +#if DEBUG_HEAP > 0 + heapcheck (h); +#endif +#if DEBUG_HEAP > 1 + printheap (h); +#endif +} + +int ILLheap_findmin ( + heap * const h) +{ + if (h->hexist == 0 || h->size <= 0) + return -1; + return h->entry[0]; +} + +void ILLheap_init ( + heap * const h) +{ + h->entry = NULL; + h->loc = NULL; + h->key = NULL; + h->hexist = 0; +} + +int ILLheap_build ( + heap * const h, + int const nelems, + EGlpNum_t * key) +{ + int rval = 0; + int i, n = 0; + + ILL_IFTRACE ("%s:%d\n", __func__, nelems); + + h->hexist = 1; + h->size = 0; + h->maxsize = nelems; + h->key = key; + ILL_SAFE_MALLOC (h->entry, nelems, int); + ILL_SAFE_MALLOC (h->loc, nelems, int); + + for (i = 0; i < nelems; i++) + { + if (EGlpNumIsGreatZero (key[i])) + { + h->entry[n] = i; + h->loc[i] = n; + n++; + } + else + h->loc[i] = -1; + } + h->size = n; + for (i = n - 1; i >= 0; i--) + { + ILL_IFTRACE2 ("insert %la\n", EGlpNumToLf (h->key[h->entry[i]])); + siftdown (h, i, h->entry[i]); + } + +#if DEBUG_HEAP > 0 + heapcheck (h); +#endif +#if DEBUG_HEAP > 1 + printheap (h); +#endif + +CLEANUP: + if (rval) + ILLheap_free (h); + ILL_RETURN (rval, "ILLheap_init"); +} + +void ILLheap_free ( + heap * const h) +{ + if (h->hexist) + { + ILL_IFFREE (h->entry, int); + ILL_IFFREE (h->loc, int); + + h->hexist = 0; + h->maxsize = 0; + h->size = 0; + } +} + + +/****************************************************************************/ +/* */ +/* matrix */ +/* */ +/* Written by: Applegate, Cook, Dash */ +/* Date: */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/****************************************************************************/ + +void ILLmatrix_init ( + ILLmatrix * A) +{ + if (A) + { + A->matval = 0; + A->matcnt = 0; + A->matbeg = 0; + A->matind = 0; + A->matcols = 0; + A->matcolsize = 0; + A->matrows = 0; + A->matsize = 0; + A->matfree = 0; + } +} + +void ILLmatrix_free ( + ILLmatrix * A) +{ + if (A) + { + EGlpNumFreeArray (A->matval); + ILL_IFFREE (A->matcnt, int); + ILL_IFFREE (A->matbeg, int); + ILL_IFFREE (A->matind, int); + + ILLmatrix_init (A); + } +} + +void ILLmatrix_prt ( + EGioFile_t * fd, + ILLmatrix * A) +{ + int j, k; + + if (A == NULL) + { + EGioPrintf (fd, "Matrix %p: empty\n", (void *) A); + } + else + { + EGioPrintf (fd, "Matrix %p: nrows = %d ncols = %d\n", + (void *) A, A->matrows, A->matcols); + for (j = 0; j < A->matcols; j++) + { + EGioPrintf (fd, "col %d: ", j); + for (k = A->matbeg[j]; k < A->matbeg[j] + A->matcnt[j]; k++) + { + EGioPrintf (fd, "row %d=%.3f ", A->matind[k], EGlpNumToLf (A->matval[k])); + } + EGioPrintf (fd, "\n"); + } + } +} diff --git a/src/dstruct.h b/src/dstruct.h new file mode 100644 index 0000000..df42090 --- /dev/null +++ b/src/dstruct.h @@ -0,0 +1,133 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: dstruct.h,v 1.3 2003/11/05 16:57:39 meven Exp $ */ +/****************************************************************************/ +/* */ +/* svector.h */ +/* */ +/****************************************************************************/ + +#ifndef __SVECTOR_H +#define __SVECTOR_H +#include "qs_config.h" + +typedef struct svector +{ + int nzcnt; + int *indx; + int size; + EGlpNum_t *coef; +} +svector; + +void ILLsvector_init ( + svector * s), + ILLsvector_free ( + svector * s); + +int ILLsvector_alloc ( + svector * s, + int nzcnt), + ILLsvector_copy ( + const svector * s_in, + svector * s_out); + +#endif /* __SVECTOR_H */ + +/****************************************************************************/ +/* */ +/* heap.h */ +/* */ +/****************************************************************************/ + +#ifndef __HEAP_H +#define __HEAP_H + +typedef struct +{ + int *entry; + int *loc; + EGlpNum_t *key; + int hexist; + int maxsize; + int size; +} +heap; + +void ILLheap_insert ( + heap * const h, + int const ix), + ILLheap_modify ( + heap * const h, + int const ix), + ILLheap_delete ( + heap * const h, + int const ix), + ILLheap_init ( + heap * const h), + ILLheap_free ( + heap * const h); + +int ILLheap_findmin ( + heap * const h), + ILLheap_build ( + heap * const h, + int const nelems, + EGlpNum_t * key); + +#endif /* __HEAP_H */ + +/****************************************************************************/ +/* */ +/* matrix.h */ +/* */ +/****************************************************************************/ + +#ifndef __MATRIX_H +#define __MATRIX_H + +typedef struct ILLmatrix +{ + EGlpNum_t *matval; /* The coefficients. */ + int *matcnt; /* Number of coefs in each col. */ + int *matind; /* The row indices of the coefs. */ + int *matbeg; /* The start of each col. */ + int matcols; /* Number of columns. */ + int matrows; + int matcolsize; /* Length of matbeg and matcnt. */ + int matsize; /* Length of matind and matval. */ + int matfree; /* Free space at end of matind. */ + /* Note: free elements marked by -1 in */ + /* matind; we keep at least 1 free at end. */ +} +ILLmatrix; + +void ILLmatrix_init ( + ILLmatrix * A); +void ILLmatrix_free ( + ILLmatrix * A); +void ILLmatrix_prt ( + EGioFile_t * fd, + ILLmatrix * A); + +#endif /* __MATRIX_H */ diff --git a/src/editor.c b/src/editor.c new file mode 100644 index 0000000..2f77a4e --- /dev/null +++ b/src/editor.c @@ -0,0 +1,780 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: editor.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +#include "qs_config.h" +#include "qsopt.h" +#include "lpdata.h" +#include "qstruct.h" +#include "qsopt.h" +#include "editor.h" +#include "readline.h" +#include "rawlp.h" +#include "stddefs.h" /* for MAX */ +#include "read_lp.h" +#include "lp.h" +#include "lib.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +static int TRACE = 0; + +#define ILL_BREAK_BODY_IF(rval) if (rval != 0) goto CLEANUP +#define ILL_BREAK_BODY goto CLEANUP + +static int transpose ( rawlpdata * lp); +static int pull_info_from_p ( QSdata * p, rawlpdata * lp); +static void add_row ( QSdata * p, rawlpdata * lp, ILLread_lp_state * state); + +/* static int new_row(QSdata *p, rawlpdata *lp, ILLread_lp_state *state); */ +static void del_row ( QSdata * p, rawlpdata * lp, ILLread_lp_state * state); + +static void add_col ( QSdata * p, rawlpdata * lp, ILLread_lp_state * state); +static void del_col ( QSdata * p, rawlpdata * lp, ILLread_lp_state * state); + +#define NONE -1 +#define QS_EXIT 0 +#define ROW 1 +#define COL 2 +#define PLP 3 +#define PRTX 4 +#define SOLVE 5 +#define PMPS 6 +#define HELP 7 +#define DEL 8 +#define NEW 9 +#define ADD 10 +#define PRIMAL 11 +#define DUAL 12 +#define NCOMMAND 13 +static const char *commands[NCOMMAND + 1]; +static char hasSubCmd[NCOMMAND + 1]; + +void ILLeditor_init ( + void) +{ + commands[QS_EXIT] = "QS_EXIT"; + commands[ROW] = "ROW"; + commands[COL] = "COL"; + commands[PLP] = "LP"; + commands[PMPS] = "MPS"; + commands[SOLVE] = "SOLVE"; + commands[PRTX] = "PRT"; + commands[HELP] = "HELP"; + commands[ADD] = "ADD"; + commands[DEL] = "DEL"; + commands[NEW] = "NEW"; + commands[PRIMAL] = "PRIMAL"; + commands[DUAL] = "DUAL"; + commands[NCOMMAND] = NULL; + + hasSubCmd[QS_EXIT] = 0; + hasSubCmd[ROW] = 1; + hasSubCmd[COL] = 1; + hasSubCmd[PLP] = 0; + hasSubCmd[PMPS] = 0; + hasSubCmd[SOLVE] = 1; + hasSubCmd[PRTX] = 0; + hasSubCmd[HELP] = 0; + hasSubCmd[ADD] = 1; + hasSubCmd[DEL] = 1; + hasSubCmd[NEW] = 1; + hasSubCmd[PRIMAL] = 1; + hasSubCmd[DUAL] = 1; + hasSubCmd[NCOMMAND] = 0; +} + +static void ILLeditor_help_cmd ( + int cmd, + int subcmd); + +static void ILLeditor_help ( + void) +{ + ILLeditor_help_cmd (ROW, ADD); + /* ILLeditor_help_cmd(ROW, NEW); */ + ILLeditor_help_cmd (ROW, DEL); + ILLeditor_help_cmd (COL, ADD); + ILLeditor_help_cmd (COL, DEL); + ILLeditor_help_cmd (SOLVE, NONE); + ILLeditor_help_cmd (PRTX, NONE); + ILLeditor_help_cmd (PLP, NONE); + ILLeditor_help_cmd (PMPS, NONE); + ILLeditor_help_cmd (QS_EXIT, NONE); + ILLeditor_help_cmd (HELP, NONE); +} + +static void ILLeditor_help_cmd ( + int cmd, + int subcmd) +{ + if (cmd == ROW && subcmd == ADD) + fprintf (stdout, "%s ADD:\t%s.\n", + commands[ROW], "add a row; enter in LP format"); + if (cmd == COL && subcmd == ADD) + fprintf (stdout, "%s ADD:\t%s.\n", + commands[COL], "add a col; enter in LP format"); + /* if (cmd == ROW && subcmd == NEW) + * fprintf(stdout, "%s NEW:\t%s.\n", + * commands[ROW], "new row; enter rowname: sense rhs"); + */ + if (cmd == ROW && subcmd == DEL) + fprintf (stdout, "%s DEL:\t%s.\n", + commands[ROW], "delete a row; give rowname"); + if (cmd == COL && subcmd == DEL) + fprintf (stdout, "%s DEL:\t%s.\n", + commands[COL], "delete a col; give colname"); + if (cmd == SOLVE) + fprintf (stdout, "%s:\t%s.\n", commands[SOLVE], "solve problem"); + if (cmd == PRTX) + fprintf (stdout, "%s:\t%s.\n", + commands[PRTX], "print variable values for optimal solution"); + if (cmd == PLP) + fprintf (stdout, "%s [file]:\t%s.\n", + commands[PLP], "print problem in LP format to file or stdout"); + if (cmd == PMPS) + fprintf (stdout, "%s [file]:\t%s.\n", + commands[PMPS], "print problem in MPS format to file or stdout"); + if (cmd == QS_EXIT) + fprintf (stdout, "%s:\t%s.\n", commands[QS_EXIT], "QS_EXIT"); + if (cmd == HELP) + fprintf (stdout, "%s:\t%s.\n", commands[HELP], "print this help"); +} + +static void getCmd ( + ILLread_lp_state * state, + int *cmd, + int *subcmd) +{ + const char *cmd_str, *subcmd_str; + int tmp; + + *cmd = ILLutil_index (commands, state->field); + *subcmd = -1; + if (hasSubCmd[*cmd] && (ILLread_lp_state_next_field_on_line (state) == 0)) + { + *subcmd = ILLutil_index (commands, state->field); + if ((*subcmd == ROW) || (*subcmd == COL) || (*subcmd == SOLVE)) + { + ILL_SWAP (*subcmd, *cmd, tmp); + } + } + cmd_str = (*cmd >= 0) ? commands[*cmd] : "???"; + subcmd_str = (*subcmd >= 0) ? commands[*subcmd] : "???"; + ILL_IFTRACE ("cmd = %s, subcmd = %s\n", cmd_str, subcmd_str); +} + +void ILLeditor ( + QSdata * p) +{ + rawlpdata raw, *lp = &raw; + int cmd, subcmd, tval, rval = 0; + ILLread_lp_state lpstate, *state = &lpstate; + qsline_reader *reader; + + ILL_IFTRACE ("ILLeditor\n"); + + reader = ILLline_reader_new ((qsread_line_fct) fgets, stdin); + rval = ILLread_lp_state_init (state, reader, "STDIN", 1); + rval = rval || pull_info_from_p (p, lp); + ILL_BREAK_BODY_IF (rval); + + while (ILLread_lp_state_next_field (state) == 0) + { + getCmd (state, &cmd, &subcmd); + switch (cmd) + { + case QS_EXIT: + ILL_BREAK_BODY; + + case ROW: + { + switch (subcmd) + { + case ADD: + add_row (p, lp, state); + break; + /* case NEW: rval = new_row(p, lp, state); break; */ + case DEL: + del_row (p, lp, state); + break; + default: + ILLeditor_help (); + break; + } + break; + } + case COL: + { + switch (subcmd) + { + case ADD: + add_col (p, lp, state); + break; + case DEL: + del_col (p, lp, state); + break; + default: + ILLeditor_help (); + break; + } + break; + } + + case SOLVE: + { + if (subcmd == PRIMAL) + { + (void) ILLeditor_solve (p, PRIMAL_SIMPLEX); + } + else if (subcmd == DUAL) + { + (void) ILLeditor_solve (p, DUAL_SIMPLEX); + } + else + { + ILLeditor_help (); + } + break; + } + + case PRTX: + { + EGioFile_t*lout = EGioOpenFILE(stdout); + if ((rval = ILLlib_print_x (lout, p->lp, 0, 0, 1))) + { + fprintf (stdout, "The problem may not be feasible.\n"); + } + EGioClose(lout); + break; + } + + case PLP: + case PMPS: + { + if (ILLread_lp_state_next_field_on_line (state) == 0) + { + if (cmd == PMPS) + { + tval = QSwrite_prob (p, state->field, "MPS"); + } + else + { + tval = QSwrite_prob (p, state->field, "LP"); + } + if (tval) + { + fprintf (stdout, "Could not write problem to \"%s\".\n", + state->field); + } + else + { + fprintf (stdout, "Saved to \"%s\".\n", state->field); + } + } + else + { + if (cmd == PMPS) + { + (void) QSwrite_prob_file (p, stdout, "MPS"); + } + else + { + (void) QSwrite_prob_file (p, stdout, "LP"); + } + } + break; + } + + case NONE: + fprintf (stdout, "Unknown command: %s\n", state->field); + default: + ILLeditor_help (); + break; + } + fflush (stdout); + ILLread_lp_state_next_line (state); + } +CLEANUP: + ILLline_reader_free (reader); + ILLfree_rawlpdata (lp); +} + +int ILLeditor_solve ( + QSdata * p, + int salgo) +{ + int rval = 0; + int status = 0; + EGlpNum_t val; + + EGlpNumInitVar (val); + + if (salgo == PRIMAL_SIMPLEX) + { + rval = QSopt_primal (p, &status); + } + else + { + rval = QSopt_dual (p, &status); + } + ILL_BREAK_BODY_IF (rval); + rval = QSget_objval (p, &val); + if (p->simplex_display) + if (rval == 0) + { + fprintf (stdout, "LP Value: %.6f, status %d\n", EGlpNumToLf (val), + status); + fflush (stdout); + } +CLEANUP: + EGlpNumClearVar (val); + ILL_RESULT (rval, "ILLeditor_solve"); +} + + +static int pull_info_from_p ( + QSdata * p, + rawlpdata * lp) +{ + int i, rval = 0; + ILLlpdata *qslp = p->lp->O; + int nrows, ncols; + + ILLinit_rawlpdata (lp, NULL); + rval = ILLsymboltab_create (&lp->rowtab, 100) || + ILLsymboltab_create (&lp->coltab, 100); + ILL_BREAK_BODY_IF (rval); + + nrows = qslp->nrows; + ncols = qslp->nstruct; + /* add rows to lp */ + ILLraw_add_row (lp, qslp->objname, 'N', zeroLpNum); + for (i = 0; i < nrows; i++) + { + ILL_FAILfalse (qslp->rownames[i] != NULL, "should have no NULL names"); + ILLraw_add_row (lp, qslp->rownames[i], qslp->sense[i], qslp->rhs[i]); + } + + /* add cols to coltab and lp */ + for (i = 0; i < ncols; i++) + { + ILL_FAILfalse (qslp->colnames[i] != NULL, "should have no NULL names"); + ILLraw_add_col (lp, qslp->colnames[i], + (qslp->intmarker) ? qslp->intmarker[i] : 0); + } +CLEANUP: + ILL_RETURN (rval, "pull_info_from_p"); +} + +static int transpose ( + rawlpdata * lp) +{ + int rval = 0; + int tmp; + ILLsymboltab tmptab; + + tmp = QSMAX (lp->nrows, lp->ncols); + if (tmp >= lp->sensesize) + { + lp->sensesize *= 1.3; + lp->sensesize += 1000; + if (lp->sensesize < tmp + 1) + lp->sensesize = tmp + 1; + lp->rowsense = EGrealloc (lp->rowsense, sizeof (char) * lp->sensesize); + //rval = ILLutil_reallocrus_scale ((void **) &lp->rowsense, + // &lp->sensesize, tmp + 1, + // 1.3, sizeof (char)); + //ILL_CLEANUP_IF (rval); + } + if (tmp >= lp->rhssize) + { + lp->rhssize *= 1.3; + lp->rhssize += 1000; + if (lp->rhssize < tmp + 1) + lp->rhssize = tmp + 1; + EGlpNumReallocArray (&(lp->rhs), lp->rhssize); + //lp->rhs = EGrealloc(lp->rhs, sizeof(double)*lp->rhssize); + //rval = ILLutil_reallocrus_scale ((void **) &lp->rhs, + // &lp->sensesize, tmp + 1, + // 1.3, sizeof (double)); + //ILL_CLEANUP_IF (rval); + } + ILL_SWAP (lp->nrows, lp->ncols, tmp); + ILL_SWAP (lp->rowtab, lp->coltab, tmptab); + ILL_RETURN (rval, "transpose"); +} + +static char *get_row_col_name ( + QSdata * p, + rawlpdata * lp, + ILLread_lp_state * state, + int doRow) +{ + int rval = 0; + int ind; + char *rname, *thename = NULL; + char buf[ILL_namebufsize]; + ILLsymboltab *tab = (doRow) ? &lp->rowtab : &lp->coltab; + int id = (doRow) ? lp->nrows : lp->ncols; + + id--; /* in rawlpdata obj counts as a row */ + + rval = ILLread_constraint_name (state, &rname); + ILL_BREAK_BODY_IF (rval); + + if (rname == NULL) + { + ILLlib_findName (p->qslp, doRow /* forRow */ , rname, id, buf); + ILL_UTIL_STR (thename, buf); + } + else + { + ILL_UTIL_STR (thename, rname); + } + if (ILLsymboltab_lookup (tab, thename, &ind) == 0) + { + rval = ILLlp_error (state, "\"%s\" already exists.", thename); + } +CLEANUP: + if (rval != 0) + { + ILL_IFFREE (thename, char); + } + return thename; +} + +static int fill_matrix ( + rawlpdata * lp, + ILLread_lp_state * state, + ILLmatrix * m, + EGlpNum_t * obj, + int n) +{ + int i, cnt, rval = 0; + colptr *cp; + EGlpNum_t val; + int newCol = (obj != NULL); + + EGlpNumInitVar (val); + + /* rely on fact that objective has rowindex 0 */ + + m->matrows = lp->nrows; + m->matcols = 1; + m->matval = EGlpNumAllocArray (lp->ncols); + ILL_SAFE_MALLOC (m->matind, lp->ncols, int); + ILL_SAFE_MALLOC (m->matbeg, 1, int); + ILL_SAFE_MALLOC (m->matcnt, 1, int); + + m->matsize = lp->ncols; + m->matbeg[0] = 0; + m->matcnt[0] = 0; + for (i = 0; i < lp->ncols; i++) + { + cnt = 0; + EGlpNumZero (val); + for (cp = lp->cols[i]; cp != NULL; cp = cp->next) + { + ILL_FAILfalse (cp->this_val == n, "n should be the only row around"); + if (EGlpNumIsNeqqZero (cp->coef)) + { + EGlpNumAddTo (val, cp->coef); + cnt++; + } + } + if (cnt > 1) + { + ILLlp_warn (state, "Multiple coefficients for \"%s\".", + ILLraw_colname (lp, i)); + } + if (EGlpNumIsNeqqZero (val)) + { + if ((i - newCol) >= 0) + { + EGlpNumCopy (m->matval[m->matcnt[0]], val); + m->matind[m->matcnt[0]] = i - newCol; + m->matcnt[0]++; + } + else + { + EGlpNumCopy (obj[0], val); + } + } + } + if (m->matcnt[0] == 0) + { + rval = ILLlp_error (state, "There are no non zero coefficients."); + } +CLEANUP: + EGlpNumClearVar (val); + ILL_RESULT (rval, "fill_matrix"); +} + +static void add_row ( + QSdata * p, + rawlpdata * lp, + ILLread_lp_state * state) +{ + int rval = 0; + int n; + char *name; + ILLmatrix m; + char sense[1]; + + ILLmatrix_init (&m); + n = lp->nrows; + name = get_row_col_name (p, lp, state, 1 /*doRow */ ); + + if (name == NULL) + { + rval = 1; + } + else + { + rval = ILLread_one_constraint (state, name, lp, 0); + + /* adds row name to lp->rowtab the checks constraint expression */ + if (rval != 0) + { + /* failed because of error in expression => + * must remove name from symbol table */ + fprintf (stdout, "Incorrect expression.\n"); + } + else + { + ILL_FAILfalse (lp->nrows == (n + 1), "Should have one row"); + ILL_IFTRACE ("ADDING row %s.\n", name); + + sense[0] = lp->rowsense[n]; + + rval = fill_matrix (lp, state, &m, NULL, n); + ILL_BREAK_BODY_IF (rval); + + QSadd_rows (p, 1, m.matcnt, m.matbeg, m.matind, m.matval, + &(lp->rhs[n]), sense, (const char **) &name); + } + } +CLEANUP: + ILLmatrix_free (&m); + if (name != NULL) + { + if (rval != 0) + ILLsymboltab_delete (&lp->rowtab, name); + ILL_IFFREE (name, char); + } + if (rval != 0) + { + lp->nrows = n; + } + ILLraw_clear_matrix (lp); +} + +static void add_col ( + QSdata * p, + rawlpdata * lp, + ILLread_lp_state * state) +{ + int rval = 0; + int n; + char *name[1]; + int transposed = 1; + ILLmatrix matrix, *m = &matrix; + EGlpNum_t obj[1], lower[1], upper[2]; + + EGlpNumInitVar (*obj); + EGlpNumInitVar (*lower); + EGlpNumInitVar (upper[0]); + EGlpNumInitVar (upper[1]); + + n = lp->ncols; + ILLmatrix_init (m); + name[0] = get_row_col_name (p, lp, state, 0 /*doRow */ ); + rval = (name[0] == NULL); + ILL_BREAK_BODY_IF (rval); + + transposed = !transpose (lp); + rval = ILLread_one_constraint (state, name[0], lp, 0); + + /* adds row name to lp->rowtab the checks constraint expression */ + if (rval != 0) + { + /* failed because of error in expression => + * must remove name from symbol table */ + fprintf (stdout, "Incorrect expression.\n"); + } + else + { + ILL_FAILfalse (lp->nrows == (n + 1), "Should have one row"); + + rval = fill_matrix (lp, state, m, obj, n); + ILL_BREAK_BODY_IF (rval); + + fprintf (stdout, "lower "); + rval = ILLread_lp_state_next_line (state) || + ILLread_lp_state_value (state, &(lower[0])); + ILL_BREAK_BODY_IF (rval); + + fprintf (stdout, "upper "); + rval = ILLread_lp_state_next_line (state) || + ILLread_lp_state_value (state, &(upper[0])); + ILL_BREAK_BODY_IF (rval); + + ILL_IFTRACE ("ADDING col %s.\n", name[0]); + + QSadd_cols (p, 1, m->matcnt, m->matbeg, m->matind, m->matval, + obj, lower, upper, (const char **) name); + + } +CLEANUP: + ILLmatrix_free (m); + if (name[0] != NULL) + { + if (rval != 0) + ILLsymboltab_delete (&lp->rowtab, name[0]); + ILL_IFFREE (name[0], char); + } + if (rval != 0) + { + lp->nrows = n; + } + ILLraw_clear_matrix (lp); + if (transposed) + transpose (lp); + ILL_IFFREE (name[0], char); + + EGlpNumClearVar (*obj); + EGlpNumClearVar (*lower); + EGlpNumClearVar (upper[0]); + EGlpNumClearVar (upper[1]); +} + +#if 0 +#ifndef JAVA_PORT +static void new_row ( + QSdata * p, + rawlpdata * lp, + ILLread_lp_state * state) +{ + int rval = 0; + char *rowname = NULL, *rname = NULL; + char sense; + double d; + int ind, hit; + + rval = ILLread_constraint_name (state, &rname); + if (rname == NULL) + { + rval = 1; + ILLeditor_help_cmd (ROW, NEW); + } + ILL_BREAK_BODY_IF (rval); + + ILLsymboltab_lookup (&lp->rowtab, rname, &ind); + if (ind != ILL_SYM_NOINDEX) + { + rval = ILLlp_error (state, "\"%s\" is already defined.\n", rname); + ILL_BREAK_BODY_IF (rval); + } + ILL_UTIL_STR (rowname, rname); + + rval = ILLread_lp_state_sense (state); + sense = state->sense_val; + ILL_BREAK_BODY_IF (rval); + + rval = ILLread_lp_state_value (state, &d); + ILL_BREAK_BODY_IF (rval); + + rval = QSnew_row (p, d, sense, rowname); + if (rval != 0) + { + fprintf (stderr, "could not add row\n"); + } + else + { + ILLsymboltab_register (&lp->rowtab, rname, &ind, &hit); + } +CLEANUP: + ILL_IFFREE (rowname, char); +} +#endif +#endif + +static int del_row_or_col ( + QSdata * p, + rawlpdata * lp, + ILLread_lp_state * state, + int isRow) +{ + int i[1], rval = 0; + char **names = (isRow) ? p->qslp->rownames : p->qslp->colnames; + int nnames = (isRow) ? p->qslp->nrows : p->qslp->nstruct; + ILLsymboltab *tab = (isRow) ? &lp->rowtab : &lp->coltab; + + rval = ILLread_lp_state_next_field_on_line (state); + ILL_BREAK_BODY_IF (rval); + + i[0] = ILLutil_array_index (names, nnames, state->field); + if (i[0] >= 0) + { + rval = (isRow) ? QSdelete_rows (p, 1, i) : QSdelete_cols (p, 1, i); + if (rval == 0) + { + ILLsymboltab_delete (tab, state->field); + } + } + else + { + rval = ILLlp_error (state, "\"%s\" is not defined.\n", state->field); + } + +CLEANUP: + ILL_RESULT (rval, "del_row_or_col"); +} + +static void del_row ( + QSdata * p, + rawlpdata * lp, + ILLread_lp_state * state) +{ + int rval = del_row_or_col (p, lp, state, 1); + + if (rval == 0) + { + lp->nrows--; + } +} + +static void del_col ( + QSdata * p, + rawlpdata * lp, + ILLread_lp_state * state) +{ + int rval = del_row_or_col (p, lp, state, 0); + + if (rval == 0) + { + lp->ncols--; + } +} diff --git a/src/editor.h b/src/editor.h new file mode 100644 index 0000000..f56cb2f --- /dev/null +++ b/src/editor.h @@ -0,0 +1,35 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: editor.h,v 1.2 2003/11/05 16:57:39 meven Exp $ */ +#ifndef EDITOR_H +#define EDITOR_H + +extern void ILLeditor_init ( + void); +extern void ILLeditor ( + QSdata * p); +extern int ILLeditor_solve ( + QSdata * p, + int salgo); + +#endif diff --git a/src/eg_exact.h b/src/eg_exact.h new file mode 100644 index 0000000..a8d436d --- /dev/null +++ b/src/eg_exact.h @@ -0,0 +1,41 @@ +/* QSopt-Exact "An exact LP solver" + * + * Copyright (C) 2006 Daniel Espinoza. + * + * This library 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.1 of the License, or (at your + * option) any later version. + * + * This library 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 library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * */ +/* ========================================================================= */ +/** @mainpage QSopt-Exact Home Page + * + * @section Introduction + +

This is a joint project of Daniel Espinoza, William Cook, Sanjeeb Dash and David Applegate. +Also, Kati Wolter has contributed with bug-fixes, bug-reports and special functionality for SCIP exact.

+ +

The objective of this software is to provide a solver for Linear Programming (and Integer Programming to a lesser degree) that returns true (rational) optimal solutions.

+ +

It relies heavilly on the GNUMP library, that provides a multiprecision library for both floating point and also rational arithmetic. +Note that if you use a dynamicly linked version of QSopt-Exact, then the GMP library should have been compiled with the option --enable-alloca=malloc-reentrant, this is needed to avoid memory corruption. +The basis for the LP solver was taken from QSopt, which is an LP solver based on floating point arithmetic and available for free for research purposes. +A brief description of the implementation and the obtained results can be obtained here (pdf), and a longer description (which is part of my Ph.D. thesis) can be found here +Much of the functionality used in QSopt-Exact comes from EGlib. +

+ +

You can see the documentation or download the program source.

+

We also have made available binaries for linux 32 bit and for linux 64 bit + +

Finally, many thanks to all people that have contributed with bug-reports, comments, and help.

+ + * */ diff --git a/src/eg_exutil.c b/src/eg_exutil.c new file mode 100644 index 0000000..5ca9f84 --- /dev/null +++ b/src/eg_exutil.c @@ -0,0 +1,483 @@ +/* ========================================================================= */ +/* ESolver "Exact Mixed Integer Linear Solver" provides some basic structures + * and algorithms commons in solving MIP's + * + * Copyright (C) 2005 Daniel Espinoza. + * + * This library 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.1 of the License, or (at your + * option) any later version. + * + * This library 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 library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * */ +/* ========================================================================= */ +/** @file + * @ingroup Esolver */ +/** @addtogroup Esolver */ +/** @{ */ +#include "eg_exutil.h" + +/* ========================================================================= */ +/** @name EXutilStatics + * Variables asociated with the #EXutilApproximate function, we use them + * as static to save some time in intialization */ +/*@{*/ +/** @brief Array of integers used in the continued fraction method */ +static mpz_t Z[7]; +/**@brief rational remainder used in the continued fraction method */ +static mpq_t cvl; +/* ========================================================================= */ +/** @brief Initialize the static variables at start-up */ +void EXutilDoInit (void) +{ + unsigned __EXui; + EGlpNumStart(); + mpq_init (cvl); + for (__EXui = 7; __EXui--;) + mpz_init (Z[__EXui]); +} + +/* ========================================================================= */ +/** @brief Clear all memory related to the static variables */ +void EXutilDoClear (void) +{ + unsigned __EXui; + mpq_clear (cvl); + for (__EXui = 7; __EXui--;) + mpz_clear (Z[__EXui]); + EGlpNumClear(); + +} + +/*@}*/ + +/* ========================================================================= */ +int EXutilIntegralize (const unsigned n, + mpq_t * const a, + mpq_t b, + mpq_t maxabs) +{ + mpz_t lcm, + gcd; + register unsigned int i; + mpz_init (lcm); + mpz_init (gcd); + mpz_set (lcm, mpq_denref (b)); + mpz_set (gcd, mpq_numref (b)); + if (mpz_cmp_ui (gcd, 0UL) == 0) + mpz_set_ui (gcd, 1UL); + /* compute the greatest common divisor ammong the numerator of a_i and b, + * and the least common multiple ammong the denominators of a_i and b */ + for (i = n; i--;) + { + mpz_lcm (lcm, lcm, mpq_denref (a[i])); + mpz_gcd (gcd, gcd, mpq_numref (a[i])); + } + /* divide everything by lcm/gcd */ + mpz_mul (mpq_numref (b), mpq_numref (b), lcm); + mpz_mul (mpq_denref (b), mpq_denref (b), gcd); + mpq_canonicalize (b); + mpz_abs (mpq_numref (maxabs), mpq_numref (b)); + for (i = n; i--;) + { + mpz_mul (mpq_denref (a[i]), mpq_denref (a[i]), gcd); + mpz_mul (mpq_numref (a[i]), mpq_numref (a[i]), lcm); + mpq_canonicalize (a[i]); + if (mpz_cmpabs (mpq_numref (maxabs), mpq_numref (a[i])) < 0) + mpz_abs (mpq_numref (maxabs), mpq_numref (a[i])); + } + /* ending */ + mpz_set_ui (mpq_denref (maxabs), 1UL); + mpz_clear (gcd); + mpz_clear (lcm); + return 0; +} + +/* ========================================================================= */ +int EXutilSimplify (const unsigned n, + mpq_t * const a, + mpq_t b) +{ + register unsigned i; + mpq_t maxabs; + mpq_init (maxabs); + EXutilIntegralize (n, a, b, maxabs); + /* normalize the cut so that |(a,b)|_inf == 1 */ + if (mpz_cmp_ui (mpq_numref (maxabs), 0UL)) + { + mpq_div (b, b, maxabs); + for (i = n; i--;) + mpq_div (a[i], a[i], maxabs); + } + /* ending */ + mpq_clear (maxabs); + return 0; +} + +/* ========================================================================= */ +void mpq_GomoryCoeff (mpq_t rop, + mpq_t coef, + unsigned const is_int, + int const bound, + unsigned const cut_mlt, + mpq_t b_frac) +{ + mpq_t fj; + mpq_init (fj); + mpq_set_ui (rop, 0UL,1UL); + /* if the variable is integer */ + if (is_int) + { + if (mpq_IsInteger (coef)) + { + mpq_set (rop, coef); + mpq_EGlpNumMultUiTo (rop, cut_mlt); + mpq_EGlpNumMultTo (rop, b_frac); + } + /* if the variable is integer, but the coefficient id fractional */ + else + { + mpq_set (fj, coef); + mpq_EGlpNumMultUiTo (fj, cut_mlt); + mpq_FracPart (fj, fj); + /* if the variable is complemented to its lower bound */ + if (bound == 'L') + { + if (mpq_cmp (fj, b_frac) <= 0) + { + mpq_set (rop, coef); + mpq_EGlpNumMultUiTo (rop, cut_mlt); + mpq_EGlpNumFloor (rop, rop); + mpq_EGlpNumMultTo (rop, b_frac); + mpq_EGlpNumAddTo (rop, fj); + } + else + { + mpq_set (rop, coef); + mpq_EGlpNumMultUiTo (rop, cut_mlt); + mpq_EGlpNumCeil (rop, rop); + mpq_EGlpNumMultTo (rop, b_frac); + } + } + /* if the variable is complemented to its upper bound */ + else + { + mpq_EGlpNumSubTo (fj, mpq_oneLpNum); + mpq_neg (fj, fj); + if (mpq_cmp (fj, b_frac) <= 0) + { + mpq_set (rop, coef); + mpq_EGlpNumMultUiTo (rop, cut_mlt); + mpq_EGlpNumCeil (rop, rop); + mpq_EGlpNumMultTo (rop, b_frac); + mpq_EGlpNumSubTo (rop, fj); + } + else + { + mpq_set (rop, coef); + mpq_EGlpNumMultUiTo (rop, cut_mlt); + mpq_EGlpNumFloor (rop, rop); + mpq_EGlpNumMultTo (rop, b_frac); + } + } + } + } + /* if the variable is continuous */ + else + { + /* if the variable is complemented to its lower bound */ + if (bound == 'L') + { + if (mpq_cmp_ui (coef, 0UL,1UL) > 0) + { + mpq_set (rop, coef); + mpq_EGlpNumMultUiTo (rop, cut_mlt); + } + } + /* if the variable is complemented to its upper bound */ + else + { + if (mpq_cmp_ui (coef, 0UL,1UL) < 0) + { + mpq_set (rop, coef); + mpq_EGlpNumMultUiTo (rop, cut_mlt); + } + } + } + /* done */ + mpq_clear (fj); +} + +/* ========================================================================= */ +int EXutilExpandLogicals (mpq_QSdata * const act_lp, + mpq_t * const vector, + mpq_t b, + mpq_ILLlp_rows * const lprows) +{ + const int n_rows = act_lp->qslp->nrows; + const int n_struct = act_lp->qslp->nstruct; + int const *const rowmap = act_lp->qslp->rowmap; + mpq_t * const rhs = act_lp->qslp->rhs; + mpq_ILLmatrix *const A = &(act_lp->qslp->A); + int rowbeg; + int rowcnt; + int *rowind; + mpq_t * rowval; + register int i, + k; + for (i = n_rows; i--;) + { + /* convert the vector */ + if (mpz_cmp_ui (mpq_numref (vector[i + n_struct]), 0UL)) + { + rowbeg = lprows->rowbeg[i]; + rowcnt = lprows->rowcnt[i]; + rowind = lprows->rowind + rowbeg; + rowval = lprows->rowval + rowbeg; + /* we use slack again as the multiplier that we need to add the + * row to the current vector so as to make dissapear the slack */ + mpq_neg (cvl, vector[i + n_struct]); + mpq_div (cvl, cvl, A->matval[A->matbeg[rowmap[i]]]); + MESSAGE (EX_UTIL_VERBOSE + 100, "Replacing constraint %s with multiple" + " %lf from integer part", act_lp->qslp->rownames[i], + mpq_get_d (cvl)); + mpq_EGlpNumAddInnProdTo (b, rhs[i], cvl); + for (k = rowcnt; k--;) + mpq_EGlpNumAddInnProdTo (vector[rowind[k]], cvl, rowval[k]); + mpq_set_ui (vector[i + n_struct], 0UL, 1UL); + } + } + return 0; +} + +/* ========================================================================= */ +void EXutilApproximate (mpq_t var, + mpq_t ori, + unsigned const max_den) +{ + /* local variables */ + unsigned lsng = mpz_cmp_ui (mpq_numref (ori), 0UL) < 0 ? 1U : 0U; + int i; + mpq_t __lpnum__; + mpq_init(__lpnum__); + /* check if the given number is zero, if so, set to zero var and return */ + if (mpz_cmp_ui (mpq_numref (ori), 0UL) == 0) + { + return; + } + /* if not, then we have some work to do */ + /* now we initialize the internal numbers */ + mpq_abs (cvl, ori); + for (i = 7; i--;) + mpz_set_ui (Z[i], 0UL); + mpz_set_ui (Z[0], 1UL); + mpz_set_ui (Z[4], 1UL); + mpz_fdiv_q (Z[1], mpq_numref (cvl), mpq_denref (cvl)); + mpq_set_z (__lpnum__, Z[1]); + mpq_sub (cvl, cvl, __lpnum__); + /* now we loop until the next t's is more than mpf_eps */ + /* the formula is + * p_i = t_i*p_{i-1} + p_{i-2}, and + * q_i = t_i*q_{i-1} + q_{i-2} + * note that |x-p_i/q_i|<1/q_i^2 + * for us t_i = Z[6], and the current number is either [0,1,2] in the Z + * array, we use those popsitions ciclicly, and use the four position as a + * temporary number, Z+4 is used to store q's, at the beginning i = 1. */ + while (1) + { + if (mpq_cmp_ui (cvl, 1UL, (unsigned long)max_den) < 0 || (mpz_cmp_ui (Z[4], (unsigned long)max_den) > 0)) + { + mpz_set (mpq_denref (var), Z[4]); + mpz_set (mpq_numref (var), Z[1]); + break; + } + /* first run */ + mpq_inv (cvl, cvl); + mpz_fdiv_q (Z[6], mpq_numref (cvl), mpq_denref (cvl)); + mpq_set_z (__lpnum__, Z[6]); + mpq_sub (cvl, cvl, __lpnum__); + mpz_set (Z[2], Z[0]); + mpz_addmul (Z[2], Z[1], Z[6]); + mpz_set (Z[5], Z[3]); + mpz_addmul (Z[5], Z[4], Z[6]); + if (mpq_cmp_ui (cvl, 1UL, (unsigned long)max_den) < 0 || (mpz_cmp_ui (Z[5], (unsigned long)max_den) > 0)) + { + mpz_set (mpq_denref (var), Z[5]); + mpz_set (mpq_numref (var), Z[2]); + break; + } + /* second run */ + mpq_inv (cvl, cvl); + mpz_fdiv_q (Z[6], mpq_numref (cvl), mpq_denref (cvl)); + mpq_set_z (__lpnum__, Z[6]); + mpq_sub (cvl, cvl, __lpnum__); + mpz_set (Z[0], Z[1]); + mpz_addmul (Z[0], Z[2], Z[6]); + mpz_set (Z[3], Z[4]); + mpz_addmul (Z[3], Z[5], Z[6]); + if (mpq_cmp_ui (cvl, 1UL, (unsigned long)max_den) < 0 || (mpz_cmp_ui (Z[3], (unsigned long)max_den) > 0)) + { + mpz_set (mpq_denref (var), Z[3]); + mpz_set (mpq_numref (var), Z[0]); + break; + } + /* third run */ + mpq_inv (cvl, cvl); + mpz_fdiv_q (Z[6], mpq_numref (cvl), mpq_denref (cvl)); + mpq_set_z (__lpnum__, Z[6]); + mpq_sub (cvl, cvl, __lpnum__); + mpz_set (Z[1], Z[2]); + mpz_addmul (Z[1], Z[0], Z[6]); + mpz_set (Z[4], Z[5]); + mpz_addmul (Z[4], Z[3], Z[6]); + } + /* ending */ + mpq_canonicalize (var); + if (lsng) + mpq_neg (var, var); + /* clean-up */ + mpq_clear(__lpnum__); + return; +} + +/* ========================================================================= */ +void EXutilOverEstimate (mpq_t var, + mpq_t ori, + unsigned const max_den) +{ + EXutilApproximate (var, ori, max_den); + /* check if var is < ori, if so, we must add one to the numerator */ + if (mpq_cmp (ori, var) > 0) + { + mpq_set_ui (cvl, 1UL, (unsigned long)(max_den * max_den)); + mpq_add (var, var, cvl); + EXIT (mpq_cmp (ori, var) > 0, "Imposible!"); + } + return; +} + +/* ========================================================================= */ +void EXutilNicefy (mpq_QSdata * const act_prob, + const unsigned char *const var_stat, + const unsigned max_den, + mpq_t * a, + mpq_t b, + int const sense) +{ + const unsigned square = max_den * max_den; + const int nstruct = act_prob->qslp->nstruct; + const int *const structmap = act_prob->qslp->structmap; + mpq_t *const lower = act_prob->qslp->lower; + mpq_t *const upper = act_prob->qslp->upper; + mpq_t num1, + num2; + register int i; + int colid = 0; + int sign = 0; + unsigned cur_stat = 0; + mpq_init (num1); + mpq_init (num2); + if (sense != 'L' && sense != 'G') + return; + /* we internally assume that the inequality is of the form ax >= b */ + if (sense == 'L') + { + mpq_neg (b, b); + for (i = nstruct; i--;) + mpq_neg (a[i], a[i]); + } + /* now we first approximate each coefficient */ + for (i = nstruct; i--;) + { + colid = structmap[i]; + cur_stat = var_stat[colid]; + /* if the variables is not bounded, we can't nicefy the coefficient */ + if ((cur_stat & (EX_STATUS_UB | EX_STATUS_LB)) == 0) + continue; + /* if the numerator is less than square, there is nothing to do */ + if (mpz_cmp_ui (mpq_denref (a[i]), (unsigned long)square) <= 0) + continue; + EXutilApproximate (num1, a[i], max_den); + mpq_sub (num2, num1, a[i]); + sign = mpz_cmp_ui (mpq_numref (num2), 0UL); + /* depending on the side that the approximation land we see what we have to + * do, first case, num1 > a[i] */ + REDO: + if (sign > 0) + { + /* if the variable is bounded bellow, we just update the RHS and set the + * coefficient */ + if (cur_stat & EX_STATUS_LB) + { + EXIT ((mpq_EGlpNumIsEqqual (lower[colid], mpq_ILL_MINDOUBLE)), + "Imposible"); + mpq_EGlpNumAddInnProdTo (b, num2, lower[colid]); + mpq_set (a[i], num1); + } + /* otherwise, we can't approximate by above, but we have to approximate + * by bellow */ + else + { + mpq_set_ui (num2, 1UL, (unsigned long)square); + mpq_sub (num1, num1, num2); + mpq_sub (num2, num1, a[i]); + sign = mpz_cmp_ui (mpq_numref (num2), 0UL); + goto REDO; + } + } + /* otherwise, we have that num1 < a[i] */ + else if (sign < 0) + { + /* if the variable is bounded by above, we just update the RHS and set + * the coefficient */ + if (cur_stat & EX_STATUS_UB) + { + EXIT ((mpq_EGlpNumIsEqqual (upper[colid], mpq_ILL_MAXDOUBLE)), + "Imposible"); + mpq_EGlpNumAddInnProdTo (b, num2, upper[colid]); + mpq_set (a[i], num1); + } + /* otherwise, we can't approximate by bellow, but we have to approximate + * by above. */ + else + { + mpq_set_ui (num2, 1UL, (unsigned long)square); + mpq_add (num1, num1, num2); + mpq_sub (num2, num1, a[i]); + sign = mpz_cmp_ui (mpq_numref (num2), 0UL); + goto REDO; + } + } + } + /* now we round the RHS, we do this by adding the constraint 0 >= -1 */ + EXutilApproximate (num1, b, max_den); + if (mpq_cmp (num1, b) > 0) + { + mpq_set_ui (num2, 1UL, (unsigned long)square); + mpq_sub (num1, num1, num2); + } + mpq_set (b, num1); + /* before ending, we return the constraint to its normal form */ + if (sense == 'L') + { + mpq_neg (b, b); + for (i = nstruct; i--;) + mpq_neg (a[i], a[i]); + } + /* ending */ + mpq_clear (num2); + mpq_clear (num1); + return; +} + +/* ========================================================================= */ +/** @} */ +/* end eg_exutil.c */ diff --git a/src/eg_exutil.h b/src/eg_exutil.h new file mode 100644 index 0000000..5f5e656 --- /dev/null +++ b/src/eg_exutil.h @@ -0,0 +1,311 @@ +/* ========================================================================= */ +/* ESolver "Exact Mixed Integer Linear Solver" provides some basic structures + * and algorithms commons in solving MIP's + * + * Copyright (C) 2005 Daniel Espinoza. + * + * This library 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.1 of the License, or (at your + * option) any later version. + * + * This library 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 library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * */ +/* ========================================================================= */ +#ifndef __EG_EX_UTIL__ +#define __EG_EX_UTIL__ +#include "qs_config.h" +#include "mpq_qstruct.h" +#include "mpq_lpdata.h" +/** @file + * @ingroup Esolver */ +/** @addtogroup Esolver */ +/** @{ */ +/* ========================================================================= */ +/** @brief status for variables that are logicals */ +#define EX_STATUS_LGC 1U + +/* ========================================================================= */ +/** @brief status for variables that are structural */ +#define EX_STATUS_STR 2U + +/* ========================================================================= */ +/** @brief status for variables that are integer */ +#define EX_STATUS_INT 4U + +/* ========================================================================= */ +/** @brief status for variables that bounded from below */ +#define EX_STATUS_LB 8U + +/* ========================================================================= */ +/** @brief status for variables that bounded from above */ +#define EX_STATUS_UB 16U + +/* ========================================================================= */ +/** @brief status for integer variable fixed at its upper bound. This status is + * not defined while calling cut callbacks. */ +#define EX_STATUS_FIX_UB 32U + +/* ========================================================================= */ +/** @brief status for integer variable fixed at its lower bound. This status is + * not defined while calling cut callbacks. */ +#define EX_STATUS_FIX_LB 64U + +/* ========================================================================= */ +/** @brief status for integer variable among our set of selected integer + * variables. This status is not defined while calling cut callbacks. */ +#define EX_STATUS_BESTFRAC 128U + +/* ========================================================================= */ +/** @brief given a cut ax <=> b, write it in integer form ,i.e. set all a,b to + * integer in such a way that a_i and b are all relativelly prime. + * @param n size of the a vector. + * @param a RHS of the inequality + * @param b LHS of the inequality. + * @param maxabs return the maximum absolute value among all resulting a_i,b. + * @return zero on success, non-zero otherwise. + * */ +int EXutilIntegralize (const unsigned n, + mpq_t * const a, + mpq_t b, + mpq_t maxabs); + +/* ========================================================================= */ +/** @brief verbosity level */ +#define EX_UTIL_VERBOSE 100 + +/* ========================================================================= */ +/** @brief given two vectors (a,b) and (v,w), compute its inner product and + * store it into rop. + * @param dim dimmension of the a and v part of the vector. + * @param a first part of the first vector. + * @param b second part of the first vector. + * @param v first part of the second vector. + * @param w second part of the second vector. + * @param rop where we store the result. + * @note we may take a == v and/or b == w. + * */ +#define EXutilInnProd(dim,a,b,v,w,rop) do{\ + register unsigned __EXuti = (dim);\ + mpq_mul(rop,b,w);\ + while(__EXuti--) mpq_EGlpNumAddInnProdTo(rop,(a)[__EXuti],(v)[__EXuti]);\ + } while(0); + +/* ========================================================================= */ +/** @brief Compute the number of non-zeros in a given vector. + * @param dim size of the a vector. + * @param a vector where we are operating. + * @param rop where to return the number of non-zeros (it should be an integer + * variable, not a pointer to such a variable) */ +#define EXutilNzSz(dim,a,rop) do{\ + register unsigned __EXuti = (dim);\ + rop = 0;\ + while(__EXuti--) if(mpz_cmp_ui(mpq_numref((a)[__EXuti]),0UL)) rop++;}while(0) + +/* ========================================================================= */ +/** @brief Compute the L_1 norm of a given vector. + * @param dim size of the a vector. + * @param a vector where we are operating. + * @param rop where to retirn the L1 norm value */ +#define EXutilL1Norm(dim,a,rop) do{\ + mpq_t*const __EXuta = (a);\ + mpq_t __qtmp__;\ + register unsigned __EXuti = (dim);\ + mpq_init(__qtmp__);\ + mpq_set_ui(rop,0UL,1UL);\ + while(__EXuti--){\ + mpq_abs(__qtmp__,__EXuta[__EXuti]);\ + mpq_add(rop,rop,__qtmp__);}mpq_clear(__qtmp__);}while(0) + +/* ========================================================================= */ +/** @brief given a cut ax <=> b, write it in normalized form ,i.e. set all a,b + * to integer in such a way that a_i and b are all relativelly prime, and + * divide them all over the + * maximum such (a_i,b) (so that the infinity norm of (a,b) is one. + * @param n size of the a vector. + * @param a RHS of the inequality + * @param b LHS of the inequality. + * @return zero on success, non-zero otherwise. + * */ +int EXutilSimplify (const unsigned n, + mpq_t * const a, + mpq_t b); + +/* ========================================================================= */ +/** @brief asign to the first number the fractional part of the second, i.e. + * \f$ rop = op1 - \lfloor op1 \rfloor \f$. + * @param rop where to retunr our result. + * @param op1 number for wich we want to compute its fractional part */ +#define mpq_FracPart(rop, op1) do{\ + mpz_fdiv_r (mpq_numref (rop), mpq_numref (op1), mpq_denref (op1));\ + mpz_set (mpq_denref (rop), mpq_denref (op1));\ + mpq_canonicalize((rop));\ +} while(0) + +/* ========================================================================= */ +/** @brief test if the given number is integer. + * @param op number to test. + * @return one if the nummber is integer, zero- otherwise. */ +#define mpq_IsInteger(op) ({\ + (mpz_cmp(mpq_denref(op),mpz_oneLpNum)==0);}) + +/* ========================================================================= */ +/** @brief round to \f$-\infty\f$ the given number to the closest fraction + * of the form \f$a/2^{exp}\f$ from bellow. + * @param op number to round. + * @param exp exponent to use in the fraction */ +#define mpq_FroundExp(op,exp) do{\ + mpz_t __ztmp__;\ + mpz_init(__ztmp__);\ + mpz_mul_2exp(__ztmp__,mpq_numref((op)),(exp));\ + mpz_fdiv_q(mpq_numref((op)),__ztmp__,mpq_denref((op)));\ + mpz_mul_2exp(mpq_denref((op)),mpz_oneLpNum,(exp));\ + mpq_canonicalize((op));mpz_clear(__ztmp__);}while(0) + +/* ========================================================================= */ +/** @brief round to \f$+\infty\f$ the given number to the closest fraction + * of the form \f$a/2^{exp}\f$ from above. + * @param op number to round. + * @param exp exponent to use in the fraction */ +#define mpq_CroundExp(op,exp) do{\ + mpz_t __ztmp__;\ + mpz_init(__ztmp__);\ + mpz_mul_2exp(__ztmp__,mpq_numref((op)),(exp));\ + mpz_cdiv_q(mpq_numref((op)),__ztmp__,mpq_denref((op)));\ + mpz_mul_2exp(mpq_denref((op)),mpz_oneLpNum,(exp));\ + mpq_canonicalize((op));mpz_clear(__ztmp__);}while(0) + +/* ========================================================================= */ +/** @brief round to \f$0\f$ the given number to the closest fraction + * of the form \f$a/2^{exp}\f$ towards zero. + * @param op number to round. + * @param exp exponent to use in the fraction */ +#define mpq_TroundExp(op,exp) do{\ + mpz_t __ztmp__;\ + mpz_init(__ztmp__);\ + mpz_mul_2exp(__ztmp__,mpq_numref((op)),(exp));\ + mpz_tdiv_q(mpq_numref((op)),__ztmp__,mpq_denref((op)));\ + mpz_mul_2exp(mpq_denref((op)),mpz_oneLpNum,(exp));\ + mpq_canonicalize((op));mpz_clear(__ztmp__);}while(0) + +/* ========================================================================= */ +/** @brief compute the gomory coefficient of the variable given the original + * coefficient, the multiplier, and all relevant information. + * @param rop Where we return the gomory coefficient. (it should be different + * location than the original coefficient). + * @param coef original coefficient in the equality that we are using to + * derive the gomory cut. + * @param is_int this is either zero (indicating that the variable asociated + * with this coefficient is continuous) or one (indicating that the variable + * asociated with this coeffcient is integer). + * @param bound indicate if this variable was complemented to its lower bound + * (then L) or to its upper bound (then U), any other value will generate an + * error. + * @param cut_mlt multiplier to use to the coefficient (and thus the effective + * coefficient would be coef*cut_mlt). + * @param b_frac fractional part of the RHS in the equation (after + * complementing variables). */ +void mpq_GomoryCoeff (mpq_t rop, + mpq_t coef, + unsigned const is_int, + int const bound, + unsigned const cut_mlt, + mpq_t b_frac); + +/* ========================================================================= */ +/** @brief Given a vector in QSopt external form, and a row description of the + * related LP, re-write the vector using only real variables, we do that by + * substracting the equation defining the logical variable multiplied by the + * coefficient of the logical variable in the vector to the vector. + * @param act_lp lp where we are working. + * @param vector vector of length at least nrows + nstruct where we want to + * replace all logical coefficients. + * @param lprows row description of the given LP. + * @param rhs if we look at vector,rhs as an inequality, then we eliminate the + * slack coefficient form the inequality as a whole. + * @return zero on success, non-zero otherwise. + * */ +int EXutilExpandLogicals (mpq_QSdata * const act_lp, + mpq_t * const vector, + mpq_t rhs, + mpq_ILLlp_rows * const lprows); + +/* ========================================================================= */ +/** @brief Approximate using continued fractions method a given rational + * \f$\frac{a}{b} \f$ with another rational \f$\frac{a'}{b'}\f$ that satisfy + * that \f$ b' < max_den^2 \f$ and also + * \f$|\frac{a}{b} - \frac{a'}{b'}|\leq\frac1{max_den^2}\f$. + * @param ori original coefficient that we want to represent as a/b with b <= + * max_den^2. + * @param dest we return here the resulting number. + * @param max_den maximum allowed denominator in the new representation. */ +void EXutilApproximate (mpq_t dest, + mpq_t ori, + unsigned const max_den); + +/* ========================================================================= */ +/** @brief Overestimate the given coefficient by another rational that is + * representble with denominators not bigger than max_den^2. + * @param ori original coefficient that we want to represent as a/b with b <= + * max_den^2. + * @param dest we return here the resulting number, note that we always + * insure that the returned value is bigger than the original value. + * @param max_den maximum allowed denominator in the new representation. */ +void EXutilOverEstimate (mpq_t dest, + mpq_t ori, + unsigned const max_den); + +/* ========================================================================= */ +/** @brief Given an inequality, we try to re-write so that no denominator is + * bigger than the square of the given number, and ensuring validity. for + * coefficients that can't be `nacified' we leave them intact. the process + * imply adding multiples of the bounds on variables, and at the end, nicify + * the rhs of the inequality. + * @param max_den the square of this value is the maximum denominator allowed. + * @param a hand side of the inequality. + * @param sense sense of the inequality, it should be either 'L' or 'G'. + * @param b right hand side of the inequality. + * @param act_prob LP from where we draw the bounds on the variables. + * @param var_stat status (as defined in #EXmipinfo_t::var_stat) for all + * variables in the LP, in the internal QSopt ordering. + * @note The length of the a vector is at least nstruct, and we assume that + * entry a[k] corresnpond to the coefficient associated with the k-th + * structural variable inside. */ +void EXutilNicefy (mpq_QSdata * const act_prob, + const unsigned char *const var_stat, + const unsigned max_den, + mpq_t * a, + mpq_t b, + int const sense); + +/* ========================================================================= */ +/** @brief given a variable in internal number, return a pointer to its name. + * @param iid internal ordering number. + * @param QSlp pointer to the mpq_QSdata structure containing the LP. + * @param QSinv_map pointer to an array containing the inverse map from internal + * numbering to external numbering as in #EXmipinfo_t::inv_map. + * @return pointer to its name. + * @note If the variable is a slack variable, it return the name of the + * inequality. */ +#define EXutilIidToStr(iid,QSlp,QSinv_map) ({\ + mpq_QSdata*const __EXlp = (QSlp);\ + const int __EXeid = (QSinv_map)[(iid)];\ + (__EXeid >= __EXlp->qslp->nstruct) ? __EXlp->qslp->rownames[__EXeid - __EXlp->qslp->nstruct] : __EXlp->qslp->colnames[__EXeid];}) + +/* ========================================================================= */ +/** @brief Initialize the static variables at start-up */ +extern void EXutilDoInit (void); +/* ========================================================================= */ +/** @brief Clear all memory related to the static variables */ +extern void EXutilDoClear (void); +/* ========================================================================= */ +/** @} */ +/* end eg_exutil.h */ +#endif diff --git a/src/eg_sloan.c b/src/eg_sloan.c new file mode 100644 index 0000000..3274d23 --- /dev/null +++ b/src/eg_sloan.c @@ -0,0 +1,234 @@ +#include "qs_config.h" +#include "QSopt_ex.h" +/* ========================================================================= */ +/** @name Static Variables + * Set of static variables for this program. */ +/*@{*/ +/** @brief range of values for first OA level */ +static unsigned s1 = 3; +/** @brief range of values for second OA level */ +static unsigned s2 = 3; +/** @brief number of columns for first OA level */ +static unsigned k1 = 3; +/** @brief number of columns for second OA level */ +static unsigned k2 = 3; +/** @brief use (or not) scaling of the resulting LP */ +static int use_scaling = 1; +/** @brief use dlouble floating point output */ +static int use_double = 0; +/** @brief file name output. */ +const char *out_file = "output.lp"; +/** @brief Strength level required */ +static unsigned t = 2; +/** @brief temporal string space */ +char strtmp[1024]; +/*@}*/ + +/* ========================================================================= */ +/** @brief Display options to the screen */ +static inline void sl_usage (char const *const s) +{ + fprintf (stderr, + "This programs compute bounds for mixed-level orthogonal arrays (OA) of different strengths for two levels\n"); + fprintf (stderr, "Usage: %s [options]\n", s); + fprintf (stderr, " -a n range of values for the first OA level (>=2)\n"); + fprintf (stderr, + " -b n range of values for the second OA level (>=2)\n"); + fprintf (stderr, + " -c n number of columns for the first OA level (>=2)\n"); + fprintf (stderr, + " -e n number of columns for the second OA level (>=2)\n"); + fprintf (stderr, + " -d n if n > 0, write the LP in double precition arithmetic, otherwise, write it in rational form\n"); + fprintf (stderr, " -o f filename where to write the output LP\n"); + fprintf (stderr, + " -s n if n > 0 scale the resulting LP, otherwise present the unscaled LP\n"); + fprintf (stderr, " -t n required strength of the OA (>=1)\n"); +} + +/* ========================================================================= */ +/** @brief Display options to the screen */ +static inline int sl_parseargs (int argc, + char **argv) +{ + int c; + while ((c = getopt (argc, argv, "a:b:c:e:s:d:o:t:")) != EOF) + { + switch (c) + { + case 'a': + s1 = atoi (optarg); + break; + case 'b': + s2 = atoi (optarg); + break; + case 'c': + k1 = atoi (optarg); + break; + case 'e': + k2 = atoi (optarg); + break; + case 's': + use_scaling = atoi (optarg); + break; + case 'd': + use_double = atoi (optarg); + break; + case 'o': + out_file = optarg; + break; + case 't': + t = atoi (optarg); + break; + default: + sl_usage (argv[0]); + return 1; + } + } + if (s1 < 2 || s2 < 2 || k1 < 1 || k2 < 1 || t < 1) + { + sl_usage (argv[0]); + return 1; + } + fprintf (stderr, "Running %s\nOptions:\n", argv[0]); + fprintf (stderr, "\tfirst level columns = %d\n", k1); + fprintf (stderr, "\tsecond level columns = %d\n", k2); + fprintf (stderr, "\tfirst level range = %d\n", s1); + fprintf (stderr, "\tsecond level range = %d\n", s2); + fprintf (stderr, "\tt = %d\n", t); + fprintf (stderr, "\t%s scaling\n", use_scaling ? "using" : "not using"); + fprintf (stderr, "\t%s output\n", use_double ? "double" : "rational"); + fprintf (stderr, "\toutput file : %s\n", out_file); + return 0; +} + +/* ========================================================================= */ +/** @brief compute the krawtchouk ppolynomial, defined as + * \f[P^s_j(x,m)=\sum\limits_{i=0}^j(-1)^i(s-1)^{j-i}\binom{x}{i}\binom{m-x}{j-i}\f] + * @param x the \f$x\f$ parameter of the function. + * @param s the \f$s\f$ parameter of the function. + * @param j the \f$j\f$ parameter of the function. + * @param m the \f$m\f$ parameter of the function. + * @param rop where to store the result */ +void Kpoly (unsigned x, + unsigned s, + unsigned j, + unsigned m, + mpz_t rop) +{ + register unsigned i = j + 1; + mpz_t z1, + z2; + mpz_init (z1); + mpz_init (z2); + mpz_set_ui (rop, (unsigned long)0); + EXIT (m < x, "m < x! impossible!"); + EXIT (s < 1, "s < 1! impossible!"); + while (i--) + { + mpz_bin_uiui (z1, (unsigned long)x, (unsigned long)i); + mpz_set (z2, z1); + mpz_bin_uiui (z1, (unsigned long)(m - x), (unsigned long)(j - i)); + mpz_mul (z2, z2, z1); + mpz_ui_pow_ui (z1, (unsigned long)(s - 1), (unsigned long)(j - i)); + mpz_mul (z2, z2, z1); + if (i & 1U) + mpz_sub (rop, rop, z2); + else + mpz_add (rop, rop, z2); + } + mpz_clear (z1); + mpz_clear (z2); +} + +/* ========================================================================= */ +/** @brief main function, here we build the LP, execute the options and exit */ +int main (int argc, + char **argv) +{ + int rval = 0; + mpq_t v1, + v2; + mpq_QSdata *p_mpq = 0; + dbl_QSdata *p_dbl = 0; + register unsigned i, + j, + k, + l; + /* parse input */ + EGlib_info(); + EGlib_version(); + QSopt_ex_version(); + QSexactStart(); + rval = sl_parseargs (argc, argv); + if (rval) + return rval; + mpq_init (v1); + mpq_init (v2); + /* create the problem with the appropriate number of variables and + * constraints */ + snprintf (strtmp, (size_t)1023, "OA_SL_%d-%d_%d-%d_t-%d", s1, k1, s2, k2, t); + p_mpq = mpq_QScreate_prob (strtmp, QS_MIN); + for (i = 0; i <= k1; i++) + for (j = 0; j <= k2; j++) + { + snprintf (strtmp, (size_t)1023, "V_%d_%d", i, j); + rval = + mpq_QSnew_col (p_mpq, mpq_oneLpNum, + (i + j == 0) ? mpq_oneLpNum : mpq_zeroLpNum, + mpq_ILL_MAXDOUBLE, strtmp); + CHECKRVALG (rval, CLEANUP); + strtmp[0] = 'C'; + rval = mpq_QSnew_row (p_mpq, mpq_zeroLpNum, + ((i + j >= 1) && (i + j <= t)) ? 'E' : 'G', strtmp); + CHECKRVALG (rval, CLEANUP); + } + /* now set the coefficients */ + for (i = 0; i <= k1; i++) + for (j = 0; j <= k2; j++) + for (k = 0; k <= k1; k++) + for (l = 0; l <= k2; l++) + { + Kpoly (k, s1, i, k1, mpq_numref (v2)); + Kpoly (l, s2, j, k2, mpq_numref (v1)); + mpq_mul (v1, v1, v2); + if (mpz_cmp_ui (mpq_numref (v1), (unsigned long)0)) + { + rval = + mpq_QSchange_coef (p_mpq, ((int)(j + i * (k2 + 1))), (int)(l + k * (k2 + 1)), v1); + CHECKRVALG (rval, CLEANUP); + } + } + /* now, if we are using scaling, we scale the non-zeros */ + if (use_scaling) + { + mpq_set_ui (v1, (unsigned long)1, (unsigned long)1); + EXutilSimplify ((unsigned)(p_mpq->qslp->A.matsize), p_mpq->qslp->A.matval, v1); + mpq_div (v2, mpq_oneLpNum, v1); + fprintf (stderr, "Scale factor %lf\n", mpq_get_d (v2)); + } + /* now we save the LP */ + if (use_double) + { + snprintf (strtmp, (size_t)1023, "OA_SL_%d-%d_%d-%d_t-%d", s1, k1, s2, k2, t); + p_dbl = QScopy_prob_mpq_dbl (p_mpq, strtmp); + rval = dbl_QSwrite_prob (p_dbl, out_file, "LP"); + CHECKRVALG (rval, CLEANUP); + } + else + { + rval = mpq_QSwrite_prob (p_mpq, out_file, "LP"); + CHECKRVALG (rval, CLEANUP); + } + + /* ending */ +CLEANUP: + if (p_mpq) + mpq_QSfree_prob (p_mpq); + if (p_dbl) + dbl_QSfree_prob (p_dbl); + mpq_clear (v1); + mpq_clear (v2); + QSexactClear(); + return rval; +} diff --git a/src/eg_sloan.h b/src/eg_sloan.h new file mode 100644 index 0000000..3f92267 --- /dev/null +++ b/src/eg_sloan.h @@ -0,0 +1,9 @@ +#ifndef __SLOAN_LP__ +#define __SLOAN_LP__ +#include +#include "qs_config.h" +#if OS == LINUX +#include +#endif +#include "exact.h" +#endif diff --git a/src/esolver.c b/src/esolver.c new file mode 100644 index 0000000..61038ea --- /dev/null +++ b/src/esolver.c @@ -0,0 +1,379 @@ +/* ========================================================================= */ +/* ESolver "Exact Mixed Integer Linear Solver" provides some basic structures + * and algorithms commons in solving MIP's + * + * Copyright (C) 2008 David Applegate, Bill Cook, Sanjeeb Dash, Daniel Espinoza. + * + * This library 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.1 of the License, or (at your + * option) any later version. + * + * This library 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 library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * */ +/* ========================================================================= */ +#include +#include "qs_config.h" +#include "QSopt_ex.h" +/* ========================================================================= */ +/** @name static parameters for the main program */ +/*@{*/ +static char *fname = 0; +static int lpfile = 0; +static int usescaling = 1; +static int showversion = 0; +static int simplexalgo = PRIMAL_SIMPLEX; +static int pstrategy = QS_PRICE_PSTEEP; +static int dstrategy = QS_PRICE_DSTEEP; +static unsigned precision = 128; +static int printsol = 0; +static char *solname = 0; +static char *readbasis = 0; +static char *writebasis = 0; +/** @brief maximum running time */ +static double max_rtime = INT_MAX; +/** @brief maximum memory usage */ +static unsigned long memlimit = UINT_MAX; +/*@}*/ +/* ========================================================================= */ +/** @brief Display options to the screen */ +static void usage (char *s) +{ + fprintf (stderr, "Usage: %s [- below -] prob_file\n", s); + fprintf (stderr, " -b f write basis to file f\n"); + fprintf (stderr, " -B f read initial basis from file f\n"); +#if 0 + fprintf (stderr, " -I solve the MIP using BestBound\n"); + fprintf (stderr, " -E edit problem after solving initial version\n"); +#endif + fprintf (stderr, " -L input file is in lp format (default: mps)\n"); + fprintf (stderr, " -O write the final solution to a .sol file\n"); + fprintf (stderr, " -p # run primal simplex with pricing rule #\n"); + fprintf (stderr, + " (%d-Dantzig, %d-Devex, %d-Steep (default), %d-Partial\n", + QS_PRICE_PDANTZIG, QS_PRICE_PDEVEX, QS_PRICE_PSTEEP, + QS_PRICE_PMULTPARTIAL); + fprintf (stderr, + " -P # number of bits to use for the float representation (default: 128)\n"); + fprintf (stderr, " -d # run dual simplex with pricing rule #\n"); + fprintf (stderr, " (%d-Dantzig, %d-Steep, %d-Partial, %d-Devex)\n", + QS_PRICE_DDANTZIG, QS_PRICE_DSTEEP, QS_PRICE_DMULTPARTIAL, + QS_PRICE_DDEVEX); + fprintf (stderr, " -S do NOT scale the initial LP\n"); + fprintf (stderr, " -v print QSopt version number\n"); + fprintf (stderr, " -R n maximum running time allowed, default %lf\n", + max_rtime); + fprintf (stderr, " -m n maximum memory usage allowed, default %lu\n", + memlimit); +} + +/* ========================================================================= */ +/** @brief decide if a given file is mps or lp (only by extension) */ +static void get_ftype (char const *const name, + int *ftype) +{ + char buff[4096],*argv[128]; + int argc; + *ftype = 0; /* by default, file is MPS */ + snprintf(buff,4096,"%s",name); + EGioNParse(buff,128,"."," ",&argc,argv); + argc-=1; + if(argc) + { + if(strncmp(argv[argc],"gz",3)==0) argc-=1; + else if(strncmp(argv[argc],"GZ",3)==0) argc-=1; + else if(strncmp(argv[argc],"bz2",4)==0) argc-=1; + else if(strncmp(argv[argc],"BZ2",4)==0) argc-=1; + } + if(argc) + { + if(strncmp(argv[argc],"lp",3)==0) *ftype=1; + else if(strncmp(argv[argc],"LP",3)==0) *ftype=1; + } +} +/* ========================================================================= */ +/** @brief signal handler for time-limit reached */ +static void sighandler(int s) +{ + switch(s) + { + case SIGXCPU: + fprintf(stderr,"TIME_LIMIT_REACHED (ending now)\n"); + exit(EXIT_FAILURE); + default: + fprintf(stderr,"Unknown signal %d (ending now)\n",s); + exit(EXIT_FAILURE); + } +} +/* ========================================================================= */ +/** @brief function to handle resource usage limits */ +static int mem_limits(void) +{ + int rval = 0; + struct rlimit mlim; + rval = getrlimit(RLIMIT_CPU,&mlim); + CHECKRVAL(rval); + fprintf(stderr, "Cur rtime limit %ld, trying to set to %lg\n", mlim.rlim_cur, max_rtime); + if(max_rtime > mlim.rlim_max) max_rtime = (double)mlim.rlim_max; + mlim.rlim_cur = (rlim_t)max_rtime; + rval = setrlimit(RLIMIT_CPU,&mlim); + TESTERRNOIF(rval); + fprintf(stderr, "New rtime limit %ld (%.3lg)\n", mlim.rlim_cur, max_rtime); + rval = getrlimit(RLIMIT_DATA,&mlim); + TESTERRNOIF(rval); + fprintf(stderr, "Cur data limit %ld,%ld (soft,hard)\n", mlim.rlim_cur, + mlim.rlim_max); + mlim.rlim_cur = memlimit; + rval = setrlimit(RLIMIT_DATA,&mlim); + TESTERRNOIF(rval); + rval = getrlimit(RLIMIT_DATA,&mlim); + TESTERRNOIF(rval); + fprintf(stderr, "New data limit %ld,%ld (soft,hard)\n", mlim.rlim_cur, + mlim.rlim_max); + rval = getrlimit(RLIMIT_AS,&mlim); + TESTERRNOIF(rval); + fprintf(stderr, "Cur address space limit %ld,%ld (soft,hard)\n", + mlim.rlim_cur, mlim.rlim_max); + mlim.rlim_cur = memlimit; + rval = setrlimit(RLIMIT_AS,&mlim); + TESTERRNOIF(rval); + rval = getrlimit(RLIMIT_AS,&mlim); + TESTERRNOIF(rval); + fprintf(stderr, "New address space limit %ld,%ld (soft,hard)\n", + mlim.rlim_cur, mlim.rlim_max); + mlim.rlim_cur = 0; + rval = setrlimit(RLIMIT_CORE,&mlim); + TESTERRNOIF(rval); + rval = getrlimit(RLIMIT_CORE,&mlim); + TESTERRNOIF(rval); + fprintf(stderr, "New core dump space limit %ld,%ld (soft,hard)\n", + mlim.rlim_cur, mlim.rlim_max); + /* set signal handler for SIGXCPU */ + signal(SIGXCPU,sighandler); + return rval; +} +/* ========================================================================= */ +/** @brief parssing options for the program */ +static int parseargs (int ac, + char **av) +{ + int c; + int boptind = 1; + char *boptarg = 0; + + while ((c = + ILLutil_bix_getopt (ac, av, "b:B:d:EILm:O:p:P:R:Sv", &boptind, + &boptarg)) != EOF) + switch (c) + { + case 'm': + memlimit = strtoul(boptarg,0,10); + break; + case 'R': + max_rtime = strtod(boptarg,0); + break; + case 'b': + writebasis = boptarg; + break; + case 'B': + readbasis = boptarg; + break; + case 'P': + precision = atoi (boptarg); + break; + case 'd': + simplexalgo = DUAL_SIMPLEX; + dstrategy = atoi (boptarg); + break; + case 'L': + lpfile = 1; + break; + case 'O': + printsol = 1; + solname = strdup(boptarg); + break; + case 'p': + simplexalgo = PRIMAL_SIMPLEX; + pstrategy = atoi (boptarg); + break; + case 'S': + usescaling = 0; + break; + case 'v': + showversion = 1; + break; + case '?': + default: + usage (av[0]); + return 1; + } + if ((boptind == ac) && (showversion)) + { + char *buf = 0; + buf = mpq_QSversion (); + printf ("%s\n", buf); + mpq_QSfree ((void *) buf); + exit(0); + } + if (boptind != (ac - 1)) + { + usage (av[0]); + return 1; + } + + fname = av[boptind++]; + fprintf (stderr, "Reading problem from %s\n", fname); + mem_limits(); + return 0; +} + +/* ========================================================================= */ +/** @brief the main thing! */ +/* ========================================================================= */ +int main (int ac, + char **av) +{ + int rval = 0, + status = 0; + mpq_QSdata *p_mpq = 0; + QSbasis *basis = 0; + ILLutil_timer timer_solve; + ILLutil_timer timer_read; + int ftype = 0; /* 0 mps, 1 lp */ + mpq_t *y_mpq = 0, + *x_mpq = 0; + EGlib_info(); + EGlib_version(); + QSopt_ex_version(); + QSexactStart(); + /* parse arguments and initialize EGlpNum related things */ + rval = parseargs (ac, av); + QSexact_set_precision (precision); + if (rval) + goto CLEANUP; + if (writebasis) + { + basis = EGsMalloc (QSbasis, 1); + memset (basis, 0, sizeof (QSbasis)); + } + + /* just for the bell's and wistle */ + if (showversion) + { + char *buf = 0; + buf = mpq_QSversion (); + if (buf == 0) + { + ILL_CLEANUP; + } + else + { + printf ("%s\n", buf); + mpq_QSfree ((void *) buf); + } + } + + /* get the file type */ + if (lpfile) + ftype = 1; + else + get_ftype (fname, &ftype); + + /* read the mpq problem */ + ILLutil_init_timer (&timer_read, "SOLVER_READ_MPQ"); + ILLutil_start_timer (&timer_read); + if (ftype == 1) + { + p_mpq = mpq_QSread_prob ((const char *) fname, "LP"); + if (p_mpq == 0) + { + fprintf (stderr, "Could not read lp file.\n"); + rval = 1; + ILL_CLEANUP_IF (rval); + } + } + else + { + p_mpq = mpq_QSread_prob ((const char *) fname, "MPS"); + if (p_mpq == 0) + { + fprintf (stderr, "Could not read mps file.\n"); + rval = 1; + ILL_CLEANUP_IF (rval); + } + } + + /* and get the basis if needed */ + if (readbasis) + { + rval = mpq_QSread_and_load_basis (p_mpq, (const char *) readbasis); + ILL_CLEANUP_IF (rval); + if (basis) + mpq_QSfree_basis (basis); + basis = mpq_QSget_basis (p_mpq); + } + ILLutil_stop_timer (&timer_read, 1); + /* set the readed flags */ + rval = mpq_QSset_param (p_mpq, QS_PARAM_SIMPLEX_DISPLAY, 1) + || mpq_QSset_param (p_mpq, QS_PARAM_PRIMAL_PRICING, pstrategy) + || mpq_QSset_param (p_mpq, QS_PARAM_DUAL_PRICING, dstrategy) + || mpq_QSset_param (p_mpq, QS_PARAM_SIMPLEX_SCALING, usescaling); + ILL_CLEANUP_IF (rval); + if (printsol) + { + x_mpq = mpq_EGlpNumAllocArray (p_mpq->qslp->ncols); + y_mpq = mpq_EGlpNumAllocArray (p_mpq->qslp->nrows); + } + ILLutil_init_timer (&timer_solve, "SOLVER"); + ILLutil_start_timer (&timer_solve); + rval = QSexact_solver (p_mpq, x_mpq, y_mpq, basis, simplexalgo, &status); + ILL_CLEANUP_IF (rval); + ILLutil_stop_timer (&timer_solve, 1); + if (printsol) + { + char out_f_name[1024]; + EGioFile_t *out_f; + sprintf (out_f_name, "%s.sol.gz", solname); + out_f = EGioOpen (out_f_name, "w+"); + switch (status) + { + case QS_LP_OPTIMAL: + EGioPrintf (out_f, "status = OPTIMAL\n"); + rval = QSexact_print_sol (p_mpq, out_f); + CHECKRVALG(rval,CLEANUP); + break; + case QS_LP_INFEASIBLE: + EGioPrintf (out_f, "status = INFEASIBLE\n"); + break; + case QS_LP_UNBOUNDED: + EGioPrintf (out_f, "status = UNBOUNDED\n"); + break; + default: + EGioPrintf (out_f, "status = UNDEFINED\n"); + break; + } + EGioClose (out_f); + } + /* ending */ +CLEANUP: + EGfree(solname); + mpq_EGlpNumFreeArray (x_mpq); + mpq_EGlpNumFreeArray (y_mpq); + /* free the last allocated basis, and if we wanted to save it, do so */ + if (basis) + { + if (writebasis) + rval = mpq_QSwrite_basis (p_mpq, 0, writebasis); + } + mpq_QSfree_basis (basis); + mpq_QSfree_prob (p_mpq); + QSexactClear(); + return rval; /* main return */ +} diff --git a/src/exact.c b/src/exact.c new file mode 100644 index 0000000..3a72610 --- /dev/null +++ b/src/exact.c @@ -0,0 +1,1848 @@ +/* ========================================================================= */ +/* ESolver "Exact Mixed Integer Linear Solver" provides some basic structures + * and algorithms commons in solving MIP's + * + * Copyright (C) 2005 Daniel Espinoza. + * + * This library 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.1 of the License, or (at your + * option) any later version. + * + * This library 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 library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * */ +/* ========================================================================= */ +/** @file + * @ingroup Esolver */ +/** @addtogroup Esolver */ +/** @{ */ +#include "exact.h" +#include "util.h" +extern mpq_t mpq_ILL_MAXDOUBLE; +extern mpq_t mpq_ILL_MINDOUBLE; +extern void mpq_ILLfct_set_variable_type (mpq_lpinfo * lp); +extern void mpq_ILLfct_compute_piz (mpq_lpinfo * lp); +extern void mpq_ILLfct_compute_dz (mpq_lpinfo * lp); +extern void mpq_ILLfct_compute_xbz (mpq_lpinfo * lp); +extern void mpq_ILLfct_compute_dobj ( mpq_lpinfo * lp); +extern void mpq_ILLfct_check_pfeasible (mpq_lpinfo * lp, + mpq_feas_info * fs, + const mpq_t ftol); +extern void mpq_ILLfct_check_dfeasible (mpq_lpinfo * lp, + mpq_feas_info * fs, + const mpq_t ftol); +extern void mpq_ILLfct_set_status_values (mpq_lpinfo * lp, + int pstatus, + int dstatus, + int ptype, + int dtype); +extern int mpq_grab_cache (mpq_QSdata * p, + int status); +extern void mpq_ILLfct_compute_phaseI_piz (mpq_lpinfo * lp); + +/* ========================================================================= */ +int QSexact_print_sol (mpq_QSdata * p, + EGioFile_t * out_f) +{ + int rval = 0, + status; + const int ncols = mpq_QSget_colcount (p); + const int nrows = mpq_QSget_rowcount (p); + mpq_t *x = mpq_EGlpNumAllocArray (ncols); + mpq_t *rc = mpq_EGlpNumAllocArray (ncols); + mpq_t *slack = mpq_EGlpNumAllocArray (nrows); + mpq_t *pi = mpq_EGlpNumAllocArray (nrows); + mpq_t value; + register int i; + char *str1 = 0; + mpq_init (value); + EGcallD(mpq_QSget_status (p, &status)); + if(mpq_QSget_x_array (p, x)) mpq_EGlpNumFreeArray (x); + if(mpq_QSget_slack_array (p, slack)) mpq_EGlpNumFreeArray (slack); + if(mpq_QSget_pi_array (p, pi)) mpq_EGlpNumFreeArray (pi); + if(mpq_QSget_rc_array (p, rc)) mpq_EGlpNumFreeArray (rc); + + switch (status) + { + case QS_LP_OPTIMAL: + EGcallD(mpq_QSget_objval (p, &value)); + str1 = mpq_EGlpNumGetStr (value); + EGioPrintf (out_f, "status OPTIMAL\n\tValue = %s\n", str1); + free (str1); + str1 = 0; + break; + case QS_LP_INFEASIBLE: + EGioPrintf (out_f, "status INFEASIBLE\n"); + break; + case QS_LP_UNBOUNDED: + EGioPrintf (out_f, "status UNBOUNDED\n"); + break; + case QS_LP_ITER_LIMIT: + case QS_LP_TIME_LIMIT: + case QS_LP_UNSOLVED: + case QS_LP_ABORTED: + case QS_LP_MODIFIED: + EGioPrintf (out_f, "status NOT_SOLVED\n"); + break; + } + if (x) + { + EGioPrintf (out_f, "VARS:\n"); + for (i = 0; i < ncols; i++) + if (!mpq_equal (x[i], __zeroLpNum_mpq__)) + { + str1 = mpq_EGlpNumGetStr (x[i]); + EGioPrintf (out_f, "%s = %s\n", p->qslp->colnames[i], str1); + free (str1); + } + } + if (rc) + { + EGioPrintf (out_f, "REDUCED COST:\n"); + for (i = 0; i < ncols; i++) + if (!mpq_equal (rc[i], __zeroLpNum_mpq__)) + { + str1 = mpq_EGlpNumGetStr (rc[i]); + EGioPrintf (out_f, "%s = %s\n", p->qslp->colnames[i], str1); + free (str1); + } + } + if (pi) + { + EGioPrintf (out_f, "PI:\n"); + for (i = 0; i < nrows; i++) + if (!mpq_equal (pi[i], __zeroLpNum_mpq__)) + { + str1 = mpq_EGlpNumGetStr (pi[i]); + EGioPrintf (out_f, "%s = %s\n", p->qslp->rownames[i], str1); + free (str1); + } + } + if (slack) + { + EGioPrintf (out_f, "SLACK:\n"); + for (i = 0; i < nrows; i++) + if (!mpq_equal (slack[i], __zeroLpNum_mpq__)) + { + str1 = mpq_EGlpNumGetStr (slack[i]); + EGioPrintf (out_f, "%s = %s\n", p->qslp->rownames[i], str1); + free (str1); + } + } + + /* ending */ +CLEANUP: + if (x) + mpq_EGlpNumFreeArray (x); + if (pi) + mpq_EGlpNumFreeArray (pi); + if (rc) + mpq_EGlpNumFreeArray (rc); + if (slack) + mpq_EGlpNumFreeArray (slack); + mpq_clear (value); + return rval; +} + +/* ========================================================================= */ +dbl_QSdata *QScopy_prob_mpq_dbl (mpq_QSdata * p, + const char *newname) +{ + const int ncol = mpq_QSget_colcount(p); + const int nrow = mpq_QSget_rowcount(p); + char*sense=0; + int*rowcnt=0; + int*rowbeg=0; + int*rowind=0; + int objsense; + mpq_t*mpq_lb=0; + mpq_t*mpq_ub=0; + mpq_t*mpq_obj=0; + mpq_t*mpq_range=0; + mpq_t*mpq_rhs=0; + mpq_t*mpq_rowval=0; + double*dbl_lb=0; + double*dbl_ub=0; + double*dbl_obj=0; + double*dbl_range=0; + double*dbl_rhs=0; + double*dbl_rowval=0; + dbl_QSdata *p2 = 0; + int rval = 0; + register int i; + mpq_t mpq_val; + double dbl_val; + mpq_init(mpq_val); + /* get all information */ + EGcallD(mpq_QSget_objsense(p,&objsense)); + mpq_lb = mpq_EGlpNumAllocArray(ncol); + mpq_ub = mpq_EGlpNumAllocArray(ncol); + EGcallD(mpq_QSget_bounds(p,mpq_lb,mpq_ub)); + dbl_lb = QScopy_array_mpq_dbl(mpq_lb); + dbl_ub = QScopy_array_mpq_dbl(mpq_ub); + mpq_EGlpNumFreeArray(mpq_ub); + mpq_obj = mpq_lb; + mpq_lb = 0; + EGcallD(mpq_QSget_obj(p, mpq_obj)); + dbl_obj = QScopy_array_mpq_dbl(mpq_obj); + mpq_EGlpNumFreeArray(mpq_obj); + EGcallD(mpq_QSget_ranged_rows(p, &rowcnt, &rowbeg, &rowind, &mpq_rowval, + &mpq_rhs, &sense, &mpq_range, 0)); + dbl_rowval = QScopy_array_mpq_dbl(mpq_rowval); + mpq_EGlpNumFreeArray(mpq_rowval); + dbl_range = QScopy_array_mpq_dbl(mpq_range); + mpq_EGlpNumFreeArray(mpq_range); + dbl_rhs = QScopy_array_mpq_dbl(mpq_rhs); + mpq_EGlpNumFreeArray(mpq_rhs); + /* create copy */ + p2 = dbl_QScreate_prob (newname, objsense); + if (!p2) goto CLEANUP; + for( i = 0 ; i < ncol; i++) + { + EGcallD(dbl_QSnew_col(p2, dbl_obj[i], dbl_lb[i], dbl_ub[i], 0)); + } + dbl_EGlpNumFreeArray(dbl_lb); + dbl_EGlpNumFreeArray(dbl_ub); + dbl_EGlpNumFreeArray(dbl_obj); + EGcallD(dbl_QSadd_ranged_rows(p2, nrow, rowcnt, rowbeg, rowind, + dbl_rowval, dbl_rhs, sense, dbl_range, 0)); + /* set parameters */ + EGcallD(mpq_QSget_param(p, QS_PARAM_PRIMAL_PRICING, &objsense)); + EGcallD(dbl_QSset_param(p2, QS_PARAM_PRIMAL_PRICING, objsense)); + EGcallD(mpq_QSget_param(p, QS_PARAM_DUAL_PRICING, &objsense)); + EGcallD(dbl_QSset_param(p2, QS_PARAM_DUAL_PRICING, objsense)); + EGcallD(mpq_QSget_param(p, QS_PARAM_SIMPLEX_DISPLAY, &objsense)); + EGcallD(dbl_QSset_param(p2, QS_PARAM_SIMPLEX_DISPLAY, objsense)); + EGcallD(mpq_QSget_param(p, QS_PARAM_SIMPLEX_MAX_ITERATIONS, &objsense)); + EGcallD(dbl_QSset_param(p2, QS_PARAM_SIMPLEX_MAX_ITERATIONS, objsense)); + EGcallD(mpq_QSget_param(p, QS_PARAM_SIMPLEX_SCALING, &objsense)); + EGcallD(dbl_QSset_param(p2, QS_PARAM_SIMPLEX_SCALING, objsense)); + EGcallD(mpq_QSget_param_EGlpNum(p, QS_PARAM_SIMPLEX_MAX_TIME, &mpq_val)); + dbl_val = mpq_get_d(mpq_val); + EGcallD(dbl_QSset_param_EGlpNum(p2, QS_PARAM_SIMPLEX_MAX_TIME, dbl_val)); + EGcallD(mpq_QSget_param_EGlpNum(p, QS_PARAM_OBJULIM, &mpq_val)); + dbl_val = mpq_get_d(mpq_val); + EGcallD(dbl_QSset_param_EGlpNum(p2, QS_PARAM_OBJULIM, dbl_val)); + EGcallD(mpq_QSget_param_EGlpNum(p, QS_PARAM_OBJLLIM, &mpq_val)); + dbl_val = mpq_get_d(mpq_val); + EGcallD(dbl_QSset_param_EGlpNum(p2, QS_PARAM_OBJLLIM, dbl_val)); + /* ending */ + CLEANUP: + mpq_clear(mpq_val); + dbl_EGlpNumFreeArray(dbl_rowval); + dbl_EGlpNumFreeArray(dbl_range); + dbl_EGlpNumFreeArray(dbl_rhs); + dbl_EGlpNumFreeArray(dbl_lb); + dbl_EGlpNumFreeArray(dbl_ub); + dbl_EGlpNumFreeArray(dbl_obj); + mpq_EGlpNumFreeArray(mpq_rowval); + mpq_EGlpNumFreeArray(mpq_range); + mpq_EGlpNumFreeArray(mpq_rhs); + mpq_EGlpNumFreeArray(mpq_lb); + mpq_EGlpNumFreeArray(mpq_ub); + mpq_EGlpNumFreeArray(mpq_obj); + EGfree(rowcnt); + EGfree(rowbeg); + EGfree(rowind); + EGfree(sense); + if (rval) + { + dbl_QSfree_prob (p2); + p2 = 0; + } +#if QSEXACT_SAVE_INT + else + { + dbl_QSwrite_prob (p2, "prob.dbl.lp", "LP"); + } +#endif + return p2; +} + +/* ========================================================================= */ +mpf_QSdata *QScopy_prob_mpq_mpf (mpq_QSdata * p, + const char *newname) +{ + const int ncol = mpq_QSget_colcount(p); + const int nrow = mpq_QSget_rowcount(p); + char*sense=0; + int*rowcnt=0; + int*rowbeg=0; + int*rowind=0; + int objsense; + mpq_t*mpq_lb=0; + mpq_t*mpq_ub=0; + mpq_t*mpq_obj=0; + mpq_t*mpq_range=0; + mpq_t*mpq_rhs=0; + mpq_t*mpq_rowval=0; + mpf_t*mpf_lb=0; + mpf_t*mpf_ub=0; + mpf_t*mpf_obj=0; + mpf_t*mpf_range=0; + mpf_t*mpf_rhs=0; + mpf_t*mpf_rowval=0; + mpf_QSdata *p2 = 0; + int rval = 0; + mpq_t mpq_val; + mpf_t mpf_val; + register int i; + mpq_init(mpq_val); + mpf_init(mpf_val); + /* get all information */ + EGcallD(mpq_QSget_objsense(p,&objsense)); + mpq_lb = mpq_EGlpNumAllocArray(ncol); + mpq_ub = mpq_EGlpNumAllocArray(ncol); + EGcallD(mpq_QSget_bounds(p,mpq_lb,mpq_ub)); + mpf_lb = QScopy_array_mpq_mpf(mpq_lb); + mpf_ub = QScopy_array_mpq_mpf(mpq_ub); + mpq_EGlpNumFreeArray(mpq_ub); + mpq_obj = mpq_lb; + mpq_lb = 0; + EGcallD(mpq_QSget_obj(p, mpq_obj)); + mpf_obj = QScopy_array_mpq_mpf(mpq_obj); + mpq_EGlpNumFreeArray(mpq_obj); + EGcallD(mpq_QSget_ranged_rows(p, &rowcnt, &rowbeg, &rowind, &mpq_rowval, &mpq_rhs, &sense, &mpq_range, 0)); + mpf_rowval = QScopy_array_mpq_mpf(mpq_rowval); + mpq_EGlpNumFreeArray(mpq_rowval); + mpf_range = QScopy_array_mpq_mpf(mpq_range); + mpq_EGlpNumFreeArray(mpq_range); + mpf_rhs = QScopy_array_mpq_mpf(mpq_rhs); + mpq_EGlpNumFreeArray(mpq_rhs); + /* create copy */ + p2 = mpf_QScreate_prob (newname, objsense); + if (!p2) goto CLEANUP; + for( i = 0 ; i < ncol; i++) + { + EGcallD(mpf_QSnew_col(p2, mpf_obj[i], mpf_lb[i], mpf_ub[i], 0)); + } + mpf_EGlpNumFreeArray(mpf_lb); + mpf_EGlpNumFreeArray(mpf_ub); + mpf_EGlpNumFreeArray(mpf_obj); + EGcallD(mpf_QSadd_ranged_rows(p2, nrow, rowcnt, rowbeg, rowind, (const mpf_t*)mpf_rowval,(const mpf_t*) mpf_rhs, sense,(const mpf_t*) mpf_range, 0)); + /* set parameters */ + EGcallD(mpq_QSget_param(p, QS_PARAM_PRIMAL_PRICING, &objsense)); + EGcallD(mpf_QSset_param(p2, QS_PARAM_PRIMAL_PRICING, objsense)); + EGcallD(mpq_QSget_param(p, QS_PARAM_DUAL_PRICING, &objsense)); + EGcallD(mpf_QSset_param(p2, QS_PARAM_DUAL_PRICING, objsense)); + EGcallD(mpq_QSget_param(p, QS_PARAM_SIMPLEX_DISPLAY, &objsense)); + EGcallD(mpf_QSset_param(p2, QS_PARAM_SIMPLEX_DISPLAY, objsense)); + EGcallD(mpq_QSget_param(p, QS_PARAM_SIMPLEX_MAX_ITERATIONS, &objsense)); + EGcallD(mpf_QSset_param(p2, QS_PARAM_SIMPLEX_MAX_ITERATIONS, objsense)); + EGcallD(mpq_QSget_param(p, QS_PARAM_SIMPLEX_SCALING, &objsense)); + EGcallD(mpf_QSset_param(p2, QS_PARAM_SIMPLEX_SCALING, objsense)); + EGcallD(mpq_QSget_param_EGlpNum(p, QS_PARAM_SIMPLEX_MAX_TIME, &mpq_val)); + mpf_set_q(mpf_val,mpq_val); + EGcallD(mpf_QSset_param_EGlpNum(p2, QS_PARAM_SIMPLEX_MAX_TIME, mpf_val)); + EGcallD(mpq_QSget_param_EGlpNum(p, QS_PARAM_OBJULIM, &mpq_val)); + mpf_set_q(mpf_val,mpq_val); + EGcallD(mpf_QSset_param_EGlpNum(p2, QS_PARAM_OBJULIM, mpf_val)); + EGcallD(mpq_QSget_param_EGlpNum(p, QS_PARAM_OBJLLIM, &mpq_val)); + mpf_set_q(mpf_val,mpq_val); + EGcallD(mpf_QSset_param_EGlpNum(p2, QS_PARAM_OBJLLIM, mpf_val)); + /* ending */ + CLEANUP: + mpq_clear(mpq_val); + mpf_clear(mpf_val); + mpf_EGlpNumFreeArray(mpf_rowval); + mpf_EGlpNumFreeArray(mpf_range); + mpf_EGlpNumFreeArray(mpf_rhs); + mpf_EGlpNumFreeArray(mpf_lb); + mpf_EGlpNumFreeArray(mpf_ub); + mpf_EGlpNumFreeArray(mpf_obj); + mpq_EGlpNumFreeArray(mpq_rowval); + mpq_EGlpNumFreeArray(mpq_range); + mpq_EGlpNumFreeArray(mpq_rhs); + mpq_EGlpNumFreeArray(mpq_lb); + mpq_EGlpNumFreeArray(mpq_ub); + mpq_EGlpNumFreeArray(mpq_obj); + EGfree(rowcnt); + EGfree(rowbeg); + EGfree(rowind); + EGfree(sense); + if (rval) + { + mpf_QSfree_prob (p2); + p2 = 0; + } +#if QSEXACT_SAVE_INT + else + { + mpf_QSwrite_prob (p2, "prob.mpf.lp", "LP"); + } +#endif + return p2; +} + +#if QSEXACT_SAVE_OPTIMAL +/* ========================================================================= */ +/** @brief used to enumerate the generated optimal tests */ +static int QSEXACT_SAVE_OPTIMAL_IND = 0; +#endif + +/* ========================================================================= */ +int QSexact_optimal_test (mpq_QSdata * p, + mpq_t * p_sol, + mpq_t * d_sol, + QSbasis * basis) +{ + /* local variables */ + register int i, + j; + mpq_ILLlpdata *qslp = p->lp->O; + int *iarr1 = 0, + *rowmap = qslp->rowmap, + *structmap = qslp->structmap, + col; + mpq_t *arr1 = 0, + *arr2 = 0, + *arr3 = 0, + *arr4 = 0, + *rhs_copy = 0; + mpq_t *dz = 0; + int objsense = (qslp->objsense == QS_MIN) ? 1 : -1; + int const msg_lvl = __QS_SB_VERB <= DEBUG ? 0 : 100000 * (1 - p->simplex_display); + int rval = 1; /* store whether or not the solution is optimal, we start + * assuming it is. */ + mpq_t num1, + num2, + num3, + p_obj, + d_obj; + mpq_init (num1); + mpq_init (num2); + mpq_init (num3); + mpq_init (p_obj); + mpq_init (d_obj); + mpq_set_ui (p_obj, 0UL, 1UL); + mpq_set_ui (d_obj, 0UL, 1UL); + + /* now check if the given basis is the optimal basis */ + arr3 = qslp->lower; + arr4 = qslp->upper; + if (mpq_QSload_basis (p, basis)) + { + rval = 0; + MESSAGE (msg_lvl, "QSload_basis failed"); + goto CLEANUP; + } + for (i = basis->nstruct; i--;) + { + /* check that the upper and lower bound define a non-empty space */ + if (mpq_cmp (arr3[structmap[i]], arr4[structmap[i]]) > 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "variable %s has empty feasible range [%lg,%lg]", + qslp->colnames[i], mpq_EGlpNumToLf(arr3[structmap[i]]), + mpq_EGlpNumToLf(arr4[structmap[i]])); + } + goto CLEANUP; + } + /* set the variable to its apropiate values, depending its status */ + switch (basis->cstat[i]) + { + case QS_COL_BSTAT_FREE: + case QS_COL_BSTAT_BASIC: + if (mpq_cmp (p_sol[i], arr4[structmap[i]]) > 0) + mpq_set (p_sol[i], arr4[structmap[i]]); + else if (mpq_cmp (p_sol[i], arr3[structmap[i]]) < 0) + mpq_set (p_sol[i], arr3[structmap[i]]); + break; + case QS_COL_BSTAT_UPPER: + mpq_set (p_sol[i], arr4[structmap[i]]); + break; + case QS_COL_BSTAT_LOWER: + mpq_set (p_sol[i], arr3[structmap[i]]); + break; + default: + rval = 0; + MESSAGE (msg_lvl, "Unknown Variable basic status %d, for variable " + "(%s,%d)", basis->cstat[i], qslp->colnames[i], i); + goto CLEANUP; + break; + } + } + for (i = basis->nrows; i--;) + { + /* check that the upper and lower bound define a non-empty space */ + if (mpq_cmp (arr3[rowmap[i]], arr4[rowmap[i]]) > 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "constraint %s logical has empty feasible range " + "[%lg,%lg]", qslp->rownames[i], + mpq_EGlpNumToLf(arr3[rowmap[i]]), + mpq_EGlpNumToLf(arr4[rowmap[i]])); + } + goto CLEANUP; + } + /* set the variable to its apropiate values, depending its status */ + switch (basis->rstat[i]) + { + case QS_ROW_BSTAT_BASIC: + if (mpq_cmp (p_sol[i + basis->nstruct], arr4[rowmap[i]]) > 0) + mpq_set (p_sol[i + basis->nstruct], arr4[rowmap[i]]); + else if (mpq_cmp (p_sol[i + basis->nstruct], arr3[rowmap[i]]) < 0) + mpq_set (p_sol[i + basis->nstruct], arr3[rowmap[i]]); + break; + case QS_ROW_BSTAT_UPPER: + mpq_set (p_sol[i + basis->nstruct], arr4[rowmap[i]]); + break; + case QS_ROW_BSTAT_LOWER: + mpq_set (p_sol[i + basis->nstruct], arr3[rowmap[i]]); + break; + default: + rval = 0; + MESSAGE (msg_lvl, "Unknown Variable basic status %d, for constraint " + "(%s,%d)", basis->cstat[i], qslp->rownames[i], i); + goto CLEANUP; + break; + } + } + + /* compute the actual RHS */ + rhs_copy = mpq_EGlpNumAllocArray (qslp->nrows); + for (i = qslp->nstruct; i--;) + { + if (!mpq_equal (p_sol[i], mpq_zeroLpNum)) + { + arr1 = qslp->A.matval + qslp->A.matbeg[structmap[i]]; + iarr1 = qslp->A.matind + qslp->A.matbeg[structmap[i]]; + for (j = qslp->A.matcnt[structmap[i]]; j--;) + { + mpq_mul (num1, arr1[j], p_sol[i]); + mpq_add (rhs_copy[iarr1[j]], rhs_copy[iarr1[j]], num1); + } + } + } + + /* now check if both rhs and copy_rhs are equal */ + arr4 = qslp->upper; + arr1 = qslp->rhs; + arr2 = qslp->lower; + for (i = qslp->nrows; i--;) + { + mpq_mul (num1, arr1[i], d_sol[i]); + mpq_add (d_obj, d_obj, num1); + mpq_sub (num2, arr1[i], rhs_copy[i]); + EXIT (qslp->A.matcnt[rowmap[i]] != 1, "Imposible!"); + if (basis->rstat[i] == QS_ROW_BSTAT_BASIC) + mpq_div (p_sol[qslp->nstruct + i], num2, + qslp->A.matval[qslp->A.matbeg[rowmap[i]]]); + else + { + mpq_mul (num1, p_sol[qslp->nstruct + i], + qslp->A.matval[qslp->A.matbeg[rowmap[i]]]); + if (!mpq_equal (num1, num2)) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "solution is infeasible for constraint %s, violation" + " %lg", qslp->rownames[i], + mpq_get_d (num1) - mpq_get_d (num2)); + } + goto CLEANUP; + } + } + mpq_set (num2, p_sol[qslp->nstruct + i]); + /* now we check the bounds on the logical variables */ + if (mpq_cmp (num2, arr2[rowmap[i]]) < 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "constraint %s artificial (%lg) bellow lower" + " bound (%lg), actual LHS (%lg), actual RHS (%lg)", + qslp->rownames[i], mpq_get_d (num2), + mpq_get_d (arr2[rowmap[i]]), mpq_get_d (rhs_copy[i]), + mpq_get_d (arr1[i])); + } + goto CLEANUP; + } + else if (mpq_cmp (num2, arr4[rowmap[i]]) > 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "constraint %s artificial (%lg) bellow lower bound" + " (%lg)", qslp->rownames[i], mpq_get_d (num2), + mpq_get_d (arr4[rowmap[i]])); + } + goto CLEANUP; + } + } + + /* compute the upper and lower bound dual variables, note that dl is the dual + * of the lower bounds, and du the dual of the upper bound, dl >= 0 and du <= + * 0 and A^t y + Idl + Idu = c, and the dual objective value is + * max y*b + l*dl + u*du, we colapse both vector dl and du into dz, note that + * if we are maximizing, then dl <= 0 and du >=0 */ + dz = mpq_EGlpNumAllocArray (qslp->ncols); + arr2 = qslp->obj; + arr3 = qslp->lower; + arr4 = qslp->upper; + for (i = qslp->nstruct; i--;) + { + col = structmap[i]; + mpq_mul (num1, arr2[col], p_sol[i]); + mpq_add (p_obj, p_obj, num1); + arr1 = qslp->A.matval + qslp->A.matbeg[col]; + iarr1 = qslp->A.matind + qslp->A.matbeg[col]; + mpq_set (num1, arr2[col]); + for (j = qslp->A.matcnt[col]; j--;) + { + mpq_mul (num2, arr1[j], d_sol[iarr1[j]]); + mpq_sub (num1, num1, num2); + } + mpq_set (dz[col], num1); + /* objective update */ + if (objsense * mpq_cmp_ui (dz[col], 0UL, 1UL) > 0) + { + mpq_mul (num3, dz[col], arr3[col]); + mpq_add (d_obj, d_obj, num3); + } + else + { + mpq_mul (num3, dz[col], arr4[col]); + mpq_add (d_obj, d_obj, num3); + } + /* now we check that only when the logical is tight then the dual + * variable may be non-zero, also check for primal feasibility with respect + * to lower/upper bounds. */ + mpq_set_ui (num2, 0UL, 1UL); + if (objsense * mpq_cmp_ui (dz[col], 0UL, 1UL) > 0) + { + mpq_sub (num1, p_sol[i], arr3[col]); + mpq_mul (num2, num1, dz[col]); + } + if (mpq_cmp_ui (num2, 0UL, 1UL) != 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "lower bound (%s,%d) slack (%lg) and dual variable (%lg)" + " don't satisfy complementary slacknes %s", + qslp->colnames[i], i, mpq_get_d(num1), mpq_get_d(dz[col]), + "(real)"); + } + goto CLEANUP; + } + mpq_set_ui (num2, 0UL, 1UL); + if (objsense * mpq_cmp_ui (dz[col], 0UL, 1UL) < 0) + { + mpq_sub (num1, p_sol[i], arr4[col]); + mpq_mul (num2, num1, dz[col]); + } + if (mpq_cmp_ui (num2, 0UL, 1UL) != 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "upper bound (%lg) variable (%lg) and dual variable" + " (%lg) don't satisfy complementary slacknes for variable" + " (%s,%d) %s", mpq_get_d(arr4[col]), mpq_get_d(p_sol[i]), + mpq_get_d(dz[col]), qslp->colnames[i], i, "(real)"); + } + goto CLEANUP; + } + } + /* complenetary slackness checked, now update the same for the logical + * variables */ + for (i = qslp->nrows; i--;) + { + col = rowmap[i]; + mpq_mul (num1, arr2[col], p_sol[i + qslp->nstruct]); + WARNING (mpq_cmp (arr2[col], mpq_zeroLpNum), "logical variable %s with " + "non-zero objective function %lf", qslp->rownames[i], + mpq_get_d (arr2[col])); + mpq_add (p_obj, p_obj, num1); + arr1 = qslp->A.matval + qslp->A.matbeg[col]; + iarr1 = qslp->A.matind + qslp->A.matbeg[col]; + mpq_set (num1, arr2[col]); + for (j = qslp->A.matcnt[col]; j--;) + { + mpq_mul (num2, arr1[j], d_sol[iarr1[j]]); + mpq_sub (num1, num1, num2); + } + mpq_set (dz[col], num1); + /* objective update */ + if (objsense * mpq_cmp_ui (dz[col], 0UL, 1UL) > 0) + { + mpq_mul (num3, dz[col], arr3[col]); + mpq_add (d_obj, d_obj, num3); + } + else + { + mpq_mul (num3, dz[col], arr4[col]); + mpq_add (d_obj, d_obj, num3); + } + /* now we check that only when the primal variable is tight then the dual + * variable may be non-zero, also check for primal feasibility with respect + * to lower/upper bounds. */ + mpq_set_ui (num2, 0UL, 1UL); + if (objsense * mpq_cmp_ui (dz[col], 0UL, 1UL) > 0) + { + mpq_sub (num1, p_sol[i + qslp->nstruct], arr3[col]); + mpq_mul (num2, num1, dz[col]); + } + if (mpq_cmp_ui (num2, 0UL, 1UL) != 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "lower bound (%s,%d) slack (%lg) and dual variable (%lg)" + " don't satisfy complementary slacknes %s", + qslp->colnames[col], i, mpq_get_d(num1), mpq_get_d(dz[col]), + "(real)"); + } + goto CLEANUP; + } + mpq_set_ui (num2, 0UL, 1UL); + if (objsense * mpq_cmp_ui (dz[col], 0UL, 1UL) < 0) + { + mpq_sub (num1, p_sol[i + qslp->nstruct], arr4[col]); + mpq_mul (num2, num1, dz[col]); + } + if (mpq_cmp_ui (num2, 0UL, 1UL) != 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "upper bound (%lg) variable (%lg) and dual variable" + " (%lg) don't satisfy complementary slacknes for variable " + "(%s,%d) %s", mpq_get_d(arr4[col]), + mpq_get_d(p_sol[i+qslp->nstruct]), mpq_get_d(dz[col]), qslp->colnames[col], i, + "(real)"); + } + goto CLEANUP; + } + } + + /* now check the objective values */ + if (mpq_cmp (p_obj, d_obj) != 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "primal and dual objective value differ %lg %lg", + mpq_get_d(p_obj), mpq_get_d(d_obj)); + } + goto CLEANUP; + } + /* now we report optimality */ + if(!msg_lvl) + { + MESSAGE(0, "Problem solved to optimality, LP value %lg", mpq_get_d(p_obj)); + } + /* now we load into cache the solution */ + if (!p->cache) + { + p->cache = EGsMalloc (mpq_ILLlp_cache, 1); + mpq_EGlpNumInitVar (p->cache->val); + mpq_ILLlp_cache_init (p->cache); + } + if (qslp->nrows != p->cache->nrows || qslp->nstruct != p->cache->nstruct) + { + mpq_ILLlp_cache_free (p->cache); + EGcallD(mpq_ILLlp_cache_alloc (p->cache, qslp->nstruct, qslp->nrows)); + } + p->cache->status = QS_LP_OPTIMAL; + p->qstatus = QS_LP_OPTIMAL; + p->lp->basisstat.optimal = 1; + mpq_set (p->cache->val, p_obj); + for (i = qslp->nstruct; i--;) + { + mpq_set (p->cache->x[i], p_sol[i]); + mpq_set (p->cache->rc[i], dz[structmap[i]]); + } + for (i = qslp->nrows; i--;) + { + mpq_set (p->cache->slack[i], p_sol[i + qslp->nstruct]); + mpq_set (p->cache->pi[i], d_sol[i]); + } + + /* save the problem and solution if enablred */ +#if QSEXACT_SAVE_OPTIMAL + { + char stmp[1024]; + EGioFile_t *out_f = 0; + snprintf (stmp, 1023, "%s-opt%03d.lp", p->name ? p->name : "UNNAMED", + QSEXACT_SAVE_OPTIMAL_IND); + if (mpq_QSwrite_prob (p, stmp, "LP")) + { + rval = 0; + MESSAGE (0, "Couldn't write output problem %s", stmp); + goto CLEANUP; + } + snprintf (stmp, 1023, "%s-opt%03d.sol.gz", p->name ? p->name : "UNNAMED", + QSEXACT_SAVE_OPTIMAL_IND); + if (!(out_f = EGioOpen (stmp, "w+"))) + { + rval = 0; + MESSAGE (0, "Couldn't open solution file %s", stmp); + goto CLEANUP; + } + if (QSexact_print_sol (p, out_f)) + { + rval = 0; + MESSAGE (0, "Couldn't write output solution %s", stmp); + goto CLEANUP; + } + EGioClose (out_f); + QSEXACT_SAVE_OPTIMAL_IND++; + } +#endif + rval = 1; + + /* ending */ +CLEANUP: + mpq_EGlpNumFreeArray (dz); + mpq_EGlpNumFreeArray (rhs_copy); + mpq_clear (num1); + mpq_clear (num2); + mpq_clear (num3); + mpq_clear (p_obj); + mpq_clear (d_obj); + return rval; +} + +/* ========================================================================= */ +int QSexact_infeasible_test (mpq_QSdata * p, + mpq_t * d_sol) +{ + /* local variables */ + register int i, + j; + int *iarr1; + mpq_ILLlpdata *qslp = p->lp->O; + mpq_t *arr1, + *arr2, + *arr3, + *arr4; + mpq_t *dl = 0, + *du = 0; + int const msg_lvl = __QS_SB_VERB <= DEBUG ? 0 : 100000 * (1 - p->simplex_display); + int rval = 1; /* store whether or not the solution is optimal, we start + * assuming it is. */ + mpq_t num1, + num2, + num3, + d_obj; + mpq_init (num1); + mpq_init (num2); + mpq_init (num3); + mpq_init (d_obj); + mpq_set_ui (d_obj, 0UL, 1UL); + + /* compute the dual objective value */ + arr2 = qslp->rhs; + for (i = qslp->nrows; i--;) + { + mpq_mul (num1, arr2[i], d_sol[i]); + mpq_add (d_obj, d_obj, num1); + } + + /* compute the upper and lower bound dual variables, note that dl is the dual + * of the lower bounds, and du the dual of the upper bound, dl <= 0 and du >= + * 0 and A^t y + Idl + Idu = c, and the dual objective value is + * max y*b + l*dl + u*du */ + du = mpq_EGlpNumAllocArray (qslp->ncols); + dl = mpq_EGlpNumAllocArray (qslp->ncols); + arr3 = qslp->lower; + arr4 = qslp->upper; + for (i = qslp->ncols; i--;) + { + arr1 = qslp->A.matval + qslp->A.matbeg[i]; + iarr1 = qslp->A.matind + qslp->A.matbeg[i]; + mpq_set_ui (num1, 0UL, 1UL); + mpq_set_ui (du[i], 0UL, 1UL); + mpq_set_ui (dl[i], 0UL, 1UL); + for (j = qslp->A.matcnt[i]; j--;) + { + mpq_mul (num2, arr1[j], d_sol[iarr1[j]]); + mpq_sub (num1, num1, num2); + } + if (mpq_cmp_ui (num1, 0UL, 1UL) < 0) + mpq_set (du[i], num1); + else + mpq_set (dl[i], num1); + if (mpq_equal (arr4[i], mpq_ILL_MAXDOUBLE) && + mpq_cmp_ui (du[i], 0UL, 1UL) != 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "upper bound of variable is INFTY, and it's dual is " + "non-zero %lg", mpq_get_d(du[i])); + } + goto CLEANUP; + } + if (mpq_equal (arr3[i], mpq_ILL_MINDOUBLE) && + mpq_cmp_ui (dl[i], 0UL, 1UL) != 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "lower bound of variable is -INFTY, and it's dual is " + "non-zero %lg", mpq_get_d(dl[i])); + } + goto CLEANUP; + } + mpq_mul (num3, dl[i], arr3[i]); + mpq_add (d_obj, d_obj, num3); + mpq_mul (num3, du[i], arr4[i]); + mpq_add (d_obj, d_obj, num3); + } + /* now check the objective values */ + if (mpq_cmp_ui (d_obj, 0UL, 1UL) <= 0) + { + rval = 0; + if(!msg_lvl) + { + MESSAGE(0, "dual ray is feasible, but objective is non " + "positive %lg", mpq_get_d(d_obj)); + } + goto CLEANUP; + } + p->qstatus = QS_LP_INFEASIBLE; + + /* ending */ +CLEANUP: + mpq_EGlpNumFreeArray (dl); + mpq_EGlpNumFreeArray (du); + mpq_clear (num1); + mpq_clear (num2); + mpq_clear (num3); + mpq_clear (d_obj); + return rval; +} + +/* ========================================================================= */ +/** @brief Used as separator while printing output to the screen (controled by + * enabling simplex_display in the mpq_QSdata */ +/* ========================================================================= */ +static const char __sp[81] = + "================================================================================"; + +/* ========================================================================= */ +/** @brief print into screen (if enable) a message indicating that we have + * successfully prove infeasibility, and save (if y is non + * NULL ) the dual ray solution provided in y_mpq. + * @param p_mpq the problem data. + * @param y where to store the optimal dual solution (if not null). + * @param y_mpq the optimal dual solution. + * */ +/* ========================================================================= */ +static void infeasible_output (mpq_QSdata * p_mpq, + mpq_t * const y, + mpq_t * y_mpq) +{ + if (p_mpq->simplex_display) + { + fprintf (stdout, "%s\n\tProblem Is Infeasible\n%s\n", __sp, __sp); + fflush(stdout); + } + if (y) + { + unsigned sz = __EGlpNumArraySize (y_mpq); + while (sz--) + mpq_set (y[sz], y_mpq[sz]); + } +} + +/* ========================================================================= */ +/** @brief print into screen (if enable) a message indicating that we have + * successfully solved the problem at optimality, and save (if x and y are non + * NULL respectivelly) the optimal primal/dual solution provided in x_mpq and + * y_mpq. + * @param p_mpq the problem data. + * @param x where to store the optimal primal solution (if not null). + * @param y where to store the optimal dual solution (if not null). + * @param x_mpq the optimal primal solution. + * @param y_mpq the optimal dual solution. + * */ +/* ========================================================================= */ +static void optimal_output (mpq_QSdata * p_mpq, + mpq_t * const x, + mpq_t * const y, + mpq_t * x_mpq, + mpq_t * y_mpq) +{ + if (p_mpq->simplex_display) + { + fprintf (stdout, "%s\n\tProblem Solved Exactly\n%s\n", __sp, __sp); + fflush(stdout); + } + if (y) + { + unsigned sz = __EGlpNumArraySize (y_mpq); + while (sz--) + mpq_set (y[sz], y_mpq[sz]); + } + if (x) + { + unsigned sz = __EGlpNumArraySize (x_mpq); + while (sz--) + mpq_set (x[sz], x_mpq[sz]); + } +} + +/* ========================================================================= */ +/** @brief get the status for a given basis in rational arithmetic, it should + * also leave everything set to get primal/dual solutions when needed. + * */ +static int QSexact_basis_status (mpq_QSdata * p_mpq, + int *status, + QSbasis * const basis, + const int msg_lvl, + int *const simplexalgo) +{ + int rval = 0, + singular; + mpq_feas_info fi; + EGtimer_t local_timer; + mpq_EGlpNumInitVar (fi.totinfeas); + EGtimerReset (&local_timer); + EGtimerStart (&local_timer); + EGcallD(mpq_QSload_basis (p_mpq, basis)); + if (p_mpq->cache) + { + mpq_ILLlp_cache_free (p_mpq->cache); + mpq_clear (p_mpq->cache->val); + ILL_IFFREE (p_mpq->cache, mpq_ILLlp_cache); + } + p_mpq->qstatus = QS_LP_MODIFIED; + if(p_mpq->qslp->sinfo) + { + mpq_ILLlp_sinfo_free(p_mpq->qslp->sinfo); + ILL_IFFREE(p_mpq->qslp->sinfo, mpq_ILLlp_sinfo); + } + if(p_mpq->qslp->rA) + { + mpq_ILLlp_rows_clear (p_mpq->qslp->rA); + ILL_IFFREE (p_mpq->qslp->rA, mpq_ILLlp_rows); + } + mpq_free_internal_lpinfo (p_mpq->lp); + mpq_init_internal_lpinfo (p_mpq->lp); + EGcallD(mpq_build_internal_lpinfo (p_mpq->lp)); + mpq_ILLfct_set_variable_type (p_mpq->lp); + EGcallD(mpq_ILLbasis_load (p_mpq->lp, p_mpq->basis)); + EGcallD(mpq_ILLbasis_factor (p_mpq->lp, &singular)); + memset (&(p_mpq->lp->basisstat), 0, sizeof (mpq_lp_status_info)); + mpq_ILLfct_compute_piz (p_mpq->lp); + mpq_ILLfct_compute_dz (p_mpq->lp); + mpq_ILLfct_compute_xbz (p_mpq->lp); + mpq_ILLfct_check_pfeasible (p_mpq->lp, &fi, mpq_zeroLpNum); + mpq_ILLfct_check_dfeasible (p_mpq->lp, &fi, mpq_zeroLpNum); + mpq_ILLfct_set_status_values (p_mpq->lp, fi.pstatus, fi.dstatus, PHASEII, + PHASEII); + if (p_mpq->lp->basisstat.optimal) + { + *status = QS_LP_OPTIMAL; + EGcallD(mpq_grab_cache (p_mpq, QS_LP_OPTIMAL)); + } + else if (p_mpq->lp->basisstat.primal_infeasible + || p_mpq->lp->basisstat.dual_unbounded) + { + if (*status == QS_LP_INFEASIBLE) + *simplexalgo = PRIMAL_SIMPLEX; + *status = QS_LP_INFEASIBLE; + p_mpq->lp->final_phase = PRIMAL_PHASEI; + p_mpq->lp->pIpiz = mpq_EGlpNumAllocArray (p_mpq->lp->nrows); + mpq_ILLfct_compute_phaseI_piz (p_mpq->lp); + } + else if (p_mpq->lp->basisstat.primal_unbounded) + *status = QS_LP_UNBOUNDED; + else + *status = QS_LP_UNSOLVED; + EGtimerStop (&local_timer); + if(!msg_lvl) + { + MESSAGE(0, "Performing Rational Basic Solve on %s, %s, check" + " done in %lg seconds, PS %s %lg, DS %s %lg", p_mpq->name, + (*status == QS_LP_OPTIMAL) ? "RAT_optimal" : + ((*status == QS_LP_INFEASIBLE) ? "RAT_infeasible" : + ((*status == QS_LP_UNBOUNDED) ? "RAT_unbounded" : "RAT_unsolved")), + local_timer.time, p_mpq->lp->basisstat.primal_feasible ? + "F":(p_mpq->lp->basisstat.primal_infeasible ? "I" : "U"), + p_mpq->lp->basisstat.primal_feasible ? + mpq_get_d(p_mpq->lp->objval) : + (p_mpq->lp->basisstat.primal_infeasible ? + mpq_get_d(p_mpq->lp->pinfeas) : mpq_get_d(p_mpq->lp->objbound)), + p_mpq->lp->basisstat.dual_feasible ? + "F":(p_mpq->lp->basisstat.dual_infeasible ? "I" : "U"), + p_mpq->lp->basisstat.dual_feasible ? mpq_get_d(p_mpq->lp->dobjval) + :(p_mpq->lp->basisstat.dual_infeasible ? + mpq_get_d(p_mpq->lp->dinfeas) : mpq_get_d(p_mpq->lp->objbound)) ); + } +CLEANUP: + mpq_EGlpNumClearVar (fi.totinfeas); + return rval; +} + +/* ========================================================================= */ +/** @brief test whether given basis is primal and dual feasible in rational arithmetic. + * @param p_mpq the problem data. + * @param basis basis to be tested. + * @param result where to store whether given basis is primal and dual feasible. + * @param msg_lvl message level. + */ +int QSexact_basis_optimalstatus( + mpq_QSdata * p_mpq, + QSbasis* basis, + char* result, + const int msg_lvl + ) +{ + int rval = 0, + singular; + mpq_feas_info fi; + EGtimer_t local_timer; + + /* test primal and dual feasibility of basic solution */ + mpq_EGlpNumInitVar (fi.totinfeas); + + EGtimerReset (&local_timer); + EGtimerStart (&local_timer); + + EGcallD(mpq_QSload_basis (p_mpq, basis)); + + if (p_mpq->cache) + { + mpq_ILLlp_cache_free (p_mpq->cache); + mpq_clear (p_mpq->cache->val); + ILL_IFFREE (p_mpq->cache, mpq_ILLlp_cache); + } + p_mpq->qstatus = QS_LP_MODIFIED; + + if(p_mpq->qslp->sinfo) + { + mpq_ILLlp_sinfo_free(p_mpq->qslp->sinfo); + ILL_IFFREE(p_mpq->qslp->sinfo, mpq_ILLlp_sinfo); + } + if(p_mpq->qslp->rA) + { + mpq_ILLlp_rows_clear (p_mpq->qslp->rA); + ILL_IFFREE (p_mpq->qslp->rA, mpq_ILLlp_rows); + } + + mpq_free_internal_lpinfo (p_mpq->lp); + mpq_init_internal_lpinfo (p_mpq->lp); + EGcallD(mpq_build_internal_lpinfo (p_mpq->lp)); + + mpq_ILLfct_set_variable_type (p_mpq->lp); + + EGcallD(mpq_ILLbasis_load (p_mpq->lp, p_mpq->basis)); + EGcallD(mpq_ILLbasis_factor (p_mpq->lp, &singular)); + + memset (&(p_mpq->lp->basisstat), 0, sizeof (mpq_lp_status_info)); + mpq_ILLfct_compute_piz (p_mpq->lp); + mpq_ILLfct_compute_dz (p_mpq->lp); + mpq_ILLfct_compute_xbz (p_mpq->lp); + mpq_ILLfct_check_pfeasible (p_mpq->lp, &fi, mpq_zeroLpNum); + mpq_ILLfct_check_dfeasible (p_mpq->lp, &fi, mpq_zeroLpNum); + mpq_ILLfct_set_status_values (p_mpq->lp, fi.pstatus, fi.dstatus, PHASEII, PHASEII); + + if( p_mpq->lp->basisstat.optimal ) + { + *result = 1; + } + else + { + *result = 0; + } + + EGtimerStop (&local_timer); + + if( !msg_lvl ) + { + MESSAGE(0, "Performing rational solution check for accuratelp on %s, sucess=%s", + p_mpq->name, + *result ? "YES" : "NO"); + } + + CLEANUP: + mpq_EGlpNumClearVar (fi.totinfeas); + return rval; +} + +/* ========================================================================= */ +/** @brief test whether given basis is dual feasible in rational arithmetic. + * @param p_mpq the problem data. + * @param basis basis to be tested. + * @param result where to store whether given basis is dual feasible. + * @param dobjval where to store dual solution value in case of dual feasibility (if not NULL). + * @param msg_lvl message level. + */ +int QSexact_basis_dualstatus( + mpq_QSdata * p_mpq, + QSbasis* basis, + char* result, + mpq_t* dobjval, + const int msg_lvl + ) +{ + int rval = 0, + singular; + mpq_feas_info fi; + EGtimer_t local_timer; + + mpq_EGlpNumInitVar (fi.totinfeas); + EGtimerReset (&local_timer); + EGtimerStart (&local_timer); + EGcallD(mpq_QSload_basis (p_mpq, basis)); + if (p_mpq->cache) + { + mpq_ILLlp_cache_free (p_mpq->cache); + mpq_clear (p_mpq->cache->val); + ILL_IFFREE (p_mpq->cache, mpq_ILLlp_cache); + } + p_mpq->qstatus = QS_LP_MODIFIED; + + if(p_mpq->qslp->sinfo) + { + mpq_ILLlp_sinfo_free(p_mpq->qslp->sinfo); + ILL_IFFREE(p_mpq->qslp->sinfo, mpq_ILLlp_sinfo); + } + + if(p_mpq->qslp->rA) + { + mpq_ILLlp_rows_clear (p_mpq->qslp->rA); + ILL_IFFREE (p_mpq->qslp->rA, mpq_ILLlp_rows); + } + + mpq_free_internal_lpinfo (p_mpq->lp); + mpq_init_internal_lpinfo (p_mpq->lp); + EGcallD(mpq_build_internal_lpinfo (p_mpq->lp)); + mpq_ILLfct_set_variable_type (p_mpq->lp); + EGcallD(mpq_ILLbasis_load (p_mpq->lp, p_mpq->basis)); + EGcallD(mpq_ILLbasis_factor (p_mpq->lp, &singular)); + + memset (&(p_mpq->lp->basisstat), 0, sizeof (mpq_lp_status_info)); + mpq_ILLfct_compute_piz (p_mpq->lp); + mpq_ILLfct_compute_dz (p_mpq->lp); + mpq_ILLfct_compute_dobj(p_mpq->lp); + mpq_ILLfct_check_dfeasible (p_mpq->lp, &fi, mpq_zeroLpNum); + mpq_ILLfct_set_status_values (p_mpq->lp, fi.pstatus, fi.dstatus, PHASEII, PHASEII); + + if( p_mpq->lp->basisstat.dual_feasible ) + { + *result = 1; + if( dobjval ) + { + mpq_EGlpNumCopy(*dobjval, p_mpq->lp->dobjval); + } + } + else if( p_mpq->lp->basisstat.dual_infeasible ) + { + *result = 0; + } + else + { + TESTG((rval=!(p_mpq->lp->basisstat.dual_unbounded)), CLEANUP, "Internal BUG, problem should be dual unbounded but is not"); + *result = 1; + if( dobjval ) + { + mpq_EGlpNumCopy(*dobjval, p_mpq->lp->objbound); + } + } + + EGtimerStop (&local_timer); + + if(!msg_lvl) + { + MESSAGE(0, "Performing Rational Basic Test on %s, check done in %lg seconds, DS %s %lg", + p_mpq->name, local_timer.time, + p_mpq->lp->basisstat.dual_feasible ? "F": (p_mpq->lp->basisstat.dual_infeasible ? "I" : "U"), + p_mpq->lp->basisstat.dual_feasible ? mpq_get_d(p_mpq->lp->dobjval) : (p_mpq->lp->basisstat.dual_infeasible ? mpq_get_d(p_mpq->lp->dinfeas) : mpq_get_d(p_mpq->lp->objbound)) ); + } + +CLEANUP: + mpq_EGlpNumClearVar (fi.totinfeas); + return rval; +} + +/* ========================================================================= */ +/** @brief test whether given basis is dual feasible in rational arithmetic. + * if wanted it will first directly test the corresponding approximate dual and primal solution + * (corrected via dual variables for bounds and primal variables for slacks if possible) for optimality + * before performing the dual feasibility test on the more expensive exact basic solution. + * @param p_mpq the problem data. + * @param basis basis to be tested. + * @param useprestep whether to directly test approximate primal and dual solution first. + * @param dbl_p_sol approximate primal solution to use in prestep + * (NULL in order to compute it by dual simplex in double precision with given starting basis). + * @param dbl_d_sol approximate dual solution to use in prestep + * (NULL in order to compute it by dual simplex in double precision with given starting basis). + * @param result where to store whether given basis is dual feasible. + * @param dobjval where to store dual solution value in case of dual feasibility (if not NULL). + * @param msg_lvl message level. + */ +int QSexact_verify ( + mpq_QSdata * p_mpq, + QSbasis* basis, + int useprestep, + double* dbl_p_sol, + double* dbl_d_sol, + char* result, + mpq_t* dobjval, + const int msg_lvl +) +{ + int rval = 0; + + //assert(basis); + //assert(basis->nstruct); + + *result = 0; + + if( useprestep ) + { + mpq_t *x_mpq = 0; + mpq_t *y_mpq = 0; + int status = 0; + + if( dbl_p_sol == NULL || dbl_d_sol == NULL ) + { + dbl_QSdata *p_dbl = 0; + double *x_dbl = 0; + double *y_dbl = 0; + + /* create double problem, warmstart with given basis and solve it using double precision + * this is only done to get approximate primal and dual solution corresponding to the given basis + */ + p_dbl = QScopy_prob_mpq_dbl(p_mpq, "dbl_problem"); + + dbl_QSload_basis(p_dbl, basis); + rval = dbl_ILLeditor_solve(p_dbl, DUAL_SIMPLEX); + CHECKRVALG(rval, CLEANUP); + + rval = dbl_QSget_status(p_dbl, &status); + CHECKRVALG(rval, CLEANUP); + + if( status == QS_LP_OPTIMAL ) + { + /* get continued fraction approximation of approximate solution */ + x_dbl = dbl_EGlpNumAllocArray(p_dbl->qslp->ncols); + y_dbl = dbl_EGlpNumAllocArray(p_dbl->qslp->nrows); + + rval = dbl_QSget_x_array(p_dbl, x_dbl); + CHECKRVALG(rval, CLEANUP); + rval = dbl_QSget_pi_array(p_dbl, y_dbl); + CHECKRVALG(rval, CLEANUP); + x_mpq = QScopy_array_dbl_mpq(x_dbl); + y_mpq = QScopy_array_dbl_mpq(y_dbl); + + /* test optimality of constructed solution */ + basis = dbl_QSget_basis(p_dbl); + rval = QSexact_optimal_test(p_mpq, x_mpq, y_mpq, basis); + if( rval ) + { + *result = 1; + if( dobjval ) + { + rval = mpq_QSget_objval(p_mpq, dobjval); + if( rval ) + *result = 0; + } + } + if( !msg_lvl ) + { + MESSAGE(0, "Performing approximated solution check on %s, sucess=%s dobjval=%lg", + p_mpq->name, + *result ? "YES" : "NO", + *result ? mpq_get_d(*dobjval) : mpq_get_d(*dobjval)); + } + } + CLEANUP: + dbl_EGlpNumFreeArray(x_dbl); + dbl_EGlpNumFreeArray(y_dbl); + mpq_EGlpNumFreeArray(x_mpq); + mpq_EGlpNumFreeArray(y_mpq); + dbl_QSfree_prob(p_dbl); + rval = 0; + } + else + { + dbl_QSdata *p_dbl = 0; + int i; + + /* for some reason, this help to avoid fails in QSexact_basis_dualstatus() after + * the test here fails, i.e., if we would not perform the test here, than QSexact_basis_dualstatus() would normally not fail + * something happens with the basis... if we do not set up the dbl-prob (?) ???????????????????????? + */ + p_dbl = QScopy_prob_mpq_dbl(p_mpq, "dbl_problem"); + dbl_QSload_basis(p_dbl, basis); + + x_mpq = mpq_EGlpNumAllocArray(p_mpq->qslp->ncols); + y_mpq = mpq_EGlpNumAllocArray(p_mpq->qslp->nrows); + + /* get continued fraction approximation of approximate solution */ + for( i = 0; i < p_mpq->qslp->ncols; ++i ) + mpq_EGlpNumSet(x_mpq[i], dbl_p_sol[i]); + + for( i = 0; i < p_mpq->qslp->nrows; ++i ) + mpq_EGlpNumSet(y_mpq[i], dbl_d_sol[i]); + + /* test optimality of constructed solution */ + basis = dbl_QSget_basis(p_dbl); + rval = QSexact_optimal_test(p_mpq, x_mpq, y_mpq, basis); + if( rval ) + { + *result = 1; + if( dobjval ) + { + rval = mpq_QSget_objval(p_mpq, dobjval); + if( rval ) + *result = 0; + } + } + if( !msg_lvl ) + { + MESSAGE(0, "Performing approximated solution check on %s, sucess=%s dobjval=%lg", + p_mpq->name, + *result ? "YES" : "NO", + *result ? mpq_get_d(*dobjval) : mpq_get_d(*dobjval)); + } + mpq_EGlpNumFreeArray(x_mpq); + mpq_EGlpNumFreeArray(y_mpq); + dbl_QSfree_prob(p_dbl); + rval = 0; + } + } + + if( !(*result) ) + { + rval = QSexact_basis_dualstatus(p_mpq, basis, result, dobjval, msg_lvl); + if( !msg_lvl ) + { + MESSAGE(0, "Performing rational solution check on %s, sucess=%s dobjval=%lg", + p_mpq->name, + *result ? "YES" : "NO", + *result ? mpq_get_d(*dobjval) : mpq_get_d(*dobjval)); + } + } + + return rval; +} + +/* ========================================================================= */ +int QSexact_solver (mpq_QSdata * p_mpq, + mpq_t * const x, + mpq_t * const y, + QSbasis * const ebasis, + int simplexalgo, + int *status) +{ + /* local variables */ + int last_status = 0, last_iter = 0; + QSbasis *basis = 0; + unsigned precision = EGLPNUM_PRECISION; + int rval = 0, + it = QS_EXACT_MAX_ITER; + dbl_QSdata *p_dbl = 0; + mpf_QSdata *p_mpf = 0; + double *x_dbl = 0, + *y_dbl = 0; + mpq_t *x_mpq = 0, + *y_mpq = 0; + mpf_t *x_mpf = 0, + *y_mpf = 0; + int const msg_lvl = __QS_SB_VERB <= DEBUG ? 0: (1 - p_mpq->simplex_display) * 10000; + *status = 0; + /* save the problem if we are really debugging */ + if(DEBUG >= __QS_SB_VERB) + { + EGcallD(mpq_QSwrite_prob(p_mpq, "qsxprob.lp","LP")); + } + /* try first with doubles */ + if (p_mpq->simplex_display || DEBUG >= __QS_SB_VERB) + { + fprintf (stdout, "%s\n\tTrying double precision\n%s\n", __sp, __sp); + fflush(stdout); + } + p_dbl = QScopy_prob_mpq_dbl (p_mpq, "dbl_problem"); + if(__QS_SB_VERB <= DEBUG) p_dbl->simplex_display = 1; + if (ebasis && ebasis->nstruct) + dbl_QSload_basis (p_dbl, ebasis); + if (dbl_ILLeditor_solve (p_dbl, simplexalgo)) + { + MESSAGE(p_mpq->simplex_display ? 0: __QS_SB_VERB, + "double approximation failed, code %d, " + "continuing in extended precision", rval); + goto MPF_PRECISION; + } + EGcallD(dbl_QSget_status (p_dbl, status)); + if ((*status == QS_LP_INFEASIBLE) && + (p_dbl->lp->final_phase != PRIMAL_PHASEI) && + (p_dbl->lp->final_phase != DUAL_PHASEII)) + dbl_QSopt_primal (p_dbl, status); + EGcallD(dbl_QSget_status (p_dbl, status)); + last_status = *status; + EGcallD(dbl_QSget_itcnt(p_dbl, 0, 0, 0, 0, &last_iter)); + /* deal with the problem depending on what status we got from our optimizer */ + switch (*status) + { + case QS_LP_OPTIMAL: + x_dbl = dbl_EGlpNumAllocArray (p_dbl->qslp->ncols); + y_dbl = dbl_EGlpNumAllocArray (p_dbl->qslp->nrows); + EGcallD(dbl_QSget_x_array (p_dbl, x_dbl)); + EGcallD(dbl_QSget_pi_array (p_dbl, y_dbl)); + x_mpq = QScopy_array_dbl_mpq (x_dbl); + y_mpq = QScopy_array_dbl_mpq (y_dbl); + dbl_EGlpNumFreeArray (x_dbl); + dbl_EGlpNumFreeArray (y_dbl); + basis = dbl_QSget_basis (p_dbl); + if (QSexact_optimal_test (p_mpq, x_mpq, y_mpq, basis)) + { + optimal_output (p_mpq, x, y, x_mpq, y_mpq); + goto CLEANUP; + } + else + { + EGcallD(QSexact_basis_status (p_mpq, status, basis, msg_lvl, &simplexalgo)); + if (*status == QS_LP_OPTIMAL) + { + if(!msg_lvl) + { + MESSAGE(0,"Retesting solution"); + } + EGcallD(mpq_QSget_x_array (p_mpq, x_mpq)); + EGcallD(mpq_QSget_pi_array (p_mpq, y_mpq)); + if (QSexact_optimal_test (p_mpq, x_mpq, y_mpq, basis)) + { + optimal_output (p_mpq, x, y, x_mpq, y_mpq); + goto CLEANUP; + } + else + { + last_status = *status = QS_LP_UNSOLVED; + } + } + else + { + if(!msg_lvl) + { + MESSAGE(0,"Status is not optimal, but %d", *status); + } + } + } + mpq_EGlpNumFreeArray (x_mpq); + mpq_EGlpNumFreeArray (y_mpq); + break; + case QS_LP_INFEASIBLE: + y_dbl = dbl_EGlpNumAllocArray (p_dbl->qslp->nrows); + if (dbl_QSget_infeas_array (p_dbl, y_dbl)) + { + MESSAGE(p_mpq->simplex_display ? 0 : __QS_SB_VERB, "double approximation" + " failed, code %d, continuing in extended precision\n", rval); + goto MPF_PRECISION; + } + y_mpq = QScopy_array_dbl_mpq (y_dbl); + dbl_EGlpNumFreeArray (y_dbl); + if (QSexact_infeasible_test (p_mpq, y_mpq)) + { + infeasible_output (p_mpq, y, y_mpq); + goto CLEANUP; + } + else + { + MESSAGE (msg_lvl, "Retesting solution in exact arithmetic"); + basis = dbl_QSget_basis (p_dbl); + EGcallD(QSexact_basis_status (p_mpq, status, basis, msg_lvl, &simplexalgo)); + #if 0 + mpq_QSset_param (p_mpq, QS_PARAM_SIMPLEX_MAX_ITERATIONS, 1); + mpq_QSload_basis (p_mpq, basis); + mpq_QSfree_basis (basis); + EGcallD(mpq_ILLeditor_solve (p_mpq, simplexalgo)); + EGcallD(mpq_QSget_status (p_mpq, status)); + #endif + if (*status == QS_LP_INFEASIBLE) + { + mpq_EGlpNumFreeArray (y_mpq); + y_mpq = mpq_EGlpNumAllocArray (p_mpq->qslp->nrows); + EGcallD(mpq_QSget_infeas_array (p_mpq, y_mpq)); + if (QSexact_infeasible_test (p_mpq, y_mpq)) + { + infeasible_output (p_mpq, y, y_mpq); + goto CLEANUP; + } + else + { + last_status = *status = QS_LP_UNSOLVED; + } + } + } + mpq_EGlpNumFreeArray (y_mpq); + break; + case QS_LP_UNBOUNDED: + MESSAGE(p_mpq->simplex_display ? 0 : __QS_SB_VERB, "%s\n\tUnbounded " + "Problem found, not implemented to deal with this\n%s\n",__sp,__sp); + break; + case QS_LP_OBJ_LIMIT: + rval=1; + IFMESSAGE(p_mpq->simplex_display,"Objective limit reached (in floating point) ending now"); + goto CLEANUP; + break; + default: + IFMESSAGE(p_mpq->simplex_display,"Re-trying inextended precision"); + break; + } + /* if we reach this point, then we have to keep going, we use the previous + * basis ONLY if the previous precision think that it has the optimal + * solution, otherwise we start from scratch. */ + precision = 128; + MPF_PRECISION: + dbl_QSfree_prob (p_dbl); + p_dbl = 0; + /* try with multiple precision floating points */ + for (; it--; precision = (unsigned) (precision * 1.5)) + { + QSexact_set_precision (precision); + if (p_mpq->simplex_display || DEBUG >= __QS_SB_VERB) + { + fprintf (stdout, "%s\n\tTrying mpf with %u bits\n%s\n", __sp, precision, + __sp); + fflush(stdout); + } + p_mpf = QScopy_prob_mpq_mpf (p_mpq, "mpf_problem"); + if(DEBUG >= __QS_SB_VERB) + { + EGcallD(mpf_QSwrite_prob(p_mpf, "qsxprob.mpf.lp","LP")); + } + if(__QS_SB_VERB <= DEBUG) p_mpf->simplex_display = 1; + simplexalgo = PRIMAL_SIMPLEX; + if(!last_iter) last_status = QS_LP_UNSOLVED; + if(last_status == QS_LP_OPTIMAL || last_status == QS_LP_INFEASIBLE) + { + if (p_mpq->simplex_display || DEBUG >= __QS_SB_VERB) + { + fprintf(stdout,"Re-using previous basis\n"); + fflush(stdout); + } + if (basis) + { + EGcallD(mpf_QSload_basis (p_mpf, basis)); + mpf_QSfree_basis (basis); + simplexalgo = DUAL_SIMPLEX; + basis = 0; + } + else if (ebasis && ebasis->nstruct) + { + mpf_QSload_basis (p_mpf, ebasis); + simplexalgo = DUAL_SIMPLEX; + } + } + else + { + if(p_mpf->basis) + { + mpf_ILLlp_basis_free(p_mpf->basis); + p_mpf->lp->basisid = -1; + p_mpf->factorok = 0; + } + if (p_mpq->simplex_display || DEBUG >= __QS_SB_VERB) + { + fprintf(stdout,"Not-using previous basis\n"); + fflush(stdout); + } + } + if (mpf_ILLeditor_solve (p_mpf, simplexalgo)) + { + if (p_mpq->simplex_display || DEBUG >= __QS_SB_VERB) + { + fprintf (stdout, + "mpf_%u precision falied, error code %d, continuing with " + "next precision", precision, rval); + fflush(stdout); + } + goto NEXT_PRECISION; + } + EGcallD(mpf_QSget_status (p_mpf, status)); + if ((*status == QS_LP_INFEASIBLE) && + (p_mpf->lp->final_phase != PRIMAL_PHASEI) && + (p_mpf->lp->final_phase != DUAL_PHASEII)) + mpf_QSopt_primal (p_mpf, status); + EGcallD(mpf_QSget_status (p_mpf, status)); + last_status = *status; + EGcallD(mpf_QSget_itcnt(p_mpf, 0, 0, 0, 0, &last_iter)); + /* deal with the problem depending on status we got from our optimizer */ + switch (*status) + { + case QS_LP_OPTIMAL: + basis = mpf_QSget_basis (p_mpf); + x_mpf = mpf_EGlpNumAllocArray (p_mpf->qslp->ncols); + y_mpf = mpf_EGlpNumAllocArray (p_mpf->qslp->nrows); + EGcallD(mpf_QSget_x_array (p_mpf, x_mpf)); + EGcallD(mpf_QSget_pi_array (p_mpf, y_mpf)); + x_mpq = QScopy_array_mpf_mpq (x_mpf); + y_mpq = QScopy_array_mpf_mpq (y_mpf); + mpf_EGlpNumFreeArray (x_mpf); + mpf_EGlpNumFreeArray (y_mpf); + if (QSexact_optimal_test (p_mpq, x_mpq, y_mpq, basis)) + { + optimal_output (p_mpq, x, y, x_mpq, y_mpq); + goto CLEANUP; + } + else + { + EGcallD(QSexact_basis_status (p_mpq, status, basis, msg_lvl, &simplexalgo)); + if (*status == QS_LP_OPTIMAL) + { + MESSAGE (msg_lvl, "Retesting solution"); + EGcallD(mpq_QSget_x_array (p_mpq, x_mpq)); + EGcallD(mpq_QSget_pi_array (p_mpq, y_mpq)); + if (QSexact_optimal_test (p_mpq, x_mpq, y_mpq, basis)) + { + optimal_output (p_mpq, x, y, x_mpq, y_mpq); + goto CLEANUP; + } + else + { + last_status = *status = QS_LP_UNSOLVED; + } + } + else + MESSAGE (msg_lvl, "Status is not optimal, but %d", *status); + } + mpq_EGlpNumFreeArray (x_mpq); + mpq_EGlpNumFreeArray (y_mpq); + break; + case QS_LP_INFEASIBLE: + y_mpf = mpf_EGlpNumAllocArray (p_mpf->qslp->nrows); + EGcallD(mpf_QSget_infeas_array (p_mpf, y_mpf)); + y_mpq = QScopy_array_mpf_mpq (y_mpf); + mpf_EGlpNumFreeArray (y_mpf); + if (QSexact_infeasible_test (p_mpq, y_mpq)) + { + infeasible_output (p_mpq, y, y_mpq); + goto CLEANUP; + } + else + { + MESSAGE (msg_lvl, "Retesting solution in exact arithmetic"); + basis = mpf_QSget_basis (p_mpf); + EGcallD(QSexact_basis_status (p_mpq, status, basis, msg_lvl, &simplexalgo)); +#if 0 + mpq_QSset_param (p_mpq, QS_PARAM_SIMPLEX_MAX_ITERATIONS, 1); + mpq_QSload_basis (p_mpq, basis); + mpq_QSfree_basis (basis); + EGcallD(mpq_ILLeditor_solve (p_mpq, simplexalgo)); + EGcallD(mpq_QSget_status (p_mpq, status)); +#endif + if (*status == QS_LP_INFEASIBLE) + { + mpq_EGlpNumFreeArray (y_mpq); + y_mpq = mpq_EGlpNumAllocArray (p_mpq->qslp->nrows); + EGcallD(mpq_QSget_infeas_array (p_mpq, y_mpq)); + if (QSexact_infeasible_test (p_mpq, y_mpq)) + { + infeasible_output (p_mpq, y, y_mpq); + goto CLEANUP; + } + else + { + last_status = *status = QS_LP_UNSOLVED; + } + } + } + mpq_EGlpNumFreeArray (y_mpq); + break; + break; + case QS_LP_OBJ_LIMIT: + rval=1; + IFMESSAGE(p_mpq->simplex_display,"Objective limit reached (in floating point) ending now"); + goto CLEANUP; + break; + case QS_LP_UNBOUNDED: + default: + MESSAGE(__QS_SB_VERB,"Re-trying inextended precision"); + break; + } + NEXT_PRECISION: + mpf_QSfree_prob (p_mpf); + p_mpf = 0; + } + /* ending */ +CLEANUP: + dbl_EGlpNumFreeArray (x_dbl); + dbl_EGlpNumFreeArray (y_dbl); + mpq_EGlpNumFreeArray (x_mpq); + mpq_EGlpNumFreeArray (y_mpq); + mpf_EGlpNumFreeArray (x_mpf); + mpf_EGlpNumFreeArray (y_mpf); + if (ebasis && basis) + { + ILL_IFFREE (ebasis->cstat, char); + ILL_IFFREE (ebasis->rstat, char); + ebasis->nstruct = basis->nstruct; + ebasis->nrows = basis->nrows; + ebasis->cstat = basis->cstat; + ebasis->rstat = basis->rstat; + basis->cstat = basis->rstat = 0; + } + mpq_QSfree_basis (basis); + dbl_QSfree_prob (p_dbl); + mpf_QSfree_prob (p_mpf); + return rval; +} + +/* ========================================================================= */ +int __QSexact_setup = 0; +/* ========================================================================= */ +void QSexactStart(void) +{ + /* if we have been initialized before, do nothing */ + if(__QSexact_setup) return; + /* we should call EGlpNumStart() */ + EGlpNumStart(); + /* now we call all setups */ + EXutilDoInit(); + dbl_ILLstart(); + mpf_ILLstart(); + mpq_ILLstart(); + fp20_ILLstart(); + #ifdef HAVE_SOFTFLOAT + float128_ILLstart(); + #endif + #if ENABLE_LONG_DOUBLE + ldbl_ILLstart(); + #endif + /* ending */ + __QSexact_setup = 1; +} +/* ========================================================================= */ +void QSexactClear(void) +{ + if(!__QSexact_setup) return; + /* now we call all ends */ + #ifdef HAVE_SOFTFLOAT + float128_ILLend(); + #endif + #if ENABLE_LONG_DOUBLE + ldbl_ILLend(); + #endif + fp20_ILLend(); + dbl_ILLend(); + mpf_ILLend(); + mpq_ILLend(); + EXutilDoClear(); + /* ending */ + EGlpNumClear(); + __QSexact_setup = 0; +} +/* ========================================================================= */ +/** @} */ +/* end of exact.c */ + diff --git a/src/exact.h b/src/exact.h new file mode 100644 index 0000000..4a99268 --- /dev/null +++ b/src/exact.h @@ -0,0 +1,485 @@ +/* ========================================================================= */ +/* ESolver "Exact Mixed Integer Linear Solver" provides some basic structures + * and algorithms commons in solving MIP's + * + * Copyright (C) 2005 Daniel Espinoza. + * + * This library 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.1 of the License, or (at your + * option) any later version. + * + * This library 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 library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * */ +/* ========================================================================= */ +#ifndef __EXACT_H__ +#define __EXACT_H__ +#include "qs_config.h" +#include "symtab.h" + +#include "dbl_basis.h" +#include "dbl_dheaps_i.h" +#include "dbl_dstruct.h" +#include "dbl_factor.h" +#include "dbl_format.h" +#include "dbl_lpdata.h" +#include "dbl_lpdefs.h" +#include "dbl_mps.h" +#include "dbl_price.h" +#include "dbl_priority.h" +#include "dbl_qsopt.h" +#include "dbl_qstruct.h" +#include "dbl_ratio.h" +#include "dbl_rawlp.h" +#include "dbl_readline.h" +#include "dbl_read_lp.h" +#include "dbl_read_mps.h" +#include "dbl_simplex.h" +#include "dbl_write_lp.h" +#include "dbl_lib.h" +#include "dbl_editor.h" + +#include "mpq_lpdata.h" +#include "mpq_lpdefs.h" +#include "mpq_basis.h" +#include "mpq_dheaps_i.h" +#include "mpq_dstruct.h" +#include "mpq_factor.h" +#include "mpq_format.h" +#include "mpq_mps.h" +#include "mpq_price.h" +#include "mpq_priority.h" +#include "mpq_qsopt.h" +#include "mpq_qstruct.h" +#include "mpq_ratio.h" +#include "mpq_rawlp.h" +#include "mpq_readline.h" +#include "mpq_read_lp.h" +#include "mpq_read_mps.h" +#include "mpq_simplex.h" +#include "mpq_write_lp.h" +#include "mpq_lib.h" +#include "mpq_editor.h" + +#include "fp20_basis.h" +#include "fp20_dheaps_i.h" +#include "fp20_dstruct.h" +#include "fp20_factor.h" +#include "fp20_format.h" +#include "fp20_lpdata.h" +#include "fp20_lpdefs.h" +#include "fp20_mps.h" +#include "fp20_price.h" +#include "fp20_priority.h" +#include "fp20_qsopt.h" +#include "fp20_qstruct.h" +#include "fp20_ratio.h" +#include "fp20_rawlp.h" +#include "fp20_readline.h" +#include "fp20_read_lp.h" +#include "fp20_read_mps.h" +#include "fp20_simplex.h" +#include "fp20_write_lp.h" +#include "fp20_lib.h" +#include "fp20_editor.h" + +#include "mpf_basis.h" +#include "mpf_dheaps_i.h" +#include "mpf_dstruct.h" +#include "mpf_factor.h" +#include "mpf_format.h" +#include "mpf_lpdata.h" +#include "mpf_lpdefs.h" +#include "mpf_mps.h" +#include "mpf_price.h" +#include "mpf_priority.h" +#include "mpf_qsopt.h" +#include "mpf_qstruct.h" +#include "mpf_ratio.h" +#include "mpf_rawlp.h" +#include "mpf_readline.h" +#include "mpf_read_lp.h" +#include "mpf_read_mps.h" +#include "mpf_simplex.h" +#include "mpf_write_lp.h" +#include "mpf_lib.h" +#include "mpf_editor.h" + +#if ENABLE_LONG_DOUBLE +#include "ldbl_basis.h" +#include "ldbl_dheaps_i.h" +#include "ldbl_dstruct.h" +#include "ldbl_factor.h" +#include "ldbl_format.h" +#include "ldbl_lpdata.h" +#include "ldbl_lpdefs.h" +#include "ldbl_mps.h" +#include "ldbl_price.h" +#include "ldbl_priority.h" +#include "ldbl_qsopt.h" +#include "ldbl_qstruct.h" +#include "ldbl_ratio.h" +#include "ldbl_rawlp.h" +#include "ldbl_readline.h" +#include "ldbl_read_lp.h" +#include "ldbl_read_mps.h" +#include "ldbl_simplex.h" +#include "ldbl_write_lp.h" +#include "ldbl_lib.h" +#include "ldbl_editor.h" +#endif + +#ifdef HAVE_SOFTFLOAT +#include "float128_basis.h" +#include "float128_dheaps_i.h" +#include "float128_dstruct.h" +#include "float128_factor.h" +#include "float128_format.h" +#include "float128_lpdata.h" +#include "float128_lpdefs.h" +#include "float128_mps.h" +#include "float128_price.h" +#include "float128_priority.h" +#include "float128_qsopt.h" +#include "float128_qstruct.h" +#include "float128_ratio.h" +#include "float128_rawlp.h" +#include "float128_readline.h" +#include "float128_read_lp.h" +#include "float128_read_mps.h" +#include "float128_simplex.h" +#include "float128_write_lp.h" +#include "float128_lib.h" +#include "float128_editor.h" +#endif + +#include "eg_exutil.h" + +/* ========================================================================= */ +/** @defgroup Esolver Esolver + * Here we define an interface to solve LP's (#QSexact_solver) and MIP's + * exactly. + * @par History: + * Revision 0.1 + * - 2005-11-14 + * - Fix handling of infeasibility testing, the problem is that + * sometimes, the QSget_infeas_array only work after calling primal + * simplex, so, if we are doing dual, ans finish with infeasibility + * status, the call will fail, the fix is to call primal simples on + * those cases before calling the infeasibility proof. + * - 2005-10-05 + * - If one of the floating point approximations fail, keep going + * to the next floating point approximation. A floating point + * approximation may fail because the basis is singular within the + * used precision. + * - 2005-09-29 + * - If the plain double approximation return unbounded we re-try + * in extended precision, but when the extended precision LP solver + * return with QS_LP_UNBOUNDED status, we just give-up and return + * QS_LP_UNBOUNDED status. + * - 2005-08-17 + * - Improve reliability of optimality test. + * - 2005-07-07 + * - Load optimal soplution into the cache. + * - Change the behavior of QSopt, when he wants to re-start simplex, + * we instead increase the precision of the numbers, this behavior + * is managed by DO_NUMER and DO_SINGULAR. + * - 2005-05-31 + * - If the status of the ending call is not optimal, we don't load + * the previous basis, this is because in some examples doing so lead + * to bad behavior of the overall code. + * - 2005-05-11 + * - First definition and implementation + * + * */ +/** @file + * @ingroup Esolver */ +/** @addtogroup Esolver */ +/** @{ */ +/* ========================================================================= */ + +/* ========================================================================= */ +/** @brief If enabled, save the last problem proved to be optimal, and its + * solution. */ +#define QSEXACT_SAVE_OPTIMAL 0 + +/* ========================================================================= */ +/** @brief If enabled, save the intermediate problems created by the functions + * #QScopy_prob_mpq_dbl and #QScopy_prob_mpq_mpf */ +#define QSEXACT_SAVE_INT 0 + +/* ========================================================================= */ +/** @brief Copy an exact problem (mpq_QSdata) to a regular double version of the + * problem (dbl_QSdata) */ +dbl_QSdata *QScopy_prob_mpq_dbl (mpq_QSdata * p, + const char *newname); + +/* ========================================================================= */ +/** @brief Copy an exact problem (mpq_QSdata) to a regular double version of the + * problem (dbl_QSdata) */ +mpf_QSdata *QScopy_prob_mpq_mpf (mpq_QSdata * p, + const char *newname); + +/* ========================================================================= */ +/** @brief Test if a given primal/dual solution is feasible and has the same + * objective value. + * @param p original problem. + * @param p_sol primal solution candidate. + * @param d_sol dual solution candidate. + * @param basis Basis for wich the current primal/dual vector is a solution. + * @return one if the given primal/dual solution is optimal, zero otherwise. + * @par Description: + * The input problem has the form \f[ \begin{array}{l}\min cx\\ + s.t. \begin{array}{lcl}Ax&=&b\end{array}\\ + l\leq x\leq u\end{array} \f] + * where some of the bounds can be \f$\infty\f$ or \f$-\infty\f$. Note that from + * this the dual problem is allways feasible (we treat \f$\infty\f$ as a + * suitable large number) because it looks like + * \f[ \begin{array}{l}\max by + d_uu-d_ll\\ + s.t. \begin{array}{lcl}A^ty-Id_l+Id_u & =& c \end{array}\\ + d_u,d_l\geq0\end{array} \f] thus we just need to check primal + * feasibility and complementary slackness (just to be sure we also check that + * both dual and primal objective values coincide. + * + * If the optimality test is true (i.e. the basis and the given solution, wich + * might have been modified inside the function) then this function store the + * optimal solution into the cache of the problem. + * + * @note We assume that p_sol and d_sol have the right size for the problem. and + * moreover, we assume that the problem already has the logical variables added + * in (to transform it into standard form), this allow us to fix somewhat the + * primal vector solution to try to get an optimality certificate. + * */ +int QSexact_optimal_test (mpq_QSdata * p, + mpq_t * p_sol, + mpq_t * d_sol, + QSbasis * basis); + +/* ========================================================================= */ +/** @brief Print into a file the optimal solution. + * @param p original problem. + * @param out_f file where to write the solution. + * @return zero on success, non-zero otherwise. + * */ +int QSexact_print_sol (mpq_QSdata * p, + EGioFile_t * out_f); + +/* ========================================================================= */ +/** @brief Check if the given dual vector is a proof of infeasibility for the + * given exact problem. + * @param p pointer to the problem data structure. + * @param d_sol array of length at least nrows with the suposed proof of + * infeasibility. + * @return zero if the given dual vector is indeed a proof of infeasibility for + * the problem, non zero otherwise. + * @par Description: + * Note that for infeasibility, we just need to proof that the problem + \f[ \begin{array}{ll} \min & 0\\ s.t. & Ax = b\\ & l\leq x\leq b\\ + \end{array} \f] + * is infeasible, but it's dual is + \f[ \begin{array}{ll} \max & by - ud_u + ld_l\\ s.t. & A^ty +Id_l - Id_u = 0\\ + & d_u,d_l\geq0\\ \end{array} \f] + * wich is always feasible (provided \f$y\geq0\f$ (set \f$ (y,d_u,d_l)=0\f$), + * and thus we just need to check whether the objective value is \f$\neq 0\f$ + * and we have a proof of infeasibility for the primal. That's what this + * function perform as a test. + * */ +int QSexact_infeasible_test (mpq_QSdata * p, + mpq_t * d_sol); + +/* ========================================================================= */ +/** @brief create a copy of a mpq_t array into a double array. + * @param array mpq_t array from where we will create the values. */ +#define QScopy_array_mpq_dbl(array) ({ \ + mpq_t*__larray = (array);\ + register unsigned __lsz = __EGlpNumArraySize(__larray);\ + double*__lres = dbl_EGlpNumAllocArray(__lsz);\ + while(__lsz--)\ + {\ + if(mpq_equal(__larray[__lsz],mpq_ILL_MAXDOUBLE))\ + __lres[__lsz] = dbl_ILL_MAXDOUBLE;\ + else if(mpq_equal(__larray[__lsz],mpq_ILL_MINDOUBLE))\ + __lres[__lsz] = dbl_ILL_MINDOUBLE;\ + else __lres[__lsz] = mpq_get_d(__larray[__lsz]);\ + }\ + __lres;}) + +/* ========================================================================= */ +/** @brief create a copy of a mpq_t array into a mpf_t array. + * @param array mpq_t array from where we will create the values. */ +#define QScopy_array_mpq_mpf(array) ({ \ + mpq_t*__larray = (array);\ + register unsigned __lsz = __EGlpNumArraySize(__larray);\ + mpf_t*__lres = mpf_EGlpNumAllocArray(__lsz);\ + while(__lsz--)\ + {\ + if(mpq_equal(__larray[__lsz],mpq_ILL_MAXDOUBLE))\ + mpf_set(__lres[__lsz], mpf_ILL_MAXDOUBLE);\ + else if(mpq_equal(__larray[__lsz],mpq_ILL_MINDOUBLE))\ + mpf_set(__lres[__lsz], mpf_ILL_MINDOUBLE);\ + else mpf_set_q(__lres[__lsz],__larray[__lsz]);\ + }\ + __lres;}) + +/* ========================================================================= */ +/** @brief create a copy of a double array into mpq_t array. + * @param array original array of double values (note that this array must have + * been allocated with dbl_EGlpNumAllocArray for this function to work). */ +#define QScopy_array_dbl_mpq(array) ({ \ + double*__larray = (array);\ + register unsigned __lsz = __EGlpNumArraySize(__larray);\ + mpq_t*__lres = mpq_EGlpNumAllocArray(__lsz);\ + while(__lsz--)\ + {\ + if(__larray[__lsz] == dbl_ILL_MAXDOUBLE)\ + mpq_set(__lres[__lsz],mpq_ILL_MAXDOUBLE);\ + else if(__larray[__lsz] == dbl_ILL_MINDOUBLE)\ + mpq_set(__lres[__lsz],mpq_ILL_MINDOUBLE);\ + else mpq_EGlpNumSet(__lres[__lsz],__larray[__lsz]);\ + }\ + __lres;}) + +/* ========================================================================= */ +/** @brief create a copy of a mpf_t array into mpq_t array. + * @param array original array of double values (note that this array must have + * been allocated with __EGlpNumAllocArray for this function to work). */ +#define QScopy_array_mpf_mpq(array) ({ \ + mpf_t*__larray = (array);\ + register unsigned __lsz = __EGlpNumArraySize(__larray);\ + mpq_t*__lres = mpq_EGlpNumAllocArray(__lsz);\ + while(__lsz--)\ + {\ + if(mpf_cmp(__larray[__lsz],mpf_ILL_MAXDOUBLE)==0)\ + mpq_set(__lres[__lsz],mpq_ILL_MAXDOUBLE);\ + else if(mpf_cmp(__larray[__lsz],mpf_ILL_MINDOUBLE)==0)\ + mpq_set(__lres[__lsz],mpq_ILL_MINDOUBLE);\ + mpq_set_f(__lres[__lsz],__larray[__lsz]);\ + }\ + __lres;}) + +/* ========================================================================= */ +/** @brief Write a given row from the LP into the given stream, in exact + * arithmetic */ +void QSexact_write_row (EGioFile_t * out_f, + mpq_ILLlpdata * lp, + int row); + +/* ========================================================================= */ +/** @brief Set the number of bits to use with mpf_t type numbers and change all + * internal constants as needed. */ +#define QSexact_set_precision(precision) mpf_QSset_precision(precision) + +#ifndef QS_EXACT_MAX_ITER +/* ========================================================================= */ +/** @brief This constant define the maximum number of try's for the exact solver + * with mpf_t numbers while incrementing the precision */ +#define QS_EXACT_MAX_ITER 12 +#endif + +/* ========================================================================= */ +/** @brief test whether given basis is primal and dual feasible in rational arithmetic. + * @param p_mpq the problem data. + * @param basis basis to be tested. + * @param result where to store whether given basis is primal and dual feasible. + * @param msg_lvl message level. + */ +int QSexact_basis_optimalstatus( + mpq_QSdata * p_mpq, + QSbasis* basis, + char* result, + const int msg_lvl + ); + +/* ========================================================================= */ +/** @brief test whether given basis is dual feasible in rational arithmetic. + * @param p_mpq the problem data. + * @param basis basis to be tested. + * @param result where to store whether given basis is dual feasible. + * @param dobjval where to store dual solution value in case of dual feasibility (if not NULL). + * @param msg_lvl message level. + */ +int QSexact_basis_dualstatus( + mpq_QSdata * p_mpq, + QSbasis* basis, + char* result, + mpq_t* dobjval, + const int msg_lvl + ); + +/* ========================================================================= */ +/** @brief test whether given basis is dual feasible in rational arithmetic. + * if wanted it will first directly test the corresponding approximate dual and primal solution + * (corrected via dual variables for bounds and primal variables for slacks if possible) for optimality + * before performing the dual feasibility test on the more expensive exact basic solution. + * @param p_mpq the problem data. + * @param basis basis to be tested. + * @param useprestep whether to directly test approximate primal and dual solution first. + * @param dbl_p_sol approximate primal solution to use in prestep + * (NULL in order to compute it by dual simplex in double precision with given starting basis). + * @param dbl_d_sol approximate dual solution to use in prestep + * (NULL in order to compute it by dual simplex in double precision with given starting basis). + * @param result where to store whether given basis is dual feasible. + * @param dobjval where to store dual solution value in case of dual feasibility (if not NULL). + * @param msg_lvl message level. + */ +int QSexact_verify ( + mpq_QSdata * p_mpq, + QSbasis* basis, + int useprestep, + double* dbl_p_sol, + double* dbl_d_sol, + char* result, + mpq_t* dobjval, + const int msg_lvl + ); + +/* ========================================================================= */ +/** @brief Given an mpq_QSdata problem, solve it exactly. + * @param x if not null, we store here the primal solution to the + * problem (if it exist). + * @param y if not null, we store here the dual solution to the + * problem, + * @param p_mpq problem to solve exactly. + * @param status pointer to the integer where we will return the status + * of the problem, either optimal, infeasible, or unbounded (we could also + * return time out). + * @param simplexalgo whether to use primal or dual simplex while solving + * to optimality the problem. + * @param basis if not null, use the given basis to start the + * iteration of simplex, and store here the optimal basis (if found). + * @return zero on success, non-zero otherwise. */ +int QSexact_solver (mpq_QSdata * p_mpq, + mpq_t * const x, + mpq_t * const y, + QSbasis * const basis, + int simplexalgo, + int *status); + +/* ========================================================================= */ +/** @brief Initializator for global data, this is needed mainly for defining + * constants in extended floating point precision and for rational precision. + * This call should be done BEFORE any mpq_xxx mpf_xxx QSxx EGxx call */ +extern void QSexactStart(void); +/* ========================================================================= */ +/** @brief This function must be called at the end of the program to free all + * internal data used in the QSexact structures, once this function is called + * any operation on EGxxx mpq_xxx mpf_xx QSxx may fail. + * */ +extern void QSexactClear(void); +/* ========================================================================= */ +/** @brief indicate if the global data needed for QSexact has been initialized, + * if zero, initialization routine should be called. This is provided to allow + * syncronization between libraries */ +extern int __QSexact_setup; +/** @} */ +/* ========================================================================= */ +/* end of exact.h */ +#endif + diff --git a/src/except.c b/src/except.c new file mode 100644 index 0000000..2d43d3e --- /dev/null +++ b/src/except.c @@ -0,0 +1,60 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: exception.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +#include "except.h" +#include +#include +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +void ILL_report ( + const char *msg, + const char *fct, + const char *file, + unsigned int line, + int with_src_info) +{ + if (msg != NULL) + { + fprintf (stderr, "FAILURE: %s", msg); + if (msg[strlen (msg) - 1] != '\n') + { + fprintf (stderr, "\n"); + } + if (with_src_info == 1) + { + fprintf (stderr, "\t"); + if (fct != NULL) + { + fprintf (stderr, "in function %s ", fct); + } + fprintf (stderr, "in file %s line %d", file, line); + } + fprintf (stderr, ".\n"); + } +} + +/* by default we turn off verbose messages of singular basis */ +int __QS_SB_VERB = 1000; diff --git a/src/except.h b/src/except.h new file mode 100644 index 0000000..0e9108e --- /dev/null +++ b/src/except.h @@ -0,0 +1,167 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: except.h,v 1.3 2003/11/05 17:02:10 meven Exp $ */ +#ifndef ILL_except +#define ILL_except + +/* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__' + which contains the name of the function currently being defined. +# define __DEV_FUNCTION__ __PRETTY_FUNCTION__ + This is broken in G++ before version 2.6. + C9x has a similar variable called __func__, but prefer the GCC one since + it demangles C++ function names. */ +# ifdef __GNUC__ +# if __GNUC__ > 2 || (__GNUC__ == 2 \ + && __GNUC_MINOR__ >= (defined __cplusplus ? 6 : 4)) +# define __DEV_FUNCTION__ __PRETTY_FUNCTION__ +# else +# define __DEV_FUNCTION__ ((__const char *) 0) +# endif +# else +# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +# define __DEV_FUNCTION__ __func__ +# else +# define __DEV_FUNCTION__ ((const char *) 0) +# endif +# endif + + +/* put debugger breakpoint here */ +extern void ILL_report ( + const char *msg, + const char *fct, + const char *file, + unsigned int line, + int with_source_info); + +/* printed message looks as follows + * + * with_source_info == 0: + "\n" + * + * with_source_info == 1: if (fct != NULL) + * + " in function \n"; + * else + * + " in file line \n"; + */ + +#define ILL_GENERAL_ERROR -1 +#define ILL_NO_MEMORY 2 +#define ILL_NULL_PTR 3 + +#define ILL_REPORT(msg,with) \ + ILL_report(msg, __DEV_FUNCTION__, __FILE__, __LINE__, with) +#ifdef NDEBUG +#define ILL_REPRT(msg) \ + ILL_report(msg, __DEV_FUNCTION__, __FILE__, __LINE__, 0) +#else +#define ILL_REPRT(msg) \ + ILL_report(msg, __DEV_FUNCTION__, __FILE__, __LINE__, 1) +#endif + +#define ILL_RESULT(expr, msg) \ +{ \ + if (TRACE > 0) { ILL_RETURN(expr, msg); } \ + return expr; \ +} + +#define ILL_RETURN_PTR(ptr, msg) \ + { void *ILL_RETURN_p = ptr; \ + if (ILL_RETURN_p == NULL) { \ + if (TRACE > 0) ILL_REPRT(msg); \ + } \ + return ILL_RETURN_p; \ + } + +#ifdef NDEBUG +#define ILL_RETURN(expr, msg) \ +{ \ + if (expr != 0) { \ + if (TRACE > 0) ILL_REPRT(msg); \ + } \ + return expr; \ +} + +#else +#define ILL_RETURN(expr, msg) \ + { \ + if (expr != 0) { \ + ILL_REPRT(msg); \ + } \ + ILL_IFTRACE("%s: returning %d\n", __DEV_FUNCTION__, expr); \ + return expr; \ + } +#endif + +#define ILL_CHECKnull(expr, msg) \ + { if ((expr) == NULL) { \ + ILL_REPRT(msg); \ + rval = ILL_NULL_PTR; \ + goto CLEANUP; \ + } } + +#define ILL_FAILtrue(expr, msg) \ + { if (expr) { \ + ILL_REPRT(msg); \ + rval = ILL_GENERAL_ERROR; \ + goto CLEANUP; \ + } } + +#define ILL_FAILtrue_no_rval(expr, msg) \ + { if (expr) { \ + ILL_REPRT(msg); \ + goto CLEANUP; \ + } } + + +#define ILL_FAILfalse(expr, msg) ILL_FAILtrue(!(expr), msg) +#define ILL_FAILfalse_no_rval(expr, msg) ILL_FAILtrue_no_rval(!(expr), msg) + +#define ILL_ERROR(rval, msg) { \ + fprintf(stderr, "%s\n", msg); \ + rval = 1; goto CLEANUP; \ + } +#define ILL_CLEANUP_IF(rval) { if ((rval) != 0) { goto CLEANUP; } } +#define ILL_CLEANUP goto CLEANUP + +#define ILL_SAFE_MALLOC(lhs, n, type) \ + { lhs = ILL_UTIL_SAFE_MALLOC(n, type, lhs); \ + if (lhs == NULL) { \ + ILL_REPRT("Out of memory"); \ + rval = ILL_NO_MEMORY; \ + goto CLEANUP; \ + }} + +#define ILL_SAFE_MALLOC_no_rval(lhs, n, type) \ + { lhs = ILL_UTIL_SAFE_MALLOC(n, type, lhs); \ + if (lhs == NULL) { \ + ILL_REPRT("Out of memory"); \ + goto CLEANUP; \ + }} + + +#define ILL_NEW(ptr, type) ILL_SAFE_MALLOC(ptr, 1, type) +#define ILL_NEW_no_rval(ptr, type) ILL_SAFE_MALLOC_no_rval(ptr, 1, type) + +/* we define debugging verbosity for singular basis */ +extern int __QS_SB_VERB; +#endif diff --git a/src/factor.c b/src/factor.c new file mode 100644 index 0000000..45e3e76 --- /dev/null +++ b/src/factor.c @@ -0,0 +1,5659 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: factor.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +//static int TRACE = 0; + +/* implement a = max(a,abs(b)) and execute the extra code if the update is + * needed */ +#define EGlpNumSetToMaxAbsAndDo(a,b,c) \ + if(EGlpNumIsGreatZero(b))\ + {\ + if(EGlpNumIsLess(a,b)){\ + EGlpNumCopy(a,b);\ + c;\ + }\ + }\ + else\ + {\ + EGlpNumSign(a);\ + if(EGlpNumIsLess(b,a)){\ + EGlpNumCopy(a,b);\ + c;\ + }\ + EGlpNumSign(a);\ + } + + +#include +#include +#include "config.h" +#include "iqsutil.h" +#include "lpdefs.h" +#include "factor.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +#undef RECORD +#undef DEBUG_FACTOR +#undef SOLVE_DEBUG + +#undef FACTOR_DEBUG +#undef UPDATE_DEBUG + +#undef TRACK_FACTOR +#undef NOTICE_BLOWUP + +#undef FACTOR_STATS +#undef UPDATE_STATS +#undef GROWTH_STATS + +#undef UPDATE_STUDY + +#undef SORT_RESULTS + +#ifdef UPDATE_STUDY +int nupdate = 0; +long int colspiketot = 0.0; +long int rowspiketot = 0.0; +long int permshifttot = 0.0; +long int leftetatot = 0.0; +#endif + +void ILLfactor_init_factor_work ( + factor_work * f) +{ + f->max_k = 1000; /* must be less than 46340 (2^15.5) */ + EGlpNumCopy (f->fzero_tol, SZERO_TOLER); /* 2^-50 */ + EGlpNumCopy (f->szero_tol, SZERO_TOLER); /* 2^-50 */ + EGlpNumCopy (f->partial_tol, OBJBND_TOLER); /* 2^-7 */ + f->ur_space_mul = 2.0; + f->uc_space_mul = 1.1; + f->lc_space_mul = 1.1; + f->er_space_mul = 1000.0; + f->grow_mul = 1.5; + f->p = 4; + f->etamax = 100; + f->minmult = 1e3; + f->maxmult = 1e5; + f->updmaxmult = 1e7; + f->dense_fract = 0.25; + f->dense_min = 25; + EGlpNumCopy (f->partial_cur, f->partial_tol); + f->work_coef = 0; + f->work_indx = 0; + f->uc_inf = 0; + f->ur_inf = 0; + f->lc_inf = 0; + f->lr_inf = 0; + f->er_inf = 0; + f->ucindx = 0; + f->ucrind = 0; + f->uccoef = 0; + f->urindx = 0; + f->urcind = 0; + f->urcoef = 0; + f->lcindx = 0; + f->lccoef = 0; + f->lrindx = 0; + f->lrcoef = 0; + f->erindx = 0; + f->ercoef = 0; + f->rperm = 0; + f->rrank = 0; + f->cperm = 0; + f->crank = 0; + f->dmat = 0; + ILLsvector_init (&f->xtmp); +} + +void ILLfactor_free_factor_work ( + factor_work * f) +{ +#ifdef UPDATE_STUDY + if (nupdate) + { + MESSAGE(0, "UPDATE STUDY: avg %d upd: %.2f col, %.2f row, %.2f lefteta, " + "%.2f perm", nupdate, ((double) colspiketot) / nupdate, + ((double) rowspiketot) / nupdate, ((double) leftetatot) / nupdate, + ((double) permshifttot) / nupdate); + } +#endif + EGlpNumFreeArray (f->work_coef); + ILL_IFFREE (f->work_indx, int); + + ILL_IFFREE (f->uc_inf, uc_info); + if (f->dim + f->max_k > 0 && f->ur_inf) + { + unsigned int i = f->dim + f->max_k + 1; + + while (i--) + EGlpNumClearVar (f->ur_inf[i].max); + } + ILL_IFFREE (f->ur_inf, ur_info); + ILL_IFFREE (f->lc_inf, lc_info); + ILL_IFFREE (f->lr_inf, lr_info); + ILL_IFFREE (f->er_inf, er_info); + ILL_IFFREE (f->ucindx, int); + ILL_IFFREE (f->ucrind, int); + + EGlpNumFreeArray (f->uccoef); + ILL_IFFREE (f->urindx, int); + ILL_IFFREE (f->urcind, int); + + EGlpNumFreeArray (f->urcoef); + ILL_IFFREE (f->lcindx, int); + + EGlpNumFreeArray (f->lccoef); + ILL_IFFREE (f->lrindx, int); + + EGlpNumFreeArray (f->lrcoef); + ILL_IFFREE (f->erindx, int); + + EGlpNumFreeArray (f->ercoef); + ILL_IFFREE (f->rperm, int); + ILL_IFFREE (f->rrank, int); + ILL_IFFREE (f->cperm, int); + ILL_IFFREE (f->crank, int); + + EGlpNumFreeArray (f->dmat); + ILLsvector_free (&f->xtmp); +} + +int ILLfactor_set_factor_iparam ( + factor_work * f, + int param, + int val) +{ + switch (param) + { + case QS_FACTOR_MAX_K: + f->max_k = val; + break; + case QS_FACTOR_P: + f->p = val; + break; + case QS_FACTOR_ETAMAX: + f->etamax = val; + break; + case QS_FACTOR_DENSE_MIN: + f->dense_min = val; + break; + default: + fprintf (stderr, "Invalid param %d in ILLfactor_set_factor_iparam\n", + param); + return 1; + } + return 0; +} + +int ILLfactor_set_factor_dparam ( + factor_work * f, + int param, + EGlpNum_t val) +{ + switch (param) + { + case QS_FACTOR_FZERO_TOL: + EGlpNumCopy (f->fzero_tol, val); + break; + case QS_FACTOR_SZERO_TOL: + EGlpNumCopy (f->szero_tol, val); + break; + case QS_FACTOR_UR_SPACE_MUL: + f->ur_space_mul = EGlpNumToLf (val); + break; + case QS_FACTOR_UC_SPACE_MUL: + f->uc_space_mul = EGlpNumToLf (val); + break; + case QS_FACTOR_LC_SPACE_MUL: + f->lc_space_mul = EGlpNumToLf (val); + break; + case QS_FACTOR_LR_SPACE_MUL: + f->lr_space_mul = EGlpNumToLf (val); + break; + case QS_FACTOR_ER_SPACE_MUL: + f->er_space_mul = EGlpNumToLf (val); + break; + case QS_FACTOR_GROW_MUL: + f->grow_mul = EGlpNumToLf (val); + break; + case QS_FACTOR_MAXMULT: + f->maxmult = EGlpNumToLf (val); + break; + case QS_FACTOR_UPDMAXMULT: + f->updmaxmult = EGlpNumToLf (val); + break; + case QS_FACTOR_DENSE_FRACT: + f->dense_fract = EGlpNumToLf (val); + break; + case QS_FACTOR_PARTIAL_TOL: + EGlpNumCopy (f->partial_tol, val); + EGlpNumCopy (f->partial_cur, val); + break; + default: + fprintf (stderr, "Invalid param %d in ILLfactor_set_factor_dparam\n", + param); + return 1; + } + return 0; +} + +int ILLfactor_create_factor_work ( + factor_work * f, + int dim) +{ + int i; + int rval; + + f->dim = dim; + f->etacnt = 0; + f->work_coef = EGlpNumAllocArray (dim); + ILL_SAFE_MALLOC (f->work_indx, dim, int); + + ILL_SAFE_MALLOC (f->uc_inf, dim + (f->max_k + 1), uc_info); + ILL_SAFE_MALLOC (f->ur_inf, dim + (f->max_k + 1), ur_info); + ILL_SAFE_MALLOC (f->lc_inf, dim, lc_info); + ILL_SAFE_MALLOC (f->lr_inf, dim, lr_info); + ILL_SAFE_MALLOC (f->rperm, dim, int); + ILL_SAFE_MALLOC (f->rrank, dim, int); + ILL_SAFE_MALLOC (f->cperm, dim, int); + ILL_SAFE_MALLOC (f->crank, dim, int); + + for (i = dim + f->max_k + 1; i--;) + EGlpNumInitVar (f->ur_inf[i].max); + + for (i = 0; i < dim; i++) + { + EGlpNumZero (f->work_coef[i]); + f->work_indx[i] = 0; + f->uc_inf[i].nzcnt = 0; + f->ur_inf[i].nzcnt = 0; + f->lc_inf[i].nzcnt = 0; + f->lr_inf[i].nzcnt = 0; + f->rperm[i] = i; + f->rrank[i] = i; + f->cperm[i] = i; + f->crank[i] = i; + } + for (i = 0; i <= f->max_k; i++) + { + f->uc_inf[dim + i].nzcnt = i; + f->uc_inf[dim + i].next = dim + i; + f->uc_inf[dim + i].prev = dim + i; + f->ur_inf[dim + i].nzcnt = i; + f->ur_inf[dim + i].next = dim + i; + f->ur_inf[dim + i].prev = dim + i; + } + + rval = ILLsvector_alloc (&f->xtmp, dim); + CHECKRVALG (rval, CLEANUP); + + rval = 0; + +CLEANUP: + if (rval) + { + ILLfactor_free_factor_work (f); + } + EG_RETURN (rval); +} +#ifdef FACTOR_DEBUG +static void dump_matrix ( + factor_work * f, + int remaining) +{ + int dim = f->dim; + ur_info *ur_inf = f->ur_inf; + uc_info *uc_inf = f->uc_inf; + lc_info *lc_inf = f->lc_inf; + lr_info *lr_inf = f->lr_inf; + er_info *er_inf = f->er_inf; + int nzcnt; + int beg; + + int i; + int j; + + for (i = 0; i < dim; i++) + { + if (!remaining || ur_inf[i].next >= 0) + { + printf ("Row %d %d (max %.3f):", i, f->rrank[i], + EGlpNumToLf (ur_inf[i].max)); + nzcnt = ur_inf[i].nzcnt; + beg = ur_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + if (j == ur_inf[i].pivcnt) + { + printf (" |"); + } + printf (" %.3f*%d", EGlpNumToLf (f->urcoef[beg + j]), + f->urindx[beg + j]); + if (f->urcind) + printf ("@%d", f->urcind[beg + j]); + } + printf ("\n"); + } + } + if (f->dmat) + { + int start = 0; + + if (remaining) + start = f->stage - f->dense_base; + printf ("Dcols at %d %d - %d :", f->stage - f->dense_base, + f->dense_base + start, f->nstages); + for (j = start; j < f->dcols; j++) + { + printf (" %5d", f->cperm[j + f->dense_base]); + } + printf ("\n"); + for (i = start; i < f->drows; i++) + { + printf ("DRow %d %d (max %.3f):", i, + f->rperm[i + f->dense_base], + EGlpNumToLf (ur_inf[f->rperm[i + f->dense_base]].max)); + for (j = start; j < f->dcols; j++) + { + if (j == f->drows) + { + printf (" |"); + } + printf (" %.3f", EGlpNumToLf (f->dmat[i * f->dcols + j])); + } + printf ("\n"); + } + } + + if (!remaining) + { + for (i = 0; i < f->stage; i++) + { + printf ("L col %d:", lc_inf[i].c); + nzcnt = lc_inf[i].nzcnt; + beg = lc_inf[i].cbeg; + for (j = 0; j < nzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (f->lccoef[beg + j]), + f->lcindx[beg + j]); + } + printf ("\n"); + } + for (i = f->nstages; i < f->dim; i++) + { + printf ("L col %d:", lc_inf[i].c); + nzcnt = lc_inf[i].nzcnt; + beg = lc_inf[i].cbeg; + for (j = 0; j < nzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (f->lccoef[beg + j]), + f->lcindx[beg + j]); + } + printf ("\n"); + } + for (i = 0; i < f->dim; i++) + { + if (!lr_inf[i].nzcnt) + continue; + printf ("L row %d:", lr_inf[i].r); + nzcnt = lr_inf[i].nzcnt; + beg = lr_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (f->lrcoef[beg + j]), + f->lrindx[beg + j]); + } + printf ("\n"); + } + } + + if (!remaining) + { + for (i = 0; i < f->etacnt; i++) + { + printf ("Eta row %d:", f->er_inf[i].r); + nzcnt = er_inf[i].nzcnt; + beg = er_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (f->ercoef[beg + j]), + f->erindx[beg + j]); + } + printf ("\n"); + } + } + + for (i = 0; i < dim; i++) + { + if (!remaining || uc_inf[i].next >= 0) + { + printf ("Col %d %d:", i, f->crank[i]); + nzcnt = uc_inf[i].nzcnt; + beg = uc_inf[i].cbeg; + for (j = 0; j < nzcnt; j++) + { + if (f->uccoef != 0) + { + printf (" %.3f*%d", EGlpNumToLf (f->uccoef[beg + j]), + f->ucindx[beg + j]); + if (f->ucrind) + printf ("@%d", f->ucrind[beg + j]); + } + else + { + printf (" %d", f->ucindx[beg + j]); + } + } + printf ("\n"); + } + } + + if (!remaining) + { + printf ("rperm:"); + for (i = 0; i < dim; i++) + { + if (i == f->nstages) + printf ("|"); + if (i == f->stage) + printf ("|"); + printf (" %d", f->rperm[i]); + } + printf ("\n"); + + printf ("cperm:"); + for (i = 0; i < dim; i++) + { + if (i == f->nstages) + printf ("|"); + if (i == f->stage) + printf ("|"); + printf (" %d", f->cperm[i]); + } + printf ("\n"); + } + + printf ("Rows by nzcnt:\n"); + for (i = 0; i <= f->max_k; i++) + { + if (ur_inf[dim + i].next != dim + i) + { + printf ("%d:", i); + for (j = ur_inf[dim + i].next; j != dim + i; j = ur_inf[j].next) + { + printf (" %d", j); + } + printf ("\n"); + } + } + + printf ("Cols by nzcnt:\n"); + for (i = 0; i <= f->max_k; i++) + { + if (uc_inf[dim + i].next != dim + i) + { + printf ("%d:", i); + for (j = uc_inf[dim + i].next; j != dim + i; j = uc_inf[j].next) + { + printf (" %d", j); + } + printf ("\n"); + } + } + + printf ("\n"); + fflush (stdout); +} +#endif + +#ifdef SORT_RESULTS +static void sort_vector2 ( + int nzcnt, + int *indx, + EGlpNum_t * coef) +{ + int i; + int j; + int itmp; + EGlpNum_t ctmp; + + EGlpNumInitVar (ctmp); + + for (i = 1; i < nzcnt; i++) + { + itmp = indx[i]; + EGlpNumCopy (ctmp, coef[i]); + for (j = i; j >= 1 && indx[j - 1] > itmp; j--) + { + indx[j] = indx[j - 1]; + EGlpNumCopy (coef[j], coef[j - 1]); + } + indx[j] = itmp; + EGlpNumCopy (coef[j], ctmp); + } + EGlpNumClearVar (ctmp); +} + +static void sort_vector ( + svector * x) +{ + sort_vector2 (x->nzcnt, x->indx, x->coef); +} +#endif + +#ifdef DEBUG_FACTOR +static int check_matrix ( + factor_work * f) +{ + ur_info *ur_inf = f->ur_inf; + uc_info *uc_inf = f->uc_inf; + int rbeg; + int nzcnt; + int cbeg; + int c; + int r; + int j; + int nerr = 0; + + for (r = 0; r < f->dim; r++) + { + nzcnt = ur_inf[r].nzcnt; + rbeg = ur_inf[r].rbeg; + for (j = 0; j < nzcnt; j++) + { + c = f->urindx[rbeg + j]; + cbeg = uc_inf[c].cbeg; + if (f->ucindx[cbeg + f->urcind[rbeg + j]] != r) + { + MESSAGE(0,"index mismatch, row %d column %d", r, c); + nerr++; + } + if (fabs(EGlpNumToLf(f->uccoef[cbeg + f->urcind[rbeg + j]]) - EGlpNumToLf(f->urcoef[rbeg + j]))>1000*EGlpNumToLf(epsLpNum)) + { + MESSAGE(0,"coef mismatch, row %d column %d", r, c); + nerr++; + } + } + } + if (f->urindx[f->ur_space] != 0) + { + MESSAGE(0,"last urindx entry %d != 0", f->urindx[f->ur_space]); + nerr++; + } + + for (c = 0; c < f->dim; c++) + { + nzcnt = uc_inf[c].nzcnt; + cbeg = uc_inf[c].cbeg; + for (j = 0; j < nzcnt; j++) + { + r = f->ucindx[cbeg + j]; + rbeg = ur_inf[r].rbeg; + if (f->urindx[rbeg + f->ucrind[cbeg + j]] != c) + { + MESSAGE(0,"index mismatch, column %d row %d", c, r); + nerr++; + } + if (f->urcoef[rbeg + f->ucrind[cbeg + j]] != f->uccoef[cbeg + j]) + { + MESSAGE(0,"coef mismatch, column %d row %d", c, r); + nerr++; + } + } + } + if (f->ucindx[f->uc_space] != 0) + { + MESSAGE(0,"last ucindx entry %d != 0", f->ucindx[f->uc_space]); + nerr++; + } + if (nerr) + { + dump_matrix (f, 0); + return E_CHECK_FAILED; + } + return 0; +} +#endif + +#ifdef FACTOR_STATS +static void dump_factor_stats ( + factor_work * f) +{ + int dim = f->dim; + int ecnt = f->etacnt; + ur_info *ur_inf = f->ur_inf; + lc_info *lc_inf = f->lc_inf; + er_info *er_inf = f->er_inf; + EGlpNum_t *urcoef = f->urcoef; + EGlpNum_t *lccoef = f->lccoef; + EGlpNum_t *ercoef = f->ercoef; + int lnzcnt = 0; + int unzcnt = 0; + int enzcnt = 0; + int nzcnt; + int beg; + EGlpNum_t umax; + EGlpNum_t lmax; + EGlpNum_t emax; + int i; + int j; + + EGlpNumInitVar (umax); + EGlpNumInitVar (lmax); + EGlpNumInitVar (emax); + EGlpNumZero (umax); + for (i = 0; i < dim; i++) + { + nzcnt = ur_inf[i].nzcnt; + beg = ur_inf[i].rbeg; + unzcnt += nzcnt; + for (j = 0; j < nzcnt; j++) + { + EGlpNumSetToMaxAbs (umax, urcoef[beg + j]); + } + } + EGlpNumZero (lmax); + for (i = 0; i < dim; i++) + { + nzcnt = lc_inf[i].nzcnt; + beg = lc_inf[i].cbeg; + lnzcnt += nzcnt; + for (j = 0; j < nzcnt; j++) + { + EGlpNumSetToMaxAbs (lmax, lccoef[beg + j]); + } + } + EGlpNumZero (emax); + for (i = 0; i < ecnt; i++) + { + nzcnt = er_inf[i].nzcnt; + beg = er_inf[i].rbeg; + enzcnt += nzcnt; + for (j = 0; j < nzcnt; j++) + { + EGlpNumSetToMaxAbs (emax, ercoef[beg + j]); + } + } + MESSAGE(0, "factor U %d nzs %.3e max L %d nzs %.3e max E %d nzs %.3e max", + unzcnt, EGlpNumToLf (umax), lnzcnt, EGlpNumToLf (lmax), enzcnt, + EGlpNumToLf (emax)); + fflush (stdout); + EGlpNumClearVar (umax); + EGlpNumClearVar (lmax); + EGlpNumClearVar (emax); +} +#endif + +static void clear_work ( + factor_work * f) +{ + int i; + int dim = f->dim; + EGlpNum_t *work_coef = f->work_coef; + + for (i = 0; i < dim; i++) + { + EGlpNumZero (work_coef[i]); + } +} + +static void load_row ( + factor_work * f, + int r) +{ + EGlpNum_t *prow_urcoef = f->urcoef + f->ur_inf[r].rbeg; + int *prow_urindx = f->urindx + f->ur_inf[r].rbeg; + int prow_nzcnt = f->ur_inf[r].nzcnt; + EGlpNum_t *work_coef = f->work_coef; + int *work_indx = f->work_indx; + int i; + int j; + + for (i = 0; i < prow_nzcnt; i++) + { + j = prow_urindx[i]; + EGlpNumCopy (work_coef[j], prow_urcoef[i]); + work_indx[j] = 1; + } +} + +static void clear_row ( + factor_work * f, + int r) +{ + int *prow_urindx = f->urindx + f->ur_inf[r].rbeg; + int prow_nzcnt = f->ur_inf[r].nzcnt; + EGlpNum_t *work_coef = f->work_coef; + int *work_indx = f->work_indx; + int i; + int j; + + for (i = 0; i < prow_nzcnt; i++) + { + j = prow_urindx[i]; + EGlpNumZero (work_coef[j]); + work_indx[j] = 0; + } +} + +static int make_ur_space ( + factor_work * f, + int space) +{ + EGlpNum_t *new_urcoef = 0; + int *new_urindx = 0; + int *new_urcind = 0; + EGlpNum_t *urcoef = f->urcoef; + int *urindx = f->urindx; + int *urcind = f->urcind; + int minspace; + ur_info *ur_inf = f->ur_inf; + int dim = f->dim; + int new_nzcnt = 0, old_nzcnt; + int rbeg; + int nzcnt; + int i; + int j; + int rval; + + minspace = f->ur_space; + nzcnt = space; + for (i = 0; i < dim; i++) + nzcnt += ur_inf[i].nzcnt; + old_nzcnt = nzcnt; + while (nzcnt * 2 >= minspace) + { + minspace = 1 + minspace * f->grow_mul; + } + +#ifdef GROWTH_STATS + printf ("make_ur_space growing from %d to %d...", f->ur_space, minspace); + fflush (stdout); +#endif + new_urcoef = EGlpNumAllocArray (minspace); + ILL_SAFE_MALLOC (new_urindx, minspace + 1, int); + + if (urcind) + { + ILL_SAFE_MALLOC (new_urcind, minspace, int); + } + + if (urcind) + { + for (j = 0; j < dim; j++) + { + rbeg = ur_inf[j].rbeg; + nzcnt = ur_inf[j].nzcnt; + ur_inf[j].rbeg = new_nzcnt; + for (i = 0; i < nzcnt; i++) + { + new_urindx[new_nzcnt] = urindx[rbeg + i]; + EGlpNumCopy (new_urcoef[new_nzcnt], urcoef[rbeg + i]); + new_urcind[new_nzcnt] = urcind[rbeg + i]; + new_nzcnt++; + } + } + } + else + { + for (j = 0; j < dim; j++) + { + rbeg = ur_inf[j].rbeg; + nzcnt = ur_inf[j].nzcnt; + ur_inf[j].rbeg = new_nzcnt; + for (i = 0; i < nzcnt; i++) + { + new_urindx[new_nzcnt] = urindx[rbeg + i]; + EGlpNumCopy (new_urcoef[new_nzcnt], urcoef[rbeg + i]); + new_nzcnt++; + } + } + } + + for (i = new_nzcnt; i < minspace; i++) + { + new_urindx[i] = -1; + } + new_urindx[minspace] = 0; + EGlpNumFreeArray (f->urcoef); + f->urcoef = new_urcoef; + new_urcoef = 0; + + ILL_IFFREE (f->urindx, int); + + f->urindx = new_urindx; + new_urindx = 0; + + ILL_IFFREE (f->urcind, int); + + f->urcind = new_urcind; + new_urcind = 0; + + f->ur_freebeg = new_nzcnt; + f->ur_space = minspace; + +#ifdef GROWTH_STATS + MESSAGE (0,"%d/%d nonzeros", new_nzcnt, old_nzcnt); + dump_factor_stats (f); +#endif + + rval = 0; + +CLEANUP: + ILL_IFFREE (new_urcoef, EGlpNum_t); + ILL_IFFREE (new_urindx, int); + ILL_IFFREE (new_urcind, int); + + EG_RETURN (rval); +} + +static int make_uc_space ( + factor_work * f, + int space) +{ + EGlpNum_t *new_uccoef = 0; + int *new_ucindx = 0; + int *new_ucrind = 0; + int uc_freebeg = f->uc_freebeg; + EGlpNum_t *uccoef = f->uccoef; + int *ucindx = f->ucindx; + int *ucrind = f->ucrind; + int minspace = uc_freebeg + space; + uc_info *uc_inf = f->uc_inf; + int dim = f->dim; + int new_nzcnt = 0; + int cbeg; + int nzcnt; + int i; + int j; + int rval; + + minspace = f->uc_space; + nzcnt = space; + for( i = 0 ; i < dim ; i++) nzcnt += uc_inf[i].nzcnt; + while(nzcnt*2 >= minspace) + { + minspace = 10 + (f->grow_mul * minspace); + } + +#ifdef GROWTH_STATS + MESSAGE (0,"make_uc_space growing from %d to %d...", f->uc_space, minspace); +#endif + + ILL_SAFE_MALLOC (new_ucindx, minspace + 1, int); + + if (ucrind) + { + new_uccoef = EGlpNumAllocArray (minspace); + ILL_SAFE_MALLOC (new_ucrind, minspace, int); + } + + if (ucrind) + { + for (j = 0; j < dim; j++) + { + cbeg = uc_inf[j].cbeg; + nzcnt = uc_inf[j].nzcnt; + uc_inf[j].cbeg = new_nzcnt; + for (i = 0; i < nzcnt; i++) + { + new_ucindx[new_nzcnt] = ucindx[cbeg + i]; + EGlpNumCopy (new_uccoef[new_nzcnt], uccoef[cbeg + i]); + new_ucrind[new_nzcnt] = ucrind[cbeg + i]; + new_nzcnt++; + } + } + } + else + { + for (j = 0; j < dim; j++) + { + cbeg = uc_inf[j].cbeg; + nzcnt = uc_inf[j].nzcnt; + uc_inf[j].cbeg = new_nzcnt; + for (i = 0; i < nzcnt; i++) + { + new_ucindx[new_nzcnt] = ucindx[cbeg + i]; + new_nzcnt++; + } + } + } + + for (i = new_nzcnt; i < minspace; i++) + { + new_ucindx[i] = -1; + } + new_ucindx[minspace] = 0; + + EGlpNumFreeArray (f->uccoef); + f->uccoef = new_uccoef; + new_uccoef = 0; + + ILL_IFFREE (f->ucindx, int); + + f->ucindx = new_ucindx; + new_ucindx = 0; + + ILL_IFFREE (f->ucrind, int); + + f->ucrind = new_ucrind; + new_ucrind = 0; + + f->uc_freebeg = new_nzcnt; + f->uc_space = minspace; + +#ifdef GROWTH_STATS + MESSAGE (0,"%d nonzeros", new_nzcnt); + dump_factor_stats (f); +#endif + + rval = 0; + +CLEANUP: + ILL_IFFREE (new_uccoef, EGlpNum_t); + ILL_IFFREE (new_ucindx, int); + ILL_IFFREE (new_ucrind, int); + + EG_RETURN (rval); +} + +static int make_lc_space ( + factor_work * f, + int space) +{ + EGlpNum_t *new_lccoef = 0; + int *new_lcindx = 0; + int lc_freebeg = f->lc_freebeg; + EGlpNum_t *lccoef = f->lccoef; + int *lcindx = f->lcindx; + int minspace = lc_freebeg + space; + int i; + int rval; + + if (f->lc_space * f->grow_mul > minspace) + { + minspace = f->lc_space * f->grow_mul; + } + +#ifdef GROWTH_STATS + MESSAGE (0,"make_lc_space growing from %d to %d...", f->lc_space, minspace); +#endif + + new_lccoef = EGlpNumAllocArray (minspace); + ILL_SAFE_MALLOC (new_lcindx, minspace, int); + + for (i = 0; i < lc_freebeg; i++) + { + EGlpNumCopy (new_lccoef[i], lccoef[i]); + new_lcindx[i] = lcindx[i]; + } + + EGlpNumFreeArray (lccoef); + f->lccoef = new_lccoef; + new_lccoef = 0; + + ILL_IFFREE (lcindx, int); + + f->lcindx = new_lcindx; + new_lcindx = 0; + + f->lc_space = minspace; + +#ifdef GROWTH_STATS + dump_factor_stats (f); +#endif + + rval = 0; + +CLEANUP: + ILL_IFFREE (new_lccoef, EGlpNum_t); + ILL_IFFREE (new_lcindx, int); + + EG_RETURN (rval); +} + +static void set_col_nz ( + factor_work * f, + int c) +{ + uc_info *uc_inf = f->uc_inf; + int nzcnt = uc_inf[c].nzcnt; + int max_k = f->max_k; + int dim = f->dim; + + if (uc_inf[c].next >= 0) + { + uc_inf[uc_inf[c].next].prev = uc_inf[c].prev; + uc_inf[uc_inf[c].prev].next = uc_inf[c].next; + + if (nzcnt >= max_k) + nzcnt = max_k; + uc_inf[c].next = uc_inf[dim + nzcnt].next; + uc_inf[c].prev = dim + nzcnt; + uc_inf[dim + nzcnt].next = c; + uc_inf[uc_inf[c].next].prev = c; + } +} + +static void set_row_nz ( + factor_work * f, + int r) +{ + ur_info *ur_inf = f->ur_inf; + int nzcnt = ur_inf[r].pivcnt; + int max_k = f->max_k; + int dim = f->dim; + + if (ur_inf[r].next >= 0) + { + ur_inf[ur_inf[r].next].prev = ur_inf[r].prev; + ur_inf[ur_inf[r].prev].next = ur_inf[r].next; + + if (nzcnt >= max_k) + nzcnt = max_k; + ur_inf[r].next = ur_inf[dim + nzcnt].next; + ur_inf[r].prev = dim + nzcnt; + ur_inf[dim + nzcnt].next = r; + ur_inf[ur_inf[r].next].prev = r; + } +} + +static void remove_col_nz ( + factor_work * f, + int r, + int c) +{ + uc_info *uc_inf = f->uc_inf; + int *ucindx = f->ucindx + uc_inf[c].cbeg; + int nzcnt = uc_inf[c].nzcnt; + int i; + + for (i = 0; i < nzcnt; i++) + { + if (ucindx[i] == r) + { + --nzcnt; + ucindx[i] = ucindx[nzcnt]; + ucindx[nzcnt] = -1; + break; + } + } + uc_inf[c].nzcnt = nzcnt; + + set_col_nz (f, c); +} + +static void remove_row_nz ( + factor_work * f, + int r, + int c) +{ + ur_info *ur_inf = f->ur_inf; + int *urindx = f->urindx + ur_inf[r].rbeg; + EGlpNum_t *urcoef = f->urcoef + ur_inf[r].rbeg; + int pivcnt = ur_inf[r].pivcnt; + EGlpNum_t max; + int tind; + EGlpNum_t tcoef; + int i; + + EGlpNumInitVar (tcoef); + EGlpNumInitVar (max); + EGlpNumZero (max); + + for (i = 0; i < pivcnt; i++) + { + if (urindx[i] == c) + { + --pivcnt; + ILL_SWAP (urindx[i], urindx[pivcnt], tind); + EGLPNUM_SWAP (urcoef[i], urcoef[pivcnt], tcoef); + --i; + } + else + { + EGlpNumSetToMaxAbs (max, urcoef[i]); + } + } + ur_inf[r].pivcnt = pivcnt; + EGlpNumCopy (ur_inf[r].max, max); + set_row_nz (f, r); + EGlpNumClearVar (max); + EGlpNumClearVar (tcoef); +} + +static int add_col_nz ( + factor_work * f, + int r, + int c) +{ + uc_info *uc_inf = f->uc_inf; + int cbeg = uc_inf[c].cbeg; + int nzcnt = uc_inf[c].nzcnt; + int uc_freebeg = f->uc_freebeg; + int *ucindx = f->ucindx; + int i; + int rval = 0; + + if (uc_inf[c].next == -1) + { + return 0; + } + + if (ucindx[cbeg + nzcnt] == -1) + { + ucindx[cbeg + nzcnt] = r; + uc_inf[c].nzcnt++; + if (nzcnt + cbeg == uc_freebeg) + { + f->uc_freebeg = uc_freebeg + 1; + } + } + else + { + if (uc_freebeg + nzcnt + 1 >= f->uc_space) + { + rval = make_uc_space (f, nzcnt + 1); + CHECKRVALG (rval, CLEANUP); + uc_freebeg = f->uc_freebeg; + cbeg = uc_inf[c].cbeg; + ucindx = f->ucindx; + } + for (i = 0; i < nzcnt; i++) + { + ucindx[uc_freebeg + i] = ucindx[cbeg + i]; + ucindx[cbeg + i] = -1; + } + ucindx[uc_freebeg + nzcnt] = r; + uc_inf[c].cbeg = uc_freebeg; + uc_inf[c].nzcnt++; + f->uc_freebeg = uc_freebeg + nzcnt + 1; + } + + set_col_nz (f, c); +CLEANUP: + EG_RETURN (rval); +} + +static void disable_col ( + factor_work * f, + int c) +{ + uc_info *uc_inf = f->uc_inf; + + if (uc_inf[c].next >= 0) + { + uc_inf[uc_inf[c].next].prev = uc_inf[c].prev; + uc_inf[uc_inf[c].prev].next = uc_inf[c].next; + + uc_inf[c].next = -2; + uc_inf[c].prev = -2; + } +} + +static void remove_col ( + factor_work * f, + int c) +{ + uc_info *uc_inf = f->uc_inf; + int cbeg = uc_inf[c].cbeg; + int nzcnt = uc_inf[c].nzcnt; + int *ucindx = f->ucindx; + int i; + + for (i = 0; i < nzcnt; i++) + { + ucindx[cbeg + i] = -1; + } + uc_inf[c].cbeg = 0; + uc_inf[c].nzcnt = 0; + + if (uc_inf[c].next >= 0) + { + uc_inf[uc_inf[c].next].prev = uc_inf[c].prev; + uc_inf[uc_inf[c].prev].next = uc_inf[c].next; + + uc_inf[c].next = -1; + uc_inf[c].prev = -1; + } +} + +static void remove_row ( + factor_work * f, + int r) +{ + ur_info *ur_inf = f->ur_inf; + + if (ur_inf[r].next >= 0) + { + ur_inf[ur_inf[r].next].prev = ur_inf[r].prev; + ur_inf[ur_inf[r].prev].next = ur_inf[r].next; + + ur_inf[r].next = -1; + ur_inf[r].prev = -1; + } +} + +static void find_coef ( + factor_work * f, + int r, + int c, + EGlpNum_t * coef) +{ + EGlpNum_t *prow_urcoef = f->urcoef + f->ur_inf[r].rbeg; + int *prow_urindx = f->urindx + f->ur_inf[r].rbeg; + int i; + int prow_nzcnt = f->ur_inf[r].nzcnt; + + EGlpNumZero (*coef); + for (i = 0; i < prow_nzcnt; i++) + { + if (prow_urindx[i] == c) + { + EGlpNumCopy (*coef, prow_urcoef[i]); + return; + } + } + fprintf (stderr, "Coefficient not found\n"); + return; +} + +static int elim_row ( + factor_work * f, + int elim_r, + int r, + int c, + EGlpNum_t * p_pivot_coef) +{ + ur_info *ur_inf = f->ur_inf; + EGlpNum_t *work_coef = f->work_coef; + int *work_indx = f->work_indx; + EGlpNum_t *urcoef = f->urcoef; + int *urindx = f->urindx; + int prow_beg = ur_inf[r].rbeg; + int prow_nzcnt = ur_inf[r].nzcnt; + int prow_pivcnt = ur_inf[r].pivcnt; + int fill = ur_inf[elim_r].nzcnt; + int cancel = 0; + EGlpNum_t max; + int erow_beg; + int erow_nzcnt; + int erow_pivcnt; + EGlpNum_t x; + int i; + int j; + int rval = 0; + EGlpNum_t elim_coef; + + EGlpNumInitVar (max); + EGlpNumInitVar (x); + EGlpNumInitVar (elim_coef); + EGlpNumZero (max); + find_coef (f, r, c, &elim_coef); + EGlpNumDivTo (elim_coef, work_coef[c]); + EGlpNumCopy (*p_pivot_coef, elim_coef); + + for (i = 0; i < prow_nzcnt; i++) + { + j = urindx[prow_beg + i]; + if (work_indx[j] == 1) + { + EGlpNumCopy (x, urcoef[prow_beg + i]); + EGlpNumSubInnProdTo (x, elim_coef, work_coef[j]); + if ((!(EGlpNumIsNeqZero (x, f->fzero_tol))) || j == c) + { + cancel++; + if (j != c) + { + remove_col_nz (f, r, j); + } + if (i < prow_pivcnt) + { + prow_pivcnt--; + prow_nzcnt--; + urindx[prow_beg + i] = urindx[prow_beg + prow_pivcnt]; + EGlpNumCopy (urcoef[prow_beg + i], urcoef[prow_beg + prow_pivcnt]); + if (prow_pivcnt != prow_nzcnt) + { + urindx[prow_beg + prow_pivcnt] = urindx[prow_beg + prow_nzcnt]; + EGlpNumCopy (urcoef[prow_beg + prow_pivcnt], + urcoef[prow_beg + prow_nzcnt]); + } + } + else + { + prow_nzcnt--; + urindx[prow_beg + i] = urindx[prow_beg + prow_nzcnt]; + EGlpNumCopy (urcoef[prow_beg + i], urcoef[prow_beg + prow_nzcnt]); + } + urindx[prow_beg + prow_nzcnt] = -1; + i--; + } + else + { + EGlpNumCopy (urcoef[prow_beg + i], x); + if (i < prow_pivcnt) + { + EGlpNumSetToMaxAbs (max, x); + } + } + work_indx[j] = 0; + fill--; + } + else + { + if (i < prow_pivcnt) + { + EGlpNumSetToMaxAbs (max, urcoef[prow_beg + i]); + } + } + } + + if (fill > 0) + { + ur_inf[r].nzcnt = prow_nzcnt; + ur_inf[r].pivcnt = prow_pivcnt; + if (fill > cancel) + { + int ur_freebeg = f->ur_freebeg; + + if (ur_freebeg + prow_nzcnt + fill >= f->ur_space) + { + rval = make_ur_space (f, prow_nzcnt + fill); + CHECKRVALG (rval, CLEANUP); + urcoef = f->urcoef; + urindx = f->urindx; + ur_freebeg = f->ur_freebeg; + prow_beg = f->ur_inf[r].rbeg; + } + for (i = 0; i < prow_nzcnt; i++) + { + urindx[ur_freebeg + i] = urindx[prow_beg + i]; + EGlpNumCopy (urcoef[ur_freebeg + i], urcoef[prow_beg + i]); + urindx[prow_beg + i] = -1; + } + ur_inf[r].rbeg = ur_freebeg; + f->ur_freebeg = ur_freebeg + prow_nzcnt + fill; + prow_beg = ur_freebeg; + } + + erow_beg = ur_inf[elim_r].rbeg; + erow_nzcnt = ur_inf[elim_r].nzcnt; + erow_pivcnt = ur_inf[elim_r].pivcnt; + + for (i = 0; i < erow_pivcnt; i++) + { + j = urindx[erow_beg + i]; + if (work_indx[j] == 1) + { + EGlpNumCopyNeg (x, elim_coef); + EGlpNumMultTo (x, urcoef[erow_beg + i]); + if (EGlpNumIsNeqZero (x, f->fzero_tol)) + { + rval = add_col_nz (f, r, j); + CHECKRVALG (rval, CLEANUP); + if (prow_pivcnt != prow_nzcnt) + { + urindx[prow_beg + prow_nzcnt] = urindx[prow_beg + prow_pivcnt]; + EGlpNumCopy (urcoef[prow_beg + prow_nzcnt], + urcoef[prow_beg + prow_pivcnt]); + } + urindx[prow_beg + prow_pivcnt] = j; + EGlpNumCopy (urcoef[prow_beg + prow_pivcnt], x); + EGlpNumSetToMaxAbs (max, x); + prow_pivcnt++; + prow_nzcnt++; + } + } + else + { + work_indx[j] = 1; + } + } + for (i = erow_pivcnt; i < erow_nzcnt; i++) + { + j = urindx[erow_beg + i]; + if (work_indx[j] == 1) + { + EGlpNumCopyNeg (x, elim_coef); + EGlpNumMultTo (x, urcoef[erow_beg + i]); + if (EGlpNumIsNeqZero (x, f->fzero_tol)) + { + rval = add_col_nz (f, r, j); + CHECKRVALG (rval, CLEANUP); + urindx[prow_beg + prow_nzcnt] = j; + EGlpNumCopy (urcoef[prow_beg + prow_nzcnt], x); + prow_nzcnt++; + } + } + else + { + work_indx[j] = 1; + } + } + } + else + { + erow_nzcnt = ur_inf[elim_r].nzcnt; + erow_beg = ur_inf[elim_r].rbeg; + for (i = 0; i < erow_nzcnt; i++) + { + j = urindx[erow_beg + i]; + work_indx[j] = 1; + } + } + + ur_inf[r].nzcnt = prow_nzcnt; + ur_inf[r].pivcnt = prow_pivcnt; + EGlpNumCopy (ur_inf[r].max, max); + + set_row_nz (f, r); +CLEANUP: + EGlpNumClearVar (elim_coef); + EGlpNumClearVar (x); + EGlpNumClearVar (max); + EG_RETURN (rval); +} + +#define SETPERM(f,s,r,c) { \ + f->rperm[f->rrank[r]] = f->rperm[s]; \ + f->rrank[f->rperm[s]] = f->rrank[r]; \ + f->rperm[s] = r; \ + f->rrank[r] = s; \ + \ + f->cperm[f->crank[c]] = f->cperm[s]; \ + f->crank[f->cperm[s]] = f->crank[c]; \ + f->cperm[s] = c; \ + f->crank[c] = s; \ +} + +static int elim ( + factor_work * f, + int r, + int c) +{ + uc_info *uc_inf = f->uc_inf; + ur_info *ur_inf = f->ur_inf; + lc_info *lc_inf = f->lc_inf; + int *urindx; + int *ucindx; + int *lcindx; + EGlpNum_t *urcoef; + EGlpNum_t *lccoef; + EGlpNum_t pivot_coef; + int nzcnt; + int lc_freebeg; + int s = f->stage; + int i; + int j; + int rval = 0; + + EGlpNumInitVar (pivot_coef); + + if (uc_inf[c].nzcnt == 1) + { + /* col singleton */ + SETPERM (f, s, r, c); + + lc_inf[s].cbeg = -1; + lc_inf[s].c = r; + lc_inf[s].nzcnt = 0; + f->stage++; + + urindx = f->urindx + ur_inf[r].rbeg; + urcoef = f->urcoef + ur_inf[r].rbeg; + nzcnt = ur_inf[r].nzcnt; + for (i = 0; i < nzcnt; i++) + { + j = urindx[i]; + remove_col_nz (f, r, j); + if (j == c) + { + urindx[i] = urindx[0]; + urindx[0] = c; + EGLPNUM_SWAP (urcoef[0], urcoef[i], pivot_coef); + } + } + remove_row (f, r); + remove_col (f, c); + } + else if (ur_inf[r].nzcnt == 1) + { + /* row singleton */ + --(f->nstages); + SETPERM (f, f->nstages, r, c); + + lc_inf[f->nstages].cbeg = -1; + lc_inf[f->nstages].c = r; + lc_inf[f->nstages].nzcnt = 0; + + ucindx = f->ucindx + uc_inf[c].cbeg; + nzcnt = uc_inf[c].nzcnt; + for (i = 0; i < nzcnt; i++) + { + j = ucindx[i]; + remove_row_nz (f, j, c); + } + remove_row (f, r); + remove_col (f, c); + } + else + { + SETPERM (f, s, r, c); + f->stage++; + + nzcnt = uc_inf[c].nzcnt; + if (f->lc_freebeg + nzcnt >= f->lc_space) + { + rval = make_lc_space (f, nzcnt); + CHECKRVALG (rval, CLEANUP); + } + lc_freebeg = f->lc_freebeg; + lc_inf[s].cbeg = lc_freebeg; + lc_inf[s].c = r; + lcindx = f->lcindx; + lccoef = f->lccoef; + load_row (f, r); + ucindx = f->ucindx + uc_inf[c].cbeg; + for (i = 0; i < nzcnt; i++) + { + j = f->ucindx[uc_inf[c].cbeg + i]; + if (j != r) + { + rval = elim_row (f, r, j, c, &pivot_coef); + CHECKRVALG (rval, CLEANUP); + lcindx[lc_freebeg] = j; + EGlpNumCopy (lccoef[lc_freebeg], pivot_coef); + lc_freebeg++; +#ifdef TRACK_FACTOR + EGlpNumSetToMaxAbs (f->maxelem_factor, pivot_coef); + if (EGlpNumIsLess (f->maxelem_factor, ur_inf[r].max)) + EGlpNumCopy (f->maxelem_factor, ur_inf[r].max); +#endif /* TRACK_FACTOR */ + } + } + lc_inf[s].nzcnt = lc_freebeg - lc_inf[s].cbeg; + f->lc_freebeg = lc_freebeg; + + clear_row (f, r); + + urindx = f->urindx + ur_inf[r].rbeg; + urcoef = f->urcoef + ur_inf[r].rbeg; + nzcnt = ur_inf[r].nzcnt; + for (i = 0; i < nzcnt; i++) + { + j = urindx[i]; + remove_col_nz (f, r, j); + if (j == c) + { + urindx[i] = urindx[0]; + urindx[0] = c; + EGLPNUM_SWAP (urcoef[0], urcoef[i], pivot_coef); + } + } + remove_row (f, r); + remove_col (f, c); + } +CLEANUP: + EGlpNumClearVar (pivot_coef); + EG_RETURN (rval); +} + +static void find_pivot_column ( + factor_work * f, + int c, + int *p_r) +{ + uc_info *uc_inf = f->uc_inf; + ur_info *ur_inf = f->ur_inf; + int *ucindx = f->ucindx; + int nzcnt = uc_inf[c].nzcnt; + int cbeg = uc_inf[c].cbeg; + EGlpNum_t num_tmp[2]; + int bestnz = -1; + int i; + int r; + + EGlpNumInitVar (num_tmp[0]); + EGlpNumInitVar (num_tmp[1]); + + *p_r = -1; + for (i = 0; i < nzcnt; i++) + { + r = ucindx[cbeg + i]; + if((bestnz == -1 || ur_inf[r].pivcnt < bestnz)) + { + find_coef (f, r, c, num_tmp); + if(EGlpNumIsLessZero(num_tmp[0])) + EGlpNumSign (num_tmp[0]); + EGlpNumCopy (num_tmp[1], f->partial_cur); + EGlpNumMultTo (num_tmp[1], ur_inf[r].max); + if(EGlpNumIsLeq (num_tmp[1], num_tmp[0])) + { + bestnz = ur_inf[r].pivcnt; + *p_r = r; + } + } + } + EGlpNumClearVar (num_tmp[0]); + EGlpNumClearVar (num_tmp[1]); +} + +static void find_pivot_row ( + factor_work * f, + int r, + int *p_c) +{ + uc_info *uc_inf = f->uc_inf; + ur_info *ur_inf = f->ur_inf; + int *urindx = f->urindx; + EGlpNum_t *urcoef = f->urcoef; + int pivcnt = ur_inf[r].pivcnt; + int rbeg = ur_inf[r].rbeg; + EGlpNum_t thresh[2]; + int bestnz = -1; + int i; + int c; + + EGlpNumInitVar (thresh[0]); + EGlpNumInitVar (thresh[1]); + EGlpNumCopy (thresh[0], f->partial_cur); + EGlpNumMultTo (thresh[0], ur_inf[r].max); + *p_c = -1; + for (i = 0; i < pivcnt; i++) + { + c = urindx[rbeg + i]; + if ((bestnz == -1 || uc_inf[c].nzcnt < bestnz)) + { + EGlpNumCopyAbs (thresh[1], urcoef[rbeg + i]); + if(EGlpNumIsLeq (thresh[0], thresh[1])) + { + bestnz = uc_inf[c].nzcnt; + *p_c = c; + } + } + } + EGlpNumClearVar (thresh[0]); + EGlpNumClearVar (thresh[1]); +} + +static int find_pivot ( + factor_work * f, + int *p_r, + int *p_c) +{ + uc_info *uc_inf = f->uc_inf; + ur_info *ur_inf = f->ur_inf; + int dim = f->dim; + int max_k = f->max_k; + int p = f->p; + int c; + int r; + int mm = 0; + int n = 0; + int m; + int k = 2; + + if (uc_inf[dim + 1].next != dim + 1) + { + c = uc_inf[dim + 1].next; + r = f->ucindx[uc_inf[c].cbeg]; + *p_c = c; + *p_r = r; + return 0; + } + else if (ur_inf[dim + 1].next != dim + 1) + { + r = ur_inf[dim + 1].next; + c = f->urindx[ur_inf[r].rbeg]; + *p_c = c; + *p_r = r; + return 0; + } + *p_r = -1; + *p_c = -1; + for (; k <= max_k && (mm == 0 || mm > (k - 1) * (k - 1)); k++) + { + if (uc_inf[dim + k].next != dim + k) + { + for (c = uc_inf[dim + k].next; c != dim + k; c = uc_inf[c].next) + { + find_pivot_column (f, c, &r); + if (r >= 0) + { + m = (uc_inf[c].nzcnt - 1) * (ur_inf[r].pivcnt - 1); + if (mm == 0 || m < mm) + { + mm = m; + *p_c = c; + *p_r = r; + if (mm <= (k - 1) * (k - 1)) + { + return 0; + } + } + } + else + { + c = uc_inf[c].prev; + disable_col (f, uc_inf[c].next); + } + n++; + if (n >= p && mm != 0) + { + return 0; + } + } + } + + if (ur_inf[dim + k].next != dim + k) + { + for (r = ur_inf[dim + k].next; r != dim + k; r = ur_inf[r].next) + { + find_pivot_row (f, r, &c); + if (c >= 0) + { + m = (uc_inf[c].nzcnt - 1) * (ur_inf[r].pivcnt - 1); + if (mm == 0 || m < mm) + { + mm = m; + *p_c = c; + *p_r = r; + if (mm <= k * (k - 1)) + { + return 0; + } + } + } + n++; + if (n >= p && mm != 0) + { + return 0; + } + } + } + } + if (mm != 0) + { + return 0; + } + else + { + //fprintf (stderr, "No acceptable pivot found\n"); + return E_NO_PIVOT; + } +} + +static int create_factor_space ( + factor_work * f) +{ + uc_info *uc_inf = f->uc_inf; + ur_info *ur_inf = f->ur_inf; + int dim = f->dim; + int nzcnt; + int i; + int rval; + + nzcnt = 0; + for (i = 0; i < dim; i++) + { + nzcnt += ur_inf[i].nzcnt; + } + + if (f->ucindx == 0) + { + f->uc_space = nzcnt * f->uc_space_mul; + ILL_SAFE_MALLOC (f->ucindx, f->uc_space + 1, int); + } + + if (f->urindx == 0 || f->urcoef == 0) + { + ILL_IFFREE (f->urindx, int); + + EGlpNumFreeArray (f->urcoef); + f->ur_space = nzcnt * f->ur_space_mul; + ILL_SAFE_MALLOC (f->urindx, f->ur_space + 1, int); + + f->urcoef = EGlpNumAllocArray (f->ur_space); + } + + if (f->lcindx == 0 || f->lccoef == 0) + { + ILL_IFFREE (f->lcindx, int); + + EGlpNumFreeArray (f->lccoef); + f->lc_space = nzcnt * f->lc_space_mul; + ILL_SAFE_MALLOC (f->lcindx, f->lc_space, int); + + f->lccoef = EGlpNumAllocArray (f->lc_space); + } + + nzcnt = 0; + for (i = 0; i < dim; i++) + { + ur_inf[i].rbeg = nzcnt; + nzcnt += ur_inf[i].nzcnt; + ur_inf[i].nzcnt = ur_inf[i].rbeg; + } + f->ur_freebeg = nzcnt; + + nzcnt = 0; + for (i = 0; i < dim; i++) + { + uc_inf[i].cbeg = nzcnt; + nzcnt += uc_inf[i].nzcnt; + uc_inf[i].nzcnt = uc_inf[i].cbeg; + } + f->uc_freebeg = nzcnt; + + f->lc_freebeg = 0; + + rval = 0; +CLEANUP: + EG_RETURN (rval); +} + +static int init_matrix ( + factor_work * f, + int *basis, + int *cbeg, + int *clen, + int *in_ucindx, + EGlpNum_t * in_uccoef) +{ + uc_info *uc_inf = f->uc_inf; + ur_info *ur_inf = f->ur_inf; + int dim = f->dim; + int max_k = f->max_k; + int *ucindx; + int *urindx; + EGlpNum_t *urcoef; + int nzcnt; + int beg; + int i; + int j; + int r; + int rval = 0; + EGlpNum_t v; + EGlpNum_t max; + + EGlpNumInitVar (v); + EGlpNumInitVar (max); + + for (i = 0; i < dim; i++) + { + ur_inf[i].nzcnt = 0; + } + for (i = 0; i < dim; i++) + { + nzcnt = clen[basis[i]]; + beg = cbeg[basis[i]]; + uc_inf[i].nzcnt = nzcnt; + for (j = 0; j < nzcnt; j++) + { + r = in_ucindx[beg + j]; + ur_inf[r].nzcnt++; + } + } + + rval = create_factor_space (f); + CHECKRVALG (rval, CLEANUP); + + urindx = f->urindx; + ucindx = f->ucindx; + urcoef = f->urcoef; + + for (i = 0; i < dim; i++) + { + nzcnt = clen[basis[i]]; + beg = cbeg[basis[i]]; + for (j = 0; j < nzcnt; j++) + { + EGlpNumCopy (v, in_uccoef[beg + j]); + if (!(EGlpNumIsNeqZero (v, f->fzero_tol))) + continue; + r = in_ucindx[beg + j]; + ucindx[uc_inf[i].nzcnt++] = r; + urindx[ur_inf[r].nzcnt] = i; + EGlpNumCopy (urcoef[ur_inf[r].nzcnt], v); + ur_inf[r].nzcnt++; + } + } + + for (i = 0; i < dim; i++) + { + uc_inf[i].nzcnt -= uc_inf[i].cbeg; + ur_inf[i].nzcnt -= ur_inf[i].rbeg; + } + + j = f->uc_space; + for (i = f->uc_freebeg; i < j; i++) + { + ucindx[i] = -1; + } + ucindx[j] = 0; + + j = f->ur_space; + for (i = f->ur_freebeg; i < j; i++) + { + urindx[i] = -1; + } + urindx[j] = 0; + + for (i = 0; i < dim; i++) + { + nzcnt = ur_inf[i].nzcnt; + ur_inf[i].pivcnt = nzcnt; + beg = ur_inf[i].rbeg; + EGlpNumZero (max); + for (j = 0; j < nzcnt; j++) + { + EGlpNumSetToMaxAbs (max, urcoef[beg + j]); + } + EGlpNumCopy (ur_inf[i].max, max); + } + + for (i = 0; i <= max_k; i++) + { + ur_inf[dim + i].next = dim + i; + ur_inf[dim + i].prev = dim + i; + uc_inf[dim + i].next = dim + i; + uc_inf[dim + i].prev = dim + i; + } + + for (i = 0; i < dim; i++) + { + nzcnt = uc_inf[i].nzcnt; + if (nzcnt >= max_k) + nzcnt = max_k; + uc_inf[i].next = uc_inf[dim + nzcnt].next; + uc_inf[i].prev = dim + nzcnt; + uc_inf[dim + nzcnt].next = i; + uc_inf[uc_inf[i].next].prev = i; + + nzcnt = ur_inf[i].pivcnt; + if (nzcnt >= max_k) + nzcnt = max_k; + ur_inf[i].next = ur_inf[dim + nzcnt].next; + ur_inf[i].prev = dim + nzcnt; + ur_inf[dim + nzcnt].next = i; + ur_inf[ur_inf[i].next].prev = i; + } + +#ifdef TRACK_FACTOR + EGlpNumZero (max); + nzcnt = 0; + for (i = 0; i < dim; i++) + { + if (EGlpNumIsLess (max, ur_inf[i].max)) + EGlpNumCopy (max, ur_inf[i].max); + nzcnt += ur_inf[i].nzcnt; + } + + EGlpNumCopy (f->maxelem_orig, max); + f->nzcnt_orig = nzcnt; + EGlpNumCopy (f->maxelem_factor, f->maxelem_orig); + f->nzcnt_factor = f->nzcnt_orig; +#endif /* TRACK_FACTOR */ + + /* sentinal for column space */ + ucindx[f->uc_space] = 0; + + clear_work (f); + +CLEANUP: + EGlpNumClearVar (max); + EGlpNumClearVar (v); + EG_RETURN (rval); +} + +static int build_iteration_u_data ( + factor_work * f) +{ + int dim = f->dim; + ur_info *ur_inf = f->ur_inf; + uc_info *uc_inf = f->uc_inf; + EGlpNum_t *uccoef = 0; + int *ucindx = 0; + int *urindx = f->urindx; + EGlpNum_t *urcoef = f->urcoef; + int *ucrind = 0; + int *urcind = 0; + int nzcnt; + int beg; + int cbeg; + int cnzcnt; + int uc_space = f->uc_space; + int er_space; + int i; + int j; + int k; + int rval; + + nzcnt = 0; + for (i = 0; i < dim; i++) + { + nzcnt += ur_inf[i].nzcnt; + } + +#ifdef TRACK_FACTOR + f->nzcnt_factor = nzcnt; +#endif /* TRACK_FACTOR */ + + EGlpNumFreeArray (f->uccoef); + uccoef = EGlpNumAllocArray (nzcnt); + f->uccoef = uccoef; + + ILL_IFFREE (f->ucrind, int); + ILL_SAFE_MALLOC (ucrind, nzcnt, int); + + f->ucrind = ucrind; + + ILL_IFFREE (f->urcind, int); + ILL_SAFE_MALLOC (urcind, f->ur_space, int); + + f->urcind = urcind; + + if (uc_space < nzcnt) + { + ILL_IFFREE (f->ucindx, int); + ILL_SAFE_MALLOC (f->ucindx, nzcnt + 1, int); + } + f->uc_space = nzcnt; + uc_space = nzcnt; + ucindx = f->ucindx; + + for (i = 0; i < dim; i++) + { + uc_inf[i].nzcnt = 0; + } + + for (i = 0; i < dim; i++) + { + nzcnt = ur_inf[i].nzcnt; + beg = ur_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + uc_inf[urindx[beg + j]].nzcnt++; + } + ur_inf[i].delay = 0; + } + + nzcnt = 0; + for (i = 0; i < dim; i++) + { + uc_inf[i].cbeg = nzcnt; + nzcnt += uc_inf[i].nzcnt; + uc_inf[i].nzcnt = 0; + uc_inf[i].delay = 0; + } + + f->uc_freebeg = nzcnt; + for (i = nzcnt; i < uc_space; i++) + { + ucindx[i] = -1; + } + ucindx[uc_space] = 0; + + for (i = 0; i < dim; i++) + { + nzcnt = ur_inf[i].nzcnt; + beg = ur_inf[i].rbeg; + k = urindx[beg]; + cbeg = uc_inf[k].cbeg; + cnzcnt = uc_inf[k].nzcnt; + if (cnzcnt != 0) + { + ucindx[cbeg + cnzcnt] = ucindx[cbeg]; + EGlpNumCopy (uccoef[cbeg + cnzcnt], uccoef[cbeg]); + ucrind[cbeg + cnzcnt] = ucrind[cbeg]; + urcind[ur_inf[ucindx[cbeg]].rbeg + ucrind[cbeg]] = cnzcnt; + } + ucindx[cbeg] = i; + EGlpNumCopy (uccoef[cbeg], urcoef[beg]); + ucrind[cbeg] = 0; + urcind[beg] = 0; + uc_inf[k].nzcnt = cnzcnt + 1; + for (j = 1; j < nzcnt; j++) + { + k = urindx[beg + j]; + cbeg = uc_inf[k].cbeg; + cnzcnt = uc_inf[k].nzcnt; + ucindx[cbeg + cnzcnt] = i; + EGlpNumCopy (uccoef[cbeg + cnzcnt], urcoef[beg + j]); + ucrind[cbeg + cnzcnt] = j; + urcind[beg + j] = cnzcnt; + uc_inf[k].nzcnt++; + } + } + + for (i = 0; i < dim; i++) + { + f->rrank[f->rperm[i]] = i; + } + + nzcnt = f->ur_space; + + for (i = f->ur_freebeg; i < nzcnt; i++) + { + urindx[i] = -1; + } + urindx[nzcnt] = 0; + + clear_work (f); + + er_space = f->er_space_mul * f->etamax; + ILL_SAFE_MALLOC (f->er_inf, f->etamax, er_info); + ILL_SAFE_MALLOC (f->erindx, er_space, int); + + f->ercoef = EGlpNumAllocArray (er_space); + f->etacnt = 0; + f->er_freebeg = 0; + f->er_space = er_space; + + rval = 0; + +CLEANUP: + EG_RETURN (rval); +} + +static int build_iteration_l_data ( + factor_work * f) +{ + int dim = f->dim; + lc_info *lc_inf = f->lc_inf; + lr_info *lr_inf = f->lr_inf; + EGlpNum_t *lrcoef = 0; + int *lrindx = 0; + EGlpNum_t *lccoef = f->lccoef; + int *lcindx = f->lcindx; + int nzcnt; + int beg; + int rnzcnt; + int rbeg; + int i; + int j; + int k; + int c; + int rval; + + nzcnt = 0; + for (i = 0; i < dim; i++) + { + nzcnt += lc_inf[i].nzcnt; + lr_inf[i].nzcnt = 0; + lr_inf[i].delay = 0; + lc_inf[lc_inf[i].c].crank = i; + } + + EGlpNumFreeArray (f->lrcoef); + if (nzcnt) + { + lrcoef = EGlpNumAllocArray (nzcnt); + f->lrcoef = lrcoef; + } + + ILL_IFFREE (f->lrindx, int); + ILL_SAFE_MALLOC (lrindx, nzcnt + 1, int); + + f->lrindx = lrindx; + + for (i = 0; i < dim; i++) + { + nzcnt = lc_inf[i].nzcnt; + beg = lc_inf[i].cbeg; + lc_inf[i].delay = 0; + for (j = 0; j < nzcnt; j++) + { + lr_inf[lc_inf[lcindx[beg + j]].crank].nzcnt++; + } + } + + nzcnt = 0; + for (i = 0; i < dim; i++) + { + lr_inf[i].rbeg = nzcnt; + nzcnt += lr_inf[i].nzcnt; + lr_inf[i].nzcnt = 0; + lr_inf[i].r = lc_inf[i].c; + lr_inf[lr_inf[i].r].rrank = i; + } + + for (i = 0; i < dim; i++) + { + nzcnt = lc_inf[i].nzcnt; + beg = lc_inf[i].cbeg; + c = lc_inf[i].c; + for (j = 0; j < nzcnt; j++) + { + k = lc_inf[lcindx[beg + j]].crank; + rbeg = lr_inf[k].rbeg; + rnzcnt = lr_inf[k].nzcnt; + lrindx[rbeg + rnzcnt] = c; + EGlpNumCopy (lrcoef[rbeg + rnzcnt], lccoef[beg + j]); + lr_inf[k].nzcnt++; + } + } + +#ifdef TRACK_FACTOR + nzcnt = f->nzcnt_factor; + for (i = 0; i < dim; i++) + { + nzcnt += lc_inf[i].nzcnt; + } + f->nzcnt_factor = nzcnt; + + EGlpNumCopy (f->maxelem_cur, f->maxelem_factor); + f->nzcnt_cur = f->nzcnt_factor; + +/* + dump_factor_stats (f); + printf ("orig max %e nzcnt %d\n", f->maxelem_orig, f->nzcnt_orig); + printf ("f maxelem %e nzcnt %d\n", f->maxelem_cur, f->nzcnt_cur); +*/ +#endif /* TRACK_FACTOR */ + + rval = 0; + +CLEANUP: + EG_RETURN (rval); +} + +static int handle_singularity ( + factor_work * f) +{ + int rval = 0; + int nsing; + int *singr = 0; + int *singc = 0; + int i; + + if (f->p_nsing == 0 || f->p_singr == 0 || f->p_singc == 0) + { + fprintf (stderr, "singular basis, but no place for singularity data\n"); + return E_SING_NO_DATA; + } + + nsing = f->nstages - f->stage; + ILL_SAFE_MALLOC (singr, nsing, int); + ILL_SAFE_MALLOC (singc, nsing, int); + + for (i = f->stage; i < f->nstages; i++) + { + singr[i - f->stage] = f->rperm[i]; + singc[i - f->stage] = f->cperm[i]; + } + *f->p_nsing = nsing; + *f->p_singr = singr; + *f->p_singc = singc; + singr = 0; + singc = 0; + +CLEANUP: + ILL_IFFREE (singr, int); + ILL_IFFREE (singc, int); + + EG_RETURN (rval); +} + +static int dense_build_matrix ( + factor_work * f) +{ + EGlpNum_t *dmat = 0; + int stage = f->stage; + int drows = f->nstages - stage; + int dcols = f->dim - stage; + int dsize = drows * dcols; + int *crank = f->crank; + EGlpNum_t *urcoef = f->urcoef; + int *urindx = f->urindx; + int nzcnt; + int beg; + int i; + int r; + int j; + int rval = 0; + + dmat = EGlpNumAllocArray (dsize); + + for (i = 0; i < dsize; i++) + EGlpNumZero (dmat[i]); + + for (i = 0; i < drows; i++) + { + r = f->rperm[i + stage]; + nzcnt = f->ur_inf[r].nzcnt; + beg = f->ur_inf[r].rbeg; + for (j = 0; j < nzcnt; j++) + { + EGlpNumCopy (dmat[i * dcols - stage + crank[urindx[beg + j]]], + urcoef[beg + j]); + } + } + + f->drows = drows; + f->dcols = dcols; + f->dense_base = f->stage; + f->dmat = dmat; + dmat = 0; + +//CLEANUP: + EGlpNumFreeArray (dmat); + EG_RETURN (rval); +} + +static int dense_find_pivot ( + factor_work * f, + int *p_r, + int *p_c) +{ + int dcols = f->dcols; + int drows = f->drows; + EGlpNum_t *dmat = f->dmat; + int dense_base = f->dense_base; + int s = f->stage - dense_base; + ur_info *ur_inf = f->ur_inf; + int *rperm = f->rperm; + EGlpNum_t maxval; + int max_r; + int max_c; + int i; + + EGlpNumInitVar (maxval); + EGlpNumZero (maxval); + max_r = -1; + for (i = s; i < drows; i++) + { + if (EGlpNumIsLess (maxval, ur_inf[rperm[dense_base + i]].max)) + { + EGlpNumCopy (maxval, ur_inf[rperm[dense_base + i]].max); + max_r = i; + } + } + if (max_r == -1) + { + return E_NO_PIVOT; + } + + EGlpNumZero (maxval); + max_c = -1; + for (i = s; i < drows; i++) + { + EGlpNumSetToMaxAbsAndDo (maxval, dmat[max_r * dcols + i], max_c = i); + } + if (max_c == -1) + { + return E_NO_PIVOT; + } + *p_r = max_r; + *p_c = max_c; + + EGlpNumClearVar (maxval); + return 0; +} + +static void dense_swap ( + factor_work * f, + int r, + int c) +{ + int dcols = f->dcols; + int drows = f->drows; + EGlpNum_t *dmat = f->dmat; + int dense_base = f->dense_base; + int s = f->stage - dense_base; + int i; + EGlpNum_t v; + + EGlpNumInitVar (v); + + if (r != s) + { + ILL_SWAP (f->rperm[dense_base + s], f->rperm[dense_base + r], i); + f->rrank[f->rperm[dense_base + s]] = dense_base + s; + f->rrank[f->rperm[dense_base + r]] = dense_base + r; + for (i = 0; i < dcols; i++) + { + EGLPNUM_SWAP (dmat[s * dcols + i], dmat[r * dcols + i], v); + } + } + if (c != s) + { + ILL_SWAP (f->cperm[dense_base + s], f->cperm[dense_base + c], i); + f->crank[f->cperm[dense_base + s]] = dense_base + s; + f->crank[f->cperm[dense_base + c]] = dense_base + c; + for (i = 0; i < drows; i++) + { + EGLPNUM_SWAP (dmat[i * dcols + s], dmat[i * dcols + c], v); + } + } + EGlpNumClearVar (v); +} + +static void dense_elim ( + factor_work * f, + int r, + int c) +{ + int dcols = f->dcols; + int drows = f->drows; + EGlpNum_t *dmat = f->dmat; + int dense_base = f->dense_base; + int s = f->stage - dense_base; + ur_info *ur_inf = f->ur_inf; + int *rperm = f->rperm; + int i; + int j; + EGlpNum_t pivval; + EGlpNum_t max; + EGlpNum_t v; + EGlpNum_t w; + +#ifdef TRACK_FACTOR + EGlpNum_t maxelem_factor; + + EGlpNumInitVar (maxelem_factor); + EGlpNumCopy (maxelem_factor, f->maxelem_factor); +#endif + EGlpNumInitVar (pivval); + EGlpNumInitVar (max); + EGlpNumInitVar (v); + EGlpNumInitVar (w); + + dense_swap (f, r, c); + f->stage++; + EGlpNumCopyFrac (pivval, oneLpNum, dmat[s * dcols + s]); + for (i = s + 1; i < drows; i++) + { + EGlpNumCopy (v, dmat[i * dcols + s]); + if (EGlpNumIsNeqqZero (v)) + { + EGlpNumMultTo (v, pivval); + if (EGlpNumIsNeqZero (v, f->fzero_tol)) + { + EGlpNumCopy (dmat[i * dcols + s], v); +#ifdef TRACK_FACTOR + EGlpNumSetToMaxAbs (maxelem_factor, v); +#endif + EGlpNumZero (max); + for (j = s + 1; j < drows; j++) + { + EGlpNumCopy (w, dmat[i * dcols + j]); + EGlpNumSubInnProdTo (w, v, dmat[s * dcols + j]); + EGlpNumCopy (dmat[i * dcols + j], w); + EGlpNumSetToMaxAbs (max, w); + } + for (j = drows; j < dcols; j++) + { + EGlpNumCopy (w, dmat[i * dcols + j]); + EGlpNumSubInnProdTo (w, v, dmat[s * dcols + j]); + EGlpNumCopy (dmat[i * dcols + j], w); + } + EGlpNumCopy (ur_inf[rperm[dense_base + i]].max, max); +#ifdef TRACK_FACTOR + if (EGlpNumIsLess (maxelem_factor, max)) + EGlpNumCopy (maxelem_factor, max); +#endif + } + else + { + EGlpNumZero (dmat[i * dcols + s]); + } + } + } +#ifdef TRACK_FACTOR + EGlpNumCopy (f->maxelem_factor, maxelem_factor); + EGlpNumClearVar (maxelem_factor); +#endif + EGlpNumClearVar (pivval); + EGlpNumClearVar (max); + EGlpNumClearVar (v); + EGlpNumClearVar (w); +} + +static int dense_replace_row ( + factor_work * f, + int i) +{ + int dcols = f->dcols; + int dense_base = f->dense_base; + EGlpNum_t *dmat = f->dmat + i * dcols; + EGlpNum_t *urcoef; + ur_info *ur_inf = f->ur_inf; + int *cperm = f->cperm; + int r = f->rperm[dense_base + i]; + int *urindx; + int nzcnt; + int beg; + int j; + int rval = 0; + + nzcnt = 0; + for (j = i; j < dcols; j++) + { + if (EGlpNumIsNeqZero (dmat[j], f->fzero_tol)) + { + nzcnt++; + } + } + if (nzcnt > ur_inf[r].nzcnt) + { + if (ur_inf[r].rbeg + ur_inf[r].nzcnt == f->ur_freebeg) + { + f->ur_freebeg = ur_inf[r].rbeg; + } + ur_inf[r].nzcnt = 0; + if (f->ur_freebeg + nzcnt > f->ur_space) + { + rval = make_ur_space (f, nzcnt); + CHECKRVALG (rval, CLEANUP); + } + ur_inf[r].rbeg = f->ur_freebeg; + f->ur_freebeg += nzcnt; + } + beg = ur_inf[r].rbeg; + urcoef = f->urcoef; + urindx = f->urindx; + for (j = i; j < dcols; j++) + { + if (EGlpNumIsNeqZero (dmat[j], f->fzero_tol)) + { + EGlpNumCopy (urcoef[beg], dmat[j]); + urindx[beg] = cperm[dense_base + j]; + beg++; + } + } + ur_inf[r].nzcnt = beg - ur_inf[r].rbeg; +CLEANUP: + EG_RETURN (rval); +} + +static int dense_create_col ( + factor_work * f, + int i) +{ + int dcols = f->dcols; + int drows = f->drows; + int dense_base = f->dense_base; + EGlpNum_t *dmat = f->dmat; + EGlpNum_t *lccoef; + lc_info *lc_inf = f->lc_inf; + int *rperm = f->rperm; + int *lcindx; + int nzcnt; + int beg; + int j; + int rval = 0; + + nzcnt = 0; + for (j = i + 1; j < drows; j++) + { + if (EGlpNumIsNeqZero (dmat[j * dcols + i], f->fzero_tol)) + { + nzcnt++; + } + } + + if (f->lc_freebeg + nzcnt >= f->lc_space) + { + rval = make_lc_space (f, nzcnt); + CHECKRVALG (rval, CLEANUP); + } + beg = f->lc_freebeg; + lc_inf[dense_base + i].cbeg = beg; + lc_inf[dense_base + i].c = rperm[dense_base + i]; + lcindx = f->lcindx; + lccoef = f->lccoef; + + for (j = i + 1; j < drows; j++) + { + if (EGlpNumIsNeqZero (dmat[j * dcols + i], f->fzero_tol)) + { + EGlpNumCopy (lccoef[beg], dmat[j * dcols + i]); + lcindx[beg] = rperm[dense_base + j]; + beg++; + } + } + lc_inf[dense_base + i].nzcnt = beg - lc_inf[dense_base + i].cbeg; + f->lc_freebeg = beg; +CLEANUP: + EG_RETURN (rval); +} + +static int dense_replace ( + factor_work * f) +{ + int drows = f->drows; + int rval = 0; + int i; + + for (i = 0; i < drows; i++) + { + rval = dense_replace_row (f, i); + CHECKRVALG (rval, CLEANUP); + rval = dense_create_col (f, i); + CHECKRVALG (rval, CLEANUP); + } + EGlpNumFreeArray (f->dmat); + f->drows = 0; + f->dcols = 0; +CLEANUP: + EG_RETURN (rval); +} + +static int dense_factor ( + factor_work * f) +{ + int r; + int c; + int rval = 0; + +#ifdef TRACK_FACTOR +#ifdef NOTICE_BLOWUP + double tmpsize; +#endif +#endif + +/* + printf ("dense kernel, %d rows, %d cols...\n", f->nstages - f->stage, + f->dim - f->stage); + fflush (stdout); +*/ + + rval = dense_build_matrix (f); + CHECKRVALG (rval, CLEANUP); + +#ifdef FACTOR_DEBUG +#if (FACTOR_DEBUG+0>1) + MESSAGE (0,"before Dense ILLfactor"); + dump_matrix (f, 1); +#endif +#endif + + while (f->stage < f->nstages) + { + r = f->stage - f->dense_base; + rval = dense_find_pivot (f, &r, &c); + if (rval == E_NO_PIVOT) + { + rval = handle_singularity (f); + CHECKRVALG (rval, CLEANUP); + return E_SINGULAR_INTERNAL; + } + else + { + CHECKRVALG (rval, CLEANUP); + } +#ifdef FACTOR_DEBUG +#if (FACTOR_DEBUG+0>2) + MESSAGE (0,"dense pivot elem: %d %d", r, c); +#endif +#endif /* FACTOR_DEBUG */ + dense_elim (f, r, c); + +#ifdef TRACK_FACTOR +#ifdef NOTICE_BLOWUP + tmpsize = f->maxmult * EGlpNumToLf (f->maxelem_orig); + if (tmpsize < EGlpNumToLf (f->maxelem_factor) && + EGlpNumIsLess (f->partial_cur, oneLpNum)) + { + return E_FACTOR_BLOWUP; + } +#endif /* NOTICE_BLOWUP */ +#endif /* TRACK_FACTOR */ + +#ifdef FACTOR_DEBUG +#if (FACTOR_DEBUG+0>1) + MESSAGE (0,"After dense pivot stage %d (%d) of %d (%d)", + f->stage - f->dense_base, f->stage, + f->nstages - f->dense_base, f->nstages); +#endif +#if (FACTOR_DEBUG+0>2) + dump_matrix (f, 1); +#endif +#endif /* FACTOR_DEBUG */ + } + +#ifdef FACTOR_DEBUG + MESSAGE (0,"After dense ILLfactor:\n"); + dump_matrix (f, 0); +#endif /* FACTOR_DEBUG */ + + rval = dense_replace (f); + CHECKRVALG (rval, CLEANUP); + +#ifdef FACTOR_DEBUG + MESSAGE (0,"After replacement:\n"); + dump_matrix (f, 0); +#endif /* FACTOR_DEBUG */ + +CLEANUP: + EG_RETURN (rval); +} + +#ifdef RECORD +EGioFile_t *fsave = 0; +int fsavecnt = 0; +#endif /* RECORD */ + +static int ILLfactor_try ( + factor_work * f, + int *basis, + int *cbeg, + int *clen, + int *cindx, + EGlpNum_t * ccoef) +{ + int rval = 0; + int r; + int c; + +#ifdef TRACK_FACTOR +#ifdef NOTICE_BLOWUP + EGlpNum_t tmpsize; + + EGlpNumInitVar (tmpsize); +#endif +#endif + +#ifdef RECORD + { + int ncol = 0; + int nzcnt = 0; + int dim = f->dim; + int i; + int j; + char fnambuf[40]; + + for (i = 0; i < dim; i++) + { + if (basis[i] > ncol) + ncol = basis[i]; + } + ncol++; + for (i = 0; i < ncol; i++) + { + nzcnt += clen[i]; + } + if (fsave) + EGioClose (fsave); + #if HAVE_ZLIB + sprintf (fnambuf, "prob.mat.%d.gz", fsavecnt); + #elif HAVE_BZLIB + sprintf (fnambuf, "prob.mat.%d.bz2", fsavecnt); + #else + sprintf (fnambuf, "prob.mat.%d", fsavecnt); + #endif + fsavecnt++; + fsave = EGioOpen (fnambuf, "w"); + EGioPrintf (fsave, "%d %d %d\n", f->dim, ncol, nzcnt); + for (i = 0; i < dim; i++) + { + EGioPrintf (fsave, "%d ", basis[i]); + } + EGioPrintf (fsave, "\n"); + for (i = 0; i < ncol; i++) + { + EGioPrintf (fsave, "%d", clen[i]); + for (j = 0; j < clen[i]; j++) + { + EGioPrintf (fsave, " %d %.16lg", cindx[cbeg[i] + j], + EGlpNumToLf (ccoef[cbeg[i] + j])); + } + EGioPrintf (fsave, "\n"); + } + EGioPrintf (fsave, "\n"); + EGioFlush (fsave); + } +#endif /* RECORD */ + + rval = init_matrix (f, basis, cbeg, clen, cindx, ccoef); + CHECKRVALG (rval, CLEANUP); + + f->stage = 0; + f->nstages = f->dim; + +#ifdef FACTOR_DEBUG + MESSAGE (0,"Initial matrix:"); +#if (FACTOR_DEBUG+0>1) + dump_matrix (f, 0); +#endif +#endif /* FACTOR_DEBUG */ +#ifdef FACTOR_STATS + printf ("Initial matrix: "); + dump_factor_stats (f); +#endif /* FACTOR_STATS */ + + while (f->stage < f->nstages) + { + rval = find_pivot (f, &r, &c); + if (rval == E_NO_PIVOT) + { + rval = handle_singularity (f); + CHECKRVALG (rval, CLEANUP); + return 0; + } + else + { + CHECKRVALG (rval, CLEANUP); + } + if (f->ur_inf[r].pivcnt > f->dense_fract * (f->nstages - f->stage) && + f->uc_inf[c].nzcnt > f->dense_fract * (f->nstages - f->stage) && + f->nstages - f->stage > f->dense_min) + { + rval = dense_factor (f); + if (rval == E_SINGULAR_INTERNAL) + return 0; + if (rval) + return rval; + break; + } +#ifdef FACTOR_DEBUG + MESSAGE (0,"pivot elem: %d %d", r, c); +#endif /* FACTOR_DEBUG */ + rval = elim (f, r, c); + CHECKRVALG (rval, CLEANUP); + +#ifdef TRACK_FACTOR +#ifdef NOTICE_BLOWUP + EGlpNumSet (tmpsize, f->maxmult); + EGlpNumMultTo (tmpsize, f->maxelem_orig); + if (EGlpNumIsLess (tmpsize, f->maxelem_factor) && + EGlpNumIsLess (f->partial_cur, oneLpNum)) + { + return E_FACTOR_BLOWUP; + } +#endif /* NOTICE_BLOWUP */ +#endif /* TRACK_FACTOR */ + +#ifdef FACTOR_DEBUG +#if (FACTOR_DEBUG+0>3) + MESSAGE (0,"After pivot stage %d of %d", f->stage, f->nstages); + dump_matrix (f, 0); +#endif +#endif /* FACTOR_DEBUG */ + } + + rval = build_iteration_u_data (f); + CHECKRVALG (rval, CLEANUP); + + rval = build_iteration_l_data (f); + CHECKRVALG (rval, CLEANUP); + +#ifdef TRACK_FACTOR +#ifdef NOTICE_BLOWUP + EGlpNumSet (tmpsize, f->minmult); + EGlpNumMultTo (tmpsize, f->maxelem_orig); + if (EGlpNumIsLess (f->maxelem_factor, tmpsize) && + EGlpNumIsLess (f->partial_tol, f->partial_cur)) + { + if (EGlpNumIsGreaDbl (f->partial_cur, 0.5)) + { + EGlpNumSet (f->partial_cur, 0.5); + } + else if (EGlpNumIsGreaDbl (f->partial_cur, 0.25)) + { + EGlpNumSet (f->partial_cur, 0.25); + } + else if (EGlpNumIsGreaDbl (f->partial_cur, 0.1)) + { + EGlpNumSet (f->partial_cur, 0.1); + } + else + { + EGlpNumDivUiTo (f->partial_cur, 10); + } + if (EGlpNumIsLess (f->partial_cur, f->partial_tol)) + { + EGlpNumCopy (f->partial_cur, f->partial_tol); + } +/* Bico - comment out for dist + fprintf (stderr, "factor good, lowering partial tolerance to %.2f\n", + f->partial_cur); +*/ + } +#endif /* NOTICE_BLOWUP */ +#endif /* TRACK_FACTOR */ + +#ifdef FACTOR_DEBUG + MESSAGE(0,"Factored matrix:"); +#if (FACTOR_DEBUG+0>1) + dump_matrix (f, 0); +#endif +#endif /* FACTOR_DEBUG */ + +#ifdef FACTOR_STATS + printf ("Factored matrix: "); + dump_factor_stats (f); +#endif /* FACTOR_STATS */ +CLEANUP: +#ifdef TRACK_FACTOR +#ifdef NOTICE_BLOWUP + EGlpNumClearVar (tmpsize); +#endif +#endif + EG_RETURN (rval); +} + +int ILLfactor ( + factor_work * f, + int *basis, + int *cbeg, + int *clen, + int *cindx, + EGlpNum_t * ccoef, + int *p_nsing, + int **p_singr, + int **p_singc) +{ + int rval; + + f->p_nsing = p_nsing; + f->p_singr = p_singr; + f->p_singc = p_singc; + *p_nsing = 0; + +AGAIN: + rval = ILLfactor_try (f, basis, cbeg, clen, cindx, ccoef); + if (rval == E_FACTOR_BLOWUP) + { + if (EGlpNumIsLessDbl (f->partial_cur, 0.1)) + { + EGlpNumMultUiTo (f->partial_cur, 10); + } + else if (EGlpNumIsLessDbl (f->partial_cur, 0.25)) + { + EGlpNumSet (f->partial_cur, 0.25); + } + else if (EGlpNumIsLessDbl (f->partial_cur, 0.5)) + { + EGlpNumSet (f->partial_cur, 0.5); + } + else if (EGlpNumIsLess (f->partial_cur, oneLpNum)) + { + EGlpNumOne (f->partial_cur); + } + else + { + EG_RETURN (rval); + } +/* Bico - comment out for dist + fprintf (stderr, "factor blowup, changing partial tolerance to %.2f\n", + f->partial_cur); +*/ + goto AGAIN; + } + EG_RETURN (rval); +} + +static void ILLfactor_ftranl ( + factor_work * f, + EGlpNum_t * a) +{ + int *lcindx = f->lcindx; + lc_info *lc_inf = f->lc_inf; + EGlpNum_t *lccoef = f->lccoef; + int dim = f->dim; + int beg; + int nzcnt; + int i; + int j; + EGlpNum_t v; + + EGlpNumInitVar (v); + + for (i = 0; i < dim; i++) + { + EGlpNumCopy (v, a[lc_inf[i].c]); + if (EGlpNumIsNeqqZero (v)) + { + nzcnt = lc_inf[i].nzcnt; + beg = lc_inf[i].cbeg; + for (j = 0; j < nzcnt; j++) + { + EGlpNumSubInnProdTo (a[lcindx[beg + j]], v, lccoef[beg + j]); + } + } +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 > 1) + fpritf (stderr,"ILLfactor_ftran a after l %d:", i); + for (j = 0; j < f->dim; j++) + { + fprintf (stderr," %.3f", EGlpNumToLf (a[j])); + } + MESSAGE(0," "); +#endif +#endif /* SOLVE_DEBUG */ + } +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 <= 1) + printf ("ILLfactor_ftran a after l:"); + for (j = 0; j < f->dim; j++) + { + printf (" %.3f", EGlpNumToLf (a[j])); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumClearVar (v); +} + +#if 0 +static void ftranl3_delay ( + factor_work * f, + int c) +{ + lc_info *lc_inf = f->lc_inf; + int nzcnt; + int *indx; + int i; + + c = lc_inf[c].crank; + nzcnt = lc_inf[c].nzcnt; + indx = f->lcindx + lc_inf[c].cbeg; + for (i = 0; i < nzcnt; i++) + { + c = indx[i]; + if (lc_inf[c].delay++ == 0) + { + ftranl3_delay (f, c); + } + } +} +#endif + +static void ftranl3_delay2 ( + factor_work * f, + int c) +{ + lc_info *lc_inf = f->lc_inf; + int nzcnt; + int *indx; + int i; + int last; + + do + { + c = lc_inf[c].crank; + nzcnt = lc_inf[c].nzcnt; + indx = f->lcindx + lc_inf[c].cbeg; + last = -1; + for (i = 0; i < nzcnt; i++) + { + c = indx[i]; + if (lc_inf[c].delay++ == 0) + { + if (last >= 0) + { + ftranl3_delay2 (f, last); + } + last = c; + } + } + c = last; + } while (c >= 0); +} + +#if 0 +static void ftranl3_process ( + factor_work * f, + int c, + svector * x) +{ + lc_info *lc_inf = f->lc_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + int i; + EGlpNum_t *coef; + EGlpNum_t v; + + EGlpNumInitVar (v); + + EGlpNumCopy (v, work[c]); + EGlpNumZero (work[c]); + if (EGlpNumIsNeqqZero (v)) + { + x->indx[x->nzcnt] = c; + EGlpNumCopy (x->coef[x->nzcnt], v); + x->nzcnt++; + } + c = lc_inf[c].crank; + nzcnt = lc_inf[c].nzcnt; + indx = f->lcindx + lc_inf[c].cbeg; + coef = f->lccoef + lc_inf[c].cbeg; + for (i = 0; i < nzcnt; i++) + { + c = indx[i]; + EGlpNumSubInnProdTo (work[c], v, coef[i]); + if (--lc_inf[c].delay == 0) + { + ftranl3_process (f, c, x); + } + } + EGlpNumClearVar (v); +} +#endif + +static void ftranl3_process2 ( + factor_work * f, + int c, + svector * x) +{ + lc_info *lc_inf = f->lc_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + EGlpNum_t *coef; + int i; + int last; + EGlpNum_t v; + + EGlpNumInitVar (v); + + do + { + EGlpNumCopy (v, work[c]); + EGlpNumZero (work[c]); + if (EGlpNumIsNeqqZero (v)) + { + x->indx[x->nzcnt] = c; + EGlpNumCopy (x->coef[x->nzcnt], v); + x->nzcnt++; + } + c = lc_inf[c].crank; + nzcnt = lc_inf[c].nzcnt; + indx = f->lcindx + lc_inf[c].cbeg; + coef = f->lccoef + lc_inf[c].cbeg; + last = -1; + for (i = 0; i < nzcnt; i++) + { + c = indx[i]; + EGlpNumSubInnProdTo (work[c], v, coef[i]); + if (--lc_inf[c].delay == 0) + { + if (last >= 0) + { + ftranl3_process2 (f, last, x); + } + last = c; + } + } + c = last; + } while (c >= 0); + EGlpNumClearVar (v); +} + +static void ILLfactor_ftranl3 ( + factor_work * f, + svector * a, + svector * x) +{ + EGlpNum_t *work = f->work_coef; + int anzcnt = a->nzcnt; + int *aindx = a->indx; + EGlpNum_t *acoef = a->coef; + lc_info *lc_inf = f->lc_inf; + int i; + + for (i = 0; i < anzcnt; i++) + { + if (lc_inf[aindx[i]].delay++ == 0) + { + ftranl3_delay2 (f, aindx[i]); + } + EGlpNumCopy (work[aindx[i]], acoef[i]); + } + x->nzcnt = 0; + for (i = 0; i < anzcnt; i++) + { + if (--lc_inf[aindx[i]].delay == 0) + { + ftranl3_process2 (f, aindx[i], x); + } + } +#ifdef SOLVE_DEBUG + printf ("ILLfactor_ftran x after l3:"); + for (i = 0; i < x->nzcnt; i++) + { + printf (" %.3f*%d", EGlpNumToLf (x->coef[i]), x->indx[i]); + } + printf ("\n"); + fflush (stdout); +#endif /* SOLVE_DEBUG */ +} + +static void ILLfactor_ftrane ( + factor_work * f, + EGlpNum_t * a) +{ + int *erindx = f->erindx; + EGlpNum_t *ercoef = f->ercoef; + er_info *er_inf = f->er_inf; + int etacnt = f->etacnt; + int beg; + int nzcnt; + int i; + int j; + EGlpNum_t v; + + EGlpNumInitVar (v); + + for (i = 0; i < etacnt; i++) + { + EGlpNumCopy (v, a[er_inf[i].r]); + nzcnt = er_inf[i].nzcnt; + beg = er_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + EGlpNumSubInnProdTo (v, ercoef[beg + j], a[erindx[beg + j]]); + } + EGlpNumCopy (a[er_inf[i].r], v); +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 > 1) + printf ("ILLfactor_ftran a after eta %d:", i); + for (j = 0; j < f->dim; j++) + { + printf (" %.3f", EGlpNumToLf (a[j])); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + } +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 <= 1) + printf ("ILLfactor_ftran a after eta:"); + for (j = 0; j < f->dim; j++) + { + printf (" %.3f", EGlpNumToLf (a[j])); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumClearVar (v); +} + +static void ILLfactor_ftrane2 ( + factor_work * f, + svector * a) +{ + int *erindx = f->erindx; + EGlpNum_t *ercoef = f->ercoef; + er_info *er_inf = f->er_inf; + int etacnt = f->etacnt; + int beg; + int nzcnt; + int anzcnt = a->nzcnt; + int *aindx = a->indx; + EGlpNum_t *acoef = a->coef; + EGlpNum_t *work_coef = f->work_coef; + int *work_indx = f->work_indx; + int i; + int j; + int r; + EGlpNum_t v; + + EGlpNumInitVar (v); + + for (i = 0; i < anzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + work_indx[aindx[i]] = i + 1; + } + for (i = 0; i < etacnt; i++) + { + r = er_inf[i].r; + EGlpNumCopy (v, work_coef[r]); + nzcnt = er_inf[i].nzcnt; + beg = er_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + EGlpNumSubInnProdTo (v, ercoef[beg + j], work_coef[erindx[beg + j]]); + } + if (EGlpNumIsNeqqZero (v)) + { + EGlpNumCopy (work_coef[r], v); + if (work_indx[r] == 0) + { + EGlpNumCopy (acoef[anzcnt], v); + aindx[anzcnt] = r; + work_indx[r] = anzcnt + 1; + anzcnt++; + } + else + { + EGlpNumCopy (acoef[work_indx[r] - 1], v); + } + } + else + { + EGlpNumZero (work_coef[r]); + if (work_indx[r]) + { + EGlpNumZero (acoef[work_indx[r] - 1]); + } + } +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 > 1) + printf ("ILLfactor_ftran a after eta2 %d:", i); + for (j = 0; j < anzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (acoef[j]), aindx[j]); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + } + i = 0; + while (i < anzcnt) + { + EGlpNumZero (work_coef[aindx[i]]); + work_indx[aindx[i]] = 0; + if (EGlpNumIsNeqZero (acoef[i], f->fzero_tol)) + { + /*if (acoef[i] > fzero_tol || acoef[i] < -fzero_tol) */ + i++; + } + else + { + --anzcnt; + EGlpNumCopy (acoef[i], acoef[anzcnt]); + aindx[i] = aindx[anzcnt]; + } + } + a->nzcnt = anzcnt; + +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 <= 1) + printf ("ILLfactor_ftran a after eta2:"); + for (j = 0; j < anzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (acoef[j]), aindx[j]); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumClearVar (v); +} + +static void ILLfactor_ftranu ( + factor_work * f, + EGlpNum_t * a, + svector * x) +{ + int *ucindx = f->ucindx; + EGlpNum_t *uccoef = f->uccoef; + uc_info *uc_inf = f->uc_inf; + int *cperm = f->cperm; + int *rperm = f->rperm; + int dim = f->dim; + int xnzcnt = 0; + int *xindx = x->indx; + EGlpNum_t *xcoef = x->coef; + int nzcnt; + int beg; + int i; + int j; + EGlpNum_t v; + + EGlpNumInitVar (v); + + for (i = dim - 1; i >= 0; i--) + { + EGlpNumCopy (v, a[rperm[i]]); + if (EGlpNumIsNeqqZero (v)) /*((v = a[rperm[i]]) != 0.0) */ + { + j = cperm[i]; + beg = uc_inf[j].cbeg; + EGlpNumDivTo (v, uccoef[beg]); + if (EGlpNumIsNeqZero (v, f->szero_tol)) + { + /*if (v > szero_tol || v < -szero_tol) */ + xindx[xnzcnt] = j; + EGlpNumCopy (xcoef[xnzcnt], v); + xnzcnt++; + } + nzcnt = uc_inf[j].nzcnt; + for (j = 1; j < nzcnt; j++) + { + EGlpNumSubInnProdTo (a[ucindx[beg + j]], v, uccoef[beg + j]); + } + EGlpNumZero (a[rperm[i]]); + } + } + x->nzcnt = xnzcnt; +#ifdef SOLVE_DEBUG + printf ("ILLfactor_ftran x after u:"); + for (j = 0; j < x->nzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (x->coef[j]), x->indx[j]); + } + printf ("\n"); + fflush (stdout); +#endif /* SOLVE_DEBUG */ + EGlpNumClearVar (v); +} + + +#if 0 +static void ftranu3_delay ( + factor_work * f, + int c) +{ + uc_info *uc_inf = f->uc_inf; + int nzcnt; + int *indx; + int i; + + c = f->cperm[f->rrank[c]]; + nzcnt = uc_inf[c].nzcnt; + indx = f->ucindx + uc_inf[c].cbeg; + for (i = 1; i < nzcnt; i++) + { + c = indx[i]; + if (uc_inf[c].delay++ == 0) + { + ftranu3_delay (f, c); + } + } +} +#endif + +static void ftranu3_delay2 ( + factor_work * f, + int c) +{ + uc_info *uc_inf = f->uc_inf; + int nzcnt; + int *indx; + int i; + int last; + + do + { + c = f->cperm[f->rrank[c]]; + nzcnt = uc_inf[c].nzcnt; + indx = f->ucindx + uc_inf[c].cbeg; + last = -1; + for (i = 1; i < nzcnt; i++) + { + c = indx[i]; + if (uc_inf[c].delay++ == 0) + { + if (last >= 0) + { + ftranu3_delay2 (f, last); + } + last = c; + } + } + c = last; + } while (c >= 0); +} + +#if 0 +static void ftranu3_process ( + factor_work * f, + int c, + svector * x) +{ + uc_info *uc_inf = f->uc_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + EGlpNum_t *coef; + int i; + EGlpNum_t v; + + EGlpNumInitVar (v); + + EGlpNumCopy (v, work[c]); + EGlpNumZero (work[c]); + c = f->cperm[f->rrank[c]]; + nzcnt = uc_inf[c].nzcnt; + indx = f->ucindx + uc_inf[c].cbeg; + coef = f->uccoef + uc_inf[c].cbeg; + EGlpNumDivTo (v, coef[0]); + if (EGlpNumIsNeqZero (v, f->szero_tol)) + /*if (v > szero_tol || v < -szero_tol) */ + { + x->indx[x->nzcnt] = c; + EGlpNumCopy (x->coef[x->nzcnt], v); + x->nzcnt++; + } + for (i = 1; i < nzcnt; i++) + { + c = indx[i]; + EGlpNumSubInnProdTo (work[c], v, coef[i]); + if (--uc_inf[c].delay == 0) + { + ftranu3_process (f, c, x); + } + } + EGlpNumClearVar (v); +} +#endif + +static void ftranu3_process2 ( + factor_work * f, + int c, + svector * x) +{ + uc_info *uc_inf = f->uc_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + EGlpNum_t *coef; + int i; + int last; + EGlpNum_t v; + + EGlpNumInitVar (v); + + do + { + EGlpNumCopy (v, work[c]); + EGlpNumZero (work[c]); + c = f->cperm[f->rrank[c]]; + nzcnt = uc_inf[c].nzcnt; + indx = f->ucindx + uc_inf[c].cbeg; + coef = f->uccoef + uc_inf[c].cbeg; + EGlpNumDivTo (v, coef[0]); + if (EGlpNumIsNeqZero (v, f->szero_tol)) + /*if (v > szero_tol || v < -szero_tol) */ + { + x->indx[x->nzcnt] = c; + EGlpNumCopy (x->coef[x->nzcnt], v); + x->nzcnt++; + } + last = -1; + for (i = 1; i < nzcnt; i++) + { + c = indx[i]; + EGlpNumSubInnProdTo (work[c], v, coef[i]); + if (--uc_inf[c].delay == 0) + { + if (last >= 0) + { + ftranu3_process2 (f, last, x); + } + last = c; + } + } + c = last; + } while (c >= 0); + EGlpNumClearVar (v); +} + +static void ILLfactor_ftranu3 ( + factor_work * f, + svector * a, + svector * x) +{ + EGlpNum_t *work = f->work_coef; + int anzcnt = a->nzcnt; + int *aindx = a->indx; + EGlpNum_t *acoef = a->coef; + uc_info *uc_inf = f->uc_inf; + int i; + + for (i = 0; i < anzcnt; i++) + { + if (uc_inf[aindx[i]].delay++ == 0) + { + ftranu3_delay2 (f, aindx[i]); + } + EGlpNumCopy (work[aindx[i]], acoef[i]); + } + x->nzcnt = 0; + for (i = 0; i < anzcnt; i++) + { + if (--uc_inf[aindx[i]].delay == 0) + { + ftranu3_process2 (f, aindx[i], x); + } + } +#ifdef SOLVE_DEBUG + printf ("ILLfactor_ftran x after u3:"); + for (i = 0; i < x->nzcnt; i++) + { + printf (" %.3f*%d", EGlpNumToLf (x->coef[i]), x->indx[i]); + } + printf ("\n"); + fflush (stdout); +#endif /* SOLVE_DEBUG */ +} + +/* ILLfactor_ftran solves Bx=a for x */ +void ILLfactor_ftran ( + factor_work * f, + svector * a, + svector * x) +{ + int i; + int nzcnt; + int sparse; + int *aindx; + EGlpNum_t *acoef; + EGlpNum_t *work_coef = f->work_coef; + +#ifdef RECORD + { + EGioPrintf (fsave, "f %d", a->nzcnt); + for (i = 0; i < a->nzcnt; i++) + { + EGioPrintf (fsave, " %d %.16e", a->indx[i], EGlpNumToLf (a->coef[i])); + } + EGioPrintf (fsave, "\n"); + EGioFlush (fsave); + } +#endif /* RECORD */ +#ifdef DEBUG_FACTOR + { + printf ("ILLfactor_ftran a:"); + for (i = 0; i < a->nzcnt; i++) + { + printf (" %d %la", a->indx[i], EGlpNumToLf (a->coef[i])); + } + printf ("\n"); + fflush (stdout); + } +#endif /* DEBUG_FACTOR */ + + if (a->nzcnt >= SPARSE_FACTOR * f->dim) + { + nzcnt = a->nzcnt; + aindx = a->indx; + acoef = a->coef; + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + else + { + sparse = 1; + } + + if (sparse) + { + ILLfactor_ftranl3 (f, a, &f->xtmp); + if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim) + { + nzcnt = f->xtmp.nzcnt; + aindx = f->xtmp.indx; + acoef = f->xtmp.coef; + + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + } + else + { + ILLfactor_ftranl (f, work_coef); + } + + if (sparse) + { + ILLfactor_ftrane2 (f, &f->xtmp); + if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim) + { + nzcnt = f->xtmp.nzcnt; + aindx = f->xtmp.indx; + acoef = f->xtmp.coef; + + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + } + else + { + ILLfactor_ftrane (f, work_coef); + } + + if (sparse) + { + ILLfactor_ftranu3 (f, &f->xtmp, x); + } + else + { + ILLfactor_ftranu (f, work_coef, x); + } + +#ifdef SORT_RESULTS + sort_vector (x); +#endif + +#ifdef DEBUG_FACTOR + { + printf ("ILLfactor_ftran x:"); + for (i = 0; i < x->nzcnt; i++) + { + printf (" %d %la", x->indx[i], EGlpNumToLf (x->coef[i])); + } + printf ("\n"); + fflush (stdout); + } +#endif /* DEBUG_FACTOR */ + return; +} + +/* ILLfactor_ftran_update solves Bx=a for x, and also returns upd, where Ux=upd */ +void ILLfactor_ftran_update ( + factor_work * f, + svector * a, + svector * upd, + svector * x) +{ + int i; + int nzcnt; + int dim; + int sparse; + int *aindx; + EGlpNum_t *acoef; + EGlpNum_t *work_coef = f->work_coef; + +#ifdef RECORD + { + EGioPrintf (fsave, "F %d", a->nzcnt); + for (i = 0; i < a->nzcnt; i++) + { + EGioPrintf (fsave, " %d %.16e", a->indx[i], EGlpNumToLf (a->coef[i])); + } + EGioPrintf (fsave, "\n"); + EGioFlush (fsave); + } +#endif /* RECORD */ +#ifdef DEBUG_FACTOR + { + printf ("ILLfactor_ftran_update a:"); + for (i = 0; i < a->nzcnt; i++) + { + printf (" %d %.3f", a->indx[i], EGlpNumToLf (a->coef[i])); + } + printf ("\n"); + fflush (stdout); + } +#endif /* DEBUG_FACTOR */ + + if (a->nzcnt >= SPARSE_FACTOR * f->dim) + { + aindx = a->indx; + acoef = a->coef; + nzcnt = a->nzcnt; + + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + else + { + sparse = 1; + } + + if (sparse) + { + ILLfactor_ftranl3 (f, a, upd); + if (upd->nzcnt >= SPARSE_FACTOR * f->dim) + { + nzcnt = upd->nzcnt; + aindx = upd->indx; + acoef = upd->coef; + + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + } + else + { + ILLfactor_ftranl (f, work_coef); + } + + if (sparse) + { + ILLfactor_ftrane2 (f, upd); + if (upd->nzcnt >= SPARSE_FACTOR * f->dim) + { + nzcnt = upd->nzcnt; + aindx = upd->indx; + acoef = upd->coef; + + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + } + else + { + ILLfactor_ftrane (f, work_coef); + nzcnt = 0; + dim = f->dim; + aindx = upd->indx; + acoef = upd->coef; + for (i = 0; i < dim; i++) + { + if (EGlpNumIsNeqqZero (work_coef[i])) + { + if (EGlpNumIsNeqZero (work_coef[i], f->szero_tol)) + /*if(work_coef[i] > szero_tol || work_coef[i] < -szero_tol) */ + { + aindx[nzcnt] = i; + EGlpNumCopy (acoef[nzcnt], work_coef[i]); + nzcnt++; + } + } + } + upd->nzcnt = nzcnt; + } + + if (sparse) + { + ILLfactor_ftranu3 (f, upd, x); + } + else + { + ILLfactor_ftranu (f, work_coef, x); + } + +#ifdef SORT_RESULTS + sort_vector (upd); + sort_vector (x); +#endif + +#ifdef DEBUG_FACTOR + { + printf ("ILLfactor_ftran update x:"); + for (i = 0; i < x->nzcnt; i++) + { + printf (" %d %.3f", x->indx[i], EGlpNumToLf (x->coef[i])); + } + printf ("\n"); + fflush (stdout); + } +#endif /* DEBUG_FACTOR */ +} + + +static void ILLfactor_btranl2 ( + factor_work * f, + EGlpNum_t * x) +{ + int *lrindx = f->lrindx; + EGlpNum_t *lrcoef = f->lrcoef; + lr_info *lr_inf = f->lr_inf; + int dim = f->dim; + int nzcnt; + int beg; + int i; + int j; + EGlpNum_t v; + + EGlpNumInitVar (v); + + for (i = dim - 1; i >= 0; i--) + { +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 > 1) + printf ("ILLfactor_btran x before l2 %d:", i); + for (j = 0; j < f->dim; j++) + { + printf (" %.3f", EGlpNumToLf (x[j])); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumCopy (v, x[lr_inf[i].r]); + if (EGlpNumIsNeqqZero (v)) + { + nzcnt = lr_inf[i].nzcnt; + beg = lr_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + EGlpNumSubInnProdTo (x[lrindx[beg + j]], v, lrcoef[beg + j]); + } + } + } +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 <= 1) + printf ("ILLfactor_btran x after l2:"); + for (j = 0; j < f->dim; j++) + { + printf (" %.3f", EGlpNumToLf (x[j])); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumClearVar (v); +} + +#if 0 +static void btranl3_delay ( + factor_work * f, + int r) +{ + lr_info *lr_inf = f->lr_inf; + int nzcnt; + int *indx; + int i; + + r = lr_inf[r].rrank; + nzcnt = lr_inf[r].nzcnt; + indx = f->lrindx + lr_inf[r].rbeg; + for (i = 0; i < nzcnt; i++) + { + r = indx[i]; + if (lr_inf[r].delay++ == 0) + { + btranl3_delay (f, r); + } + } +} +#endif + +static void btranl3_delay2 ( + factor_work * f, + int r) +{ + lr_info *lr_inf = f->lr_inf; + int nzcnt; + int *indx; + int i; + int last; + + do + { + r = lr_inf[r].rrank; + nzcnt = lr_inf[r].nzcnt; + indx = f->lrindx + lr_inf[r].rbeg; + last = -1; + for (i = 0; i < nzcnt; i++) + { + r = indx[i]; + if (lr_inf[r].delay++ == 0) + { + if (last >= 0) + { + btranl3_delay2 (f, last); + } + last = r; + } + } + r = last; + } while (r >= 0); +} + +#if 0 +static void btranl3_process ( + factor_work * f, + int r, + svector * x) +{ + lr_info *lr_inf = f->lr_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + EGlpNum_t *coef; + int i; + EGlpNum_t v; + + EGlpNumInitVar (v); + + EGlpNumCopy (v, work[r]); + EGlpNumZero (work[r]); + if (EGlpNumIsNeqZero (v, f->szero_tol)) + /*if (v > szero_tol || v < -szero_tol) */ + { + x->indx[x->nzcnt] = r; + EGlpNumCopy (x->coef[x->nzcnt], v); + x->nzcnt++; + } + r = lr_inf[r].rrank; + nzcnt = lr_inf[r].nzcnt; + indx = f->lrindx + lr_inf[r].rbeg; + coef = f->lrcoef + lr_inf[r].rbeg; + for (i = 0; i < nzcnt; i++) + { + r = indx[i]; + EGlpNumSubInnProdTo (work[r], v, coef[i]); + if (--lr_inf[r].delay == 0) + { + btranl3_process (f, r, x); + } + } + EGlpNumClearVar (v); +} +#endif + +static void btranl3_process2 ( + factor_work * f, + int r, + svector * x) +{ + lr_info *lr_inf = f->lr_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + EGlpNum_t *coef; + int i; + int last; + EGlpNum_t v; + + EGlpNumInitVar (v); + + do + { + EGlpNumCopy (v, work[r]); + EGlpNumZero (work[r]); + if (EGlpNumIsNeqZero (v, f->szero_tol)) + /*if (v > szero_tol || v < -szero_tol) */ + { + x->indx[x->nzcnt] = r; + EGlpNumCopy (x->coef[x->nzcnt], v); + x->nzcnt++; + } + r = lr_inf[r].rrank; + nzcnt = lr_inf[r].nzcnt; + indx = f->lrindx + lr_inf[r].rbeg; + coef = f->lrcoef + lr_inf[r].rbeg; + last = -1; + for (i = 0; i < nzcnt; i++) + { + r = indx[i]; + EGlpNumSubInnProdTo (work[r], v, coef[i]); + if (--lr_inf[r].delay == 0) + { + if (last >= 0) + { + btranl3_process2 (f, last, x); + } + last = r; + } + } + r = last; + } while (r >= 0); + EGlpNumClearVar (v); +} + +static void ILLfactor_btranl3 ( + factor_work * f, + svector * a, + svector * x) +{ + EGlpNum_t *work = f->work_coef; + int anzcnt = a->nzcnt; + int *aindx = a->indx; + EGlpNum_t *acoef = a->coef; + lr_info *lr_inf = f->lr_inf; + int i; + + for (i = 0; i < anzcnt; i++) + { + if (lr_inf[aindx[i]].delay++ == 0) + { + btranl3_delay2 (f, aindx[i]); + } + EGlpNumCopy (work[aindx[i]], acoef[i]); + } + x->nzcnt = 0; + for (i = 0; i < anzcnt; i++) + { + if (--lr_inf[aindx[i]].delay == 0) + { + btranl3_process2 (f, aindx[i], x); + } + } +#ifdef SOLVE_DEBUG + printf ("ILLfactor_btran x after l3:"); + for (i = 0; i < x->nzcnt; i++) + { + printf (" %.3f*%d", EGlpNumToLf (x->coef[i]), x->indx[i]); + } + printf ("\n"); + fflush (stdout); +#endif /* SOLVE_DEBUG */ +} + +static void ILLfactor_btrane ( + factor_work * f, + EGlpNum_t * x) +{ + int *erindx = f->erindx; + EGlpNum_t *ercoef = f->ercoef; + er_info *er_inf = f->er_inf; + int etacnt = f->etacnt; + int beg; + int nzcnt; + int i; + int j; + EGlpNum_t v; + + EGlpNumInitVar (v); + + for (i = etacnt - 1; i >= 0; i--) + { +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 > 1) + printf ("ILLfactor_btran x before eta %d:", i); + for (j = 0; j < f->dim; j++) + { + printf (" %.3f", EGlpNumToLf (x[j])); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumCopy (v, x[er_inf[i].r]); + if (EGlpNumIsNeqqZero (v)) + { + nzcnt = er_inf[i].nzcnt; + beg = er_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + EGlpNumSubInnProdTo (x[erindx[beg + j]], v, ercoef[beg + j]); + } + } + } +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 <= 1) + printf ("ILLfactor_btran x after eta:"); + for (j = 0; j < f->dim; j++) + { + printf (" %.3f", EGlpNumToLf (x[j])); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumClearVar (v); +} + +static void ILLfactor_btrane2 ( + factor_work * f, + svector * x) +{ + int *erindx = f->erindx; + EGlpNum_t *ercoef = f->ercoef; + er_info *er_inf = f->er_inf; + int etacnt = f->etacnt; + int beg; + int nzcnt; + int xnzcnt = x->nzcnt; + int *xindx = x->indx; + EGlpNum_t *xcoef = x->coef; + EGlpNum_t *work_coef = f->work_coef; + int *work_indx = f->work_indx; + int i; + int j; + EGlpNum_t v; + + EGlpNumInitVar (v); + + for (i = 0; i < xnzcnt; i++) + { + EGlpNumCopy (work_coef[xindx[i]], xcoef[i]); + work_indx[xindx[i]] = i + 1; + } + for (i = etacnt - 1; i >= 0; i--) + { +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 > 1) + printf ("ILLfactor_btran x before eta2 %d:", i); + for (j = 0; j < xnzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (work_coef[xindx[j]]), xindx[j]); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumCopy (v, work_coef[er_inf[i].r]); + if (EGlpNumIsNeqqZero (v)) + { + nzcnt = er_inf[i].nzcnt; + beg = er_inf[i].rbeg; + for (j = 0; j < nzcnt; j++) + { + if (work_indx[erindx[beg + j]] == 0) + { + work_indx[erindx[beg + j]] = xnzcnt; + xindx[xnzcnt++] = erindx[beg + j]; + } + EGlpNumSubInnProdTo (work_coef[erindx[beg + j]], v, ercoef[beg + j]); + } + } + } + + j = 0; + while (j < xnzcnt) + { + EGlpNumCopy (xcoef[j], work_coef[xindx[j]]); + EGlpNumZero (work_coef[xindx[j]]); + work_indx[xindx[j]] = 0; + if (!EGlpNumIsNeqqZero (xcoef[j])) + { + --xnzcnt; + xindx[j] = xindx[xnzcnt]; + } + else + { + j++; + } + } + x->nzcnt = xnzcnt; + +#ifdef SOLVE_DEBUG +#if (SOLVE_DEBUG+0 <= 1) + printf ("ILLfactor_btran x after eta2:"); + for (j = 0; j < xnzcnt; j++) + { + printf (" %.3f*%d", EGlpNumToLf (xcoef[j]), xindx[j]); + } + printf ("\n"); + fflush (stdout); +#endif +#endif /* SOLVE_DEBUG */ + EGlpNumClearVar (v); +} + +static void ILLfactor_btranu ( + factor_work * f, + EGlpNum_t * a, + svector * x) +{ + int *urindx = f->urindx; + EGlpNum_t *urcoef = f->urcoef; + ur_info *ur_inf = f->ur_inf; + int *rperm = f->rperm; + int *cperm = f->cperm; + int dim = f->dim; + int xnzcnt = 0; + int *xindx = x->indx; + EGlpNum_t *xcoef = x->coef; + int nzcnt; + int beg; + int i; + int j; + EGlpNum_t v; + + EGlpNumInitVar (v); + + for (i = 0; i < dim; i++) + { + EGlpNumCopy (v, a[cperm[i]]); + if (EGlpNumIsNeqqZero (v)) + { + j = rperm[i]; + beg = ur_inf[j].rbeg; + EGlpNumDivTo (v, urcoef[beg]); + if (EGlpNumIsNeqZero (v, f->szero_tol)) /* + * if (v > szero_tol || v < -szero_tol) */ + { + xindx[xnzcnt] = j; + EGlpNumCopy (xcoef[xnzcnt], v); + xnzcnt++; + } + nzcnt = ur_inf[j].nzcnt; + for (j = 1; j < nzcnt; j++) + { + EGlpNumSubInnProdTo (a[urindx[beg + j]], v, urcoef[beg + j]); + } + EGlpNumZero (a[cperm[i]]); + } + } + x->nzcnt = xnzcnt; +#ifdef SOLVE_DEBUG + printf ("ILLfactor_btran x after u:"); + for (i = 0; i < x->nzcnt; i++) + { + printf (" %.3f*%d", EGlpNumToLf (x->coef[i]), x->indx[i]); + } + printf ("\n"); + fflush (stdout); +#endif /* SOLVE_DEBUG */ + EGlpNumClearVar (v); +} + + +#if 0 +static void btranu3_delay ( + factor_work * f, + int r) +{ + ur_info *ur_inf = f->ur_inf; + int nzcnt; + int *indx; + int i; + + r = f->rperm[f->crank[r]]; + nzcnt = ur_inf[r].nzcnt; + indx = f->urindx + ur_inf[r].rbeg; + for (i = 1; i < nzcnt; i++) + { + r = indx[i]; + if (ur_inf[r].delay++ == 0) + { + btranu3_delay (f, r); + } + } +} +#endif + +static void btranu3_delay2 ( + factor_work * f, + int r) +{ + ur_info *ur_inf = f->ur_inf; + int nzcnt; + int *indx; + int i; + int last; + + do + { + r = f->rperm[f->crank[r]]; + nzcnt = ur_inf[r].nzcnt; + indx = f->urindx + ur_inf[r].rbeg; + last = -1; + for (i = 1; i < nzcnt; i++) + { + r = indx[i]; + if (ur_inf[r].delay++ == 0) + { + if (last >= 0) + { + btranu3_delay2 (f, last); + } + last = r; + } + } + r = last; + } while (r >= 0); +} + +#if 0 +static void btranu3_process ( + factor_work * f, + int r, + svector * x) +{ + ur_info *ur_inf = f->ur_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + EGlpNum_t *coef; + int i; + EGlpNum_t v; + + EGlpNumInitVar (v); + + EGlpNumCopy (v, work[r]); + EGlpNumZero (work[r]); + r = f->rperm[f->crank[r]]; + nzcnt = ur_inf[r].nzcnt; + indx = f->urindx + ur_inf[r].rbeg; + coef = f->urcoef + ur_inf[r].rbeg; + EGlpNumDivTo (v, coef[0]); + if (EGlpNumIsNeqqZero (v)) + { + x->indx[x->nzcnt] = r; + EGlpNumCopy (x->coef[x->nzcnt], v); + x->nzcnt++; + } + for (i = 1; i < nzcnt; i++) + { + r = indx[i]; + EGlpNumSubInnProdTo (work[r], v, coef[i]); + if (--ur_inf[r].delay == 0) + { + btranu3_process (f, r, x); + } + } + EGlpNumClearVar (v); +} +#endif + +static void btranu3_process2 ( + factor_work * f, + int r, + svector * x) +{ + ur_info *ur_inf = f->ur_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + EGlpNum_t *coef; + int i; + int last; + EGlpNum_t v; + + EGlpNumInitVar (v); + + do + { + EGlpNumCopy (v, work[r]); + EGlpNumZero (work[r]); + r = f->rperm[f->crank[r]]; + nzcnt = ur_inf[r].nzcnt; + indx = f->urindx + ur_inf[r].rbeg; + coef = f->urcoef + ur_inf[r].rbeg; + EGlpNumDivTo (v, coef[0]); + if (EGlpNumIsNeqqZero (v)) + { + x->indx[x->nzcnt] = r; + EGlpNumCopy (x->coef[x->nzcnt], v); + x->nzcnt++; + } + last = -1; + for (i = 1; i < nzcnt; i++) + { + r = indx[i]; + EGlpNumSubInnProdTo (work[r], v, coef[i]); + if (--ur_inf[r].delay == 0) + { + if (last >= 0) + { + btranu3_process2 (f, last, x); + } + last = r; + } + } + r = last; + } while (r >= 0); + EGlpNumClearVar (v); +} + +static void ILLfactor_btranu3 ( + factor_work * f, + svector * a, + svector * x) +{ + EGlpNum_t *work = f->work_coef; + int anzcnt = a->nzcnt; + int *aindx = a->indx; + EGlpNum_t *acoef = a->coef; + ur_info *ur_inf = f->ur_inf; + int i; + + for (i = 0; i < anzcnt; i++) + { + if (ur_inf[aindx[i]].delay++ == 0) + { + btranu3_delay2 (f, aindx[i]); + } + EGlpNumCopy (work[aindx[i]], acoef[i]); + } + x->nzcnt = 0; + for (i = 0; i < anzcnt; i++) + { + if (--ur_inf[aindx[i]].delay == 0) + { + btranu3_process2 (f, aindx[i], x); + } + } +#ifdef SOLVE_DEBUG + printf ("ILLfactor_btran x after u3:"); + for (i = 0; i < x->nzcnt; i++) + { + printf (" %.3f*%d", EGlpNumToLf (x->coef[i]), x->indx[i]); + } + printf ("\n"); + fflush (stdout); +#endif /* SOLVE_DEBUG */ +} + +/* ILLfactor_btran solves x^tB=a^t (or, B^t x = a) for x */ +void ILLfactor_btran ( + factor_work * f, + svector * a, + svector * x) +{ + int i; + int nzcnt; + int sparse; + int *aindx = a->indx; + EGlpNum_t *acoef = a->coef; + EGlpNum_t *work_coef = f->work_coef; + int dim = f->dim; + +#ifdef RECORD + { + EGioPrintf (fsave, "b %d", a->nzcnt); + for (i = 0; i < a->nzcnt; i++) + { + EGioPrintf (fsave, " %d %.16e", a->indx[i], EGlpNumToLf (a->coef[i])); + } + EGioPrintf (fsave, "\n"); + EGioFlush (fsave); + } +#endif /* RECORD */ +#ifdef DEBUG_FACTOR + { + printf ("ILLfactor_btran a:"); + for (i = 0; i < a->nzcnt; i++) + { + printf (" %d %.3f", a->indx[i], EGlpNumToLf (a->coef[i])); + } + printf ("\n"); + fflush (stdout); + } +#endif /* DEBUG_FACTOR */ + + if (a->nzcnt >= SPARSE_FACTOR * f->dim) + { + aindx = a->indx; + acoef = a->coef; + work_coef = f->work_coef; + nzcnt = a->nzcnt; + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + else + { + sparse = 1; + } + + if (sparse) + { + ILLfactor_btranu3 (f, a, &f->xtmp); + } + else + { + ILLfactor_btranu (f, work_coef, &f->xtmp); + } + + if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim) + { + aindx = f->xtmp.indx; + acoef = f->xtmp.coef; + work_coef = f->work_coef; + nzcnt = f->xtmp.nzcnt; + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + else + { + sparse = 1; + } + + if (sparse) + { + ILLfactor_btrane2 (f, &f->xtmp); + if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim) + { + aindx = f->xtmp.indx; + acoef = f->xtmp.coef; + work_coef = f->work_coef; + nzcnt = f->xtmp.nzcnt; + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + sparse = 0; + } + } + else + { + ILLfactor_btrane (f, work_coef); + } + + if (sparse) + { + ILLfactor_btranl3 (f, &f->xtmp, x); + } + else + { + ILLfactor_btranl2 (f, work_coef); + dim = f->dim; + nzcnt = 0; + aindx = x->indx; + acoef = x->coef; + for (i = 0; i < dim; i++) + { + if (EGlpNumIsNeqqZero (work_coef[i])) + { + if (EGlpNumIsNeqZero (work_coef[i], f->szero_tol)) + /*if (work_coef[i] > szero_tol || work_coef[i] < -szero_tol) */ + { + aindx[nzcnt] = i; + EGlpNumCopy (acoef[nzcnt], work_coef[i]); + nzcnt++; + } + EGlpNumZero (work_coef[i]); + } + } + x->nzcnt = nzcnt; + } + +#ifdef SORT_RESULTS + sort_vector (x); +#endif + +#ifdef DEBUG_FACTOR + { + printf ("ILLfactor_btran x:"); + for (i = 0; i < x->nzcnt; i++) + { + printf (" %d %.3f", x->indx[i], EGlpNumToLf (x->coef[i])); + } + printf ("\n"); + fflush (stdout); + } +#endif /* DEBUG_FACTOR */ + return; +} + +static int expand_col ( + factor_work * f, + int col) +{ + uc_info *uc_inf = f->uc_inf + col; + int uc_freebeg = f->uc_freebeg; + int nzcnt = uc_inf->nzcnt; + int cbeg; + EGlpNum_t *uccoef; + int *ucindx; + int *ucrind; + int i; + int rval = 0; + + if (uc_freebeg + nzcnt + 1 >= f->uc_space) + { + rval = make_uc_space (f, nzcnt + 1); + CHECKRVALG (rval, CLEANUP); + uc_freebeg = f->uc_freebeg; + } + cbeg = uc_inf->cbeg; + uccoef = f->uccoef; + ucindx = f->ucindx; + ucrind = f->ucrind; + + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (uccoef[uc_freebeg + i], uccoef[cbeg + i]); + ucindx[uc_freebeg + i] = ucindx[cbeg + i]; + ucrind[uc_freebeg + i] = ucrind[cbeg + i]; + ucindx[cbeg + i] = -1; + } + + uc_inf->cbeg = uc_freebeg; + f->uc_freebeg = uc_freebeg + nzcnt; +CLEANUP: + EG_RETURN (rval); +} + +static int expand_row ( + factor_work * f, + int row) +{ + ur_info *ur_inf = f->ur_inf + row; + int ur_freebeg = f->ur_freebeg; + int nzcnt = ur_inf->nzcnt; + int rbeg; + EGlpNum_t *urcoef; + int *urindx; + int *urcind; + int i; + int rval = 0; + + if (ur_freebeg + nzcnt + 1 >= f->ur_space) + { + rval = make_ur_space (f, nzcnt + 1); + CHECKRVALG (rval, CLEANUP); + ur_freebeg = f->ur_freebeg; + } + rbeg = ur_inf->rbeg; + urcoef = f->urcoef; + urindx = f->urindx; + urcind = f->urcind; + + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (urcoef[ur_freebeg + i], urcoef[rbeg + i]); + urindx[ur_freebeg + i] = urindx[rbeg + i]; + urcind[ur_freebeg + i] = urcind[rbeg + i]; + urindx[rbeg + i] = -1; + } + + ur_inf->rbeg = ur_freebeg; + f->ur_freebeg = ur_freebeg + nzcnt; +CLEANUP: + EG_RETURN (rval); +} + +static int add_nonzero ( + factor_work * f, + int row, + int col, + EGlpNum_t val) +{ + ur_info *ur_inf = f->ur_inf + row; + uc_info *uc_inf = f->uc_inf + col; + int cnzcnt = uc_inf->nzcnt; + int rnzcnt = ur_inf->nzcnt; + int cloc = uc_inf->cbeg + cnzcnt; + int rloc = ur_inf->rbeg + rnzcnt; + int rval = 0; + + if (f->ucindx[cloc] != -1) + { + rval = expand_col (f, col); + CHECKRVALG (rval, CLEANUP); + cloc = uc_inf->cbeg + cnzcnt; + } + TESTG ((rval = (rloc < 0 || rloc > f->ur_space)), CLEANUP, + "rloc %d outside boundaries [0:%d]", rloc, f->ur_space); + if (f->urindx[rloc] != -1) + { + rval = expand_row (f, row); + CHECKRVALG (rval, CLEANUP); + rloc = ur_inf->rbeg + rnzcnt; + } + f->ucindx[cloc] = row; + EGlpNumCopy (f->uccoef[cloc], val); + f->ucrind[cloc] = rnzcnt; + f->urindx[rloc] = col; + EGlpNumCopy (f->urcoef[rloc], val); + f->urcind[rloc] = cnzcnt; + + if (cloc == f->uc_freebeg) + f->uc_freebeg++; + if (rloc == f->ur_freebeg) + f->ur_freebeg++; + + uc_inf->nzcnt = cnzcnt + 1; + ur_inf->nzcnt = rnzcnt + 1; +CLEANUP: + EG_RETURN (rval); +} + +static int delete_nonzero_row ( + factor_work * f, + int row, + int ind) +{ + ur_info *ur_inf = f->ur_inf; + EGlpNum_t *urcoef = f->urcoef; + int *urindx = f->urindx; + int *urcind = f->urcind; + int *ucrind = f->ucrind; + int rbeg = ur_inf[row].rbeg; + int nzcnt = ur_inf[row].nzcnt - 1; + int cbeg, rval = 0; + #ifdef DEBUG_FACTOR + TESTG((rval=(nzcnt<0)),CLEANUP,"Deleting empty row %d ind %d!",row, ind); + #endif + + if (ind != nzcnt) + { + EGlpNumCopy (urcoef[rbeg + ind], urcoef[rbeg + nzcnt]); + urindx[rbeg + ind] = urindx[rbeg + nzcnt]; + urcind[rbeg + ind] = urcind[rbeg + nzcnt]; + cbeg = f->uc_inf[urindx[rbeg + nzcnt]].cbeg; + ucrind[cbeg + urcind[rbeg + nzcnt]] = ind; + urindx[rbeg + nzcnt] = -1; + } + ur_inf[row].nzcnt = nzcnt; + #ifdef DEBUG_FACTOR + CLEANUP: + #endif + return rval; +} + +static void delete_nonzero_col ( + factor_work * f, + int col, + int ind) +{ + uc_info *uc_inf = f->uc_inf; + EGlpNum_t *uccoef = f->uccoef; + int *ucindx = f->ucindx; + int *ucrind = f->ucrind; + int *urcind = f->urcind; + int cbeg = uc_inf[col].cbeg; + int nzcnt = uc_inf[col].nzcnt - 1; + int rbeg; + + if (ind != nzcnt) + { + EGlpNumCopy (uccoef[cbeg + ind], uccoef[cbeg + nzcnt]); + ucindx[cbeg + ind] = ucindx[cbeg + nzcnt]; + ucrind[cbeg + ind] = ucrind[cbeg + nzcnt]; + rbeg = f->ur_inf[ucindx[cbeg + nzcnt]].rbeg; + urcind[rbeg + ucrind[cbeg + nzcnt]] = ind; + ucindx[cbeg + nzcnt] = -1; + } + uc_inf[col].nzcnt = nzcnt; +} + +static int delete_column ( + factor_work * f, + int col) +{ + uc_info *uc_inf = f->uc_inf; + int beg = uc_inf[col].cbeg; + int nzcnt = uc_inf[col].nzcnt; + int *ucindx = f->ucindx + beg; + int *ucrind = f->ucrind + beg; + int i, rval = 0; + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + #endif + + for (i = 0; i < nzcnt; i++) + { + rval = delete_nonzero_row (f, ucindx[i], ucrind[i]); + CHECKRVALG(rval,CLEANUP); + ucindx[i] = -1; + } + uc_inf[col].nzcnt = 0; + +#ifdef TRACK_FACTOR + f->nzcnt_cur -= nzcnt; +#endif + + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + #endif /* DEBUG_FACTOR */ + CLEANUP: + EG_RETURN(rval); +} + +static int delete_row ( + factor_work * f, + int row, + svector * x) +{ + ur_info *ur_inf = f->ur_inf; + int beg = ur_inf[row].rbeg; + int nzcnt = ur_inf[row].nzcnt; + int *urindx = f->urindx + beg; + EGlpNum_t *urcoef = f->urcoef + beg; + int *urcind = f->urcind + beg; + int i,rval=0; + + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + #endif /* DEBUG_FACTOR */ + + for (i = 0; i < nzcnt; i++) + { + x->indx[i] = urindx[i]; + EGlpNumCopy (x->coef[i], urcoef[i]); + delete_nonzero_col (f, urindx[i], urcind[i]); + urindx[i] = -1; + } + x->nzcnt = nzcnt; + ur_inf[row].nzcnt = 0; + +#ifdef TRACK_FACTOR + f->nzcnt_cur -= nzcnt; +#endif + + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + CLEANUP: + #endif /* DEBUG_FACTOR */ + return rval; +} + +static int create_column ( + factor_work * f, + svector * a, + int col, + int *p_last_rank) +{ + int *rrank = f->rrank; + int nzcnt = a->nzcnt; + int *aindx = a->indx; + EGlpNum_t *acoef = a->coef; + int i; + int j; + int rval = 0; + int last_rank = -1; + +#ifdef TRACK_FACTOR + EGlpNum_t max; + + EGlpNumInitVar (max); + EGlpNumCopy (max, f->maxelem_cur); +#endif /* TRACK_FACTOR */ + + last_rank = 0; + + for (i = 0; i < nzcnt; i++) + { + rval = add_nonzero (f, aindx[i], col, acoef[i]); + CHECKRVALG (rval, CLEANUP); +#ifdef TRACK_FACTOR + EGlpNumSetToMaxAbs (max, acoef[i]); +#endif /* TRACK_FACTOR */ + j = rrank[aindx[i]]; + if (j > last_rank) + last_rank = j; + } + *p_last_rank = last_rank; + +#ifdef TRACK_FACTOR + f->nzcnt_cur += nzcnt; + EGlpNumCopy (f->maxelem_cur, max); + EGlpNumClearVar (max); +#endif /* TRACK_FACTOR */ + + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + #endif /* DEBUG_FACTOR */ + + CLEANUP: + EG_RETURN (rval); +} + +#ifdef UPDATE_STUDY +static int column_rank ( + factor_work * f, + int col) +{ + int *cperm = f->cperm; + int dim = f->dim; + int i; + + for (i = 0; i < dim; i++) + { + if (cperm[i] == col) + { + return i; + } + } + return 0; +} +#endif + +static void shift_permutations ( + factor_work * f, + int rank_p, + int rank_r) +{ + int *cperm = f->cperm; + int *crank = f->crank; + int *rperm = f->rperm; + int *rrank = f->rrank; + int col_p = cperm[rank_p]; + int row_p = rperm[rank_p]; + int i; + + for (i = rank_p; i < rank_r; i++) + { + cperm[i] = cperm[i + 1]; + crank[cperm[i]] = i; + rperm[i] = rperm[i + 1]; + rrank[rperm[i]] = i; + } + cperm[rank_r] = col_p; + crank[col_p] = rank_r; + rperm[rank_r] = row_p; + rrank[row_p] = rank_r; +} + +static int eliminate_row ( + factor_work * f, + int rank_p, + int rank_r) +{ + ur_info *ur_inf = f->ur_inf; + int *rperm = f->rperm; + int *cperm = f->cperm; + int *urindx = f->urindx; + EGlpNum_t *urcoef = f->urcoef; + int *erindx = f->erindx; + EGlpNum_t *ercoef = f->ercoef; + EGlpNum_t *work_coef = f->work_coef; + int er_freebeg = f->er_freebeg; + int er_space = f->er_space; + int beg; + int nzcnt; + int i; + int j; + int c; + int r; + EGlpNum_t pivot_mul; + +#ifdef TRACK_FACTOR + EGlpNum_t max; + + EGlpNumInitVar (max); + EGlpNumCopy (max, f->maxelem_cur); +#endif /* TRACK_FACTOR */ + EGlpNumInitVar (pivot_mul); + + for (i = rank_p; i < rank_r; i++) + { + c = cperm[i]; + if (EGlpNumIsNeqZero (work_coef[c], f->fzero_tol)) /* + * if (work_coef[c] > fzero_tol || work_coef[c] < -fzero_tol) */ + { + r = rperm[i]; + beg = ur_inf[r].rbeg; + nzcnt = ur_inf[r].nzcnt; + EGlpNumCopyFrac (pivot_mul, work_coef[c], urcoef[beg]); + EGlpNumZero (work_coef[c]); + for (j = 1; j < nzcnt; j++) + { + EGlpNumSubInnProdTo (work_coef[urindx[beg + j]], pivot_mul, urcoef[beg + j]); /* 0.85 */ + } + if (er_freebeg >= er_space) + { + /* fprintf (stderr, "no space in eliminate_row\n"); */ +#ifdef TRACK_FACTOR + EGlpNumClearVar (max); +#endif + EGlpNumClearVar (pivot_mul); + return E_UPDATE_NOSPACE; + } + erindx[er_freebeg] = r; + EGlpNumCopy (ercoef[er_freebeg], pivot_mul); +#ifdef TRACK_FACTOR + EGlpNumSetToMaxAbs (max, pivot_mul); +#endif /* TRACK_FACTOR */ + er_freebeg++; + } + else + { + EGlpNumZero (work_coef[c]); + } + } + f->er_freebeg = er_freebeg; +#ifdef TRACK_FACTOR + EGlpNumCopy (f->maxelem_cur, max); + EGlpNumClearVar (max); +#endif /* TRACK_FACTOR */ + EGlpNumClearVar (pivot_mul); + return 0; +} + +static int create_row ( + factor_work * f, + EGlpNum_t * a, + int row, + int minrank) +{ + int *cperm = f->cperm; + int dim = f->dim; + int i; + int j; + int rval = 0; + +#ifdef TRACK_FACTOR + EGlpNum_t max; + + EGlpNumInitVar (max); + EGlpNumCopy (max, f->maxelem_cur); +#endif /* TRACK_FACTOR */ + + for (i = minrank; i < dim; i++) + { + if (EGlpNumIsNeqqZero (a[cperm[i]])) + { + j = cperm[i]; + if (EGlpNumIsNeqZero (a[j], f->fzero_tol)) /* + * if (a[j] > fzero_tol || a[j] < -fzero_tol) */ + { + rval = add_nonzero (f, row, j, a[j]); + CHECKRVALG (rval, CLEANUP); +#ifdef TRACK_FACTOR + EGlpNumSetToMaxAbs (max, a[j]); +#endif /* TRACK_FACTOR */ + } + EGlpNumZero (a[j]); + } + } + +#ifdef TRACK_FACTOR + f->nzcnt_cur += f->ur_inf[row].nzcnt; + EGlpNumCopy (f->maxelem_cur, max); + EGlpNumClearVar (max); +#endif /* TRACK_FACTOR */ + + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + #endif /* DEBUG_FACTOR */ + CLEANUP: + EG_RETURN (rval); +} + +static void serow_delay ( + factor_work * f, + int r, + int rank_r) +{ + ur_info *ur_inf = f->ur_inf; + int *crank = f->crank; + int nzcnt; + int *indx; + int i; + int last; + + do + { + r = f->rperm[crank[r]]; + nzcnt = ur_inf[r].nzcnt; + indx = f->urindx + ur_inf[r].rbeg; + last = -1; + for (i = 1; i < nzcnt; i++) + { + r = indx[i]; + if (ur_inf[r].delay++ == 0 && crank[r] < rank_r) + { + if (last >= 0) + { + serow_delay (f, last, rank_r); + } + last = r; + } + } + r = last; + } while (r >= 0); +} + +static int serow_process ( + factor_work * f, + int r, + svector * newr, + int rank_r) +{ + ur_info *ur_inf = f->ur_inf; + EGlpNum_t *work = f->work_coef; + int nzcnt; + int *indx; + EGlpNum_t *coef; + int i; + EGlpNum_t v; + int last; + int rval; + + EGlpNumInitVar (v); + + do + { + EGlpNumCopy (v, work[r]); + EGlpNumZero (work[r]); + if (f->crank[r] >= rank_r) + { + if (EGlpNumIsNeqZero (v, f->fzero_tol)) /* + * if (v > fzero_tol || v < -fzero_tol) */ + { + /* stash this nonzero in the resulting row */ +#ifdef TRACK_FACTOR + EGlpNumSetToMaxAbs (f->maxelem_cur, v); +#endif /* TRACK_FACTOR */ + newr->indx[newr->nzcnt] = r; + EGlpNumCopy (newr->coef[newr->nzcnt], v); + newr->nzcnt++; + EGlpNumClearVar (v); + return 0; + } + else + { + EGlpNumClearVar (v); + return 0; + } + } + r = f->rperm[f->crank[r]]; + nzcnt = ur_inf[r].nzcnt; + indx = f->urindx + ur_inf[r].rbeg; + coef = f->urcoef + ur_inf[r].rbeg; + EGlpNumDivTo (v, coef[0]); + if (EGlpNumIsNeqZero (v, f->fzero_tol)) /* + * if (v > fzero_tol || v < -fzero_tol) */ + { + /* stash v in eta */ + if (f->er_freebeg >= f->er_space) + { + /* fprintf (stderr, "no space in eliminate_row\n"); */ + EGlpNumClearVar (v); + return E_UPDATE_NOSPACE; + } + f->erindx[f->er_freebeg] = r; + EGlpNumCopy (f->ercoef[f->er_freebeg], v); +#ifdef TRACK_FACTOR + EGlpNumSetToMaxAbs (f->maxelem_cur, v); +#endif /* TRACK_FACTOR */ + f->er_freebeg++; + } + last = -1; + for (i = 1; i < nzcnt; i++) + { + r = indx[i]; + EGlpNumSubInnProdTo (work[r], v, coef[i]); + if (--ur_inf[r].delay == 0) + { + if (last >= 0) + { + rval = serow_process (f, last, newr, rank_r); + if (rval) + { + EGlpNumClearVar (v); + return rval; + } + } + last = r; + } + } + r = last; + } while (r >= 0); + EGlpNumClearVar (v); + return 0; +} + +static int sparse_eliminate_row ( + factor_work * f, + svector * x, + int row_p, + int rank_r) +{ + EGlpNum_t *work = f->work_coef; + int xnzcnt = x->nzcnt; + int *xindx = x->indx; + EGlpNum_t *xcoef = x->coef; + ur_info *ur_inf = f->ur_inf; + int *crank = f->crank; + int i; + int j; + int rval = 0; + svector newr; + + newr.indx = 0; + newr.coef = 0; + + for (i = 0; i < xnzcnt; i++) + { + j = xindx[i]; + if (ur_inf[j].delay++ == 0 && crank[j] < rank_r) + { + serow_delay (f, j, rank_r); + } + EGlpNumCopy (work[j], xcoef[i]); + } + + newr.nzcnt = 0; + ILL_SAFE_MALLOC (newr.indx, f->dim, int); + + newr.coef = EGlpNumAllocArray (f->dim); + + for (i = 0; i < xnzcnt; i++) + { + j = xindx[i]; + if (--ur_inf[j].delay == 0) + { + rval = serow_process (f, j, &newr, rank_r); + CHECKRVALG (rval, CLEANUP); + } + } + + for (i = 0; i < newr.nzcnt; i++) + { + rval = add_nonzero (f, row_p, newr.indx[i], newr.coef[i]); + CHECKRVALG (rval, CLEANUP); + } + +#ifdef TRACK_FACTOR + f->nzcnt_cur += newr.nzcnt; +#endif /* TRACK_FACTOR */ + +CLEANUP: + EGlpNumFreeArray (newr.coef); + ILL_IFFREE (newr.indx, int); + + /* Bico 031210 - chg from ILL_RETURN */ + EG_RETURN (rval); +} + +static int move_pivot_row ( + factor_work * f, + int r, + int c) +{ + ur_info *ur_inf = f->ur_inf + r; + uc_info *uc_inf = f->uc_inf; + int beg = ur_inf->rbeg; + int nzcnt = ur_inf->nzcnt; + int *urindx = f->urindx; + int *urcind = f->urcind; + int *ucrind = f->ucrind; + EGlpNum_t *urcoef = f->urcoef; + EGlpNum_t dt; + int it; + int i; + + if (urindx[beg] == c) + return 0; + EGlpNumInitVar (dt); + + for (i = 1; i < nzcnt; i++) + { + if (urindx[beg + i] == c) + { + EGLPNUM_SWAP (urcoef[beg], urcoef[beg + i], dt); + ILL_SWAP (urcind[beg], urcind[beg + i], it); + urindx[beg + i] = urindx[beg]; + urindx[beg] = c; + ucrind[uc_inf[c].cbeg + urcind[beg]] = 0; + ucrind[uc_inf[urindx[beg + i]].cbeg + urcind[beg + i]] = i; + EGlpNumClearVar (dt); + return 0; + } + } + MESSAGE (__QS_SB_VERB, "pivot row nonzero not found"); + EGlpNumClearVar (dt); + return E_UPDATE_SINGULAR_ROW; +} + +static int move_pivot_col ( + factor_work * f, + int c, + int r) +{ + uc_info *uc_inf = f->uc_inf + c; + ur_info *ur_inf = f->ur_inf; + int beg = uc_inf->cbeg; + int nzcnt = uc_inf->nzcnt; + int *ucindx = f->ucindx; + int *ucrind = f->ucrind; + int *urcind = f->urcind; + EGlpNum_t *uccoef = f->uccoef; + EGlpNum_t dt; + int i, it; + + if (ucindx[beg] == r) + return 0; + EGlpNumInitVar (dt); + + for (i = 1; i < nzcnt; i++) + { + if (ucindx[beg + i] == r) + { + EGLPNUM_SWAP (uccoef[beg], uccoef[beg + i], dt); + ILL_SWAP (ucrind[beg], ucrind[beg + i], it); + ucindx[beg + i] = ucindx[beg]; + ucindx[beg] = r; + urcind[ur_inf[r].rbeg + ucrind[beg]] = 0; + urcind[ur_inf[ucindx[beg + i]].rbeg + ucrind[beg + i]] = i; + EGlpNumClearVar (dt); + return 0; + } + } + MESSAGE(__QS_SB_VERB, "pivot col nonzero not found"); + EGlpNumClearVar (dt); + return E_UPDATE_SINGULAR_COL; +} + +static int move_pivot ( + factor_work * f, + int rank_r) +{ + int r = f->rperm[rank_r]; + int c = f->cperm[rank_r]; + int rval = 0; + + rval = move_pivot_row (f, r, c); + CHECKRVALG (rval, CLEANUP); + + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + #endif /* DEBUG_FACTOR */ + + rval = move_pivot_col (f, c, r); + if(rval != E_UPDATE_SINGULAR_COL) CHECKRVALG (rval, CLEANUP); + else goto CLEANUP; + + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + #endif /* DEBUG_FACTOR */ + + CLEANUP: + if(rval != E_UPDATE_SINGULAR_COL) EG_RETURN (rval); /* Bico 031209 - chg from RETURN */ + return rval; +} + +int ILLfactor_update ( + factor_work * f, + svector * a, + int col_p, + int *p_refact) +{ + int row_p; + int rank_r = 0; + int rank_p = 0; + int rval = 0; + int nzcnt; + int *aindx; + EGlpNum_t *acoef; + EGlpNum_t *work_coef = f->work_coef; + +#ifdef TRACK_FACTOR +#ifdef NOTICE_BLOWUP + EGlpNum_t tmpsize; +#endif +#endif + int i; + +#ifdef RECORD + { + EGioPrintf (fsave, "u %d %d", col_p, a->nzcnt); + for (i = 0; i < a->nzcnt; i++) + { + EGioPrintf (fsave, " %d %.16e", a->indx[i], EGlpNumToLf (a->coef[i])); + } + EGioPrintf (fsave, "\n"); + EGioFlush (fsave); + } +#endif /* RECORD */ + +#ifdef DEBUG_FACTOR + { + printf ("ILLfactor_update col %d:", col_p); + for (i = 0; i < a->nzcnt; i++) + { + printf (" %.3f*%d", EGlpNumToLf (a->coef[i]), a->indx[i]); + } + printf ("\n"); + fflush (stdout); + } +#endif /* DEBUG_FACTOR */ + + #ifdef DEBUG_FACTOR + rval = check_matrix(f); + TESTG(rval,CLEANUP,"Corrupted Matrix"); + #endif /* DEBUG_FACTOR */ + + if (f->etacnt >= f->etamax) + { + *p_refact = 1; + return 0; + } + +#ifdef UPDATE_STUDY + nupdate++; +#endif + + row_p = f->ucindx[f->uc_inf[col_p].cbeg]; + + rval = delete_column (f, col_p); + CHECKRVALG (rval, CLEANUP); + + rval = create_column (f, a, col_p, &rank_r); + /* if (rval) fprintf (stderr, "create_column failed\n"); */ + CHECKRVALG (rval, CLEANUP); + + rank_p = f->crank[col_p]; +#ifdef UPDATE_STUDY + if (rank_p != f->rrank[row_p] || rank_p != column_rank (f, col_p)) + { + printf ("rank_p %d rrank[row_p] %d column_rank(f,col_p) %d\n", + rank_p, f->rrank[row_p], column_rank (f, col_p)); + } + if (rank_r > rank_p) + { + permshifttot += rank_r - rank_p; + } + for (i = 0; i < a->nzcnt; i++) + { + if (f->rrank[a->indx[i]] > rank_p) + colspiketot++; + } + for (i = 0; i < f->ur_inf[row_p].nzcnt; i++) + { + if (f->crank[f->urindx[f->ur_inf[row_p].rbeg + i]] <= rank_r && + f->crank[f->urindx[f->ur_inf[row_p].rbeg + i]] != rank_p) + { + rowspiketot++; + } + } +#endif + + shift_permutations (f, rank_p, rank_r); + + rval = delete_row (f, row_p, &f->xtmp); + CHECKRVALG(rval,CLEANUP); + + f->er_inf[f->etacnt].rbeg = f->er_freebeg; + f->er_inf[f->etacnt].r = row_p; + + if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim) + { + nzcnt = f->xtmp.nzcnt; + aindx = f->xtmp.indx; + acoef = f->xtmp.coef; + + for (i = 0; i < nzcnt; i++) + { + EGlpNumCopy (work_coef[aindx[i]], acoef[i]); + } + + rval = eliminate_row (f, rank_p, rank_r); + /* if (rval) fprintf (stderr, "eliminate_row failed\n"); */ + CHECKRVALG (rval, CLEANUP); + + rval = create_row (f, f->work_coef, row_p, rank_r); + /* if (rval) fprintf (stderr, "create_row failed\n"); */ + CHECKRVALG (rval, CLEANUP); + } + else + { + rval = sparse_eliminate_row (f, &f->xtmp, row_p, rank_r); + /* if (rval) fprintf (stderr, "sparse_eliminate_row failed\n"); */ + CHECKRVALG (rval, CLEANUP); + } + + if (f->er_freebeg - f->er_inf[f->etacnt].rbeg > 0) + { + f->er_inf[f->etacnt].nzcnt = f->er_freebeg - f->er_inf[f->etacnt].rbeg; +#ifdef TRACK_FACTOR + f->nzcnt_cur += f->er_inf[f->etacnt].nzcnt; +#endif /* TRACK_FACTOR */ +#ifdef UPDATE_STUDY + leftetatot += f->er_inf[f->etacnt].nzcnt; +#endif + +#ifdef SORT_RESULTS + sort_vector2 (f->er_inf[f->etacnt].nzcnt, + f->erindx + f->er_inf[f->etacnt].rbeg, + f->ercoef + f->er_inf[f->etacnt].rbeg); +#endif + + f->etacnt++; + } + + rval = move_pivot (f, rank_r); + /* if (rval) fprintf (stderr, "move_pivot failed\n"); */ + if(rval != E_UPDATE_SINGULAR_COL) CHECKRVALG (rval, CLEANUP); + else goto CLEANUP; + +#ifdef UPDATE_DEBUG + printf ("Updated factorization:\n"); +#if (UPDATE_DEBUG+0>1) + dump_matrix (f, 0); +#endif + fflush (stdout); +#endif /* UPDATE_DEBUG */ + +#ifdef TRACK_FACTOR +#ifdef NOTICE_BLOWUP + EGlpNumInitVar (tmpsize); + EGlpNumSet (tmpsize, f->updmaxmult); + EGlpNumMultTo (tmpsize, f->maxelem_orig); + if (EGlpNumIsLess (tmpsize, f->maxelem_cur)) + { +/* Bico - comment out for dist + fprintf (stderr, "factor_update blowup max cur %e max orig %e\n", + f->maxelem_cur, f->maxelem_orig); +*/ + EGlpNumClearVar (tmpsize); + return E_FACTOR_BLOWUP; + } + EGlpNumClearVar (tmpsize); +#endif /* NOTICE_BLOWUP */ +#endif +#ifdef UPDATE_STATS + dump_factor_stats (f); +#endif +CLEANUP: + if(rval != E_UPDATE_SINGULAR_COL) EG_RETURN (rval); /* Bico 031209 - chg from RETURN */ + return rval; +} diff --git a/src/factor.h b/src/factor.h new file mode 100644 index 0000000..11d4ef1 --- /dev/null +++ b/src/factor.h @@ -0,0 +1,206 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: factor.h,v 1.3 2003/11/05 16:57:39 meven Exp $ */ +#ifndef __QS_FACTOR_H_ +#define __QS_FACTOR_H_ +#include "basicdefs.h" +#include "qs_config.h" +#include "dstruct.h" + +typedef char QSbool; + +typedef struct uc_info +{ + int cbeg; + int nzcnt; + int next; + int prev; + int delay; +} +uc_info; + +typedef struct ur_info +{ + EGlpNum_t max; + int rbeg; + int nzcnt; + int pivcnt; + int next; + int prev; + int delay; +} +ur_info; + +typedef struct lc_info +{ + int cbeg; + int nzcnt; + int c; + int crank; + int delay; +} +lc_info; + +typedef struct lr_info +{ + int rbeg; + int nzcnt; + int r; + int rrank; + int delay; +} +lr_info; + +typedef struct er_info +{ + int rbeg; + int nzcnt; + int r; +} +er_info; + +typedef struct factor_work +{ + int max_k; + EGlpNum_t fzero_tol; + EGlpNum_t szero_tol; + EGlpNum_t partial_tol; + double ur_space_mul; + double uc_space_mul; + double lc_space_mul; + double lr_space_mul; + double er_space_mul; + double grow_mul; + int p; + int etamax; + double minmult; + double maxmult; + double updmaxmult; + double dense_fract; + int dense_min; + + EGlpNum_t maxelem_orig; + int nzcnt_orig; + EGlpNum_t maxelem_factor; + int nzcnt_factor; + EGlpNum_t maxelem_cur; + int nzcnt_cur; + + EGlpNum_t partial_cur; + + int dim; + int stage; + int nstages; + int etacnt; + EGlpNum_t *work_coef; + int *work_indx; + uc_info *uc_inf; + ur_info *ur_inf; + lc_info *lc_inf; + lr_info *lr_inf; + er_info *er_inf; + int *ucindx; /* row index for column data */ + int *ucrind; /* index of column in row data */ + EGlpNum_t *uccoef; /* coefficient for column data */ + int *urindx; /* col index for row data */ + int *urcind; /* index of row in column data */ + EGlpNum_t *urcoef; /* coefficient for row data */ + int *lcindx; /* row index for L data */ + EGlpNum_t *lccoef; /* coefficient for L row data */ + int *lrindx; /* col index for L data */ + EGlpNum_t *lrcoef; /* coefficient for L col data */ + int *erindx; /* col index for eta data */ + EGlpNum_t *ercoef; /* coefficient for eta data */ + int *rperm; + int *rrank; + int *cperm; + int *crank; + svector xtmp; + int ur_freebeg; + int ur_space; + int uc_freebeg; + int uc_space; + int lc_freebeg; + int lc_space; + int lr_freebeg; + int lr_space; + int er_freebeg; + int er_space; + + int *p_nsing; + int **p_singr; + int **p_singc; + + EGlpNum_t *dmat; + int drows; + int dcols; + int dense_base; +} +factor_work; + +void ILLfactor_init_factor_work ( + factor_work * f), + ILLfactor_free_factor_work ( + factor_work * f), + ILLfactor_ftran ( + factor_work * f, + svector * a, + svector * x), + ILLfactor_ftran_update ( + factor_work * f, + svector * a, + svector * upd, + svector * x), + ILLfactor_btran ( + factor_work * f, + svector * a, + svector * x); + +int ILLfactor_create_factor_work ( + factor_work * f, + int dim), + ILLfactor_set_factor_iparam ( + factor_work * f, + int param, + int val), + ILLfactor_set_factor_dparam ( + factor_work * f, + int param, + EGlpNum_t val), + ILLfactor ( + factor_work * f, + int *basis, + int *cbeg, + int *clen, + int *cindx, + EGlpNum_t * ccoef, + int *p_nsing, + int **p_singr, + int **p_singc), + ILLfactor_update ( + factor_work * f, + svector * a, + int col, + int *p_refact); + +#endif /* __QS_FACTOR_H_ */ diff --git a/src/fct.c b/src/fct.c new file mode 100644 index 0000000..c5dec3f --- /dev/null +++ b/src/fct.c @@ -0,0 +1,2488 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: fct.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +static int TRACE = 0; + +//#define FCT_DEBUG 10 +#define FCT_DEBUG 0 + +#include "qs_config.h" +#include "iqsutil.h" +#include "lpdefs.h" +#include "stddefs.h" +#include "basis.h" +#include "fct.h" +#include "price.h" +#include "ratio.h" +#include "dstruct.h" + +bndinfo *ILLfct_new_bndinfo ( + void) +{ + bndinfo *nbnd = (bndinfo *) malloc (sizeof (bndinfo)); + + if (!nbnd) + { + fprintf (stderr, "not enough memory, in %s\n", __func__); + exit (1); + } + EGlpNumInitVar ((nbnd->pbound)); + EGlpNumInitVar ((nbnd->cbound)); + return nbnd; +} + +void ILLfct_free_bndinfo ( + bndinfo * binfo) +{ + EGlpNumClearVar ((binfo->pbound)); + EGlpNumClearVar ((binfo->cbound)); + ILL_IFFREE (binfo, bndinfo); + return; +} + +static int compute_zA1 ( + lpinfo * lp, + svector * z, + svector * zA, + EGlpNum_t ztoler), +/* + compute_zA2 (lpinfo * lp, + svector * z, + svector * zA, + const EGlpNum_t* ztoler), */ + compute_zA3 ( + lpinfo * lp, + svector * z, + svector * zA, + EGlpNum_t ztoler), + expand_var_bounds ( + lpinfo * lp, + EGlpNum_t ftol, + int *chgb), + expand_var_coefs ( + lpinfo * lp, + EGlpNum_t ftol, + int *chgc); + +static void update_piv_values ( + count_struct * c, + int phase, + const EGlpNum_t piv), +/* copy_vectors (svector * a, + svector * b),*/ + add_vectors ( + lpinfo * lp, + svector * a, + svector * b, + svector * c, + const EGlpNum_t t); + +static double my_rand ( + int bound, + ILLrandstate * r); + + +void ILLfct_load_workvector ( + lpinfo * lp, + svector * s) +{ + int i; + + for (i = 0; i < s->nzcnt; i++) + { + lp->work.indx[i] = s->indx[i]; + EGlpNumCopy (lp->work.coef[s->indx[i]], s->coef[i]); + } + lp->work.nzcnt = s->nzcnt; +} + +void ILLfct_zero_workvector ( + lpinfo * lp) +{ + int i; + + for (i = 0; i < lp->work.nzcnt; i++) + EGlpNumZero (lp->work.coef[lp->work.indx[i]]); + lp->work.nzcnt = 0; +} + +void ILLfct_set_variable_type ( + lpinfo * lp) +{ + int j; + + for (j = 0; j < lp->ncols; j++) + { + + if (lp->matcnt[j] == 1 && lp->O->rowmap[lp->matind[lp->matbeg[j]]] == j) + lp->vclass[j] = CLASS_LOGICAL; + else + lp->vclass[j] = CLASS_STRUCT; + switch ((EGlpNumIsEqqual (lp->uz[j], INFTY) ? 1U : 0U) | + (EGlpNumIsEqqual (lp->lz[j], NINFTY) ? 2U : 0U)) + { + case 0: + if (EGlpNumIsLess (lp->lz[j], lp->uz[j])) + lp->vtype[j] = VBOUNDED; + else if (!EGlpNumIsNeqqZero (lp->lz[j]) && + (lp->vclass[j] == CLASS_LOGICAL)) + lp->vtype[j] = VARTIFICIAL; + else + lp->vtype[j] = VFIXED; + break; + case 3: + lp->vtype[j] = VFREE; + break; + case 1: + lp->vtype[j] = VLOWER; + break; + case 2: + lp->vtype[j] = VUPPER; + break; + } + } +} + +/* compute various vectors */ + +void ILLfct_compute_pobj ( + lpinfo * lp) +{ + int i, j; + int col; + EGlpNum_t sum; + + EGlpNumInitVar (sum); + EGlpNumZero (sum); + + for (i = 0; i < lp->nrows; i++) + EGlpNumAddInnProdTo (sum, lp->cz[lp->baz[i]], lp->xbz[i]); + + for (j = 0; j < lp->nnbasic; j++) + { + col = lp->nbaz[j]; + if (lp->vstat[col] == STAT_UPPER) + EGlpNumAddInnProdTo (sum, lp->cz[col], lp->uz[col]); + else if (lp->vstat[col] == STAT_LOWER) + EGlpNumAddInnProdTo (sum, lp->cz[col], lp->lz[col]); + } + EGlpNumCopy (lp->pobjval, sum); + EGlpNumCopy (lp->objval, sum); + EGlpNumClearVar (sum); +} + +void ILLfct_compute_dobj ( + lpinfo * lp) +{ + int i, j; + int col; + EGlpNum_t sum; + + EGlpNumInitVar (sum); + EGlpNumZero (sum); + + for (i = 0; i < lp->nrows; i++) + EGlpNumAddInnProdTo (sum, lp->piz[i], lp->bz[i]); + + for (j = 0; j < lp->nnbasic; j++) + { + col = lp->nbaz[j]; + if (lp->vstat[col] == STAT_UPPER) + EGlpNumAddInnProdTo (sum, lp->dz[j], lp->uz[col]); + else if (lp->vstat[col] == STAT_LOWER) + EGlpNumAddInnProdTo (sum, lp->dz[j], lp->lz[col]); + } + EGlpNumCopy (lp->dobjval, sum); + EGlpNumCopy (lp->objval, sum); + EGlpNumClearVar (sum); +} + +void ILLfct_compute_xbz ( + lpinfo * lp) +{ + int i, j, r; + int col, mcnt, mbeg; + svector *srhs = &(lp->srhs); + svector *ssoln = &(lp->ssoln); + EGlpNum_t xval; + + EGlpNumInitVar (xval); + + for (i = 0; i < lp->nrows; i++) + { + EGlpNumZero (lp->xbz[i]); + EGlpNumCopy (srhs->coef[i], lp->bz[i]); + } + for (j = 0; j < lp->nnbasic; j++) + { + col = lp->nbaz[j]; + EGlpNumZero (xval); + if (lp->vstat[col] == STAT_UPPER && EGlpNumIsNeqqZero (lp->uz[col])) + EGlpNumCopy (xval, lp->uz[col]); + else if (lp->vstat[col] == STAT_LOWER && EGlpNumIsNeqqZero (lp->lz[col])) + EGlpNumCopy (xval, lp->lz[col]); + + if (EGlpNumIsNeqqZero (xval)) + { + mcnt = lp->matcnt[col]; + mbeg = lp->matbeg[col]; + for (i = 0; i < mcnt; i++) + EGlpNumSubInnProdTo (srhs->coef[lp->matind[mbeg + i]], xval, + lp->matval[mbeg + i]); + } + } + for (i = 0, r = 0; i < lp->nrows; i++) + if (EGlpNumIsNeqqZero (srhs->coef[i])) + { + EGlpNumCopy (srhs->coef[r], srhs->coef[i]); + srhs->indx[r] = i; + r++; + } + srhs->nzcnt = r; + + ILLbasis_column_solve (lp, srhs, ssoln); + for (i = 0; i < ssoln->nzcnt; i++) + EGlpNumCopy (lp->xbz[ssoln->indx[i]], ssoln->coef[i]); + EGlpNumClearVar (xval); +} + +void ILLfct_compute_piz ( + lpinfo * lp) +{ + int i, r; + svector *srhs = &(lp->srhs); + svector *ssoln = &(lp->ssoln); + + for (i = 0, r = 0; i < lp->nrows; i++) + { + EGlpNumZero (lp->piz[i]); + if (EGlpNumIsNeqqZero (lp->cz[lp->baz[i]])) + { + srhs->indx[r] = i; + EGlpNumCopy (srhs->coef[r], lp->cz[lp->baz[i]]); + r++; + } + } + srhs->nzcnt = r; + + ILLbasis_row_solve (lp, srhs, ssoln); + for (i = 0; i < ssoln->nzcnt; i++) + EGlpNumCopy (lp->piz[ssoln->indx[i]], ssoln->coef[i]); +} + +void ILLfct_compute_dz ( + lpinfo * lp) +{ + int i, j; + int col; + int mcnt, mbeg; + EGlpNum_t sum; + + EGlpNumInitVar (sum); + + for (j = 0; j < lp->nnbasic; j++) + { + EGlpNumZero (sum); + col = lp->nbaz[j]; + mcnt = lp->matcnt[col]; + mbeg = lp->matbeg[col]; + for (i = 0; i < mcnt; i++) + EGlpNumAddInnProdTo (sum, lp->piz[lp->matind[mbeg + i]], + lp->matval[mbeg + i]); + EGlpNumCopyDiff (lp->dz[j], lp->cz[col], sum); + } + EGlpNumClearVar (sum); +} + +void ILLfct_compute_phaseI_xbz ( + lpinfo * lp) +{ + int i, j, r; + int col, mcnt, mbeg; + svector *srhs = &(lp->srhs); + svector *ssoln = &(lp->ssoln); + + for (i = 0; i < lp->nrows; i++) + { + EGlpNumZero (lp->xbz[i]); + EGlpNumZero (srhs->coef[i]); + } + for (j = 0; j < lp->nnbasic; j++) + { + col = lp->nbaz[j]; + + if (lp->dfeas[j]) + { + mcnt = lp->matcnt[col]; + mbeg = lp->matbeg[col]; + if (lp->dfeas[j] == -1) + for (i = 0; i < mcnt; i++) + EGlpNumSubTo (srhs->coef[lp->matind[mbeg + i]], lp->matval[mbeg + i]); + else + for (i = 0; i < mcnt; i++) + EGlpNumAddTo (srhs->coef[lp->matind[mbeg + i]], lp->matval[mbeg + i]); + } + } + for (i = 0, r = 0; i < lp->nrows; i++) + if (EGlpNumIsNeqqZero (srhs->coef[i])) + { + EGlpNumCopy (srhs->coef[r], srhs->coef[i]); + srhs->indx[r] = i; + r++; + } + srhs->nzcnt = r; + + ILLbasis_column_solve (lp, srhs, ssoln); + for (i = 0; i < ssoln->nzcnt; i++) + EGlpNumCopy (lp->xbz[ssoln->indx[i]], ssoln->coef[i]); +} + +void ILLfct_compute_phaseI_piz ( + lpinfo * lp) +{ + int i, r; + svector *srhs = &(lp->srhs); + svector *ssoln = &(lp->ssoln); + + for (i = 0, r = 0; i < lp->nrows; i++) + { + EGlpNumZero (lp->pIpiz[i]); + if (lp->bfeas[i] != 0) + { + srhs->indx[r] = i; + EGlpNumSet (srhs->coef[r], (double) lp->bfeas[i]); + r++; + } + } + srhs->nzcnt = r; + + ILLbasis_row_solve (lp, srhs, ssoln); + for (i = 0; i < ssoln->nzcnt; i++) + EGlpNumCopy (lp->pIpiz[ssoln->indx[i]], ssoln->coef[i]); + ILLfct_update_counts (lp, CNT_P1PINZ, ssoln->nzcnt, zeroLpNum); +} + +void ILLfct_compute_phaseI_dz ( + lpinfo * lp) +{ + int i, j; + int col; + int mcnt, mbeg; + EGlpNum_t sum; + + EGlpNumInitVar (sum); + ILL_IFTRACE ("%s\n", __func__); + + for (j = 0; j < lp->nnbasic; j++) + { + EGlpNumZero (sum); + col = lp->nbaz[j]; + mcnt = lp->matcnt[col]; + mbeg = lp->matbeg[col]; + for (i = 0; i < mcnt; i++) + EGlpNumAddInnProdTo (sum, lp->pIpiz[lp->matind[mbeg + i]], + lp->matval[mbeg + i]); + EGlpNumCopyNeg (lp->pIdz[j], sum); + ILL_IFTRACE ("%d:%d:%lf:%la\n", j, col, EGlpNumToLf (sum), + EGlpNumToLf (sum)); + } + EGlpNumClearVar (sum); +} + +void ILLfct_compute_yz ( + lpinfo * lp, + svector * yz, + svector * updz, + int col) +{ + svector a; + + a.nzcnt = lp->matcnt[col]; + a.indx = &(lp->matind[lp->matbeg[col]]); + a.coef = &(lp->matval[lp->matbeg[col]]); + + ILLfactor_set_factor_dparam (lp->f, QS_FACTOR_SZERO_TOL, PIVZ_TOLER); + if (updz) + ILLbasis_column_solve_update (lp, &a, updz, yz); + else + ILLbasis_column_solve (lp, &a, yz); + ILLfactor_set_factor_dparam (lp->f, QS_FACTOR_SZERO_TOL, SZERO_TOLER); +} + +void ILLfct_compute_zz ( + lpinfo * lp, + svector * zz, + int row) +{ + ILLfct_compute_binvrow (lp, zz, row, PIVZ_TOLER); +} + +void ILLfct_compute_binvrow ( + lpinfo * lp, + svector * zz, + int row, + EGlpNum_t ztoler) +{ + svector a; + EGlpNum_t e; + + EGlpNumInitVar (e); + EGlpNumOne (e); + + a.nzcnt = 1; + a.coef = &e; + a.indx = &row; + + if (EGlpNumIsGreatZero (ztoler)) + ILLfactor_set_factor_dparam (lp->f, QS_FACTOR_SZERO_TOL, ztoler); + ILLbasis_row_solve (lp, &a, zz); + if (EGlpNumIsGreatZero (ztoler)) + ILLfactor_set_factor_dparam (lp->f, QS_FACTOR_SZERO_TOL, SZERO_TOLER); + EGlpNumClearVar (e); +} + +void ILLfct_compute_psteep_upv ( + lpinfo * lp, + svector * swz) +{ + ILLbasis_row_solve (lp, &(lp->yjz), swz); +} + +void ILLfct_compute_dsteep_upv ( + lpinfo * lp, + svector * swz) +{ + ILLbasis_column_solve (lp, &(lp->zz), swz); +} + +static int compute_zA1 ( + lpinfo * lp, + svector * z, + svector * zA, + EGlpNum_t ztoler) +{ + int rval = 0; + int i, j, nz = 0; + int col, mcnt, mbeg; + EGlpNum_t sum; + EGlpNum_t *v = 0; + + EGlpNumInitVar (sum); + v = EGlpNumAllocArray (lp->nrows); + + for (i = 0; i < lp->nrows; i++) + EGlpNumZero (v[i]); + for (i = 0; i < z->nzcnt; i++) + EGlpNumCopy (v[z->indx[i]], z->coef[i]); + + for (j = 0; j < lp->nnbasic; j++) + { + EGlpNumZero (sum); + col = lp->nbaz[j]; + mcnt = lp->matcnt[col]; + mbeg = lp->matbeg[col]; + for (i = 0; i < mcnt; i++) + EGlpNumAddInnProdTo (sum, v[lp->matind[mbeg + i]], lp->matval[mbeg + i]); + + if (EGlpNumIsNeqZero (sum, ztoler)) + { + EGlpNumCopy (zA->coef[nz], sum); + zA->indx[nz] = j; + nz++; + } + } + zA->nzcnt = nz; + + EGlpNumClearVar (sum); + EGlpNumFreeArray (v); + EG_RETURN (rval); +} + + +static int compute_zA3 ( + lpinfo * lp, + svector * z, + svector * zA, + EGlpNum_t ztoler) +{ + int rval = 0; + int i, j, k, ix; + int nz = 0; + int row, col; + int rcnt, rbeg; + EGlpNum_t val; + + EGlpNumInitVar (val); + k = 0; + for (i = 0; i < z->nzcnt; i++) + { + row = z->indx[i]; + EGlpNumCopy (val, z->coef[i]); + rcnt = lp->rowcnt[row]; + rbeg = lp->rowbeg[row]; + for (j = 0; j < rcnt; j++) + { + col = lp->rowind[rbeg + j]; + if (lp->vstat[col] != STAT_BASIC) + { + ix = lp->vindex[col]; + if (lp->iwork[ix] == 0) + { + lp->iwork[ix] = 1; + lp->work.indx[k++] = ix; + } + EGlpNumAddInnProdTo (lp->work.coef[ix], val, lp->rowval[rbeg + j]); + } + } + } + for (j = 0; j < k; j++) + { + ix = lp->work.indx[j]; + EGlpNumCopy (val, lp->work.coef[ix]); + EGlpNumZero (lp->work.coef[ix]); + lp->iwork[ix] = 0; + if (EGlpNumIsNeqZero (val, ztoler)) + { + EGlpNumCopy (zA->coef[nz], val); + zA->indx[nz] = ix; + nz++; + } + } + zA->nzcnt = nz; + EGlpNumClearVar (val); + EG_RETURN (rval); +} + +int ILLfct_compute_zA ( + lpinfo * lp, + svector * z, + svector * zA) +{ + if (z->nzcnt < lp->nrows / 2) + return compute_zA3 (lp, z, zA, PIVZ_TOLER); + else + return compute_zA1 (lp, z, zA, PIVZ_TOLER); +} + +/* compute v^T A */ +void ILLfct_compute_vA ( + lpinfo * lp, + svector * v, + EGlpNum_t * vA) +{ + int i, j; + int row, col; + int rcnt, rbeg; + EGlpNum_t val; + + EGlpNumInitVar (val); + + for (j = 0; j < lp->ncols; j++) + EGlpNumZero (vA[j]); + + for (i = 0; i < v->nzcnt; i++) + { + row = v->indx[i]; + EGlpNumCopy (val, v->coef[i]); + rcnt = lp->rowcnt[row]; + rbeg = lp->rowbeg[row]; + for (j = 0; j < rcnt; j++) + { + col = lp->rowind[rbeg + j]; + EGlpNumAddInnProdTo (vA[col], val, lp->rowval[rbeg + j]); + } + } + + for (j = 0; j < lp->ncols; j++) + if (!EGlpNumIsNeqZero (vA[j], SZERO_TOLER)) + EGlpNumZero (vA[j]); + + EGlpNumClearVar (val); + return; +} + +/* update information */ + +/* +1) lvstat - new status of leaving var. +*/ +void ILLfct_update_basis_info ( + lpinfo * lp, + int eindex, + int lindex, + int lvstat) +{ + int evar; + int lvar; + + evar = lp->nbaz[eindex]; + + if (lindex >= 0) + { /* variable leaves basis */ + lvar = lp->baz[lindex]; + lp->vstat[evar] = STAT_BASIC; + lp->vstat[lvar] = lvstat; + lp->vindex[evar] = lindex; + lp->vindex[lvar] = eindex; + lp->baz[lindex] = evar; + lp->nbaz[eindex] = lvar; + (lp->basisid)++; + } + else + { + lp->vstat[evar] = (lp->vstat[evar] == STAT_LOWER) ? STAT_UPPER : STAT_LOWER; + } +} + +void ILLfct_update_xz ( + lpinfo * lp, + EGlpNum_t tz, + int eindex, + int lindex) +{ + int i, evar, estat; + + ILL_IFTRACE ("%s:%la:%d:%d:%d\n", __func__, EGlpNumToLf (tz), eindex, + lindex, lp->yjz.nzcnt); + + if (EGlpNumIsNeqqZero (tz)) + for (i = 0; i < lp->yjz.nzcnt; i++) + EGlpNumSubInnProdTo (lp->xbz[lp->yjz.indx[i]], tz, lp->yjz.coef[i]); + + if (lindex >= 0) + { /* variable leaves basis */ + evar = lp->nbaz[eindex]; + estat = lp->vstat[evar]; + if (estat == STAT_LOWER) + EGlpNumCopySum (lp->xbz[lindex], lp->lz[evar], tz); + else if (estat == STAT_UPPER) + EGlpNumCopySum (lp->xbz[lindex], lp->uz[evar], tz); + else if (estat == STAT_ZERO) + EGlpNumCopy (lp->xbz[lindex], tz); + } +} + +void ILLfct_update_piz ( + lpinfo * lp, + EGlpNum_t alpha) +{ + int i; + + for (i = 0; i < lp->zz.nzcnt; i++) + EGlpNumAddInnProdTo (lp->piz[lp->zz.indx[i]], alpha, lp->zz.coef[i]); +} + +void ILLfct_update_pIpiz ( + lpinfo * lp, + svector * z, + const EGlpNum_t alpha) +{ + int i; + + if (!EGlpNumIsNeqqZero (alpha)) + return; + if (EGlpNumIsEqqual (alpha, oneLpNum)) + { + for (i = 0; i < z->nzcnt; i++) + EGlpNumAddTo (lp->pIpiz[z->indx[i]], z->coef[i]); + } + else + { + for (i = 0; i < z->nzcnt; i++) + EGlpNumAddInnProdTo (lp->pIpiz[z->indx[i]], alpha, z->coef[i]); + } +} + +void ILLfct_update_dz ( + lpinfo * lp, + int eindex, + EGlpNum_t alpha) +{ + int i; + + for (i = 0; i < lp->zA.nzcnt; i++) + EGlpNumSubInnProdTo (lp->dz[lp->zA.indx[i]], alpha, lp->zA.coef[i]); + EGlpNumCopyNeg (lp->dz[eindex], alpha); +} + +void ILLfct_update_pIdz ( + lpinfo * lp, + svector * zA, + int eindex, + const EGlpNum_t alpha) +{ + int i; + + if (!EGlpNumIsNeqqZero (alpha)) + return; + + if (EGlpNumIsEqqual (alpha, oneLpNum)) + { + for (i = 0; i < zA->nzcnt; i++) + EGlpNumSubTo (lp->pIdz[zA->indx[i]], zA->coef[i]); + } + else + { + for (i = 0; i < zA->nzcnt; i++) + EGlpNumSubInnProdTo (lp->pIdz[zA->indx[i]], alpha, zA->coef[i]); + } + if (eindex > -1) + EGlpNumCopyNeg (lp->pIdz[eindex], alpha); +} + +/* bound and coef shift routines */ + +/* scale bound in my_rand to get more random digits, unless bound is large */ +static double my_rand ( + int bound, + ILLrandstate * r) +{ + int k = bound, scale = 1; + double v = 0.0; + + if (bound < 100000) + { + k = 20000 * bound; + scale = 20000; + } + v = 1 + (ILLutil_lprand (r) % (k)); + return v / (double) scale; +} + +static int expand_var_bounds ( + lpinfo * lp, + EGlpNum_t ftol, + int *chgb) +{ + int rval = 0; + int i, col, nchg = 0; + EGlpNum_t newb, cftol; + EGlpNum_t *x, *l, *u; + ILLrandstate r; + + EGlpNumInitVar (newb); + EGlpNumInitVar (cftol); + EGlpNumCopyAbs (cftol, ftol); + EGlpNumDivUiTo (cftol, 10); + + ILLutil_sprand (1, &r); + + for (i = 0; i < lp->nrows; i++) + { + col = lp->baz[i]; + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFREE) + continue; + x = &(lp->xbz[i]); + l = &(lp->lz[col]); + u = &(lp->uz[col]); + /* we use newb as temporal variable outside the if's scope */ + EGlpNumCopyDiff (newb, *x, ftol); + if (EGlpNumIsNeqq (*l, NINFTY) && EGlpNumIsLess (newb, *l)) + { + EGlpNumSet (newb, -1.0 * (my_rand (50, &(lp->rstate)) + 1.0)); + EGlpNumMultTo (newb, cftol); + if (EGlpNumIsLess (*x, *l)) + EGlpNumAddTo (newb, *x); + else + EGlpNumAddTo (newb, *l); + rval = ILLfct_bound_shift (lp, col, BOUND_LOWER, newb); + CHECKRVALG (rval, CLEANUP); + nchg++; + } + EGlpNumCopySum (newb, *x, ftol); + if (EGlpNumIsNeqq (*u, INFTY) && EGlpNumIsLess (*u, newb)) + { + EGlpNumSet (newb, my_rand (50, &(lp->rstate)) + 1.0); + EGlpNumMultTo (newb, cftol); + if (EGlpNumIsLess (*x, *u)) + EGlpNumAddTo (newb, *u); + else + EGlpNumAddTo (newb, *x); + rval = ILLfct_bound_shift (lp, col, BOUND_UPPER, newb); + CHECKRVALG (rval, CLEANUP); + nchg++; + } + } + *chgb = nchg; + +CLEANUP: + EGlpNumClearVar (newb); + EGlpNumClearVar (cftol); + EG_RETURN (rval); +} + +static int expand_phaseI_bounds ( + lpinfo * lp, + int *chgb) +{ + int rval = 0; + int i, col, nchg = 0; + EGlpNum_t newb, cftol; + EGlpNum_t *u, *l, *x; + ILLrandstate r; + + EGlpNumInitVar (newb); + EGlpNumInitVar (cftol); + EGlpNumCopyAbs (cftol, lp->tol->ip_tol); + EGlpNumDivUiTo (cftol, 10); + ILLutil_sprand (1, &r); + + for (i = 0; i < lp->nrows; i++) + { + col = lp->baz[i]; + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFREE) + continue; + x = &(lp->xbz[i]); + l = &(lp->lz[col]); + u = &(lp->uz[col]); + + if (EGlpNumIsNeqq (*l, NINFTY) && EGlpNumIsEqual (*x, *l, cftol)) + { + EGlpNumSet (newb, my_rand (50, &(lp->rstate)) + 1.0); + EGlpNumMultTo (newb, cftol); + EGlpNumSign (newb); + EGlpNumAddTo (newb, *l); + rval = ILLfct_bound_shift (lp, col, BOUND_LOWER, newb); + CHECKRVALG (rval, CLEANUP); + nchg++; + } + if (EGlpNumIsNeqq (*u, INFTY) && EGlpNumIsEqual (*x, *u, cftol)) + { + EGlpNumSet (newb, my_rand (50, &(lp->rstate)) + 1.0); + EGlpNumMultTo (newb, cftol); + EGlpNumAddTo (newb, *u); + rval = ILLfct_bound_shift (lp, col, BOUND_UPPER, newb); + CHECKRVALG (rval, CLEANUP); + nchg++; + } + } + *chgb = nchg; + +CLEANUP: + EGlpNumClearVar (newb); + EGlpNumClearVar (cftol); + EG_RETURN (rval); +} + +int ILLfct_adjust_viol_bounds ( + lpinfo * lp) +{ + int rval = 0; + int chgb = 0; + EGlpNum_t tol; + + EGlpNumInitVar (tol); + EGlpNumCopyNeg (tol, lp->tol->pfeas_tol); + rval = expand_var_bounds (lp, tol, &chgb); +#if FCT_DEBUG > 0 + if (rval == 0) + printf ("adjusting %d bounds\n", chgb); +#endif + EGlpNumClearVar (tol); + EG_RETURN (rval); +} + +int ILLfct_perturb_bounds ( + lpinfo * lp) +{ + int rval = 0; + int chgb = 0; + + rval = expand_var_bounds (lp, lp->tol->ip_tol, &chgb); +#if FCT_DEBUG > 0 + if (rval == 0) + printf ("perturbing %d bounds\n", chgb); +#endif + EG_RETURN (rval); +} + +int ILLfct_perturb_phaseI_bounds ( + lpinfo * lp) +{ + int rval = 0; + int chgb = 0; + + rval = expand_phaseI_bounds (lp, &chgb); +#if FCT_DEBUG > 0 + if (rval == 0) + printf ("perturbing %d phase I bounds\n", chgb); +#endif + EG_RETURN (rval); +} + +int ILLfct_bound_shift ( + lpinfo * lp, + int col, + int bndtype, + EGlpNum_t newbnd) +{ + int rval = 0; + bndinfo *nbnd = 0; + + ILL_IFTRACE ("\n%s:%d:%d:%la", __func__, col, bndtype, EGlpNumToLf (newbnd)); + nbnd = ILLfct_new_bndinfo (); + + nbnd->varnum = col; + nbnd->btype = bndtype; + if (bndtype == BOUND_LOWER) + { + EGlpNumCopy (nbnd->pbound, lp->lz[col]); + EGlpNumCopy (nbnd->cbound, newbnd); + EGlpNumCopy (lp->lz[col], newbnd); + } + else + { + EGlpNumCopy (nbnd->pbound, lp->uz[col]); + EGlpNumCopy (nbnd->cbound, newbnd); + EGlpNumCopy (lp->uz[col], newbnd); + } + ILL_IFTRACE (":%la", EGlpNumToLf (nbnd->pbound)); + if (lp->vtype[col] == VFIXED || lp->vtype[col] == VARTIFICIAL) + { + /* printf ("changing f/a bound\n"); */ + if (EGlpNumIsLess (lp->lz[col], lp->uz[col])) + lp->vtype[col] = VBOUNDED; + } + + nbnd->next = lp->bchanges; + lp->bchanges = nbnd; + lp->nbchange++; + +//CLEANUP: + if (rval) + ILLfct_free_bndinfo (nbnd); + ILL_IFTRACE ("\n"); + EG_RETURN (rval); +} + +void ILLfct_unroll_bound_change ( + lpinfo * lp) +{ + int col; + int changex = 0; + bndinfo *bptr = lp->bchanges; + bndinfo *nptr = 0; + + ILL_IFTRACE ("%s:", __func__); + + while (lp->nbchange != 0) + { + col = bptr->varnum; + ILL_IFTRACE (":%d", col); + + if (bptr->btype == BOUND_UPPER) + EGlpNumCopy (lp->uz[col], bptr->pbound); + else + EGlpNumCopy (lp->lz[col], bptr->pbound); + + if (lp->vtype[col] == VBOUNDED) + { + if (EGlpNumIsEqqual (lp->lz[col], lp->uz[col])) + lp->vtype[col] = (!EGlpNumIsNeqqZero (lp->lz[col])) ? + VARTIFICIAL : VFIXED; + } + + if (lp->vstat[col] != STAT_BASIC) + { + if ((bptr->btype == BOUND_UPPER && lp->vstat[col] == STAT_UPPER) || + (bptr->btype == BOUND_LOWER && lp->vstat[col] == STAT_LOWER)) + changex++; + } + nptr = bptr->next; + EGlpNumClearVar ((bptr->cbound)); + EGlpNumClearVar ((bptr->pbound)); + ILL_IFFREE (bptr, bndinfo); + bptr = nptr; + lp->nbchange--; + } + lp->bchanges = bptr; + ILL_IFTRACE ("\n"); + if (changex) + ILLfct_compute_xbz (lp); +} + +static int expand_var_coefs ( + lpinfo * lp, + EGlpNum_t ftol, + int *chgc) +{ + int rval = 0; + int i, col, vs, vt; + int nchg = 0; + EGlpNum_t newc, cftol, mftol[1]; + EGlpNum_t *c, *dj; + ILLrandstate r; + + EGlpNumInitVar (newc); + EGlpNumInitVar (cftol); + EGlpNumInitVar (mftol[0]); + EGlpNumCopyAbs (cftol, ftol); + EGlpNumDivUiTo (cftol, 10); + EGlpNumCopyNeg (mftol[0], ftol); + ILLutil_sprand (1, &r); + + for (i = 0; i < lp->nnbasic; i++) + { + dj = &(lp->dz[i]); + col = lp->nbaz[i]; + c = &(lp->cz[col]); + vs = lp->vstat[col]; + vt = lp->vtype[col]; + + if (vt == VARTIFICIAL || vt == VFIXED) + continue; + switch (vs) + { + case STAT_ZERO: + EGlpNumCopyDiff (newc, *c, *dj); + rval = ILLfct_coef_shift (lp, col, newc); + CHECKRVALG (rval, CLEANUP); + nchg++; + break; + case STAT_LOWER: + if (EGlpNumIsLess (*dj, ftol)) + { + EGlpNumSet (newc, my_rand (50, &(lp->rstate)) + 1.0); + EGlpNumMultTo (newc, cftol); + EGlpNumAddTo (newc, *c); + if (EGlpNumIsLessZero (*dj)) + EGlpNumSubTo (newc, *dj); + rval = ILLfct_coef_shift (lp, col, newc); + CHECKRVALG (rval, CLEANUP); + nchg++; + } + break; + case STAT_UPPER: + if (EGlpNumIsLess (mftol[0], *dj)) + { + EGlpNumSet (newc, my_rand (50, &(lp->rstate)) + 1.0); + EGlpNumMultTo (newc, cftol); + EGlpNumSign (newc); + EGlpNumAddTo (newc, *c); + if (EGlpNumIsGreatZero (*dj)) + EGlpNumSubTo (newc, *dj); + rval = ILLfct_coef_shift (lp, col, newc); + CHECKRVALG (rval, CLEANUP); + nchg++; + } + break; + default: + break; + } + } + *chgc = nchg; + +CLEANUP: + EGlpNumClearVar (mftol[0]); + EGlpNumClearVar (newc); + EGlpNumClearVar (cftol); + EG_RETURN (rval); +} + +int ILLfct_adjust_viol_coefs ( + lpinfo * lp) +{ + int rval = 0; + int chgc = 0; + EGlpNum_t tol; + + EGlpNumInitVar (tol); + EGlpNumCopyNeg (tol, lp->tol->dfeas_tol); + + rval = expand_var_coefs (lp, tol, &chgc); +#if FCT_DEBUG > 0 + if (rval == 0) + printf ("perturbing %d coefs\n", chgc); +#endif + EGlpNumClearVar (tol); + EG_RETURN (rval); +} + +int ILLfct_perturb_coefs ( + lpinfo * lp) +{ + int rval = 0; + int chgc = 0; + + rval = expand_var_coefs (lp, lp->tol->id_tol, &chgc); +#if FCT_DEBUG > 0 + if (rval == 0) + printf ("perturbing %d coefs\n", chgc); +#endif + EG_RETURN (rval); +} + +int ILLfct_coef_shift ( + lpinfo * lp, + int col, + EGlpNum_t newcoef) +{ + int rval = 0; + coefinfo *ncoef = 0; + + ILL_SAFE_MALLOC (ncoef, 1, coefinfo); + EGlpNumInitVar ((ncoef->pcoef)); + EGlpNumInitVar ((ncoef->ccoef)); + + ncoef->varnum = col; + EGlpNumCopy (ncoef->pcoef, lp->cz[col]); + EGlpNumCopy (ncoef->ccoef, newcoef); + EGlpNumCopy (lp->cz[col], newcoef); + ncoef->next = lp->cchanges; + lp->cchanges = ncoef; + EGlpNumAddTo (lp->dz[lp->vindex[col]], ncoef->ccoef); + EGlpNumSubTo (lp->dz[lp->vindex[col]], ncoef->pcoef); + lp->ncchange++; + +CLEANUP: + if (rval) + { + EGlpNumClearVar ((ncoef->pcoef)); + EGlpNumClearVar ((ncoef->ccoef)); + ILL_IFFREE (ncoef, coefinfo); + } + EG_RETURN (rval); +} + +void ILLfct_unroll_coef_change ( + lpinfo * lp) +{ + int bascoef = 0; + coefinfo *cptr = (coefinfo *) lp->cchanges; + coefinfo *nptr = 0; + + while (lp->ncchange != 0) + { + EGlpNumCopy (lp->cz[cptr->varnum], cptr->pcoef); + if (lp->vstat[cptr->varnum] != STAT_BASIC) + { + EGlpNumAddTo (lp->dz[lp->vindex[cptr->varnum]], cptr->pcoef); + EGlpNumSubTo (lp->dz[lp->vindex[cptr->varnum]], cptr->ccoef); + } + else + bascoef++; + + nptr = cptr->next; + EGlpNumClearVar ((cptr->pcoef)); + EGlpNumClearVar ((cptr->ccoef)); + ILL_IFFREE (cptr, coefinfo); + cptr = nptr; + lp->ncchange--; + } + lp->cchanges = cptr; + if (bascoef) + { + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + } +} + +/* feasibility routines */ +void ILLfct_check_pfeasible ( + lpinfo * lp, + feas_info * fs, + const EGlpNum_t ftol) +{ + int i, col; + EGlpNum_t infeas, err1, err2; + + EGlpNumInitVar (infeas); + EGlpNumInitVar (err1); + EGlpNumInitVar (err2); + EGlpNumZero (infeas); + fs->pstatus = PRIMAL_FEASIBLE; + EGlpNumZero (fs->totinfeas); + ILL_IFTRACE ("%s:tol %la\n", __func__, EGlpNumToLf (ftol)); + + for (i = 0; i < lp->nrows; i++) + { + col = lp->baz[i]; + EGlpNumCopyDiff (err1, lp->xbz[i], lp->uz[col]); + EGlpNumCopyDiff (err2, lp->lz[col], lp->xbz[i]); + if (EGlpNumIsLess (ftol, err1) + && EGlpNumIsNeq (lp->uz[col], INFTY, oneLpNum)) + { + EGlpNumAddTo (infeas, err1); + WARNINGL (QSE_WLVL, EGlpNumIsLess (INFTY, err1), + "This is imposible lu = %15lg xbz = %15lg" " INFTY = %15lg", + EGlpNumToLf (lp->uz[col]), EGlpNumToLf (lp->xbz[i]), + EGlpNumToLf (INFTY)); + lp->bfeas[i] = 1; + } + else if (EGlpNumIsLess (ftol, err2) + && EGlpNumIsNeq (lp->lz[col], NINFTY, oneLpNum)) + { + EGlpNumAddTo (infeas, err2); + WARNINGL (QSE_WLVL, EGlpNumIsLess (INFTY, err2), + "This is imposible lz = %15lg xbz = %15lg" " NINFTY = %15lg", + EGlpNumToLf (lp->lz[col]), EGlpNumToLf (lp->xbz[i]), + EGlpNumToLf (NINFTY)); + lp->bfeas[i] = -1; + } + else + lp->bfeas[i] = 0; + } + if (EGlpNumIsNeqqZero (infeas)) + { + fs->pstatus = PRIMAL_INFEASIBLE; + EGlpNumCopy (fs->totinfeas, infeas); + ILL_IFTRACE ("%s:inf %la\n", __func__, EGlpNumToLf (infeas)); + if (EGlpNumIsLessZero (fs->totinfeas)) + { + printf ("Negative infeasibility, Imposible! %lf %la\n", + EGlpNumToLf (infeas), EGlpNumToLf (infeas)); + } + } + EGlpNumCopy (lp->pinfeas, infeas); + EGlpNumClearVar (infeas); + EGlpNumClearVar (err1); + EGlpNumClearVar (err2); +} + +/* feasibility routines */ +void ILLfct_check_pIpfeasible ( + lpinfo * lp, + feas_info * fs, + EGlpNum_t ftol) +{ + int i, col; + int ninf = 0; + + fs->pstatus = PRIMAL_FEASIBLE; + EGlpNumZero (fs->totinfeas); + + for (i = 0; i < lp->nrows; i++) + { + if (!EGlpNumIsNeqZero (lp->xbz[i], ftol)) + continue; + col = lp->baz[i]; + if (EGlpNumIsGreatZero(lp->xbz[i]) && + EGlpNumIsNeqq (lp->uz[col], INFTY)) + { + ninf++; + } + else if (EGlpNumIsLessZero (lp->xbz[i]) && + EGlpNumIsNeqq (lp->lz[col], NINFTY)) + { + ninf++; + } + } + if (ninf != 0) + fs->pstatus = PRIMAL_INFEASIBLE; +} + +void ILLfct_check_dfeasible ( + lpinfo * lp, + feas_info * fs, + const EGlpNum_t ftol) +{ + int j, col; + EGlpNum_t infeas; + + EGlpNumInitVar (infeas); + EGlpNumZero (infeas); + fs->dstatus = DUAL_FEASIBLE; + EGlpNumZero (fs->totinfeas); + + for (j = 0; j < lp->nnbasic; j++) + { + lp->dfeas[j] = 0; + if (!EGlpNumIsNeqZero (lp->dz[j], ftol)) + continue; + col = lp->nbaz[j]; + + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED) + continue; + + if (EGlpNumIsLessZero (lp->dz[j]) && + (lp->vstat[col] == STAT_LOWER || lp->vstat[col] == STAT_ZERO)) + { + EGlpNumSubTo (infeas, lp->dz[j]); + lp->dfeas[j] = -1; + } + else if (EGlpNumIsGreatZero (lp->dz[j]) && + (lp->vstat[col] == STAT_UPPER || lp->vstat[col] == STAT_ZERO)) + { + EGlpNumAddTo (infeas, lp->dz[j]); + lp->dfeas[j] = 1; + } + } + + if (EGlpNumIsNeqqZero (infeas)) + { + EGlpNumCopy (fs->totinfeas, infeas); + fs->dstatus = DUAL_INFEASIBLE; + ILL_IFTRACE ("%s:inf %la\n", __func__, EGlpNumToLf (infeas)); + if (EGlpNumIsLessZero (fs->totinfeas)) + { + printf ("Negative infeasibility, Imposible! %lf %la\n", + EGlpNumToLf (infeas), EGlpNumToLf (infeas)); + } + } + EGlpNumCopy (lp->dinfeas, infeas); + EGlpNumClearVar (infeas); +} + +void ILLfct_check_pIdfeasible ( + lpinfo * lp, + feas_info * fs, + EGlpNum_t ftol) +{ + int j, col; + int ninf = 0; + EGlpNum_t *dz = lp->pIdz; + + fs->dstatus = DUAL_FEASIBLE; + + for (j = 0; j < lp->nnbasic; j++) + { + if (!EGlpNumIsNeqZero (dz[j], ftol)) + continue; + col = lp->nbaz[j]; + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED) + continue; + + if (EGlpNumIsLessZero (dz[j]) && + (lp->vstat[col] == STAT_LOWER || lp->vstat[col] == STAT_ZERO)) + ninf++; + else if (EGlpNumIsGreatZero (dz[j]) && + (lp->vstat[col] == STAT_UPPER || lp->vstat[col] == STAT_ZERO)) + ninf++; + } + + if (ninf != 0) + fs->dstatus = DUAL_INFEASIBLE; +} + +void ILLfct_dual_adjust ( + lpinfo * lp, + const EGlpNum_t ftol) +{ + int j, col; + + for (j = 0; j < lp->nnbasic; j++) + { + if (!EGlpNumIsNeqZero (lp->dz[j], ftol)) + continue; + col = lp->nbaz[j]; + if (EGlpNumIsLessZero (lp->dz[j]) && + EGlpNumIsNeqq (lp->uz[col], INFTY)) + lp->vstat[col] = STAT_UPPER; + else if (EGlpNumIsGreatZero (lp->dz[j]) && + EGlpNumIsNeqq (lp->lz[col], NINFTY)) + lp->vstat[col] = STAT_LOWER; + } +} + +void ILLfct_dphaseI_simple_update ( + lpinfo * lp, + EGlpNum_t ftol) +{ + int j, col; + + for (j = 0; j < lp->nnbasic; j++) + { + if (!EGlpNumIsNeqZero (lp->dz[j], ftol)) + continue; + col = lp->nbaz[j]; + if (EGlpNumIsLessZero (lp->dz[j] ) && lp->vtype[col] == VBOUNDED) + lp->vstat[col] = STAT_UPPER; + else if (EGlpNumIsGreatZero (lp->dz[j]) && lp->vtype[col] == VBOUNDED) + lp->vstat[col] = STAT_LOWER; + } +} + +/* set status values */ +void ILLfct_set_status_values ( + lpinfo * lp, + int pstatus, + int dstatus, + int ptype, + int dtype) +{ + if (dstatus == DUAL_FEASIBLE && dtype == PHASEII) + { + if (!lp->ncchange) + { + lp->probstat.dual_feasible = 1; + lp->basisstat.dual_feasible = 1; + lp->basisstat.dual_infeasible = 0; + } + } + if (dstatus == DUAL_INFEASIBLE && dtype == PHASEII) + { + if (!lp->ncchange) + { + lp->basisstat.dual_feasible = 0; + lp->basisstat.dual_infeasible = 1; + } + if (pstatus == PRIMAL_FEASIBLE && ptype == PHASEI) + if (!lp->ncchange) + lp->probstat.dual_infeasible = 1; + } + if (pstatus == PRIMAL_FEASIBLE && ptype == PHASEII) + { + if (!lp->nbchange) + { + lp->probstat.primal_feasible = 1; + lp->basisstat.primal_feasible = 1; + lp->basisstat.primal_infeasible = 0; + } + } + if (pstatus == PRIMAL_INFEASIBLE && ptype == PHASEII) + { + lp->basisstat.primal_feasible = 0; + lp->basisstat.primal_infeasible = 1; + + if (dstatus == DUAL_FEASIBLE && dtype == PHASEI) + lp->probstat.primal_infeasible = 1; + } + if (pstatus == PRIMAL_UNBOUNDED) + { + if (!lp->nbchange) + { + lp->probstat.primal_unbounded = 1; + lp->basisstat.primal_unbounded = 1; + lp->probstat.dual_infeasible = 1; + lp->basisstat.dual_infeasible = 1; + lp->basisstat.dual_feasible = 0; + } + } + if (dstatus == DUAL_UNBOUNDED) + { + if (!lp->ncchange) + { + lp->probstat.dual_unbounded = 1; + lp->basisstat.dual_unbounded = 1; + lp->probstat.primal_infeasible = 1; + lp->basisstat.primal_infeasible = 1; + lp->basisstat.primal_feasible = 0; + } + } + if (lp->probstat.primal_feasible && lp->probstat.dual_feasible) + lp->probstat.optimal = 1; + + if (lp->basisstat.primal_feasible && lp->basisstat.dual_feasible) + lp->basisstat.optimal = 1; + else + lp->basisstat.optimal = 0; +} + +void ILLfct_init_counts ( + lpinfo * lp) +{ + int i; + count_struct *c = lp->cnts; + +#define C_VALUE(a) (1.0+(double)(a)/(PARAM_HEAP_RATIO*ILLutil_our_log2(a))) + EGlpNumSet (c->y_ravg, C_VALUE (lp->nrows)); + EGlpNumSet (c->za_ravg, C_VALUE (lp->nnbasic)); + ILL_IFTRACE ("%s:%la\n", __func__, EGlpNumToLf (c->za_ravg)); +#undef C_VALUE + c->ynz_cnt = 0; + c->num_y = 0; + c->znz_cnt = 0; + c->num_z = 0; + c->zanz_cnt = 0; + c->num_za = 0; + c->pnorm_cnt = 0; + c->dnorm_cnt = 0; + c->pinz_cnt = 0; + c->num_pi = 0; + c->pi1nz_cnt = 0; + c->num_pi1 = 0; + c->upnz_cnt = 0; + c->num_up = 0; + c->pupv_cnt = 0; + c->dupv_cnt = 0; + c->pI_iter = 0; + c->pII_iter = 0; + c->dI_iter = 0; + c->dII_iter = 0; + c->tot_iter = 0; + for (i = 0; i < 10; i++) + { + c->pivpI[i] = 0; + c->pivpII[i] = 0; + c->pivdI[i] = 0; + c->pivdII[i] = 0; + } +} + +static void update_piv_values ( + count_struct * c, + int phase, + const EGlpNum_t piv2) +{ + int i = 0; + EGlpNum_t v, piv; + + if (!EGlpNumIsNeqqZero(piv2)) + return; + EGlpNumInitVar (v); + EGlpNumInitVar (piv); + EGlpNumCopyAbs (piv, piv2); + EGlpNumOne (v); + while (EGlpNumIsLess (piv, v) && i < 9) + { + EGlpNumDivUiTo (v, 10); + i++; + } + switch (phase) + { + case PRIMAL_PHASEI: + c->pivpI[i]++; + break; + case PRIMAL_PHASEII: + c->pivpII[i]++; + break; + case DUAL_PHASEI: + c->pivdI[i]++; + break; + case DUAL_PHASEII: + c->pivdII[i]++; + break; + default: + break; + } + EGlpNumClearVar (v); + EGlpNumClearVar (piv); +} + +void ILLfct_update_counts ( + lpinfo * lp, + int f, + int upi, + const EGlpNum_t upd) +{ + count_struct *c = lp->cnts; + + switch (f) + { + case CNT_PPHASE1ITER: + c->pI_iter++; + c->tot_iter++; + break; + case CNT_PPHASE2ITER: + c->pII_iter++; + c->tot_iter++; + break; + case CNT_DPHASE1ITER: + c->dI_iter++; + c->tot_iter++; + break; + case CNT_DPHASE2ITER: + c->dII_iter++; + c->tot_iter++; + break; + case CNT_YNZ: + c->ynz_cnt += upi; + c->num_y++; + break; + case CNT_ZANZ: + c->zanz_cnt += upi; + c->num_za++; + break; + case CNT_PINZ: + c->pinz_cnt += upi; + c->num_pi++; + break; + case CNT_P1PINZ: + c->pi1nz_cnt += upi; + c->num_pi1++; + break; + case CNT_UPNZ: + c->upnz_cnt += upi; + c->num_up++; + break; + case CNT_PIPIV: + update_piv_values (c, PRIMAL_PHASEI, upd); + break; + case CNT_PIIPIV: + update_piv_values (c, PRIMAL_PHASEII, upd); + break; + case CNT_DIPIV: + update_piv_values (c, DUAL_PHASEI, upd); + break; + case CNT_DIIPIV: + update_piv_values (c, DUAL_PHASEII, upd); + break; + case CNT_YRAVG: + EGlpNumMultUiTo (c->y_ravg, c->tot_iter); + EGlpNumAddUiTo (c->y_ravg, upi); + EGlpNumDivUiTo (c->y_ravg, c->tot_iter + 1); + break; + case CNT_ZARAVG: + ILL_IFTRACE ("%s:%d:%d:%d:%la:%la", __func__, f, c->tot_iter, upi, + EGlpNumToLf (upd), EGlpNumToLf (c->za_ravg)); + EGlpNumMultUiTo (c->za_ravg, c->tot_iter); + EGlpNumAddUiTo (c->za_ravg, upi); + EGlpNumDivUiTo (c->za_ravg, c->tot_iter + 1); + ILL_IFTRACE (":%la\n", EGlpNumToLf (c->za_ravg)); + break; + } +} + +void ILLfct_print_counts ( + lpinfo * lp) +{ + int i, niter; + count_struct *c = lp->cnts; + + c->tot_iter = c->pI_iter + c->pII_iter + c->dI_iter + c->dII_iter; + niter = (c->tot_iter == 0) ? 1 : c->tot_iter; + printf ("Counts for problem %s\n", lp->O->probname); + if (c->num_y != 0) + printf ("avg ynz = %.2f\n", (double) c->ynz_cnt / c->num_y); + if (c->num_z != 0) + printf ("avg znz = %.2f\n", (double) c->znz_cnt / c->num_z); + if (c->num_za != 0) + printf ("avg zanz = %.2f\n", (double) c->zanz_cnt / c->num_za); + printf ("avg pnorm = %.2f\n", (double) c->pnorm_cnt / lp->nnbasic); + printf ("avg dnorm = %.2f\n", (double) c->dnorm_cnt / lp->nrows); + if (c->num_pi != 0) + printf ("avg pinz = %.2f\n", (double) c->pinz_cnt / c->num_pi); + if (c->num_pi1 != 0) + printf ("avg piInz = %.2f\n", (double) c->pi1nz_cnt / c->num_pi1); + if (c->num_up != 0) + printf ("avg upnz = %.2f\n", (double) c->upnz_cnt / c->num_up); + + for (i = 0; i < 10; i++) + printf ("piv 1.0e-%d : %d %d %d %d\n", + i, c->pivpI[i], c->pivpII[i], c->pivdI[i], c->pivdII[i]); +} + + +/* c <- a + t*b */ +static void add_vectors ( + lpinfo * lp, + svector * a, + svector * b, + svector * c, + const EGlpNum_t t) +{ + int i, r, l; + svector *w = &(lp->work); + + for (i = 0; i < b->nzcnt; i++) + { + r = b->indx[i]; + w->indx[i] = r; + EGlpNumCopy (w->coef[r], t); + EGlpNumMultTo (w->coef[r], b->coef[i]); + lp->iwork[r] = 1; + } + l = b->nzcnt; + + for (i = 0; i < a->nzcnt; i++) + { + r = a->indx[i]; + if (lp->iwork[r] == 0) + w->indx[l++] = r; + EGlpNumAddTo (w->coef[r], a->coef[i]); + } + for (i = 0; i < l; i++) + { + r = w->indx[i]; + c->indx[i] = r; + EGlpNumCopy (c->coef[i], w->coef[r]); + EGlpNumZero (w->coef[r]); + lp->iwork[r] = 0; + } + w->nzcnt = 0; + c->nzcnt = l; +} + +void ILLfct_update_pfeas ( + lpinfo * lp, + int lindex, + svector * srhs) +{ + int i, k, r; + int col, nz = 0; + int cbnd, f; + int *perm = lp->upd.perm; + int *ix = lp->upd.ix; + int tctr = lp->upd.tctr; + EGlpNum_t *t = lp->upd.t; + EGlpNum_t tz, *dty, ntmp; + EGlpNum_t *l, *x, *u, *pftol = &(lp->tol->ip_tol); + + EGlpNumInitVar (tz); + EGlpNumInitVar (ntmp); + dty = &(lp->upd.dty); + EGlpNumZero (*dty); + EGlpNumCopyAbs (tz, lp->upd.tz); + EGlpNumDivUiTo (tz, 100); + EGlpNumAddTo (tz, lp->upd.tz); + ILL_IFTRACE ("%s:%d", __func__, tctr); + for (i = 0; i < tctr && EGlpNumIsLeq (t[perm[i]], tz); i++) + { + cbnd = ix[perm[i]] % 10; + ILL_IFTRACE (":%d", cbnd); + if (cbnd == BBOUND) + continue; + k = ix[perm[i]] / 10; + r = lp->yjz.indx[k]; + ILL_IFTRACE (":%d:%d:%d", k, r, lp->iwork[r]); + + if (lp->iwork[r] != 1) + { + lp->iwork[r] = 1; + x = &(lp->xbz[r]); + col = lp->baz[r]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + + if (r != lindex) + { + f = 0; + EGlpNumCopyDiff (ntmp, *l, *x); + if (EGlpNumIsNeqq (*l, NINFTY) && EGlpNumIsLess (*pftol, ntmp)) + f = -1; + else + { + EGlpNumCopyDiff (ntmp, *x, *u); + if (EGlpNumIsNeqq (*u, INFTY) && EGlpNumIsLess (*pftol, ntmp)) + f = 1; + } + + ILL_IFTRACE (":%d:%d", f, lp->bfeas[r]); + if (f != lp->bfeas[r]) + { + srhs->indx[nz] = r; + EGlpNumSet (srhs->coef[nz], (double) (f - lp->bfeas[r])); + EGlpNumAddInnProdTo (*dty, srhs->coef[nz], lp->yjz.coef[k]); + nz++; + lp->bfeas[r] = f; + } + } + else + { + lp->bfeas[r] = 0; + } + } + } + while (--i >= 0) + { + cbnd = ix[perm[i]] % 10; + if (cbnd == BBOUND) + continue; + k = ix[perm[i]] / 10; + r = lp->yjz.indx[k]; + lp->iwork[r] = 0; + } + srhs->nzcnt = nz; + ILL_IFTRACE (":%d\n", nz); + EGlpNumClearVar (tz); + EGlpNumClearVar (ntmp); +} + +void ILLfct_compute_ppIzz ( + lpinfo * lp, + svector * srhs, + svector * ssoln) +{ + if (srhs->nzcnt != 0) + { + ILL_IFTRACE ("%s:\n", __func__); + ILLbasis_row_solve (lp, srhs, ssoln); + } +} + +void ILLfct_update_ppI_prices ( + lpinfo * lp, + price_info * pinf, + svector * srhs, + svector * ssoln, + int eindex, + int lindex, + const EGlpNum_t alpha) +{ + EGlpNum_t ntmp; + + EGlpNumInitVar (ntmp); + EGlpNumCopy (ntmp, alpha); + ILL_IFTRACE ("%s:\n", __func__); + if (lindex == -1) + { + if (srhs->nzcnt != 0) + { + ILLfct_update_pIpiz (lp, ssoln, oneLpNum); + if (pinf->p_strategy == COMPLETE_PRICING) + { + ILLfct_compute_zA (lp, ssoln, &(lp->zA)); + ILLfct_update_pIdz (lp, &(lp->zA), -1, oneLpNum); + } + } + else + { + if (pinf->p_strategy == COMPLETE_PRICING) + ILLprice_compute_dual_inf (lp, pinf, &eindex, 1, PRIMAL_PHASEI); + else + ILLprice_update_mpartial_price (lp, pinf, PRIMAL_PHASEI, COL_PRICING); + EGlpNumClearVar (ntmp); + return; + } + } + else + { + if (srhs->nzcnt == 0) + { + ILLfct_update_pIpiz (lp, &(lp->zz), ntmp); + if (pinf->p_strategy == COMPLETE_PRICING) + ILLfct_update_pIdz (lp, &(lp->zA), eindex, ntmp); + } + else + { + EGlpNumCopyFrac (ntmp, lp->upd.dty, lp->upd.piv); + EGlpNumSubTo (ntmp, alpha); + EGlpNumSign (ntmp); + add_vectors (lp, ssoln, &(lp->zz), &(lp->zz), ntmp); + ILLfct_update_pIpiz (lp, &(lp->zz), oneLpNum); + if (pinf->p_strategy == COMPLETE_PRICING) + { + ILLfct_compute_zA (lp, &(lp->zz), &(lp->zA)); + ILLfct_update_pIdz (lp, &(lp->zA), eindex, oneLpNum); + } + } + EGlpNumSet (lp->pIdz[eindex], (double) (lp->upd.fs)); + EGlpNumAddTo (lp->pIdz[eindex], ntmp); + EGlpNumSign (lp->pIdz[eindex]); + } + if (pinf->p_strategy == COMPLETE_PRICING) + { + ILLprice_compute_dual_inf (lp, pinf, lp->zA.indx, lp->zA.nzcnt, + PRIMAL_PHASEI); + if (eindex > -1) + ILLprice_compute_dual_inf (lp, pinf, &eindex, 1, PRIMAL_PHASEI); + ILLfct_update_counts (lp, CNT_ZARAVG, lp->zA.nzcnt, zeroLpNum); + } + else + ILLprice_update_mpartial_price (lp, pinf, PRIMAL_PHASEI, COL_PRICING); + EGlpNumClearVar (ntmp); + return; +} + +void ILLfct_update_dfeas ( + lpinfo * lp, + int eindex, + svector * srhs) +{ + int i, j, k, c; + int cbnd, col, nz = 0; + int vs, vt, f; + int delta; + int *perm = lp->upd.perm; + int *ix = lp->upd.ix; + int tctr = lp->upd.tctr; + int mcnt, mbeg; + EGlpNum_t *t = lp->upd.t; + EGlpNum_t *w = lp->work.coef; + EGlpNum_t tz; + EGlpNum_t *dty = &(lp->upd.dty); + EGlpNum_t *dftol = &(lp->tol->id_tol); + EGlpNum_t dj; + + EGlpNumInitVar (dj); + EGlpNumInitVar (tz); + EGlpNumZero (*dty); + EGlpNumCopy (tz, lp->upd.tz); + EGlpNumMultUiTo (tz, 101); + EGlpNumDivUiTo (tz, 100); + + for (j = 0; j < tctr && EGlpNumIsLeq (t[perm[j]], tz); j++) + { + k = ix[perm[j]] / 10; + c = lp->zA.indx[k]; + + if (lp->iwork[c] != 1) + { + lp->iwork[c] = 1; + cbnd = ix[perm[j]] % 10; + col = lp->nbaz[c]; + EGlpNumCopy (dj, lp->dz[c]); + vs = lp->vstat[col]; + vt = lp->vtype[col]; + + if (cbnd == BSKIP) + { + if (!EGlpNumIsNeqZero (dj, *dftol)); + else if (EGlpNumIsLessZero (dj) && vs == STAT_LOWER) + lp->vstat[col] = STAT_UPPER; + else if (EGlpNumIsGreatZero (dj) && vs == STAT_UPPER) + lp->vstat[col] = STAT_LOWER; + } + else if (c != eindex) + { + if (!EGlpNumIsNeqZero (dj, *dftol)) + f = 0; + else if (EGlpNumIsLessZero (dj) && + (vs == STAT_LOWER || vs == STAT_ZERO)) + f = -1; + else if (EGlpNumIsGreatZero (dj) && + (vs == STAT_UPPER || vs == STAT_ZERO)) + f = 1; + else + f = 0; + + if (f != lp->dfeas[c]) + { + delta = f - lp->dfeas[c]; + mcnt = lp->matcnt[col]; + mbeg = lp->matbeg[col]; + EGlpNumSet (dj, (double) (delta)); + for (i = 0; i < mcnt; i++) + EGlpNumAddInnProdTo (w[lp->matind[mbeg + i]], dj, + lp->matval[mbeg + i]); + EGlpNumAddInnProdTo (*dty, dj, lp->zA.coef[k]); + nz = 1; + lp->dfeas[c] = f; + } + } + else + { + lp->dfeas[c] = 0; + } + } + } + while (--j >= 0) + { + k = ix[perm[j]] / 10; + c = lp->zA.indx[k]; + lp->iwork[c] = 0; + } + + if (nz) + { + for (i = 0, nz = 0; i < lp->nrows; i++) + if (EGlpNumIsNeqqZero (w[i])) + { + EGlpNumCopy (srhs->coef[nz], w[i]); + srhs->indx[nz] = i; + nz++; + EGlpNumZero (w[i]); + } + } + + srhs->nzcnt = nz; + EGlpNumClearVar (dj); + EGlpNumClearVar (tz); +} + +void ILLfct_compute_dpIy ( + lpinfo * lp, + svector * srhs, + svector * ssoln) +{ + if (srhs->nzcnt != 0) + { + ILLbasis_column_solve (lp, srhs, ssoln); + } +} + +void ILLfct_update_dpI_prices ( + lpinfo * lp, + price_info * pinf, + svector * srhs, + svector * ssoln, + int lindex, + EGlpNum_t alpha) +{ + int i; + EGlpNum_t ntmp; + + EGlpNumInitVar (ntmp); + EGlpNumZero (ntmp); + + if (srhs->nzcnt == 0) + { + ILLfct_update_xz (lp, alpha, -1, -1); + } + else + { + EGlpNumCopyFrac (ntmp, lp->upd.dty, lp->upd.piv); + EGlpNumAddTo (ntmp, alpha); + EGlpNumSign (ntmp); + add_vectors (lp, ssoln, &(lp->yjz), &(lp->yjz), ntmp); + EGlpNumSign (ntmp); + for (i = 0; i < lp->yjz.nzcnt; i++) + EGlpNumAddTo (lp->xbz[lp->yjz.indx[i]], lp->yjz.coef[i]); + } + EGlpNumSet (lp->xbz[lindex], ((double) (-lp->upd.fs))); + EGlpNumAddTo (lp->xbz[lindex], ntmp); + + if (pinf->d_strategy == COMPLETE_PRICING) + { + ILLprice_compute_primal_inf (lp, pinf, lp->yjz.indx, lp->yjz.nzcnt, + DUAL_PHASEI); + ILLprice_compute_primal_inf (lp, pinf, &lindex, 1, DUAL_PHASEI); + ILLfct_update_counts (lp, CNT_YRAVG, lp->yjz.nzcnt, zeroLpNum); + } + else + ILLprice_update_mpartial_price (lp, pinf, DUAL_PHASEI, ROW_PRICING); + EGlpNumClearVar (ntmp); +} + +void ILLfct_update_dIIfeas ( + lpinfo * lp, + int eindex, + svector * srhs) +{ + int j, k; + int col, indx, vs; + int *perm = lp->upd.perm; + int *ix = lp->upd.ix; + int tctr = lp->upd.tctr; + EGlpNum_t *zAj, *l, *u; + EGlpNum_t *dty = &(lp->upd.dty); + EGlpNum_t *t_max = &(lp->upd.tz); + EGlpNum_t *t = lp->upd.t; + EGlpNum_t delta; + svector a; + + EGlpNumInitVar (delta); + EGlpNumZero (delta); + EGlpNumZero (*dty); + + srhs->nzcnt = 0; + for (j = 0; j < tctr && EGlpNumIsLeq (t[perm[j]], *t_max); j++) + { + k = ix[perm[j]]; + indx = lp->zA.indx[k]; + + if (indx != eindex) + { + zAj = &(lp->zA.coef[k]); + col = lp->nbaz[indx]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + vs = lp->vstat[col]; + if (vs == STAT_UPPER) + EGlpNumCopyDiff (delta, *l, *u); + else + EGlpNumCopyDiff (delta, *u, *l); + EGlpNumAddInnProdTo (*dty, delta, *zAj); + lp->vstat[col] = (vs == STAT_UPPER) ? STAT_LOWER : STAT_UPPER; + + a.nzcnt = lp->matcnt[col]; + a.indx = &(lp->matind[lp->matbeg[col]]); + a.coef = &(lp->matval[lp->matbeg[col]]); + add_vectors (lp, srhs, &a, srhs, delta); + } + } + EGlpNumClearVar (delta); +} + +void ILLfct_compute_dpIIy ( + lpinfo * lp, + svector * srhs, + svector * ssoln) +{ + if (srhs->nzcnt != 0) + { + ILLbasis_column_solve (lp, srhs, ssoln); + } +} + +void ILLfct_update_dpII_prices ( + lpinfo * lp, + price_info * pinf, + svector * srhs, + svector * ssoln, + /*int eindex,*/ + int lindex, + EGlpNum_t eval, + EGlpNum_t alpha) +{ + int i; + svector *u; + + if (srhs->nzcnt == 0) + { + ILLfct_update_xz (lp, alpha, -1, -1); + u = &(lp->yjz); + } + else + { + if (ssoln->nzcnt != 0) + for (i = 0; i < ssoln->nzcnt; i++) + EGlpNumSubTo (lp->xbz[ssoln->indx[i]], ssoln->coef[i]); + ILLfct_update_xz (lp, alpha, -1, -1); + add_vectors (lp, ssoln, &(lp->yjz), ssoln, oneLpNum); + u = ssoln; + } + EGlpNumCopySum (lp->xbz[lindex], eval, alpha); + + if (pinf->d_strategy == COMPLETE_PRICING) + { + ILLprice_compute_primal_inf (lp, pinf, u->indx, u->nzcnt, DUAL_PHASEII); + ILLprice_compute_primal_inf (lp, pinf, &lindex, 1, DUAL_PHASEII); + ILLfct_update_counts (lp, CNT_YRAVG, u->nzcnt, zeroLpNum); + } + else + ILLprice_update_mpartial_price (lp, pinf, DUAL_PHASEII, ROW_PRICING); +} + +int ILLfct_test_pivot ( + lpinfo * lp, + int indx, + int indxtype, + EGlpNum_t piv_val) +{ + int i; + EGlpNum_t pval, ntmp; + + EGlpNumInitVar (pval); + EGlpNumInitVar (ntmp); + EGlpNumZero (pval); + + if (indxtype == ROW_PIVOT) + { + for (i = 0; i < lp->yjz.nzcnt; i++) + if (lp->yjz.indx[i] == indx) + { + EGlpNumCopy (pval, lp->yjz.coef[i]); + break; + } + } + else + { + for (i = 0; i < lp->zA.nzcnt; i++) + if (lp->zA.indx[i] == indx) + { + EGlpNumCopy (pval, lp->zA.coef[i]); + break; + } + } + EGlpNumCopyDiff (ntmp, pval, piv_val); + EGlpNumDivTo (ntmp, piv_val); + if (EGlpNumIsLessZero (ntmp)) + EGlpNumSign (ntmp); + if (EGlpNumIsLess (ALTPIV_TOLER, ntmp)) + { +#if FCT_DEBUG > 1 + if (indxtype == ROW_PIVOT) + printf ("y_i = %.8f, z_j = %.8f %la %la\n", EGlpNumToLf (pval), + EGlpNumToLf (piv_val), EGlpNumToLf (ALTPIV_TOLER), + EGlpNumToLf (ntmp)); + else + printf ("z_j = %.8f, y_i = %.8f\n", EGlpNumToLf (pval), + EGlpNumToLf (piv_val)); +#endif + EGlpNumClearVar (ntmp); + EGlpNumClearVar (pval); + return 1; + } + EGlpNumClearVar (pval); + EGlpNumClearVar (ntmp); + return 0; +} + +#if FCT_DEBUG > 0 + +void fct_test_workvector ( + lpinfo * lp) +{ + int i, err = 0; + + for (i = 0; i < lp->ncols; i++) + { + if (EGlpNumIsNeqqZero (lp->work.coef[i])) + { + err++; + EGlpNumZero (lp->work.coef[i]); + } + if (lp->iwork[i] != 0) + { + err++; + lp->iwork[i] = 0; + } + } + if (err) + printf ("bad work vector, err=%d\n", err); +} + +void fct_test_pfeasible ( + lpinfo * lp) +{ + int i, col; + int err = 0; + EGlpNum_t *ftol = &(lp->tol->pfeas_tol); + + for (i = 0; i < lp->nrows; i++) + { + col = lp->baz[i]; + + if (EGlpNumIsNeqq (lp->uz[col], INFTY) + && EGlpNumIsSumLess (*ftol, lp->uz[col], lp->xbz[i])) + { + if (lp->bfeas[i] != 1) + { + err++; + lp->bfeas[i] = 1; + } + } + else if (EGlpNumIsNeqq (lp->lz[col], NINFTY) + && EGlpNumIsSumLess (lp->xbz[i], *ftol, lp->lz[col])) + { + if (lp->bfeas[i] != -1) + { + err++; + lp->bfeas[i] = -1; + } + } + /* else if (lp->bfeas[i] != 0) {err++; lp->bfeas[i] = 0;} */ + } + if (err != 0) + printf ("test_pfeas err =%d\n", err); +} + +void fct_test_dfeasible ( + lpinfo * lp) +{ + int j, col; + int err = 0; + EGlpNum_t *ftol = &(lp->tol->dfeas_tol); + EGlpNum_t mftol[1]; + + EGlpNumInitVar (mftol[0]); + EGlpNumCopyNeg (mftol[0], *ftol); + + for (j = 0; j < lp->nnbasic; j++) + { + col = lp->nbaz[j]; + + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED) + continue; + if (EGlpNumIsLess (lp->dz[j], mftol[0]) && + (lp->vstat[col] == STAT_LOWER || lp->vstat[col] == STAT_ZERO)) + { + if (lp->dfeas[j] != -1) + { + err++; + lp->dfeas[j] = -1; + } + } + if (EGlpNumIsLess (*ftol, lp->dz[j]) && + (lp->vstat[col] == STAT_UPPER || lp->vstat[col] == STAT_ZERO)) + { + if (lp->dfeas[j] != 1) + { + err++; + lp->dfeas[j] = 1; + } + } + /* else if (lp->dfeas[j] != 0) {err++; lp->dfeas[j] = 0;} */ + } + if (err != 0) + printf ("test_dfeas err =%d\n", err); +} + +void fct_test_pI_x ( + lpinfo * lp, + price_info * p) +{ + int i; + int ern = 0; + EGlpNum_t *x; + EGlpNum_t err, diff; + + EGlpNumInitVar (err); + EGlpNumInitVar (diff); + EGlpNumZero (err); + x = EGlpNumAllocArray (lp->nrows); + + for (i = 0; i < lp->nrows; i++) + EGlpNumCopy (x[i], lp->xbz[i]); + ILLfct_compute_phaseI_xbz (lp); + for (i = 0; i < lp->nrows; i++) + { + EGlpNumCopyDiff (diff, x[i], lp->xbz[i]); + if (EGlpNumIsLessZero (diff)) + EGlpNumSign (diff); + if (EGlpNumIsLess (PFEAS_TOLER, diff)) + { + EGlpNumAddTo (err, diff); + ern++; + printf ("bad i = %d\n", i); + } + } + if (EGlpNumIsNeqqZero (err)) + printf ("dI x err = %.7f, ern = %d\n", EGlpNumToLf (err), ern); + ILLprice_compute_primal_inf (lp, p, NULL, 0, DUAL_PHASEI); + EGlpNumFreeArray (x); + EGlpNumClearVar (diff); + EGlpNumClearVar (err); +} + +void fct_test_pII_x ( + lpinfo * lp, + price_info * p) +{ + int i; + int ern = 0; + EGlpNum_t *x; + EGlpNum_t err, diff; + + EGlpNumInitVar (err); + EGlpNumInitVar (diff); + EGlpNumZero (err); + x = EGlpNumAllocArray (lp->nrows); + + for (i = 0; i < lp->nrows; i++) + EGlpNumCopy (x[i], lp->xbz[i]); + ILLfct_compute_xbz (lp); + for (i = 0; i < lp->nrows; i++) + { + EGlpNumCopyDiff (diff, x[i], lp->xbz[i]); + if (EGlpNumIsLessZero (diff )) + EGlpNumSign (diff); + if (EGlpNumIsLess (PFEAS_TOLER, diff)) + { + EGlpNumAddTo (err, diff); + ern++; + printf ("bad i = %d\n", i); + } + } + if (EGlpNumIsNeqqZero (err)) + printf ("dII x err = %.7f, ern = %d\n", EGlpNumToLf (err), ern); + ILLprice_compute_primal_inf (lp, p, NULL, 0, DUAL_PHASEII); + EGlpNumFreeArray (x); + EGlpNumClearVar (diff); + EGlpNumClearVar (err); +} + +void fct_test_pI_pi_dz ( + lpinfo * lp, + price_info * p) +{ + int i; + int ern = 0; + EGlpNum_t *pidz; + EGlpNum_t err, diff; + + EGlpNumInitVar (err); + EGlpNumInitVar (diff); + pidz = EGlpNumAllocArray (lp->ncols); + EGlpNumZero (err); + + for (i = 0; i < lp->nrows; i++) + EGlpNumCopy (pidz[i], lp->pIpiz[i]); + ILLfct_compute_phaseI_piz (lp); + for (i = 0; i < lp->nrows; i++) + { + EGlpNumCopyDiff (diff, pidz[i], lp->pIpiz[i]); + if (EGlpNumIsLessZero (diff)) + EGlpNumSign (diff); + if (EGlpNumIsLess (DFEAS_TOLER, diff)) + { + EGlpNumAddTo (err, diff); + ern++; + } + } + if (EGlpNumIsNeqqZero (err)) + printf ("pI pi err = %.7f, ern = %d\n", EGlpNumToLf (err), ern); + + EGlpNumZero (err); + ern = 0; + for (i = 0; i < lp->nnbasic; i++) + EGlpNumCopy (pidz[i], lp->pIdz[i]); + ILLfct_compute_phaseI_dz (lp); + for (i = 0; i < lp->nnbasic; i++) + { + EGlpNumCopyDiff (diff, pidz[i], lp->pIdz[i]); + if (EGlpNumIsLessZero (diff)) + EGlpNumSign (diff); + if (EGlpNumIsLess (DFEAS_TOLER, diff)) + { + EGlpNumAddTo (err, diff); + ern++; + } + } + if (EGlpNumIsNeqqZero (err)) + printf ("pI dz err = %.7f, ern = %d\n", EGlpNumToLf (err), ern); + ILLprice_compute_dual_inf (lp, p, NULL, 0, PRIMAL_PHASEI); + EGlpNumClearVar (err); + EGlpNumClearVar (diff); + EGlpNumFreeArray (pidz); +} + +void fct_test_pII_pi_dz ( + lpinfo * lp, + price_info * p) +{ + int i; + int ern = 0; + EGlpNum_t *pidz; + EGlpNum_t err, diff; + + EGlpNumInitVar (err); + EGlpNumInitVar (diff); + EGlpNumZero (err); + pidz = EGlpNumAllocArray (lp->ncols); + + for (i = 0; i < lp->nrows; i++) + EGlpNumCopy (pidz[i], lp->piz[i]); + ILLfct_compute_piz (lp); + for (i = 0; i < lp->nrows; i++) + { + EGlpNumCopyDiff (diff, pidz[i], lp->piz[i]); + if (EGlpNumIsLessZero (diff)) + EGlpNumSign (diff); + if (EGlpNumIsLess (DFEAS_TOLER, diff)) + { + EGlpNumAddTo (err, diff); + ern++; + } + } + if (EGlpNumIsNeqqZero (err)) + printf ("pII pi err = %.7f, ern = %d\n", EGlpNumToLf (err), ern); + + EGlpNumZero (err); + ern = 0; + for (i = 0; i < lp->nnbasic; i++) + EGlpNumCopy (pidz[i], lp->dz[i]); + ILLfct_compute_dz (lp); + for (i = 0; i < lp->nnbasic; i++) + { + EGlpNumCopyDiff (diff, pidz[i], lp->dz[i]); + if (EGlpNumIsLessZero (diff)) + EGlpNumSign (diff); + if (EGlpNumIsLess (DFEAS_TOLER, diff)) + { + EGlpNumAddTo (err, diff); + ern++; + } + } + if (EGlpNumIsNeqqZero (err)) + printf ("pII dz err = %.7f, ern = %d\n", EGlpNumToLf (err), ern); + /* + * ILLprice_compute_dual_inf (lp, p, NULL, 0, PRIMAL_PHASEII); + */ + EGlpNumClearVar (err); + EGlpNumClearVar (diff); + EGlpNumFreeArray (pidz); +} + +#endif diff --git a/src/fct.h b/src/fct.h new file mode 100644 index 0000000..10acaac --- /dev/null +++ b/src/fct.h @@ -0,0 +1,246 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: fct.h,v 1.3 2003/11/05 16:57:39 meven Exp $ */ +#ifndef __FUNCTIONS_H +#define __FUNCTIONS_H +#include "basicdefs.h" +int ILLfct_compute_zA ( + lpinfo * lp, + svector * z, + svector * zA), + ILLfct_compute_wz ( + lpinfo * lp, + EGlpNum_t * wz), + ILLfct_adjust_viol_bounds ( + lpinfo * lp), + ILLfct_perturb_bounds ( + lpinfo * lp), + ILLfct_perturb_phaseI_bounds ( + lpinfo * lp), + ILLfct_bound_shift ( + lpinfo * lp, + int col, + int bndtype, + EGlpNum_t newbnd), + ILLfct_adjust_viol_coefs ( + lpinfo * lp), + ILLfct_perturb_coefs ( + lpinfo * lp), + ILLfct_coef_shift ( + lpinfo * lp, + int col, + EGlpNum_t newcoef), + ILLfct_test_pivot ( + lpinfo * lp, + int indx, + int indxtype, + EGlpNum_t piv_val); + +void ILLfct_load_workvector ( + lpinfo * lp, + svector * s), + ILLfct_zero_workvector ( + lpinfo * lp), + ILLfct_set_variable_type ( + lpinfo * lp), + ILLfct_compute_pobj ( + lpinfo * lp), + ILLfct_compute_dobj ( + lpinfo * lp), + ILLfct_compute_xbz ( + lpinfo * lp), + ILLfct_compute_piz ( + lpinfo * lp), + ILLfct_compute_phaseI_xbz ( + lpinfo * lp), + ILLfct_compute_phaseI_piz ( + lpinfo * lp), + ILLfct_compute_dz ( + lpinfo * lp), + ILLfct_compute_phaseI_dz ( + lpinfo * lp), + ILLfct_compute_yz ( + lpinfo * lp, + svector * yz, + svector * updz, + int ecol), + ILLfct_compute_zz ( + lpinfo * lp, + svector * zz, + int lindex), + ILLfct_compute_binvrow ( + lpinfo * lp, + svector * zz, + int row, + EGlpNum_t ztoler), + ILLfct_compute_vA ( + lpinfo * lp, + svector * v, + EGlpNum_t * vA), + ILLfct_compute_psteep_upv ( + lpinfo * lp, + svector * swz), + ILLfct_compute_dsteep_upv ( + lpinfo * lp, + svector * swz), + ILLfct_update_basis_info ( + lpinfo * lp, + int eindex, + int lindex, + int lvstat), + ILLfct_update_xz ( + lpinfo * lp, + EGlpNum_t tz, + int eindex, + int lindex), + ILLfct_update_piz ( + lpinfo * lp, + EGlpNum_t alpha), + ILLfct_update_pIpiz ( + lpinfo * lp, + svector * z, + const EGlpNum_t alpha), + ILLfct_update_dz ( + lpinfo * lp, + int eindex, + EGlpNum_t alpha), + ILLfct_update_pIdz ( + lpinfo * lp, + svector * zA, + int eindex, + const EGlpNum_t alpha), + ILLfct_unroll_bound_change ( + lpinfo * lp), + ILLfct_unroll_coef_change ( + lpinfo * lp), + ILLfct_check_pfeasible ( + lpinfo * lp, + feas_info * fs, + const EGlpNum_t ftol), + ILLfct_check_pIpfeasible ( + lpinfo * lp, + feas_info * fs, + EGlpNum_t ftol), + ILLfct_check_dfeasible ( + lpinfo * lp, + feas_info * fs, + const EGlpNum_t ftol), + ILLfct_dual_adjust ( + lpinfo * lp, + const EGlpNum_t ftol), + ILLfct_dphaseI_simple_update ( + lpinfo * lp, + EGlpNum_t ftol), + ILLfct_set_status_values ( + lpinfo * lp, + int pstatus, + int dstatus, + int ptype, + int dtype), + ILLfct_init_counts ( + lpinfo * lp), + ILLfct_update_counts ( + lpinfo * lp, + int f, + int upi, + const EGlpNum_t upd), + ILLfct_print_counts ( + lpinfo * lp), + ILLfct_check_pIdfeasible ( + lpinfo * lp, + feas_info * fs, + EGlpNum_t ftol), + ILLfct_update_pfeas ( + lpinfo * lp, + int lindex, + svector * srhs), + ILLfct_compute_ppIzz ( + lpinfo * lp, + svector * srhs, + svector * ssoln), + ILLfct_update_ppI_prices ( + lpinfo * lp, + price_info * pinf, + svector * srhs, + svector * ssoln, + int eindex, + int lindex, + const EGlpNum_t alpha), + ILLfct_update_dfeas ( + lpinfo * lp, + int eindex, + svector * srhs), + ILLfct_compute_dpIy ( + lpinfo * lp, + svector * srhs, + svector * ssoln), + ILLfct_update_dpI_prices ( + lpinfo * lp, + price_info * pinf, + svector * srhs, + svector * ssoln, + int lindex, + EGlpNum_t alpha), + ILLfct_update_dIIfeas ( + lpinfo * lp, + int eindex, + svector * srhs), + ILLfct_compute_dpIIy ( + lpinfo * lp, + svector * srhs, + svector * ssoln), + ILLfct_update_dpII_prices ( + lpinfo * lp, + price_info * pinf, + svector * srhs, + svector * ssoln, + /*int eindex,*/ + int lindex, + EGlpNum_t eval, + EGlpNum_t alpha); + +void fct_test_workvector ( + lpinfo * lp), + fct_test_pfeasible ( + lpinfo * lp), + fct_test_dfeasible ( + lpinfo * lp), + fct_test_pI_x ( + lpinfo * lp, + price_info * p), + fct_test_pII_x ( + lpinfo * lp, + price_info * p), + fct_test_pI_pi_dz ( + lpinfo * lp, + price_info * p), + fct_test_pII_pi_dz ( + lpinfo * lp, + price_info * p); + +bndinfo *ILLfct_new_bndinfo ( + void); +void ILLfct_free_bndinfo ( + bndinfo * binfo); + +#endif /* __FUNCTIONS_H */ diff --git a/src/format.c b/src/format.c new file mode 100644 index 0000000..0ba7b0e --- /dev/null +++ b/src/format.c @@ -0,0 +1,220 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: format_error.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +#include "qs_config.h" +#include "format.h" +#include "qsopt.h" +#include "iqsutil.h" + +int ILLformat_error_create ( + qsformat_error * error, + int mode, + const char *desc, + int lineNum, + const char *theLine, + int atPos) +{ + int len; + int rval = 0; + + error->theLine = NULL; + error->desc = NULL; + error->next = NULL; + + ILL_FAILtrue (desc == NULL, "non empty error desc please"); + ILL_FAILtrue (mode >= QS_INPUT_NERROR + || mode < 0, "0<= mode <=QS_INPUT_NERROR"); + error->type = mode; + len = strlen (desc); + ILL_SAFE_MALLOC (error->desc, len + 1, char); + + strcpy (error->desc, desc); + error->lineNumber = lineNum; + if (theLine != NULL) + { + len = strlen (theLine); + ILL_SAFE_MALLOC (error->theLine, len + 2, char); + + strcpy (error->theLine, theLine); + if (error->theLine[len - 1] != '\n') + { + error->theLine[len] = '\n'; + error->theLine[len + 1] = '\0'; + } + } + error->at = atPos; +CLEANUP: + if (rval) + { + ILLformat_error_delete (error); + } + return rval; +} + +void ILLformat_error_delete ( + qsformat_error * error) +{ + ILL_IFFREE (error->desc, char); + ILL_IFFREE (error->theLine, char); +} + +void ILLformat_error_print ( + EGioFile_t * out, + qsformat_error * error) +{ + int at = error->at; + int tp = error->type; + const char *type = "Error"; + const char *line = NULL; + int i; + + type = QSformat_error_type_string (tp); + + EGioPrintf (out, "%s line %d pos %d\n", + type, QSerror_get_line_number (error), at); + line = QSerror_get_line (error); + if (line != NULL) + { + EGioPrintf (out, "LINE %s", line); + if (at >= 0) + { + EGioPrintf (out, "....."); + for (i = 0; i <= (at - 1); i++) + { + if (line[i] == '\t') + { + EGioPrintf(out, "\t"); + } + else + { + EGioPrintf(out, "."); + } + } + EGioPrintf (out, "^\n"); + } + } + else + { + EGioPrintf (out, "NO LINE\n"); + } + EGioPrintf (out, "MSG: %s\n", QSerror_get_desc (error)); +} + + +qserror_collector *ILLerror_collector_new ( + qsadd_error_fct fct, + void *dest) +{ + int rval = 0; + qserror_collector *c = NULL; + + ILL_SAFE_MALLOC (c, 1, qserror_collector); + c->add_error = fct; + c->dest = dest; + +CLEANUP: + if (rval) + { + ILL_IFFREE (c, qserror_collector); + } + return c; +} + +qserror_collector *ILLerror_memory_collector_new ( + qserror_memory * dest) +{ + return ILLerror_collector_new (ILLadd_error_to_memory, dest); +} + +void ILLerror_collector_free ( + qserror_collector * c) +{ + ILL_IFFREE (c, qserror_collector); +} + +qserror_memory *ILLerror_memory_create ( + int takeErrorLines) +{ + int rval = 0, i; + qserror_memory *mem = NULL; + + ILL_SAFE_MALLOC (mem, 1, qserror_memory); + for (i = 0; i < QS_INPUT_NERROR; i++) + { + mem->has_error[i] = 0; + } + mem->error_list = NULL; + mem->nerror = 0; + mem->hasErrorLines = takeErrorLines; +CLEANUP: + return mem; +} + +void ILLerror_memory_free ( + qserror_memory * mem) +{ + qsformat_error *ths, *nxt; + + if (mem != NULL) + { + ths = mem->error_list; + while (ths != NULL) + { + nxt = ths->next; + ILL_IFFREE (ths, qsformat_error); + ths = nxt; + } + ILL_IFFREE (mem, qserror_memory); + } +} + +int ILLadd_error_to_memory ( + void *dest, + const qsformat_error * error) +{ + int rval = 0; + qserror_memory *mem = (qserror_memory *) dest; + qsformat_error *e = 0; + + ILL_CHECKnull (mem, "must give non NULL qserror_memory"); + + ILL_SAFE_MALLOC (e, 1, qsformat_error); + rval = ILLformat_error_create (e, error->type, error->desc, + error->lineNumber, + (mem->hasErrorLines) ? error->theLine : NULL, + error->at); + ILL_CLEANUP_IF (rval); + e->next = mem->error_list; + mem->error_list = e; + mem->nerror++; + mem->has_error[error->type]++; + +CLEANUP: + if (rval) + { + ILLformat_error_delete (e); + ILL_IFFREE (e, qsformat_error); + } + return rval; +} diff --git a/src/format.h b/src/format.h new file mode 100644 index 0000000..682bd51 --- /dev/null +++ b/src/format.h @@ -0,0 +1,136 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: format.h,v 1.3 2003/11/05 16:59:48 meven Exp $ */ +#ifndef QS_FORMAT_ERROR_H +#define QS_FORMAT_ERROR_H + +#include +#include "qs_config.h" +#include "qsopt.h" + +/****************************************************************************/ +/* + The LP/MPS readers, writers, + ILLrawlpdata_to_lpdata, and + use ILLformat_error to report problems with their input iff + the line reader used in reading the problem or + the qserror_collector pointer passed to ILLwrite_lp_file + is not NULL. + + The QSgui code uses this feature to collect qsformat_error instances + which it uses after reading is done to insert error messages into the + input window. +*/ +/****************************************************************************/ + +/* +for error type USE: + QS_DATA_ERROR + QS_DATA_WARN + QS_MPS_FORMAT_ERROR + QS_MPS_FORMAT_WARN + QS_LP_FORMAT_ERROR + QS_LP_FORMAT_WARN + QS_LP_OBJ_WARN + QS_GENERIC_ERROR +*/ + +typedef struct qsformat_error +{ + char *desc; + char *theLine; + struct qsformat_error *next; + int type; + int lineNumber; /* 1 based line counting */ + int at; +} +qsformat_error; + +extern int ILLformat_error_create ( + qsformat_error * error, + int mode, + const char *desc, + int lineNum, + const char *theLine, + int atPos); +extern void ILLformat_error_delete ( + qsformat_error * error); + +extern void ILLformat_error_print ( + EGioFile_t * out, + qsformat_error * e); + + + +/***************************************************************************** + * collecting error messages + * either with defining own qsad_error_fct and corresponding data structure + * or by using predefined ILLadd_error_to_memory fct with qserror_memory + */ + +typedef int ( + *qsadd_error_fct) ( + void *dest, + const qsformat_error * error); + +typedef struct qserror_collector +{ + qsadd_error_fct add_error; + void *dest; +} +qserror_collector; + +typedef struct qserror_memory +{ + unsigned int nerror; + qsformat_error *error_list; + char has_error[QS_INPUT_NERROR]; + char hasErrorLines; +} +qserror_memory; + + +extern qserror_collector *ILLerror_collector_new ( + qsadd_error_fct fct, + void *dest); + +qserror_collector *ILLerror_memory_collector_new ( + qserror_memory * dest); + +extern void ILLerror_collector_free ( + qserror_collector * c); + +#define ILLformat_error(collector, error) \ + ((collector)->add_error((collector)->dest, error)) + + +extern int ILLadd_error_to_memory ( + void *dest, + const qsformat_error * error); + +extern qserror_memory *ILLerror_memory_create ( + int takeErrorLines); +extern void ILLerror_memory_free ( + qserror_memory * mem); + +#endif diff --git a/src/ftest.c b/src/ftest.c new file mode 100644 index 0000000..73865f5 --- /dev/null +++ b/src/ftest.c @@ -0,0 +1,303 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: ftest.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +#include "qs_config.h" +#include "config.h" +#include "iqsutil.h" +#include "lpdefs.h" +#include "factor.h" + +#define NREP 2 +#define MAXITER 10000 +#undef DENSE_READ +//static int TRACE = 0; + +#if 0 +static int handle_singularity ( + void *sdata, + int c, + int r) +{ + fprintf (stderr, "singular basis, replace column %d by row %d logical\n", + r, c); + return 0; +} +#endif + +int main ( + int ac, + char **av) +{ + factor_work f; + int dim = 0; + int ncol = 0; + int nzcnt = 0; + int *basis = (int *) NULL; + int *cbeg = (int *) NULL; + int *clen = (int *) NULL; + int *cind = (int *) NULL; + EGlpNum_t *coef = (EGlpNum_t *) NULL; + int niter = 0; + char str[4096]; + char*l_argv[1024]; + int l_argc,l_par; + char cmd[MAXITER]; + int col[MAXITER]; + svector a[MAXITER]; + svector x; + svector upd; + int rval; + int i; + int j; + int rep; + int nz; + EGioFile_t *fin = 0; + char c; + int iter; + int nsing, *psrow, *pscol; + double szeit; + double factor_szeit; + double ftran_szeit; + double btran_szeit; + double update_szeit; + double factor_zeit = 0.0; + double ftran_zeit = 0.0; + double btran_zeit = 0.0; + double update_zeit = 0.0; + double dtmp; + QSexactStart(); + ILLfactor_init_factor_work (&f); + for (i = 0; i < MAXITER; i++) + { + ILLsvector_init (&a[i]); + } + ILLsvector_init (&x); + ILLsvector_init (&upd); + + szeit = ILLutil_zeit (); + + if (ac > 1) + { + fin = EGioOpen (av[1], "r"); + if (!fin) + { + perror (av[1]); + fprintf (stderr, "Unable to open %s for input\n", av[1]); + return 1; + } + } + else + { + fin = EGioOpenFILE(stdin); + } + do{ + EGioGets(str,4096,fin); + EGioNParse(str,1024," ","%#",&i,l_argv); + }while(i==0 && !EGioEof(fin)); + WARNING (i != 3, "Couldn't read dimension, columns and nonzeros, only read" + " %d elements", i); + dim = atoi(l_argv[0]); + ncol = atoi(l_argv[1]); + nzcnt = atoi(l_argv[2]); + fprintf (stderr, "Using dimension %d columns %d and nonzero %d\n", dim, + ncol, nzcnt); + + ILL_SAFE_MALLOC (basis, dim, int); + ILL_SAFE_MALLOC (cbeg, ncol, int); + ILL_SAFE_MALLOC (clen, ncol, int); + ILL_SAFE_MALLOC (cind, nzcnt, int); + + coef = EGlpNumAllocArray (nzcnt); + + do{ + EGioGets(str,4096,fin); + EGioNParse(str,1024," ","%#",&i,l_argv); + }while(i==0 && !EGioEof(fin)); + TESTG((rval=(i!=dim)), CLEANUP, "Wrong format!"); + for (i = 0; i < dim; i++) + { + basis[i] = atoi(l_argv[i]); + } + + nz = 0; + for (i = 0; i < ncol; i++) + { + cbeg[i] = nz; + do + { + EGioGets(str,4096,fin); + EGioNParse(str,1024," ","%#",&l_argc,l_argv); + }while(l_argc==0 && !EGioEof(fin)); + TESTG((rval=(l_argc<1)), CLEANUP, "Wrong format!"); + clen[i] = l_argv[0]; + TESTG((rval=(l_argc!= 2*clen[i]+1)), CLEANUP, "Wrong format or too long lines!"); + for (j = 0; j < clen[i]; j++) + { + cind[nz] = atoi(l_argv[2*i+1]); + dtmp = strtod(l_argv[2*i+2],0); + EGlpNumSet (coef[nz], dtmp); + nz++; + } + } + + rval = ILLsvector_alloc (&x, dim); + ILL_CLEANUP_IF (rval); + rval = ILLsvector_alloc (&upd, dim); + ILL_CLEANUP_IF (rval); + + while (niter < MAXITER) + { + do + { + EGioGets(str,4096,fin); + EGioNParse(str,1024," ","%#",&l_argc,l_argv); + }while(l_argc==0 && !EGioEof(fin)); + l_par = 0; + if(l_argc==0) break; + TESTG((rval=(l_argc<2)), CLEANUP,"Wrong Format"); + c = l_argv[l_par++][0]; + cmd[niter] = c; + + switch (c) + { + case 'u': + col[niter] = atoi(l_argv[l_par++]); + case 'F': + case 'f': + case 'b': +#ifdef DENSE_READ + nzcnt = 0; + TESTG((rval=(l_argc!=dim+l_par)), CLEANUP, "Wrng format or too long lines!"); + for (i = 0; i < dim; i++) + { + dtmp = strtod(l_argv[l_par++],0); + if (dtmp != 0.0) + { + x.indx[nzcnt] = i; + EGlpNumSet (x.coef[nzcnt], dtmp); + nzcnt++; + } + } +#else + nzcnt = atoi(l_argv[l_par++]); + TESTG((rval=(l_argc!=2*nzcnt+l_par)), CLEANUP, "Wrong format or too log lines!"); + for (i = 0; i < nzcnt; i++) + { + x.indx[i] = atoi(l_argv[l_par++]); + dtmp = strtod(l_argv[l_par++],0); + EGlpNumSet (x.coef[i], dtmp); + + } +#endif + x.nzcnt = nzcnt; + rval = ILLsvector_copy (&x, &a[niter]); + ILL_CLEANUP_IF (rval); + break; + } + niter++; + } + + printf ("Matrix and iterations read in %.2f seconds\n", + ILLutil_zeit () - szeit); + fflush (stdout); + + szeit = ILLutil_zeit (); + + for (rep = 0; rep < NREP; rep++) + { + + factor_szeit = ILLutil_zeit (); + +#if 0 + ILLfactor_init_factor_work (&f); +#endif + + rval = ILLfactor_create_factor_work (&f, dim); + ILL_CLEANUP_IF (rval); + + rval = + ILLfactor (&f, basis, cbeg, clen, cind, coef, &nsing, &psrow, &pscol); + ILL_CLEANUP_IF (rval); + + factor_zeit += ILLutil_zeit () - factor_szeit; + + for (iter = 0; iter < niter; iter++) + { + switch (cmd[iter]) + { + case 'f': + ftran_szeit = ILLutil_zeit (); + ILLfactor_ftran (&f, &a[iter], &x); + ftran_zeit += ILLutil_zeit () - ftran_szeit; + break; + case 'F': + ftran_szeit = ILLutil_zeit (); + ILLfactor_ftran_update (&f, &a[iter], &upd, &x); + ftran_zeit += ILLutil_zeit () - ftran_szeit; + break; + case 'b': + btran_szeit = ILLutil_zeit (); + ILLfactor_btran (&f, &a[iter], &x); + btran_zeit += ILLutil_zeit () - btran_szeit; + break; + case 'u': + update_szeit = ILLutil_zeit (); + ILLfactor_update (&f, &a[iter], col[iter], &nz); + update_zeit += ILLutil_zeit () - update_szeit; + break; + } + } + ILLfactor_free_factor_work (&f); + } + printf ("%d reps of %d steps finished in %.2f seconds\n", rep, niter, + ILLutil_zeit () - szeit); + printf ("factor: %.2f\n", factor_zeit); + printf ("ftran: %.2f\n", ftran_zeit); + printf ("btran: %.2f\n", btran_zeit); + printf ("update: %.2f\n", update_zeit); + fflush (stdout); + + rval = 0; + +CLEANUP: + if (fin) + { + EGioClose (fin); + } + ILLfactor_free_factor_work (&f); + ILL_IFFREE (basis, int); + ILL_IFFREE (cbeg, int); + ILL_IFFREE (clen, int); + ILL_IFFREE (cind, int); + + EGlpNumFreeArray (coef); + for (i = 0; i < niter; i++) + { + ILLsvector_free (&a[i]); + } + ILLsvector_free (&upd); + ILLsvector_free (&x); + QSexactClear(); + return rval; +} diff --git a/src/ftest.h b/src/ftest.h new file mode 100644 index 0000000..86a0d9b --- /dev/null +++ b/src/ftest.h @@ -0,0 +1,21 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ diff --git a/src/iqsutil.h b/src/iqsutil.h new file mode 100644 index 0000000..b1aadca --- /dev/null +++ b/src/iqsutil.h @@ -0,0 +1,30 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#include "config.h" +#include "trace.h" +#include "config.h" +#include "machdefs.h" +#include "util.h" +#include "except.h" +#include "symtab.h" +#include "names.h" diff --git a/src/lib.c b/src/lib.c new file mode 100644 index 0000000..0f9d9dc --- /dev/null +++ b/src/lib.c @@ -0,0 +1,4343 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: lib.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +//static int TRACE = 0; + +/****************************************************************************/ +/* */ +/* Interface Routines to Core LP Solver */ +/* */ +/* EXPORTED FUNCTIONS */ +/* */ +/* int ILLlib_optimize (lpinfo *lp, ILLlp_basis *B, price_info *pinf, */ +/* int algo, int *status, int simplex_display) */ +/* int ILLlib_cache_solution (lpinfo *lp, ILLlp_cache *C) */ +/* int ILLlib_solution (lpinfo *lp, ILLlp_cache *C, double *val, */ +/* double *x, double *pi, double *slack, double *rc) */ +/* int ILLlib_get_x (lpinfo *lp, ILLlp_cache *C, double *x) */ +/* int ILLlib_get_slack (lpinfo *lp, ILLlp_cache *C, double *slack) */ +/* int ILLlib_objval (lpinfo *lp, ILLlp_cache *C, double *val) */ +/* int ILLlib_newrow (lpinfo *lp, ILLlp_basis *B, double rhs, */ +/* char sense, double range, const char *name) */ +/* -range can specify a rangeval for the row (if sense is not 'R', */ +/* then range is ignored); it should be 0 if no range is needed; */ +/* if sense is 'R' but no rangeval array exists for the LP, the */ +/* array will be allocated and initialized. */ +/* int ILLlib_newrows (lpinfo *lp, ILLlp_basis *B, int num, double *rhs, */ +/* char *sense, double *range, const char **names) */ +/* -range is an array specifying the rangevals for the rows; range */ +/* should be NULL if no rangevals are needed. */ +/* int ILLlib_addrow (lpinfo *lp, ILLlp_basis *B, int cnt, int *ind, */ +/* double *val, double rhs, char sense, double range, */ +/* const char *name) */ +/* int ILLlib_addrows (lpinfo *lp, ILLlp_basis *B, int num, */ +/* int *rmatcnt, int *rmatbeg, int *rmatind, double *rmatval, */ +/* double *rhs, char *sense, double *range, const char **names, */ +/* int *factorok) */ +/* int ILLlib_delrows (lpinfo *lp, ILLlp_basis *B, */ +/* int num, int *dellist, int *basis_ok) */ +/* int ILLlib_newcol (lpinfo *lp, ILLlp_basis *B, */ +/* double obj, double lower, double upper, const char *name, */ +/* int factorok) */ +/* int ILLlib_newcols (lpinfo *lp, ILLlp_basis *B, */ +/* int num, double *obj, double *lower, double *upper, */ +/* const char **names, int factorok) */ +/* int ILLlib_addcol (lpinfo *lp, ILLlp_basis *B, */ +/* int cnt, int *ind, double *val, double obj, double lower, */ +/* double upper, const char *name, int factorok) */ +/* int ILLlib_addcols (lpinfo *lp, ILLlp_basis *B, */ +/* int num, int *cmatcnt, int *cmatbeg, int *cmatind, */ +/* double *cmatval, double *obj, double *lower, double *upper, */ +/* const char **names, int factorok) */ +/* int ILLlib_delcols (lpinfo *lp, ILLlp_basis *B, int num, int *dellist */ +/* int *basis_ok) */ +/* int ILLlib_chgcoef (lpinfo *lp, int rowindex, int colindex, */ +/* double coef) */ +/* int ILLlib_chgsense (lpinfo *lp, int num, int *rowlist, char *sense) */ +/* int ILLlib_getrows (lpinfo *lp, int num, int *rowlist, int **rowcnt, */ +/* int **rowbeg, int **rowind, double **rowval, double **rhs, */ +/* char **sense, char ***names) */ +/* int ILLlib_getcols (lpinfo *lp, int num, int *collist, int **colcnt, */ +/* int **colbeg, int **colind, double **colval, double **obj, */ +/* double **lower, double **upper, char ***names) */ +/* int ILLlib_getobj (lpinfo *lp, double *obj) */ +/* int ILLlib_chgobj (lpinfo *lp, int indx, double coef) */ +/* int ILLlib_getrhs (lpinfo *lp, double *rhs) */ +/* int ILLlib_chgrhs (lpinfo *lp, int indx, double coef) */ +/* int ILLlib_getintflags (lpinfo *lp, int *intflags) */ +/* int ILLlib_rownames (lpinfo *lp, char **rownames) */ +/* int ILLlib_colnames (lpinfo *lp, char **colnames) */ +/* int ILLlib_colindex (lpinfo *lp, char *name, int *colindex) */ +/* int ILLlib_rowindex (lpinfo *lp, char *name, int *rowindex) */ +/* int ILLlib_chgbnd (lpinfo *lp, int indx, char lu, double bnd) */ +/* int ILLlib_chgbnds (lpinfo *lp, int cnt, int *indx, char *lu, */ +/* double *bnd) */ +/* int ILLlib_getbnd (lpinfo *lp, int indx, char lu, double *bnd) */ +/* int ILLlib_getbnds (lpinfo *lp, double *lower, double *upper) */ +/* int ILLlib_strongbranch (lpinfo *lp, price_info *pinf, */ +/* int *candidatelist, int ncand, double *xlist, double *downpen, */ +/* double *uppen, int iterations, double objbound) */ +/* int ILLlib_getbasis (lpinfo *lp, char *cstat, char *rstat) */ +/* int ILLlib_loadbasis (ILLlp_basis *B, int nstruct, int nrows, */ +/* char *cstat, char *rstat) */ +/* int ILLlib_readbasis (lpinfo *lp, ILLlp_basis *B, char *fname) */ +/* int ILLlib_writebasis (lpinfo *lp, const char *fname) */ +/* int ILLlib_getrownorms (lpinfo *lp, price_info *pinf, */ +/* double *rownorms) */ +/* int ILLlib_loadrownorms (lpinfo *lp, price_info *pinf, */ +/* double *rownorms) */ +/* int ILLlib_recompute_rownorms (lpinfo *lp, price_info *pinf) */ +/* int ILLlib_print_x (EGioFile_t *fd, lpinfo *lp, ILLlp_cache *C, double *x, */ +/* int nonZerosOnly) */ +/* int ILLlib_print_x (lpinfo *lp, ILLlp_cache *C) */ +/* int ILLlib_iter (lpinfo *lp) */ +/* */ +/* NOTES */ +/* */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "iqsutil.h" +#include "lpdata.h" +#include "lpdefs.h" +#include "simplex.h" +#include "price.h" +#include "basis.h" +#include "lib.h" +#include "qstruct.h" +#include "qsopt.h" +#include "lp.h" +#include "mps.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +static void check_pinf ( + price_info * pinf, + int *it_exists); + +static int matrix_addrow ( + ILLmatrix * A, + int rowcnt, + int *rowind, + const EGlpNum_t * rowval), + matrix_addrow_end ( + ILLmatrix * A, + int row, + int rowcnt, + int *rowind, + const EGlpNum_t * rowval), + matrix_addcoef ( + lpinfo * lp, + ILLmatrix * A, + int row, + int col, + EGlpNum_t val), + matrix_addcol ( + ILLmatrix * A, + int colcnt, + int *colind, + EGlpNum_t * colval), + delcols_work ( + lpinfo * lp, + char *colmark), + reset_colindex ( + lpinfo * lp), + reset_rowindex ( + lpinfo * lp); + +int ILLlib_optimize ( + lpinfo * lp, + ILLlp_basis * B, + price_info * pinf, + int algo, + int *status, + int simplex_display, + itcnt_t*itcnt) +{ + int rval = 0; + int sol_status; + + if (status) + *status = QS_LP_UNSOLVED; + + /* ILLprice_free_pricing_info (pinf); *//* Should be removed later */ + + rval = ILLsimplex (lp, algo, B, pinf, &sol_status, simplex_display, itcnt); + CHECKRVALG (rval, CLEANUP); + + if (status) + *status = sol_status; + +CLEANUP: + + if (rval == E_SIMPLEX_ERROR) + { + EGioFile_t *eout = 0; + int tval; + + printf ("write bad lp to error.lp\n"); + fflush (stdout); + #ifdef HAVE_ZLIB_H + eout = EGioOpen ("error.lp.gz", "w"); + #else + #ifdef HAVE_BZLIB_H + eout = EGioOpen ("error.lp.bz2", "w"); + #else + eout = EGioOpen ("error.lp", "w"); + #endif + #endif + if (!eout) + { + fprintf (stderr, "could not open file to write bad lp\n"); + } + else + { + tval = ILLwrite_lp (lp->O, NULL); + if (tval) + { + fprintf (stderr, "error while writing bad lp\n"); + } + EGioClose (eout); + } + + printf ("write bad basis to error.bas\n"); + fflush (stdout); + tval = ILLlib_writebasis (lp, 0, "error.bas"); + if (tval) + { + fprintf (stderr, "error while writing bad basis\n"); + } + } + if (rval == QS_LP_CHANGE_PREC) + { + MESSAGE (__QS_SB_VERB, "Changing precision"); + return rval; + } + MESSAGE (rval ? 0 : 1000, "Error code %d", rval); + EG_RETURN (rval); +} + +int ILLlib_cache_solution ( + lpinfo * lp, + ILLlp_cache * C) +{ + int rval = 0; + + if (C) + { + if (C->nstruct != lp->O->nstruct || C->nrows != lp->O->nrows) + { + fprintf (stderr, "lp_cache does not match size of lp\n"); + rval = 1; + ILL_CLEANUP; + } + rval = ILLlib_solution (lp, 0, &(C->val), C->x, C->pi, C->slack, C->rc); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_solution ( + lpinfo * lp, + ILLlp_cache * C, + EGlpNum_t * val, + EGlpNum_t * x, + EGlpNum_t * pi, + EGlpNum_t * slack, + EGlpNum_t * rc) +{ + int i, rval = 0; + EGlpNum_t *tempx = 0; + EGlpNum_t *temprc = 0; + int ncols = lp->O->ncols; + int nrows = lp->O->nrows; + int nstruct = lp->O->nstruct; + ILLlpdata *qslp = lp->O; + + if (C) + { + if (C->nrows != nrows || C->nstruct != nstruct) + { + fprintf (stderr, "cache mismatch in ILLlib_solution\n"); + rval = 0; + ILL_CLEANUP; + } + if (val) + { + EGlpNumCopy (*val, C->val); + } + if (x) + { + for (i = 0; i < nstruct; i++) + { + EGlpNumCopy (x[i], C->x[i]); + } + } + if (pi) + { + for (i = 0; i < nrows; i++) + { + EGlpNumCopy (pi[i], C->pi[i]); + } + } + if (slack) + { + for (i = 0; i < nrows; i++) + { + EGlpNumCopy (slack[i], C->slack[i]); + } + } + if (rc) + { + for (i = 0; i < nstruct; i++) + { + EGlpNumCopy (rc[i], C->rc[i]); + } + } + } + else + { + if (x || slack) + tempx = EGlpNumAllocArray (ncols); + + if (rc) + temprc = EGlpNumAllocArray (ncols); + + rval = ILLsimplex_solution (lp, tempx, pi, temprc, val); + CHECKRVALG (rval, CLEANUP); + + if (x) + { + for (i = 0; i < nstruct; i++) + { + EGlpNumCopy (x[i], tempx[qslp->structmap[i]]); + } + } + if (slack) + { + for (i = 0; i < nrows; i++) + { + EGlpNumCopy (slack[i], tempx[qslp->rowmap[i]]); + } + } + + if (rc) + { + for (i = 0; i < nstruct; i++) + { + EGlpNumCopy (rc[i], temprc[qslp->structmap[i]]); + } + } + + + if (lp->O->objsense == ILL_MAX) + { /* Reverse signs for max prob */ + if (val) + { + EGlpNumSign (*val); + } + if (pi) + { + for (i = 0; i < nrows; i++) + { + EGlpNumSign (pi[i]); + } + } + if (rc) + { + for (i = 0; i < nstruct; i++) + { + EGlpNumSign (rc[i]); + } + } + } + } + +CLEANUP: + + EGlpNumFreeArray (tempx); + EGlpNumFreeArray (temprc); + EG_RETURN (rval); +} + +int ILLlib_get_x ( + lpinfo * lp, + ILLlp_cache * C, + EGlpNum_t * x) +{ + int rval = 0; + + rval = ILLlib_solution (lp, C, 0, x, 0, 0, 0); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_get_slack ( + lpinfo * lp, + ILLlp_cache * C, + EGlpNum_t * slack) +{ + int rval = 0; + + rval = ILLlib_solution (lp, C, 0, 0, 0, slack, 0); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + + +int ILLlib_objval ( + lpinfo * lp, + ILLlp_cache * C, + EGlpNum_t * val) +{ + int rval = 0; + + if (lp->basisstat.optimal) + { + rval = ILLlib_solution (lp, C, val, 0, 0, 0, 0); + CHECKRVALG (rval, CLEANUP); + } + else + { + EGlpNumCopy (*val, lp->dobjval); /* Ask Sanjeeb */ + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_tableau ( + lpinfo * lp, + int row, + EGlpNum_t * binv, + EGlpNum_t * tabrow) +{ + int rval = 0; + int i; + int ncols = lp->O->ncols; + int nrows = lp->O->nrows; + int nstruct = lp->O->nstruct; + EGlpNum_t *brow = 0; + EGlpNum_t *trow = 0; + ILLlpdata *qslp = lp->O; + + if (row < 0 || row >= qslp->nrows) + { + fprintf (stderr, "ILLlib_tableau called with bad row: %d\n", row); + rval = 1; + ILL_CLEANUP; + } + brow = EGlpNumAllocArray (nrows); + + if (tabrow) + trow = EGlpNumAllocArray (ncols); + + rval = ILLbasis_tableau_row (lp, row, brow, trow, 0, 0); + CHECKRVALG (rval, CLEANUP); + + if (binv) + { + for (i = 0; i < nrows; i++) + { + EGlpNumCopy (binv[i], brow[i]); + } + } + + if (tabrow) + { + for (i = 0; i < nstruct; i++) + { + EGlpNumCopy (tabrow[i], trow[qslp->structmap[i]]); + } + for (i = 0; i < nrows; i++) + { + EGlpNumCopy (tabrow[nstruct + i], trow[qslp->rowmap[i]]); + } + } + +CLEANUP: + + EGlpNumFreeArray (brow); + EGlpNumFreeArray (trow); + EG_RETURN (rval); +} + +int ILLlib_basis_order ( + lpinfo * lp, + int *header) +{ + int rval = 0; + int i, j; + int ncols = lp->O->ncols; + int nrows = lp->O->nrows; + int nstruct = lp->O->nstruct; + ILLlpdata *qslp = lp->O; + int *invmap = 0; + + ILL_SAFE_MALLOC (invmap, ncols, int); + + for (j = 0; j < nstruct; j++) + { + invmap[qslp->structmap[j]] = j; + } + for (i = 0; i < nrows; i++) + { + invmap[qslp->rowmap[i]] = nstruct + i; + } + + for (i = 0; i < nrows; i++) + { + header[i] = invmap[lp->baz[i]]; + } + +CLEANUP: + + ILL_IFFREE (invmap, int); + + EG_RETURN (rval); +} + +int ILLlib_chgbnd ( + lpinfo * lp, + int indx, + int lu, + const EGlpNum_t bnd) +{ + int rval = 0; + int col; + + if (!lp) + { + fprintf (stderr, "ILLlib_chgbnd called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + if (indx < 0 || indx > lp->O->nstruct) + { + fprintf (stderr, "ILLlib_chgbnd called with bad indx: %d\n", indx); + rval = 1; + ILL_CLEANUP; + } + + if (lp->O->sinfo) + { /* Presolve LP is no longer valid, free the data */ + ILLlp_sinfo_free (lp->O->sinfo); + ILL_IFFREE (lp->O->sinfo, ILLlp_sinfo); + } + + col = lp->O->structmap[indx]; + + switch (lu) + { + case 'L': + EGlpNumCopy (lp->O->lower[col], bnd); + break; + case 'U': + EGlpNumCopy (lp->O->upper[col], bnd); + break; + case 'B': + EGlpNumCopy (lp->O->lower[col], bnd); + EGlpNumCopy (lp->O->upper[col], bnd); + break; + default: + fprintf (stderr, "ILLlib_chgbnd called with lu: %c\n", lu); + rval = 1; + ILL_CLEANUP; + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_chgbnds ( + lpinfo * lp, + int cnt, + int *indx, + char *lu, + const EGlpNum_t * bnd) +{ + int rval = 0; + int i; + + for (i = 0; i < cnt; i++) + { + rval = ILLlib_chgbnd (lp, indx[i], lu[i], bnd[i]); + if (rval) + ILL_CLEANUP; + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_getbnd ( + lpinfo * lp, + int indx, + int lu, + EGlpNum_t * bnd) +{ + int rval = 0; + int col; + + if (!lp) + { + fprintf (stderr, "ILLlib_getbnd called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + if (indx < 0 || indx > lp->O->nstruct) + { + fprintf (stderr, "ILLlib_getbnd called with bad indx: %d\n", indx); + rval = 1; + ILL_CLEANUP; + } + + col = lp->O->structmap[indx]; + + switch (lu) + { + case 'L': + EGlpNumCopy (*bnd, lp->O->lower[col]); + break; + case 'U': + EGlpNumCopy (*bnd, lp->O->upper[col]); + break; + default: + fprintf (stderr, "ILLlib_getbnd called with lu: %c\n", lu); + rval = 1; + ILL_CLEANUP; + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_getbnds_list ( + lpinfo *lp, + int num, + int*collist, + EGlpNum_t *lower, + EGlpNum_t *upper) +{ + int rval = 0; + ILLlpdata *qslp; + int nstruct; + int j, col; + + if (!lp) { + fprintf (stderr, "ILLlib_getbnds_list called without an lp\n"); + rval = 1; ILL_CLEANUP; + } + + qslp = lp->O; + nstruct = qslp->nstruct; + for (j = 0; j < num ; j++) { + if(collist[j]<0|| collist[j] >= nstruct) + { + fprintf (stderr, "ILLlib_getbnds_list collist[%d] = %d out " + "of range\n", j, collist[j]); + } + col = qslp->structmap[collist[j]]; + if (lower) + EGlpNumCopy(lower[j], qslp->lower[col]); + if (upper) + EGlpNumCopy(upper[j], qslp->upper[col]); + } + +CLEANUP: + + EG_RETURN(rval); +} + + +int ILLlib_getbnds ( + lpinfo * lp, + EGlpNum_t * lower, + EGlpNum_t * upper) +{ + int rval = 0; + ILLlpdata *qslp; + int nstruct; + int j, col; + + if (!lp) + { + fprintf (stderr, "ILLlib_getbnd called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nstruct = qslp->nstruct; + + for (j = 0; j < nstruct; j++) + { + col = qslp->structmap[j]; + if (lower) + EGlpNumCopy (lower[j], qslp->lower[col]); + if (upper) + EGlpNumCopy (upper[j], qslp->upper[col]); + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_strongbranch ( + lpinfo * lp, + price_info * pinf, + int *candidatelist, + int ncand, + EGlpNum_t * xlist, + EGlpNum_t * downpen, + EGlpNum_t * uppen, + int iterations, + EGlpNum_t objbound, + itcnt_t*itcnt) +{ + int rval = 0; + int i, k, status, have_norms; + int olditer = lp->maxiter; + int nstruct = lp->O->nstruct; + int nrows = lp->O->nrows; + EGlpNum_t *myx = 0; + EGlpNum_t xi, t, oldbnd; + price_info lpinf; + ILLlp_basis B, origB; + + EGlpNumInitVar (lpinf.htrigger); + EGlpNumInitVar (xi); + EGlpNumInitVar (t); + EGlpNumInitVar (oldbnd); + EGlpNumZero (oldbnd); + ILLlp_basis_init (&B); + ILLlp_basis_init (&origB); + ILLprice_init_pricing_info (&lpinf); + lpinf.dI_price = QS_PRICE_DSTEEP; + lpinf.dII_price = QS_PRICE_DSTEEP; + + if (xlist == 0) + { + myx = EGlpNumAllocArray (nstruct); + rval = ILLlib_get_x (lp, 0, myx); + CHECKRVALG (rval, CLEANUP); + } + + rval = ILLlp_basis_alloc (&origB, nstruct, nrows); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getbasis (lp, origB.cstat, origB.rstat); + CHECKRVALG (rval, CLEANUP); + + check_pinf (pinf, &have_norms); + if (have_norms == 0) + { + origB.rownorms = EGlpNumAllocArray (nrows); + rval = ILLlib_getrownorms (lp, pinf, origB.rownorms); + CHECKRVALG (rval, CLEANUP); + } + else + { + lp->basisid = -1; + rval = ILLlib_optimize (lp, 0, &lpinf, DUAL_SIMPLEX, &status, 0, itcnt); + CHECKRVALG (rval, CLEANUP); + } + + rval = ILLlp_basis_alloc (&B, nstruct, nrows); /* Note: B and orgiB may */ + /* differ. */ + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getbasis (lp, B.cstat, B.rstat); + CHECKRVALG (rval, CLEANUP); + B.rownorms = EGlpNumAllocArray (nrows); + + if (have_norms == 0) + { + rval = ILLlib_getrownorms (lp, pinf, B.rownorms); + CHECKRVALG (rval, CLEANUP); + } + else + { + rval = ILLlib_getrownorms (lp, &lpinf, B.rownorms); + CHECKRVALG (rval, CLEANUP); + } + + lp->maxiter = iterations; + + for (i = 0; i < ncand; i++) + { + k = candidatelist[i]; + rval = ILLlib_getbnd (lp, k, 'U', &oldbnd); + CHECKRVALG (rval, CLEANUP); + if (xlist) + EGlpNumCopy (xi, xlist[i]); + else + EGlpNumCopy (xi, myx[k]); + EGlpNumFloor (t, xi); + if (EGlpNumIsLessDbl (t, 0.1) && EGlpNumIsGreaDbl (t, -0.1)) + EGlpNumZero (t); + + rval = ILLlib_chgbnd (lp, k, 'U', t); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_optimize (lp, &B, &lpinf, DUAL_SIMPLEX, &status, 0, itcnt); + CHECKRVALG (rval, CLEANUP); + + EGlpNumCopy (downpen[i], lp->dobjval); + rval = ILLlib_chgbnd (lp, k, 'U', oldbnd); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getbnd (lp, k, 'L', &oldbnd); + CHECKRVALG (rval, CLEANUP); + EGlpNumCeil (t, xi); + if (EGlpNumIsLessDbl (t, 1.1) && EGlpNumIsGreaDbl (t, 0.9)) + EGlpNumOne (t); + rval = ILLlib_chgbnd (lp, k, 'L', t); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_optimize (lp, &B, &lpinf, DUAL_SIMPLEX, &status, 0, itcnt); + CHECKRVALG (rval, CLEANUP); + + EGlpNumCopy (uppen[i], lp->dobjval); + rval = ILLlib_chgbnd (lp, k, 'L', oldbnd); + CHECKRVALG (rval, CLEANUP); + } + + if (lp->O->objsense == ILL_MAX) + { + + } + else + { + for (i = 0; i < ncand; i++) + { + if (EGlpNumIsLess (objbound, downpen[i])) + EGlpNumCopy (downpen[i], objbound); + if (EGlpNumIsLess (objbound, uppen[i])) + EGlpNumCopy (uppen[i], objbound); + } + } + + /* Restore the old optimal solution */ + + lp->maxiter = olditer; + rval = ILLlib_optimize (lp, &origB, pinf, DUAL_SIMPLEX, &status, 0, itcnt); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EGlpNumClearVar (xi); + EGlpNumClearVar (t); + EGlpNumClearVar (oldbnd); + lp->maxiter = olditer; + ILLprice_free_pricing_info (&lpinf); + ILLlp_basis_free (&B); + ILLlp_basis_free (&origB); + if (xlist == 0) + EGlpNumFreeArray (myx); + EGlpNumClearVar (lpinf.htrigger); + EG_RETURN (rval); +} + +#define EXTRA_ROWS (100) +#define EXTRA_COLS (100) +#define EXTRA_MAT (1000) + +int ILLlib_newrow ( + lpinfo * lp, + ILLlp_basis * B, + const EGlpNum_t rhs, + int sense, + const EGlpNum_t range, + const char *name) +{ + int rval = 0; + + rval = ILLlib_addrow (lp, B, 0, 0, 0, rhs, sense, range, name); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_newrows ( + lpinfo * lp, + ILLlp_basis * B, + int num, + const EGlpNum_t * rhs, + char *sense, + const EGlpNum_t * range, + const char **names) +{ + int rval = 0; + int *rmatcnt = 0; + int *rmatbeg = 0; + int i; + + if (!num) + ILL_CLEANUP; + + ILL_SAFE_MALLOC (rmatcnt, num, int); + + ILL_SAFE_MALLOC (rmatbeg, num, int); + + for (i = 0; i < num; i++) + { + rmatcnt[i] = 0; + rmatbeg[i] = 0; + } + + rval = ILLlib_addrows (lp, B, num, rmatcnt, rmatbeg, 0, 0, rhs, sense, + range, names, 0); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + ILL_IFFREE (rmatcnt, int); + ILL_IFFREE (rmatbeg, int); + + EG_RETURN (rval); +} + +int ILLlib_addrows ( + lpinfo * lp, + ILLlp_basis * B, + int num, + int *rmatcnt, + int *rmatbeg, + int *rmatind, + const EGlpNum_t * rmatval, + const EGlpNum_t * rhs, + char *sense, + const EGlpNum_t * range, + const char **names, + int *factorok) +{ + int rval = 0; + int i, j, total, bsing; + int *imap = 0; + int *bbeg = 0; + int *bcnt = 0; + int *bindi = 0; + int *rindi = 0; + int *jstat = 0; + EGlpNum_t *bval = 0; + EGlpNum_t rng; + int badfactor = 0; + + EGlpNumInitVar (rng); + + if (B == 0 || B->rownorms == 0) + { + if (factorok) + *factorok = 0; + } + + if (B) + EGlpNumFreeArray (B->colnorms); + + if (B && B->rownorms && factorok && *factorok == 1) + { + int *structmap = lp->O->structmap; + + lp->matbeg = lp->O->A.matbeg; + lp->matcnt = lp->O->A.matcnt; + lp->matind = lp->O->A.matind; + lp->matval = lp->O->A.matval; + + lp->nrows = lp->O->nrows; + lp->ncols = lp->O->ncols; + if (B->rownorms_size < lp->O->nrows + num) + EGlpNumReallocArray (&(B->rownorms), lp->O->nrows + num); + + ILL_SAFE_MALLOC (bcnt, num, int); + ILL_SAFE_MALLOC (bbeg, num, int); + ILL_SAFE_MALLOC (imap, lp->O->nstruct, int); + + ILL_SAFE_MALLOC (jstat, lp->ncols, int); + + for (i = 0; i < lp->ncols; i++) + { + jstat[i] = -1; + } + for (i = 0; i < lp->O->nstruct; i++) + { + jstat[structmap[i]] = i; + } + + for (i = 0; i < lp->O->nstruct; i++) + { + imap[i] = -1; + } + for (i = 0; i < lp->O->nrows; i++) + { + if (jstat[lp->baz[i]] != -1) + { + imap[jstat[lp->baz[i]]] = i; + } + } + + for (i = 0, total = 0; i < num; i++) + { + bcnt[i] = 0; + bbeg[i] = total; + for (j = 0; j < rmatcnt[i]; j++) + { + if (imap[rmatind[rmatbeg[i] + j]] != -1) + { + bcnt[i]++; + total++; + } + } + } + if (total) + { + ILL_SAFE_MALLOC (bindi, total, int); + + bval = EGlpNumAllocArray (total); + } + for (i = 0, total = 0; i < num; i++) + { + for (j = 0; j < rmatcnt[i]; j++) + { + if (imap[rmatind[rmatbeg[i] + j]] != -1) + { + EGlpNumCopy (bval[total], rmatval[rmatbeg[i] + j]); + bindi[total] = imap[rmatind[rmatbeg[i] + j]]; + total++; + } + } + } + + rval = ILLprice_get_new_rownorms (lp, num, B->rownorms + lp->O->nrows, + bcnt, bbeg, bindi, bval); + CHECKRVALG (rval, CLEANUP); + + ILL_IFFREE (bcnt, int); + ILL_IFFREE (bbeg, int); + ILL_IFFREE (bindi, int); + + EGlpNumFreeArray (bval); + ILL_IFFREE (imap, int); + + badfactor = 1; + } + + for (i = 0; i < num; i++) + { + if (range) + EGlpNumCopy (rng, range[i]); + else + EGlpNumZero (rng); + if (names) + { + rval = ILLlib_addrow (lp, B, rmatcnt[i], rmatind + rmatbeg[i], + rmatval + rmatbeg[i], rhs[i], sense[i], rng, + names[i]); + } + else + { + rval = ILLlib_addrow (lp, B, rmatcnt[i], rmatind + rmatbeg[i], + rmatval + rmatbeg[i], rhs[i], sense[i], rng, 0); + } + CHECKRVALG (rval, CLEANUP); + } + + + if (B && B->rownorms && (factorok && *factorok == 0)) + { + lp->matbeg = lp->O->A.matbeg; + lp->matcnt = lp->O->A.matcnt; + lp->matind = lp->O->A.matind; + lp->matval = lp->O->A.matval; + lp->nrows = lp->O->nrows; + lp->ncols = lp->O->ncols; + lp->bz = lp->O->rhs; + lp->nnbasic = lp->ncols - lp->nrows; + + rval = ILLbasis_load (lp, B); + CHECKRVALG (rval, CLEANUP); + + if (lp->f) + ILLfactor_free_factor_work (lp->f); + + rval = ILLbasis_factor (lp, &bsing); + CHECKRVALG (rval, CLEANUP); + if (bsing) + MESSAGE (__QS_SB_VERB, "Singular Basis found!"); + *factorok = 1; + + if (B->rownorms_size < lp->O->nrows) + EGlpNumReallocArray (&(B->rownorms), lp->O->nrows); + + ILL_SAFE_MALLOC (rindi, lp->O->nrows /* num */ , int); + + for (i = 0; i < num; i++) + { + rindi[i] = lp->O->nrows - num + i; + } + + rval = ILLprice_get_dsteep_norms (lp, num, rindi, + B->rownorms + lp->O->nrows - num); + CHECKRVALG (rval, CLEANUP); + } + + if (factorok != 0 && badfactor == 1) + { + *factorok = 0; + } + + +CLEANUP: + + ILL_IFFREE (bcnt, int); + ILL_IFFREE (bbeg, int); + ILL_IFFREE (bindi, int); + + EGlpNumFreeArray (bval); + ILL_IFFREE (imap, int); + ILL_IFFREE (jstat, int); + ILL_IFFREE (rindi, int); + + EGlpNumClearVar (rng); + EG_RETURN (rval); +} + +int ILLlib_addrow ( + lpinfo * lp, + ILLlp_basis * B, + int cnt, + int *ind, + const EGlpNum_t * val, + const EGlpNum_t rhs, + int sense, + const EGlpNum_t range, + const char *name) +{ + int rval = 0; + ILLlpdata *qslp; + ILLmatrix *A; + int i, nrows, ncols; + char buf[ILL_namebufsize]; + int tind[1]; + EGlpNum_t tval[1]; + int *tempind = 0; + int pind, hit; + + EGlpNumInitVar (tval[0]); + + if (!lp) + { + fprintf (stderr, "ILLlib_addrow called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + A = &qslp->A; + + if (qslp->rA) + { /* After an addrow call, needs to be updated */ + ILLlp_rows_clear (qslp->rA); + ILL_IFFREE (qslp->rA, ILLlp_rows); + } + + if (qslp->sinfo) + { /* Presolve LP is no longer valid, free the data */ + ILLlp_sinfo_free (qslp->sinfo); + ILL_IFFREE (qslp->sinfo, ILLlp_sinfo); + } + + nrows = qslp->nrows; + ncols = qslp->ncols; + + /* If the row has a range, create the rangeval array if needed */ + + if (sense == 'R' && !(qslp->rangeval) && qslp->rowsize > 0) + { + qslp->rangeval = EGlpNumAllocArray (qslp->rowsize); + for (i = 0; i < qslp->nrows; i++) + { + EGlpNumZero (qslp->rangeval[i]); + } + } + + /* Add the row to the row structures */ + + if (qslp->rowsize < nrows + 1) + { + EGlpNumReallocArray (&(qslp->rhs), qslp->rowsize + EXTRA_ROWS); + qslp->sense = EGrealloc (qslp->sense, + sizeof (char) * (qslp->rowsize + EXTRA_ROWS)); + //rval = ILLutil_reallocrus_count ((void **) &(qslp->sense), + // qslp->rowsize + EXTRA_ROWS, sizeof (char)); + //CHECKRVALG(rval,CLEANUP); + + qslp->rowmap = EGrealloc (qslp->rowmap, + sizeof (int) * (qslp->rowsize + EXTRA_ROWS)); + //rval = ILLutil_reallocrus_count ((void **) &(qslp->rowmap), + // qslp->rowsize + EXTRA_ROWS, sizeof (int)); + //CHECKRVALG(rval,CLEANUP); + + if (qslp->rangeval || sense == 'R') + EGlpNumReallocArray (&(qslp->rangeval), qslp->rowsize + EXTRA_ROWS); + + qslp->rownames = EGrealloc (qslp->rownames, + sizeof (char *) * (qslp->rowsize + EXTRA_ROWS)); + //rval = ILLutil_reallocrus_count ((void **) &(qslp->rownames), + // qslp->rowsize + EXTRA_ROWS, + // sizeof (char *)); + //CHECKRVALG(rval,CLEANUP); + qslp->rowsize += EXTRA_ROWS; + } + + EGlpNumCopy (qslp->rhs[nrows], rhs); + qslp->sense[nrows] = sense; + qslp->rowmap[nrows] = ncols; /* this will be the new logical */ + if (qslp->rangeval) + { + if (sense == 'R') + EGlpNumCopy (qslp->rangeval[nrows], range); + else + EGlpNumZero (qslp->rangeval[nrows]); + } + ILL_FAILtrue (qslp->rownames == NULL, "must always be non NULL"); + ILLlib_findName (qslp, 1 /*row */ , name, nrows, buf); + ILL_UTIL_STR (qslp->rownames[nrows], buf); + ILLsymboltab_register (&qslp->rowtab, buf, qslp->nrows, &pind, &hit); + ILL_FAILfalse (hit == 0, "must be new"); + + + /* Add the logical variable to the column structures */ + + if (qslp->colsize < ncols + 1) + { + EGlpNumReallocArray (&(qslp->lower), qslp->colsize + EXTRA_COLS); + EGlpNumReallocArray (&(qslp->upper), qslp->colsize + EXTRA_COLS); + EGlpNumReallocArray (&(qslp->obj), qslp->colsize + EXTRA_COLS); + qslp->colsize += EXTRA_COLS; + } + + EGlpNumZero (qslp->obj[ncols]); + EGlpNumZero (qslp->lower[ncols]); + if (sense == 'E') + { + EGlpNumZero (qslp->upper[ncols]); /* Artificial */ + } + else if (sense == 'R') + { + EGlpNumCopy (qslp->upper[ncols], range); /* Range */ + } + else + { + EGlpNumCopy (qslp->upper[ncols], ILL_MAXDOUBLE); /* Slack */ + } + + /* Add new row and new logical col to matrix */ + + /* Need to map the structural indices to their proper place */ + + if (cnt) + { + ILL_SAFE_MALLOC (tempind, cnt, int); + + for (i = 0; i < cnt; i++) + { + tempind[i] = qslp->structmap[ind[i]]; + } + } + + rval = matrix_addrow (A, cnt, tempind, val); + CHECKRVALG (rval, CLEANUP); + + tind[0] = nrows; + EGlpNumOne (*tval); + if (sense == 'G' || sense == 'R') + EGlpNumSign (*tval); + + rval = matrix_addcol (A, 1, tind, tval); + CHECKRVALG (rval, CLEANUP); + + if (B != 0) + { + B->rstat = EGrealloc (B->rstat, sizeof (char) * (nrows + 1)); + //rval = ILLutil_reallocrus_count ((void **) &(B->rstat), nrows + 1, + // sizeof (char)); + //CHECKRVALG(rval,CLEANUP); + B->rstat[nrows] = QS_ROW_BSTAT_BASIC; + } + +#if 0 + lp->basisid = -1; /* To get optimizer to reload the basis */ +#endif + + qslp->ncols++; + qslp->nrows++; + qslp->nzcount += (cnt + 1); + + if (B != 0) + { + B->nrows++; + } + +CLEANUP: + ILL_IFFREE (tempind, int); + + EGlpNumClearVar (tval[0]); + EG_RETURN (rval); +} + +int ILLlib_delrows ( + lpinfo * lp, + ILLlp_basis * B, + ILLlp_cache * C, + int num, + int *dellist, + int *basis_ok, + int *cache_ok) +{ + int rval = 0; + int i, j, k, nrows, ncols, nstruct, spot, dk, bok = 0, cok = 0; + ILLlpdata *qslp; + ILLmatrix *A; + char *rowmark = 0; + char *colmark = 0; + int *newrowindex = 0; + int *newcolindex = 0; + int *ind, *beg, *cnt; + EGlpNum_t *val; + + if (!lp) + { + fprintf (stderr, "ILLlib_delrows called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + if (num <= 0) + { + if (basis_ok) + *basis_ok = 1; + if (cache_ok) + *cache_ok = 1; + ILL_CLEANUP; + } + + if (basis_ok) + *basis_ok = 0; + if (cache_ok) + *cache_ok = 0; + + qslp = lp->O; + A = &qslp->A; + + if (qslp->rA) + { /* After a delrow call, needs to be updated */ + ILLlp_rows_clear (qslp->rA); + ILL_IFFREE (qslp->rA, ILLlp_rows); + } + + nrows = A->matrows; + ncols = A->matcols; + ind = A->matind; + beg = A->matbeg; + cnt = A->matcnt; + val = A->matval; + nstruct = qslp->nstruct; + + ILL_SAFE_MALLOC (rowmark, nrows, char); + + for (i = 0; i < nrows; i++) + { + rowmark[i] = 0; + } + for (i = 0; i < num; i++) + { + rowmark[dellist[i]] = 1; + } + + + /* Try to update the basis */ + + if (B) + { + bok = 1; + cok = 1; + for (i = 0; i < num; i++) + { + j = dellist[i]; + if (B->rstat[j] == QS_ROW_BSTAT_LOWER || + B->rstat[j] == QS_ROW_BSTAT_UPPER) + { + bok = 0; + break; + } + if (C && EGlpNumIsLess (DFEAS_TOLER, C->pi[j])) + { +/* + printf ("XXXX: Postive pi (%f) at basic row\n", C->pi[j]); + fflush (stdout); +*/ + cok = 0; + } + } + if (bok == 1) + { + EGlpNumFreeArray (B->colnorms); + if (B->rownorms) + { + for (i = 0, k = 0; i < nstruct; i++) + { + if (B->cstat[i] == QS_COL_BSTAT_BASIC) + k++; + } + for (i = 0, j = k; i < nrows; i++) + { + if (B->rstat[i] == QS_ROW_BSTAT_BASIC) + { + if (rowmark[i] == 0) + { + EGlpNumCopy (B->rownorms[k++], B->rownorms[j]); + } + j++; + } + } + if (k != nrows - num) + { + fprintf (stderr, "error in ILLlib_delrows\n"); + rval = 1; + ILL_CLEANUP; + } + } + + for (i = 0, j = 0; i < nrows; i++) + { + if (rowmark[i] == 0) + { + B->rstat[j++] = B->rstat[i]; + } + } + B->nrows = j; + + if (C && cok == 1) + { + for (i = 0, j = 0; i < nrows; i++) + { + if (rowmark[i] == 0) + { + EGlpNumCopy (C->pi[j], C->pi[i]); + EGlpNumCopy (C->slack[j++], C->slack[i]); + } + } + C->nrows = j; + if (cache_ok) + *cache_ok = 1; + } + if (basis_ok) + *basis_ok = 1; + } + } + + ILL_SAFE_MALLOC (newrowindex, nrows, int); + + + /* Delete the marked rows */ + + ILL_FAILtrue (qslp->rownames == NULL, "must always be non NULL"); + for (i = 0, j = 0; i < nrows; i++) + { + if (rowmark[i] == 0) + { + if (i != j) + { + EGlpNumCopy (qslp->rhs[j], qslp->rhs[i]); + qslp->sense[j] = qslp->sense[i]; + if (qslp->rangeval) + EGlpNumCopy (qslp->rangeval[j], qslp->rangeval[i]); + if (qslp->rownames) + qslp->rownames[j] = qslp->rownames[i]; + } + newrowindex[i] = j++; + } + else + { + if (qslp->rownames) + { + rval = ILLsymboltab_delete (&qslp->rowtab, qslp->rownames[i]); + CHECKRVALG (rval, CLEANUP); + ILL_IFFREE (qslp->rownames[i], char); + } + } + } + + + /* Delete the logicals */ + + ILL_SAFE_MALLOC (colmark, ncols, char); + + for (i = 0; i < ncols; i++) + { + colmark[i] = 0; + } + for (i = 0; i < num; i++) + { + colmark[qslp->rowmap[dellist[i]]] = 1; + } + + rval = delcols_work (lp, colmark); + CHECKRVALG (rval, CLEANUP); + + A->matcols -= num; + qslp->ncols -= num; + + + /* Pack the rowmap */ + + for (i = 0, j = 0; i < nrows; i++) + { + if (rowmark[i] == 0) + { + qslp->rowmap[j++] = qslp->rowmap[i]; + } + } + + /* Remove the entries to deleted rows, and update the indices */ + + for (i = 0; i < ncols - num; i++) + { + dk = 0; + spot = beg[i]; + for (j = 0; j < cnt[i]; j++) + { + if (rowmark[ind[beg[i] + j]] == 1) + { + dk++; + } + else + { + EGlpNumCopy (val[spot], val[beg[i] + j]); + ind[spot] = newrowindex[ind[beg[i] + j]]; + spot++; + } + } + for (; spot < beg[i] + cnt[i]; spot++) + { + ind[spot] = -1; + } + + cnt[i] -= dk; + if (cnt[i] == 0) + { + ind[beg[i]] = 1; /* we always mark the empty cols */ + } + } + + A->matrows -= num; + qslp->nrows -= num; + +#if 0 + lp->basisid = -1; /* To get optimizer to reload the basis */ +#endif + + /* if the base is OK, we MUST load the status variables again */ + if(bok) + { + rval = ILLbasis_load( lp, B); + CHECKRVALG (rval, CLEANUP); + } +CLEANUP: + + ILL_IFFREE (rowmark, char); + ILL_IFFREE (colmark, char); + ILL_IFFREE (newcolindex, int); + ILL_IFFREE (newrowindex, int); + + EG_RETURN (rval); +} + +int ILLlib_delcols ( + lpinfo * lp, + ILLlp_basis * B, + int num, + int *dellist, + int *basis_ok) +{ + int rval = 0; + int i, j, bok = 0, ncols; + char *colmark = 0; + ILLlpdata *qslp; + + if (!lp) + { + fprintf (stderr, "ILLlib_delcols called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + if (basis_ok) + *basis_ok = 0; + + if (num <= 0) + { + *basis_ok = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + ncols = qslp->A.matcols; + + if (qslp->rA) + { /* After a delcol call, needs to be updated */ + ILLlp_rows_clear (qslp->rA); + ILL_IFFREE (qslp->rA, ILLlp_rows); + } + + ILL_SAFE_MALLOC (colmark, ncols, char); + + for (i = 0; i < ncols; i++) + { + colmark[i] = 0; + } + for (i = 0; i < num; i++) + { + colmark[qslp->structmap[dellist[i]]] = 1; + } + + if (B) + { + B->nstruct -= num; + bok = 1; + for (i = 0; i < num; i++) + { + j = dellist[i]; + if (B->cstat[j] == QS_COL_BSTAT_BASIC) + { + bok = 0; + //printf ("BONG\n"); + //fflush (stdout); + break; + } + } + if (bok == 1) + { + EGlpNumFreeArray (B->colnorms); + for (i = 0, j = 0; i < qslp->nstruct; i++) + { + if (colmark[qslp->structmap[i]] == 0) + { + B->cstat[j++] = B->cstat[i]; + } + } + if (basis_ok) + *basis_ok = 1; + } + } + + rval = delcols_work (lp, colmark); + CHECKRVALG (rval, CLEANUP); + + + qslp->A.matcols -= num; + qslp->ncols -= num; + qslp->nstruct -= num; + + /* if the base is OK, we MUST load the status variables again */ + if(bok) + { + rval = ILLbasis_load( lp, B); + CHECKRVALG (rval, CLEANUP); + } +#if 0 + lp->basisid = -1; /* To get optimizer to reload the basis */ +#endif + +CLEANUP: + + ILL_IFFREE (colmark, char); + + EG_RETURN (rval); +} + +static int matrix_getcoef ( + ILLmatrix *A, + int row, + int col, + EGlpNum_t*val) +{ + int i; + int rval = 0; + if (row >= A->matrows || row < 0) + { + fprintf (stderr, "illegal row index in matrix_getcoef\n"); + rval= 1; + ILL_CLEANUP; + } + + if (col >= A->matcols || col < 0) + { + fprintf (stderr, "illegal col index in matrix_getcoef\n"); + rval= 1; + ILL_CLEANUP; + } + + /* by default value is zero */ + EGlpNumZero(*val); + for (i = A->matbeg[col]; i < A->matbeg[col] + A->matcnt[col]; i++) + { + if (A->matind[i] == row) + { + EGlpNumCopy(*val, A->matval[i]); + ILL_CLEANUP; + } + } + +CLEANUP: + + EG_RETURN(rval); +} + +static int delcols_work ( + lpinfo * lp, + char *colmark) +{ + int rval = 0; + int i, j, k, nrows, ncols; + ILLlpdata *qslp; + ILLmatrix *A; + int *newcolindex = 0; + int *ind, *beg, *cnt; + + /* Allows logicals to be deleted, to handle call from delcols. */ + + qslp = lp->O; + A = &qslp->A; + nrows = A->matrows; + ncols = A->matcols; + ind = A->matind; + beg = A->matbeg; + cnt = A->matcnt; + + ILL_SAFE_MALLOC (newcolindex, ncols, int); + + /* Delete the columns */ + + for (i = 0, j = 0; i < ncols; i++) + { + if (colmark[i] == 0) + { + if (i != j) + { + beg[j] = beg[i]; + cnt[j] = cnt[i]; + EGlpNumCopy (qslp->obj[j], qslp->obj[i]); + EGlpNumCopy (qslp->lower[j], qslp->lower[i]); + EGlpNumCopy (qslp->upper[j], qslp->upper[i]); + } + newcolindex[i] = j++; + } + else + { + for (k = 0; k < cnt[i]; k++) + { + ind[beg[i] + k] = -1; + } + newcolindex[i] = -1; + } + } + + /* Update the struct arrays */ + + for (i = 0, j = 0; i < qslp->nstruct; i++) + { + k = qslp->structmap[i]; + if (colmark[k] == 0) + { + qslp->structmap[j] = newcolindex[k]; + qslp->colnames[j] = qslp->colnames[i]; + if (qslp->intmarker) + qslp->intmarker[j] = qslp->intmarker[i]; + j++; + } + else + { + rval = ILLsymboltab_delete (&qslp->coltab, qslp->colnames[i]); + CHECKRVALG (rval, CLEANUP); + ILL_IFFREE (qslp->colnames[i], char); + } + } + + /* Update the rowmap: note if logicals deleted, map will be -1 */ + + for (i = 0; i < nrows; i++) + { + qslp->rowmap[i] = newcolindex[qslp->rowmap[i]]; + } + +CLEANUP: + + ILL_IFFREE (newcolindex, int); + + EG_RETURN (rval); +} + +int ILLlib_getcoef ( + lpinfo *lp, + int rowindex, + int colindex, + EGlpNum_t* coef) +{ + int rval = 0; + ILLlpdata *qslp; + ILLmatrix *A; + int nrows, nstruct, j; + if (!lp) + { + fprintf (stderr, "ILLlib_chgcoef called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + A = &qslp->A; + nrows = qslp->nrows; + nstruct = qslp->nstruct; + + if (rowindex < 0 || rowindex >= nrows || colindex < 0 || colindex >= nstruct) + { + fprintf (stderr, "ILLlib_getcoef called with out-of-range index\n"); + rval = 1; + ILL_CLEANUP; + } + + j = qslp->structmap[colindex]; + rval = matrix_getcoef (A, rowindex, j, coef); + CHECKRVALG(rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_chgcoef ( + lpinfo * lp, + int rowindex, + int colindex, + EGlpNum_t coef) +{ + int rval = 0; + ILLlpdata *qslp; + ILLmatrix *A; + int nrows, nstruct, j; + + if (!lp) + { + fprintf (stderr, "ILLlib_chgcoef called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + A = &qslp->A; + + nrows = qslp->nrows; + nstruct = qslp->nstruct; + + if (rowindex < 0 || rowindex >= nrows || colindex < 0 || colindex >= nstruct) + { + fprintf (stderr, "ILLlib_chgcoef called with out-of-range index\n"); + rval = 1; + ILL_CLEANUP; + } + + if (qslp->rA) + { /* After a chgcoef call, needs to be updated */ + ILLlp_rows_clear (qslp->rA); + ILL_IFFREE (qslp->rA, ILLlp_rows); + } + + if (qslp->sinfo) + { /* Presolve LP is no longer valid, free the data */ + ILLlp_sinfo_free (qslp->sinfo); + ILL_IFFREE (qslp->sinfo, ILLlp_sinfo); + } + + j = qslp->structmap[colindex]; + + rval = matrix_addcoef (lp, A, rowindex, j, coef); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_chgsense ( + lpinfo * lp, + int num, + int *rowlist, + char *sense) +{ + int rval = 0; + int i, j, k; + ILLlpdata *qslp = lp->O; + ILLmatrix *A = &(lp->O->A); + + for (i = 0; i < num; i++) + { + j = qslp->rowmap[rowlist[i]]; + if (A->matcnt[j] != 1) + { + fprintf (stderr, "logical variable is not a singleton\n"); + rval = 1; + ILL_CLEANUP; + } + k = A->matbeg[j]; + switch (sense[i]) + { + case 'R': /* Range constraint, we will set its upper bound + once we call QSchange_range, by default it + will be zero, i.e. an equation. */ + qslp->sense[rowlist[i]] = 'R'; + EGlpNumZero(qslp->lower[j]); + EGlpNumZero(qslp->upper[j]); + EGlpNumOne(A->matval[k]); + break; + case 'E': /* Artificial */ + qslp->sense[rowlist[i]] = 'E'; + EGlpNumZero (qslp->lower[j]); + EGlpNumZero (qslp->upper[j]); + EGlpNumOne (A->matval[k]); + break; + case 'G': /* Surplus */ + qslp->sense[rowlist[i]] = 'G'; + EGlpNumZero (qslp->lower[j]); + EGlpNumCopy (qslp->upper[j], ILL_MAXDOUBLE); + EGlpNumOne (A->matval[k]); + EGlpNumSign (A->matval[k]); + break; + case 'L': /* Slack */ + qslp->sense[rowlist[i]] = 'L'; + EGlpNumZero (qslp->lower[j]); + EGlpNumCopy (qslp->upper[j], ILL_MAXDOUBLE); + EGlpNumOne (A->matval[k]); + break; + default: + fprintf (stderr, "illegal sense %c in ILLlib_chgsense\n", sense[i]); + rval = 1; + ILL_CLEANUP; + } + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_getsenses ( + lpinfo *lp, + char *senses) +{ + ILLlpdata *qslp; + int nrows, i; + int rval = 0; + + if (!lp) { + fprintf (stderr, "ILLlib_getsense called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nrows = qslp->nrows; + + for (i = 0; i < nrows; i++) + { + senses[i] = qslp->sense[i]; + } + +CLEANUP: + + EG_RETURN(rval); +} + +int ILLlib_newcol ( + lpinfo * lp, + ILLlp_basis * B, + const EGlpNum_t obj, + const EGlpNum_t lower, + const EGlpNum_t upper, + const char *name, + int factorok) +{ + int rval = 0; + + rval = ILLlib_addcol (lp, B, 0, 0, 0, obj, lower, upper, name, factorok); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_newcols ( + lpinfo * lp, + ILLlp_basis * B, + int num, + EGlpNum_t * obj, + EGlpNum_t * lower, + EGlpNum_t * upper, + const char **names, + int factorok) +{ + int rval = 0; + int *cmatcnt = 0; + int *cmatbeg = 0; + int i; + + ILL_SAFE_MALLOC (cmatcnt, num, int); + + ILL_SAFE_MALLOC (cmatbeg, num, int); + + for (i = 0; i < num; i++) + { + cmatcnt[i] = 0; + cmatbeg[i] = 0; + } + + rval = ILLlib_addcols (lp, B, num, cmatcnt, cmatbeg, 0, + 0, obj, lower, upper, names, factorok); + CHECKRVALG (rval, CLEANUP); + + +CLEANUP: + + ILL_IFFREE (cmatcnt, int); + ILL_IFFREE (cmatbeg, int); + + EG_RETURN (rval); +} + +int ILLlib_addcols ( + lpinfo * lp, + ILLlp_basis * B, + int num, + int *cmatcnt, + int *cmatbeg, + int *cmatind, + EGlpNum_t * cmatval, + EGlpNum_t * obj, + EGlpNum_t * lower, + EGlpNum_t * upper, + const char **names, + int factorok) +{ + int rval = 0; + int i; + + for (i = 0; i < num; i++) + { + if (names) + { + rval = ILLlib_addcol (lp, B, cmatcnt[i], cmatind + cmatbeg[i], + cmatval + cmatbeg[i], obj[i], lower[i], + upper[i], names[i], factorok); + } + else + { + rval = ILLlib_addcol (lp, B, cmatcnt[i], cmatind + cmatbeg[i], + cmatval + cmatbeg[i], obj[i], lower[i], + upper[i], 0, factorok); + } + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_addcol ( + lpinfo * lp, + ILLlp_basis * B, + int cnt, + int *ind, + EGlpNum_t * val, + const EGlpNum_t obj, + const EGlpNum_t lower, + const EGlpNum_t upper, + const char *name, + int factorok) +{ + int rval = 0; + ILLlpdata *qslp; + ILLmatrix *A; + int ncols; + char buf[ILL_namebufsize]; + int pind, hit; + EGlpNum_t l, u; + + EGlpNumInitVar (l); + EGlpNumInitVar (u); + + if (!lp) + { + fprintf (stderr, "ILLlib_addcol called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + A = &qslp->A; + ncols = qslp->ncols; + + if (qslp->rA) + { /* After an addcol call, needs to be updated */ + ILLlp_rows_clear (qslp->rA); + ILL_IFFREE (qslp->rA, ILLlp_rows); + } + + if (qslp->sinfo) + { /* Presolve LP is no longer valid, free the data */ + ILLlp_sinfo_free (qslp->sinfo); + ILL_IFFREE (qslp->sinfo, ILLlp_sinfo); + } + + + /* Add the new variable to the column structures */ + + if (qslp->colsize < ncols + 1) + { + EGlpNumReallocArray (&(qslp->lower), qslp->colsize + EXTRA_COLS); + EGlpNumReallocArray (&(qslp->upper), qslp->colsize + EXTRA_COLS); + EGlpNumReallocArray (&(qslp->obj), qslp->colsize + EXTRA_COLS); + qslp->colsize += EXTRA_COLS; + } + + EGlpNumCopy (qslp->obj[ncols], obj); + EGlpNumCopy (qslp->lower[ncols], lower); + EGlpNumCopy (qslp->upper[ncols], upper); + + /* Add the variable to the structural arrays */ + + if (qslp->structsize < qslp->nstruct + 1) + { + qslp->structmap = EGrealloc (qslp->structmap, + sizeof (int) * (qslp->structsize + + EXTRA_COLS)); + //rval = ILLutil_reallocrus_count ((void **) &(qslp->structmap), + // qslp->structsize + EXTRA_COLS, + // sizeof (int)); + //CHECKRVALG(rval,CLEANUP); + + qslp->colnames = EGrealloc (qslp->colnames, + sizeof (char *) * (qslp->structsize + + EXTRA_COLS)); + //rval = ILLutil_reallocrus_count ((void **) &(qslp->colnames), + // qslp->structsize + EXTRA_COLS, + // sizeof (char *)); + //CHECKRVALG(rval,CLEANUP); + + if (qslp->intmarker) + { + qslp->intmarker = EGrealloc (qslp->intmarker, + sizeof (char) * (qslp->structsize + + EXTRA_COLS)); + //rval = ILLutil_reallocrus_count ((void **) &(qslp->intmarker), + // qslp->structsize + EXTRA_COLS, + // sizeof (char)); + //CHECKRVALG(rval,CLEANUP); + } + qslp->structsize += EXTRA_COLS; + } + + qslp->structmap[qslp->nstruct] = ncols; + if (qslp->intmarker) + { + /* NOTE: If we want to add integer variables, this is the place. */ + qslp->intmarker[qslp->nstruct] = (char) 0; + } + + ILL_FAILtrue (qslp->colnames == NULL, "must always be non NULL"); + ILLlib_findName (qslp, 0 /*isRow */ , name, qslp->nstruct, buf); + ILLsymboltab_register (&qslp->coltab, buf, qslp->nstruct, &pind, &hit); + ILL_FAILfalse ((pind == qslp->nstruct) && (hit == 0), "must be new"); + ILL_UTIL_STR (qslp->colnames[qslp->nstruct], buf); + + + /* Add col to the matrix */ + + rval = matrix_addcol (A, cnt, ind, val); + CHECKRVALG (rval, CLEANUP); + + + if (B) + { + B->cstat = EGrealloc (B->cstat, sizeof (char) * (qslp->nstruct + 1)); + //rval = ILLutil_reallocrus_count ((void **) &(B->cstat), + // qslp->nstruct + 1, sizeof (char)); + //CHECKRVALG(rval,CLEANUP); + if (EGlpNumIsEqual (lower, ILL_MINDOUBLE, oneLpNum) && + EGlpNumIsEqual (upper, ILL_MAXDOUBLE, oneLpNum)) + { + B->cstat[qslp->nstruct] = QS_COL_BSTAT_FREE; + } + else if (EGlpNumIsEqual (upper, ILL_MAXDOUBLE, oneLpNum)) + { + B->cstat[qslp->nstruct] = QS_COL_BSTAT_LOWER; + } + //else if (lower == ILL_MAXDOUBLE) + else if (EGlpNumIsEqual (lower, ILL_MAXDOUBLE, oneLpNum)) + { + B->cstat[qslp->nstruct] = QS_COL_BSTAT_UPPER; + } + else + { + /*l = fabs (lower); + * u = fabs (upper); */ + EGlpNumCopyAbs (l, lower); + EGlpNumCopyAbs (u, upper); + if (EGlpNumIsLess (l, u)) + { + B->cstat[qslp->nstruct] = QS_COL_BSTAT_LOWER; + } + else + { + B->cstat[qslp->nstruct] = QS_COL_BSTAT_UPPER; + } + } + + /* UPDATE THE PINF PRIMAL NORMS */ + EGlpNumFreeArray (B->colnorms); + } + + if (factorok == 0) + { +#if 0 + lp->basisid = -1; /* To get optimizer to reload the basis */ +#endif + } + else + { + if (!lp->nbaz || !lp->vindex || !lp->vstat) + { + fprintf (stderr, "ERROR: factorok set without a current basis\n"); + rval = 1; + ILL_CLEANUP; + } + + lp->nbaz = EGrealloc (lp->nbaz, sizeof (int) * (qslp->nstruct + 1)); + //rval = ILLutil_reallocrus_count ((void **) &(lp->nbaz), + // qslp->nstruct + 1, sizeof (int)); + //CHECKRVALG(rval,CLEANUP); + + lp->vindex = EGrealloc (lp->vindex, sizeof (int) * (qslp->ncols + 1)); + //rval = ILLutil_reallocrus_count ((void **) &(lp->vindex), + // qslp->ncols + 1, sizeof (int)); + //CHECKRVALG(rval,CLEANUP); + + lp->vstat = EGrealloc (lp->vstat, sizeof (int) * (qslp->ncols + 1)); + //rval = ILLutil_reallocrus_count ((void **) &(lp->vstat), + // qslp->ncols + 1, sizeof (int)); + + + lp->nbaz[qslp->nstruct] = qslp->ncols; + lp->vindex[qslp->ncols] = qslp->nstruct; + + if (EGlpNumIsEqual (lower, ILL_MINDOUBLE, oneLpNum) && + EGlpNumIsEqual (upper, ILL_MAXDOUBLE, oneLpNum)) + { + lp->vstat[qslp->ncols] = STAT_ZERO; + } + else if (EGlpNumIsEqual (upper, ILL_MAXDOUBLE, oneLpNum)) + { + lp->vstat[qslp->ncols] = STAT_LOWER; + } + //else if (lower == ILL_MAXDOUBLE) + else if (EGlpNumIsEqual (lower, ILL_MAXDOUBLE, oneLpNum)) + { + lp->vstat[qslp->ncols] = STAT_UPPER; + } + else + { + /*l = fabs (lower); + * u = fabs (upper); */ + EGlpNumCopyAbs (l, lower); + EGlpNumCopyAbs (u, upper); + if (EGlpNumIsLess (l, u)) + { + lp->vstat[qslp->ncols] = STAT_LOWER; + } + else + { + lp->vstat[qslp->ncols] = STAT_UPPER; + } + } + } + + + qslp->ncols++; + qslp->nstruct++; + (qslp->nzcount) += cnt; + + if (B) + { + B->nstruct++; + } + +CLEANUP: + EGlpNumClearVar (l); + EGlpNumClearVar (u); + EG_RETURN (rval); +} + +static int matrix_addrow ( + ILLmatrix * A, + int rowcnt, + int *rowind, + const EGlpNum_t * rowval) +{ + int rval = 0; + int i, j, k, ind, memo, stop, delta = 0; + + /* matsize will be the length of the array. */ + /* matfree will keep track of the free space at end of array. */ + + for (i = 0; i < rowcnt; i++) + { + if (rowind[i] >= A->matcols || rowind[i] < 0) + { + fprintf (stderr, "illegal col index in matrix_addrow\n"); + rval = 1; + ILL_CLEANUP; + } + } + + for (i = 0; i < rowcnt; i++) + { + j = rowind[i]; + if (A->matcnt[j] > 0 && + (A->matbeg[j] + A->matcnt[j] + 1 > A->matsize || + A->matind[A->matbeg[j] + A->matcnt[j]] != -1)) + { + delta += (A->matcnt[j] + 2); /* 1 for the new coef and 1 for */ + /* an extra space */ + } + } + + if (delta < A->matfree) + { + for (i = 0; i < rowcnt; i++) + { + j = rowind[i]; + if (A->matcnt[j] == 0) + { + A->matind[A->matbeg[j]] = A->matrows; + EGlpNumCopy (A->matval[A->matbeg[j]], rowval[i]); + A->matcnt[j] = 1; + } + else if (A->matind[A->matbeg[j] + A->matcnt[j]] == -1) + { + /* Since A->matfree is positive, we know that we are not */ + /* sitting at the end of the array. */ + A->matind[A->matbeg[j] + A->matcnt[j]] = A->matrows; + EGlpNumCopy (A->matval[A->matbeg[j] + A->matcnt[j]], rowval[i]); + if ((A->matbeg[j] + A->matcnt[j]) == (A->matsize - A->matfree)) + { + A->matfree--; /* at end of used space */ + } + (A->matcnt[j])++; + } + else + { + ind = A->matsize - A->matfree + 1; /* leave space for -1 */ + memo = ind; + stop = A->matbeg[j] + A->matcnt[j]; + for (k = A->matbeg[j]; k < stop; k++) + { + if (ind >= A->matsize) + { + printf ("WHAT: %d, %d\n", A->matsize, ind); + fflush (stdout); + exit (1); + } + A->matind[ind] = A->matind[k]; + EGlpNumCopy (A->matval[ind], A->matval[k]); + A->matind[k] = -1; + ind++; + } + A->matind[ind] = A->matrows; + EGlpNumCopy (A->matval[ind], rowval[i]); + A->matbeg[j] = memo; + (A->matcnt[j])++; + (A->matfree) -= (A->matcnt[j] + 1); + } + } + } + else + { + rval = matrix_addrow_end (A, A->matrows, rowcnt, rowind, rowval); + CHECKRVALG (rval, CLEANUP); + } + A->matrows++; + +CLEANUP: + + EG_RETURN (rval); +} + +static int matrix_addrow_end ( + ILLmatrix * A, + int row, + int rowcnt, + int *rowind, + const EGlpNum_t * rowval) +{ + int rval = 0; + int i, j, k, start, stop, total; + int *newbeg = 0; + int *newind = 0; + EGlpNum_t *newval = 0; + int ncols = A->matcols; + + if (A->matcolsize > 0) + { + ILL_SAFE_MALLOC (newbeg, A->matcolsize, int); + } + ILL_SAFE_MALLOC (newind, A->matsize + rowcnt + EXTRA_MAT, int); + + newval = EGlpNumAllocArray (A->matsize + rowcnt + EXTRA_MAT); + + A->matsize += (rowcnt + EXTRA_MAT); + + for (i = 0; i < rowcnt; i++) + { + A->matcnt[rowind[i]]++; + } + for (total = 0, j = 0; j < ncols; j++) + { + newbeg[j] = total; + if (A->matcnt[j] > 0) + total += A->matcnt[j]; + else + total += 1; + } + for (i = 0; i < rowcnt; i++) + { + A->matcnt[rowind[i]]--; + } + for (j = total; j < A->matsize; j++) + { + newind[j] = -1; + } + A->matfree = A->matsize - total; + + for (j = 0; j < ncols; j++) + { + if (A->matcnt[j] > 0) + { + stop = A->matbeg[j] + A->matcnt[j]; + start = newbeg[j]; + for (k = A->matbeg[j]; k < stop; k++) + { + newind[start] = A->matind[k]; + EGlpNumCopy (newval[start], A->matval[k]); + start++; + } + } + else + { + newind[newbeg[j]] = 1; + } + } + for (i = 0; i < rowcnt; i++) + { + j = rowind[i]; + newind[newbeg[j] + A->matcnt[j]] = row; + EGlpNumCopy (newval[newbeg[j] + A->matcnt[j]], rowval[i]); + (A->matcnt[j])++; + } + + ILL_IFFREE (A->matbeg, int); + ILL_IFFREE (A->matind, int); + + EGlpNumFreeArray (A->matval); + + A->matbeg = newbeg; + A->matind = newind; + A->matval = newval; + +CLEANUP: + + if (rval) + { + ILL_IFFREE (newbeg, int); + ILL_IFFREE (newind, int); + + EGlpNumFreeArray (newval); + } + + EG_RETURN (rval); +} + +static int matrix_addcoef ( + lpinfo * lp, + ILLmatrix * A, + int row, + int col, + EGlpNum_t val) +{ + int i, k, delta, ind, stop, memo; + int tind[1]; + EGlpNum_t tval[1]; + int rval = 0; + + EGlpNumInitVar (tval[0]); + EGlpNumCopy (tval[0], val); + + if (row >= A->matrows || row < 0) + { + fprintf (stderr, "illegal row index in matrix_addcoef\n"); + rval = 1; + ILL_CLEANUP; + } + + if (col >= A->matcols || col < 0) + { + fprintf (stderr, "illegal col index in matrix_addcoef\n"); + rval = 1; + ILL_CLEANUP; + } + + for (i = A->matbeg[col]; i < A->matbeg[col] + A->matcnt[col]; i++) + { + if (A->matind[i] == row) + { + EGlpNumCopy (A->matval[i], val); + ILL_CLEANUP; + } + } + + /* The coef is new, we need to add it to A */ + + lp->O->nzcount++; + delta = A->matcnt[col] + 2; + + if (A->matcnt[col] == 0) + { + /* First entry, always a free space */ + A->matind[A->matbeg[col]] = row; + EGlpNumCopy (A->matval[A->matbeg[col]], val); + A->matcnt[col] = 1; + } + else if (A->matbeg[col] + A->matcnt[col] < A->matsize && + A->matind[A->matbeg[col] + A->matcnt[col]] == -1) + { + /* Free space in the column */ + A->matind[A->matbeg[col] + A->matcnt[col]] = row; + EGlpNumCopy (A->matval[A->matbeg[col] + A->matcnt[col]], val); + if ((A->matbeg[col] + A->matcnt[col]) == (A->matsize - A->matfree)) + { + A->matfree--; + } + (A->matcnt[col])++; + } + else if (A->matfree > delta) + { + /* Enough space to move column to end of array */ + ind = A->matsize - A->matfree + 1; + memo = ind; + stop = A->matbeg[col] + A->matcnt[col]; + for (k = A->matbeg[col]; k < stop; k++) + { + A->matind[ind] = A->matind[k]; + EGlpNumCopy (A->matval[ind], A->matval[k]); + A->matind[k] = -1; + ind++; + } + A->matind[ind] = row; + EGlpNumCopy (A->matval[ind], val); + + A->matbeg[col] = memo; + (A->matcnt[col])++; + (A->matfree) -= (A->matcnt[col] + 1); + } + else + { + /* Need to malloc space to move column to end of array */ + + tind[0] = col; + + rval = matrix_addrow_end (A, row, 1, tind, tval); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + EGlpNumClearVar (tval[0]); + EG_RETURN (rval); +} + +static int matrix_addcol ( + ILLmatrix * A, + int colcnt, + int *colind, + EGlpNum_t * colval) +{ + int rval = 0; + int i, ind; + + for (i = 0; i < colcnt; i++) + { + if (colind[i] >= A->matrows || colind[i] < 0) + { + fprintf (stderr, "illegal row index in matrix_addcol\n"); + rval = 1; + ILL_CLEANUP; + } + } + + if (A->matcolsize < A->matcols + 1) + { + A->matbeg = + EGrealloc (A->matbeg, sizeof (int) * (A->matcolsize + EXTRA_COLS)); + //rval = ILLutil_reallocrus_count ((void **) &(A->matbeg), + // A->matcolsize + EXTRA_COLS, sizeof (int)); + //CHECKRVALG(rval,CLEANUP); + + A->matcnt = + EGrealloc (A->matcnt, sizeof (int) * (A->matcolsize + EXTRA_COLS)); + //rval = ILLutil_reallocrus_count ((void **) &(A->matcnt), + // A->matcolsize + EXTRA_COLS, sizeof (int)); + //CHECKRVALG(rval,CLEANUP); + + (A->matcolsize) += EXTRA_COLS; + } + + if (A->matfree < colcnt + 1) + { + A->matind = EGrealloc (A->matind, + sizeof (int) * (A->matsize + colcnt + EXTRA_MAT + + 1)); + //rval = ILLutil_reallocrus_count ((void **) &(A->matind), + // A->matsize + colcnt + EXTRA_MAT + 1, + // sizeof (int)); + //CHECKRVALG(rval,CLEANUP); + EGlpNumReallocArray (&(A->matval), A->matsize + colcnt + EXTRA_MAT + 1); + + for (i = 0; i < colcnt + EXTRA_MAT + 1; i++) + { + A->matind[A->matsize + i] = -1; + } + A->matsize += (colcnt + EXTRA_MAT + 1); + A->matfree += (colcnt + EXTRA_MAT + 1); + } + + ind = A->matsize - A->matfree; + A->matbeg[A->matcols] = ind; + A->matcnt[A->matcols] = colcnt; + if (colcnt == 0) + { + A->matind[ind] = 1; /* Dummy value to stop columns from stealing */ + /* this space in addrows. */ + A->matfree -= 1; + } + else + { + for (i = 0; i < colcnt; i++) + { + EGlpNumCopy (A->matval[ind], colval[i]); + A->matind[ind] = colind[i]; + ind++; + } + A->matfree -= colcnt; + } + A->matcols++; + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_getrows ( + lpinfo * lp, + int num, + int *rowlist, + int **rowcnt, + int **rowbeg, + int **rowind, + EGlpNum_t ** rowval, + EGlpNum_t ** rhs, + char **sense, + EGlpNum_t ** range, + char ***names) +{ + int rval = 0; + int *allbeg = 0; + int *allcnt = 0; + int *allind = 0; + EGlpNum_t *allval = 0; + int i, row, k, start, stop, len, tcnt, cnt = 0; + ILLlpdata *qslp; + ILLlp_rows lprows; + + if (rowcnt) *rowcnt = 0; + if (rowbeg) *rowbeg = 0; + if (rowind) *rowind = 0; + if (rowval) *rowval = 0; + if (rhs) *rhs = 0; + if (range) *range = 0; + if (sense) *sense = 0; + if (names) *names = 0; + + if (!lp) + { + fprintf (stderr, "ILLlib_getrows called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + if (!num) + ILL_CLEANUP; + + qslp = lp->O; + + rval = ILLlp_rows_init (&lprows, qslp, 0); + CHECKRVALG (rval, CLEANUP); + allbeg = lprows.rowbeg; + allcnt = lprows.rowcnt; + allind = lprows.rowind; + allval = lprows.rowval; + + for (i = 0; i < num; i++) + { + cnt += allcnt[rowlist[i]]; + } + + if (rowcnt) + { + ILL_SAFE_MALLOC (*rowcnt, num, int); + + for (i = 0; i < num; i++) + { + (*rowcnt)[i] = allcnt[rowlist[i]]; + } + } + + if (rowbeg) + { + ILL_SAFE_MALLOC (*rowbeg, num, int); + + tcnt = 0; + for (i = 0; i < num; i++) + { + (*rowbeg)[i] = tcnt; + tcnt += allcnt[rowlist[i]]; + } + } + + if (cnt && rowind) + { + ILL_SAFE_MALLOC (*rowind, cnt, int); + + tcnt = 0; + for (i = 0; i < num; i++) + { + row = rowlist[i]; + start = allbeg[row]; + stop = start + allcnt[row]; + for (k = start; k < stop; k++) + { + (*rowind)[tcnt++] = allind[k]; + } + } + } + + if (cnt && rowval) + { + *rowval = EGlpNumAllocArray (cnt); + tcnt = 0; + for (i = 0; i < num; i++) + { + row = rowlist[i]; + start = allbeg[row]; + stop = start + allcnt[row]; + for (k = start; k < stop; k++) + { + EGlpNumCopy ((*rowval)[tcnt++], allval[k]); + } + } + } + + if (rhs) + { + *rhs = EGlpNumAllocArray (num); + for (i = 0; i < num; i++) + { + EGlpNumCopy ((*rhs)[i], qslp->rhs[rowlist[i]]); + } + } + + if (range) + { + *range = EGlpNumAllocArray(num); + if(qslp->rangeval) + { + for(i = 0; i < num ; i++) + { + EGlpNumCopy((*range)[i], qslp->rangeval[rowlist[i]]); + } + } + else + { + for(i = 0; i < num ; i++) + { + EGlpNumZero((*range)[i]); + } + } + } + + if (sense) + { + ILL_SAFE_MALLOC (*sense, num, char); + + for (i = 0; i < num; i++) + { + (*sense)[i] = qslp->sense[rowlist[i]]; + } + } + + if (names) + { + if (qslp->rownames == 0) + { + fprintf (stderr, "LP does not have row names\n"); + rval = 1; + ILL_CLEANUP; + } + ILL_SAFE_MALLOC (*names, num, char *); + + for (i = 0; i < num; i++) + { + (*names)[i] = 0; + } + for (i = 0; i < num; i++) + { + len = strlen (qslp->rownames[rowlist[i]]) + 1; + ILL_SAFE_MALLOC ((*names)[i], len, char); + + strcpy ((*names)[i], qslp->rownames[rowlist[i]]); + } + } + +CLEANUP: + + ILL_IFFREE (allbeg, int); + ILL_IFFREE (allcnt, int); + ILL_IFFREE (allind, int); + + EGlpNumFreeArray (allval); + + if (rval) + { + if (rowcnt) + ILL_IFFREE (*rowcnt, int); + + if (rowbeg) + ILL_IFFREE (*rowbeg, int); + + if (rowind) + ILL_IFFREE (*rowind, int); + + if (rowval) + EGlpNumFreeArray (*rowval); + if (rhs) + EGlpNumFreeArray (*rhs); + if (sense) + ILL_IFFREE (*sense, char); + + if (names && (*names)) + { + for (i = 0; i < num; i++) + { + ILL_IFFREE ((*names)[i], char); + } + ILL_IFFREE (*names, char *); + } + } + + EG_RETURN (rval); +} + +int ILLlib_getcols ( + lpinfo * lp, + int num, + int *collist, + int **colcnt, + int **colbeg, + int **colind, + EGlpNum_t ** colval, + EGlpNum_t ** obj, + EGlpNum_t ** lower, + EGlpNum_t ** upper, + char ***names) +{ + int rval = 0; + int i, col, k, start, stop, len, tcnt, cnt = 0; + ILLlpdata *qslp; + ILLmatrix *A; + int *tlist = 0; + + if (colcnt) + *colcnt = 0; + if (colbeg) + *colbeg = 0; + if (colind) + *colind = 0; + if (colval) + *colval = 0; + if (lower) + *lower = 0; + if (upper) + *upper = 0; + if (obj) + *obj = 0; + if (names) + *names = 0; + + if (!lp) + { + fprintf (stderr, "ILLlib_getcols called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + if (!num) + ILL_CLEANUP; + + qslp = lp->O; + A = &(qslp->A); + + ILL_SAFE_MALLOC (tlist, num, int); + + for (i = 0; i < num; i++) + { + tlist[i] = qslp->structmap[collist[i]]; + } + + for (i = 0; i < num; i++) + { + cnt += A->matcnt[tlist[i]]; + } + + if (colcnt) + { + ILL_SAFE_MALLOC (*colcnt, num, int); + + for (i = 0; i < num; i++) + { + (*colcnt)[i] = A->matcnt[tlist[i]]; + } + } + + if (colbeg) + { + ILL_SAFE_MALLOC (*colbeg, num, int); + + tcnt = 0; + for (i = 0; i < num; i++) + { + (*colbeg)[i] = tcnt; + tcnt += A->matcnt[tlist[i]]; + } + } + + if (cnt && colind) + { + ILL_SAFE_MALLOC (*colind, cnt, int); + + tcnt = 0; + for (i = 0; i < num; i++) + { + col = tlist[i]; + start = A->matbeg[col]; + stop = start + A->matcnt[col]; + for (k = start; k < stop; k++) + { + (*colind)[tcnt++] = A->matind[k]; + } + } + } + + if (cnt && colval) + { + *colval = EGlpNumAllocArray (cnt); + tcnt = 0; + for (i = 0; i < num; i++) + { + col = tlist[i]; + start = A->matbeg[col]; + stop = start + A->matcnt[col]; + for (k = start; k < stop; k++) + { + EGlpNumCopy ((*colval)[tcnt++], A->matval[k]); + } + } + } + + if (obj) + { + *obj = EGlpNumAllocArray (num); + for (i = 0; i < num; i++) + { + EGlpNumCopy ((*obj)[i], qslp->obj[tlist[i]]); + } + } + + if (lower) + { + *lower = EGlpNumAllocArray (num); + for (i = 0; i < num; i++) + { + EGlpNumCopy ((*lower)[i], qslp->lower[tlist[i]]); + } + } + + if (upper) + { + *upper = EGlpNumAllocArray (num); + for (i = 0; i < num; i++) + { + EGlpNumCopy ((*upper)[i], qslp->upper[tlist[i]]); + } + } + + if (names) + { + if (qslp->colnames == 0) + { + fprintf (stderr, "LP does not have col names\n"); + rval = 1; + ILL_CLEANUP; + } + ILL_SAFE_MALLOC (*names, num, char *); + + for (i = 0; i < num; i++) + { + (*names)[i] = 0; + } + for (i = 0; i < num; i++) + { + len = strlen (qslp->colnames[collist[i]]) + 1; + ILL_SAFE_MALLOC ((*names)[i], len, char); + + strcpy ((*names)[i], qslp->colnames[collist[i]]); + } + } + +CLEANUP: + + if (rval) + { + if (colcnt) + ILL_IFFREE (*colcnt, int); + + if (colbeg) + ILL_IFFREE (*colbeg, int); + + if (colind) + ILL_IFFREE (*colind, int); + + if (colval) + EGlpNumFreeArray (*colval); + if (obj) + EGlpNumFreeArray (*obj); + if (lower) + EGlpNumFreeArray (*lower); + if (upper) + EGlpNumFreeArray (*upper); + if (names && (*names)) + { + for (i = 0; i < num; i++) + { + ILL_IFFREE ((*names)[i], char); + } + ILL_IFFREE (*names, char *); + } + } + ILL_IFFREE (tlist, int); + + EG_RETURN (rval); +} + +int ILLlib_getobj_list ( + lpinfo *lp, + int num, + int* collist, + EGlpNum_t* obj) +{ + const int*const structmap = lp->O->structmap; + ILLlpdata *qslp; + int nstruct, j, col; + int rval = 0; + + if (!lp) + { + fprintf (stderr, "ILLlib_getobj_list called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nstruct = qslp->nstruct; + + for (j = 0; j < num; j++) + { + col = collist[j]; + if(col<0 || col >= nstruct) + { + fprintf(stderr, "ILLlib_getobj_list collist[%d] = %d outside" + " valid range\n", j, col); + rval = 1; + ILL_CLEANUP; + } + EGlpNumCopy(obj[j],qslp->obj[structmap[col]]); + } + +CLEANUP: + + EG_RETURN (rval); +} + + +int ILLlib_getobj ( + lpinfo * lp, + EGlpNum_t * obj) +{ + const int*const structmap = lp->O->structmap; + ILLlpdata *qslp; + int nstruct, j; + int rval = 0; + + if (!lp) + { + fprintf (stderr, "ILLlib_getobj called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nstruct = qslp->nstruct; + + for (j = 0; j < nstruct; j++) + { + EGlpNumCopy (obj[j], qslp->obj[structmap[j]]); + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_chgobj ( + lpinfo * lp, + int indx, + EGlpNum_t coef) +{ + int rval = 0; + int col; + + if (!lp) + { + fprintf (stderr, "ILLlib_chgobj called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + if (indx < 0 || indx >= lp->O->nstruct) + { + fprintf (stderr, "ILLlib_chgrhs called with bad indx: %d\n", indx); + rval = 1; + ILL_CLEANUP; + } + + if (lp->O->sinfo) + { /* Presolve LP is no longer valid, free the data */ + ILLlp_sinfo_free (lp->O->sinfo); + ILL_IFFREE (lp->O->sinfo, ILLlp_sinfo); + } + + col = lp->O->structmap[indx]; + EGlpNumCopy (lp->O->obj[col], coef); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_getrhs ( + lpinfo * lp, + EGlpNum_t * rhs) +{ + ILLlpdata *qslp; + int nrows, i; + int rval = 0; + + if (!lp) + { + fprintf (stderr, "ILLlib_getrhs called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nrows = qslp->nrows; + + for (i = 0; i < nrows; i++) + { + EGlpNumCopy (rhs[i], qslp->rhs[i]); + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_chgrange ( + lpinfo *lp, + int indx, + EGlpNum_t coef) +{ + register int i; + int rval = 0; + ILLlpdata *qslp; + + if (!lp) + { + fprintf (stderr, "ILLlib_chgrhs called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + if (indx < 0 || indx >= lp->O->nrows) + { + fprintf (stderr, "ILLlib_chgrhs called with bad indx: %d\n", indx); + rval = 1; + ILL_CLEANUP; + } + + if (lp->O->sinfo) + {/* Presolve LP is no longer valid, free the data */ + ILLlp_sinfo_free (lp->O->sinfo); + ILL_IFFREE (lp->O->sinfo, ILLlp_sinfo); + } + + qslp = lp->O; + if(qslp->rangeval == 0) + { + qslp->rangeval = EGlpNumAllocArray(qslp->rowsize); + for( i = qslp->nrows ; i-- ; ) + { + EGlpNumZero(qslp->rangeval[i]); + } + } + + if(qslp->sense[indx] != 'R') + { + fprintf(stderr,"setting range for non-range constraint\n"); + rval = 1; + ILL_CLEANUP; + } + + EGlpNumCopy(qslp->rangeval[indx], coef); + +CLEANUP: + + EG_RETURN (rval); +} + + +int ILLlib_chgrhs ( + lpinfo * lp, + int indx, + EGlpNum_t coef) +{ + int rval = 0; + + if (!lp) + { + fprintf (stderr, "ILLlib_chgrhs called without an lp\n"); + rval = 1; + ILL_CLEANUP; + } + + if (indx < 0 || indx >= lp->O->nrows) + { + fprintf (stderr, "ILLlib_chgrhs called with bad indx: %d\n", indx); + rval = 1; + ILL_CLEANUP; + } + + if (lp->O->sinfo) + { /* Presolve LP is no longer valid, free the data */ + ILLlp_sinfo_free (lp->O->sinfo); + ILL_IFFREE (lp->O->sinfo, ILLlp_sinfo); + } + + EGlpNumCopy (lp->O->rhs[indx], coef); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_rownames ( + lpinfo * lp, + char **rownames) +{ + ILLlpdata *qslp; + int nrows, len, i, rcount = 0; + int rval = 0; + + if (!lp) + { + fprintf (stderr, "ILLlib_rownames called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + if (!rownames) + { + fprintf (stderr, "ILLlib_rownames called with NULL rownames\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nrows = qslp->nrows; + + if (qslp->rownames == 0) + { + fprintf (stderr, "LP does not have rownames assigned\n"); + rval = 1; + ILL_CLEANUP; + } + + for (i = 0; i < nrows; i++) + { + len = strlen (qslp->rownames[i]) + 1; + ILL_SAFE_MALLOC (rownames[i], len, char); + + strcpy (rownames[i], qslp->rownames[i]); + rcount++; + } + +CLEANUP: + + if (rval) + { + for (i = 0; i < rcount; i++) + { + ILL_IFFREE (rownames[i], char); + } + } + EG_RETURN (rval); +} + +int ILLlib_getintflags ( + lpinfo * lp, + int *intflags) +{ + int j, nstruct, rval = 0; + ILLlpdata *qslp; + + if (!lp) + { + fprintf (stderr, "ILLlib_getintflags called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nstruct = qslp->nstruct; + + if (qslp->intmarker == 0) + { + for (j = 0; j < nstruct; j++) + { + intflags[j] = 0; + } + } + else + { + for (j = 0; j < nstruct; j++) + { + if (qslp->intmarker[j]) + { + intflags[j] = 1; + } + else + { + intflags[j] = 0; + } + } + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_colnames ( + lpinfo * lp, + char **colnames) +{ + ILLlpdata *qslp; + int nstruct, len, i, ccount = 0; + int rval = 0; + + if (!lp) + { + fprintf (stderr, "ILLlib_colnames called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + if (!colnames) + { + fprintf (stderr, "ILLlib_colnames called with NULL colnames\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nstruct = qslp->nstruct; + + if (qslp->colnames == 0) + { + fprintf (stderr, "LP does not have colnames assigned\n"); + rval = 1; + ILL_CLEANUP; + } + + for (i = 0; i < nstruct; i++) + { + len = strlen (qslp->colnames[i]) + 1; + ILL_SAFE_MALLOC (colnames[i], len, char); + + strcpy (colnames[i], qslp->colnames[i]); + ccount++; + } + + +CLEANUP: + + if (rval) + { + for (i = 0; i < ccount; i++) + { + ILL_IFFREE (colnames[i], char); + } + } + + EG_RETURN (rval); +} + +static int reset_colindex ( + lpinfo * lp) +{ + int rval = 0; + int test; + ILLlpdata *qslp = lp->O; + + test = ILLsymboltab_index_ok (&qslp->coltab); + if (!test) + { + rval = ILLsymboltab_index_reset (&qslp->coltab, qslp->nstruct, + qslp->colnames); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + EG_RETURN (rval); +} + +static int reset_rowindex ( + lpinfo * lp) +{ + int rval = 0; + int test; + ILLlpdata *qslp = lp->O; + + test = ILLsymboltab_index_ok (&qslp->rowtab); + if (!test) + { + rval = ILLsymboltab_index_reset (&qslp->rowtab, qslp->nrows, + qslp->rownames); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_colindex ( + lpinfo * lp, + const char *name, + int *colindex) +{ + int rval = 0; + ILLlpdata *qslp; + + *colindex = -1; + + if (!lp) + { + fprintf (stderr, "ILLlib_colindex called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + + rval = reset_colindex (lp); + CHECKRVALG (rval, CLEANUP); + + rval = ILLsymboltab_getindex (&qslp->coltab, name, colindex); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_rowindex ( + lpinfo * lp, + const char *name, + int *rowindex) +{ + int rval = 0; + ILLlpdata *qslp; + + *rowindex = -1; + + if (!lp) + { + fprintf (stderr, "ILLlib_rowindex called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + + rval = reset_rowindex (lp); + CHECKRVALG (rval, CLEANUP); + + rval = ILLsymboltab_getindex (&qslp->rowtab, name, rowindex); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_getbasis ( + lpinfo * lp, + char *cstat, + char *rstat) +{ + int rval = 0; + int i, j, nrows; + ILLlpdata *qslp; + + if (!lp) + { + fprintf (stderr, "ILLlib_getbasis called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + + if (lp->basisid == -1) + { + fprintf (stderr, "ILLlib_getbasis called with modifed LP\n"); + rval = 1; + ILL_CLEANUP; + } + + nrows = lp->O->nrows; + qslp = lp->O; + + for (i = 0; i < qslp->nstruct; i++) + { + j = qslp->structmap[i]; + switch (lp->vstat[j]) + { + case STAT_BASIC: + cstat[i] = QS_COL_BSTAT_BASIC; + break; + case STAT_LOWER: + cstat[i] = QS_COL_BSTAT_LOWER; + break; + case STAT_UPPER: + cstat[i] = QS_COL_BSTAT_UPPER; + break; + case STAT_ZERO: + cstat[i] = QS_COL_BSTAT_FREE; + break; + default: + fprintf (stderr, "unknown vstat in ILLlib_getbasis: %d\n", lp->vstat[j]); + rval = 1; + ILL_CLEANUP; + } + } + + for (i = 0; i < nrows; i++) + { + j = qslp->rowmap[i]; + if (qslp->rangeval && EGlpNumIsNeqqZero (qslp->rangeval[i])) + { + switch (lp->vstat[j]) + { + case STAT_BASIC: + rstat[i] = QS_ROW_BSTAT_BASIC; + break; + case STAT_LOWER: + rstat[i] = QS_ROW_BSTAT_LOWER; + break; + case STAT_UPPER: + rstat[i] = QS_ROW_BSTAT_UPPER; + break; + default: + fprintf (stderr, "unknown vstat in ILLlib_getbasis 2\n"); + rval = 1; + ILL_CLEANUP; + } + } + else + { + switch (lp->vstat[j]) + { + case STAT_BASIC: + rstat[i] = QS_ROW_BSTAT_BASIC; + break; + case STAT_UPPER: + case STAT_LOWER: + rstat[i] = QS_ROW_BSTAT_LOWER; + break; + default: + fprintf (stderr, "unknown vstat in ILLlib_getbasis 3: %d, %d\n", + i, lp->vstat[j]); + rval = 1; + ILL_CLEANUP; + } + } + } + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_loadbasis ( + ILLlp_basis * B, + int nstruct, + int nrows, + char *cstat, + char *rstat) +{ + int i; + int rval = 0; + + ILLlp_basis_init (B); + + if (!cstat || !rstat) + { + rval = 1; + CHECKRVALG (rval, CLEANUP); + } + + rval = ILLlp_basis_alloc (B, nstruct, nrows); + CHECKRVALG (rval, CLEANUP); + + for (i = 0; i < nstruct; i++) + { + B->cstat[i] = cstat[i]; + } + for (i = 0; i < nrows; i++) + { + B->rstat[i] = rstat[i]; + } + +CLEANUP: + + EG_RETURN (rval); +} + +#define READ_BASIS_XL 0 +#define READ_BASIS_XU 1 +#define READ_BASIS_LL 2 +#define READ_BASIS_UL 3 + +int ILLlib_readbasis ( + lpinfo * lp, + ILLlp_basis * B, + const char *fname) +{ + int rval = 0; + ILLlpdata *qslp = lp->O; + int nstruct = qslp->nstruct; + int nrows = qslp->nrows; + int i, j, end = 0, sec, havename = 0; + int rowtype, row, col; + char *bname = 0; + EGioFile_t *file_in = 0; + ILLread_mps_state state; + qsline_reader *in = NULL; + + ILLlp_basis_init (B); + + ILL_SAFE_MALLOC (B->cstat, qslp->nstruct, char); + ILL_SAFE_MALLOC (B->rstat, qslp->nrows, char); + + B->nstruct = nstruct; + B->nrows = nrows; + + for (j = 0; j < nstruct; j++) + { + B->cstat[j] = QS_COL_BSTAT_LOWER; + } + for (i = 0; i < nrows; i++) + { + B->rstat[i] = QS_ROW_BSTAT_BASIC; + } + + file_in = EGioOpen (fname, "r"); + if (file_in == 0) + { + fprintf (stderr, "unable to open %s for reading\n", fname); + rval = 1; + ILL_CLEANUP; + } + + in = ILLline_reader_new ((qsread_line_fct) EGioGets, file_in); + rval = ILLmps_state_init (&state, in, fname); + CHECKRVALG (rval, CLEANUP); + + while (ILLmps_next_line (&state) == 0) + { + if (ILLmps_empty_key (&state)) + { + + /* Get the XL XU LL UL line */ + + if (!havename) + { + rval = ILLmps_error (&state, "BASIS data before NAME\n"); + ILL_CLEANUP; + } + + if (!strcmp (state.field, "XL")) + { + rowtype = READ_BASIS_XL; + } + else if (!strcmp (state.field, "XU")) + { + rowtype = READ_BASIS_XU; + } + else if (!strcmp (state.field, "LL")) + { + rowtype = READ_BASIS_LL; + } + else if (!strcmp (state.field, "UL")) + { + rowtype = READ_BASIS_UL; + } + else + { + rval = ILLmps_error (&state, "BASIS \"%s\" is invalid\n", state.field); + ILL_CLEANUP; + } + + if (ILLmps_next_field (&state) == 0) + { + + rval = ILLlib_colindex (lp, (const char *) state.field, &col); + CHECKRVALG (rval, CLEANUP); + if (col == -1) + { + rval = ILLmps_error (&state, "BASIS col not in LP\n"); + ILL_CLEANUP; + } + + if (rowtype == READ_BASIS_XL || rowtype == READ_BASIS_XU) + { + if (ILLmps_next_field (&state) == 0) + { + rval = ILLlib_rowindex (lp, (const char *) state.field, &row); + CHECKRVALG (rval, CLEANUP); + if (row == -1) + { + rval = ILLmps_error (&state, "BASIS row not in LP\n"); + ILL_CLEANUP; + } + if (rowtype == READ_BASIS_XL) + { + B->cstat[col] = QS_COL_BSTAT_BASIC; + B->rstat[row] = QS_ROW_BSTAT_LOWER; + + } + else + { + B->cstat[col] = QS_COL_BSTAT_BASIC; + B->rstat[row] = QS_ROW_BSTAT_UPPER; + } + } + else + { + rval = ILLmps_error (&state, "BASIS line needs row and column\n"); + ILL_CLEANUP; + } + } + else + { + if (rowtype == READ_BASIS_LL) + { + B->cstat[col] = QS_COL_BSTAT_LOWER; + } + else + { + B->cstat[col] = QS_COL_BSTAT_UPPER; + } + } + } + else + { + rval = ILLmps_error (&state, "BASIS line has no row/column\n"); + ILL_CLEANUP; + } + } + else + { + /* found a section indicator in col 1 */ + if (!strcmp (state.key, ILLmps_section_name[ILL_MPS_ENDATA])) + { + end = 1; + break; /* done reading */ + } + + sec = ILLutil_index (ILLmps_section_name, state.key); + if (sec < 0 || sec != ILL_MPS_NAME) + { + rval = ILLmps_error (&state, "BASIS \"%s\" is not a key\n", state.key); + ILL_CLEANUP; + } + + if (havename) + { + rval = ILLmps_error (&state, "BASIS two name sections\n"); + ILL_CLEANUP; + } + + havename = 1; + + if (ILLmps_empty_field (&state)) + { + ILLmps_warn (&state, "BASIS blank NAME."); + } + else + { + ILL_UTIL_STR (bname, state.field); + printf ("Basis Name: %s\n", bname); + fflush (stdout); + if (strcmp (bname, qslp->probname)) + { + ILLmps_warn (&state, "BASIS name does not match LP."); + } + } + } + } + + if (!end) + { + ILLmps_warn (&state, "Missing ENDATA in basis file."); + } + if (!ILLmps_next_line (&state)) + { + ILLmps_warn (&state, "Ignoring text after ENDATA."); + } + + if (!havename) + { + rval = ILLmps_error (&state, "BASIS no name section\n"); + ILL_CLEANUP; + } + + /* Correct the free variables */ + + for (j = 0; j < nstruct; j++) + { + col = lp->O->structmap[j]; + if (EGlpNumIsEqqual (qslp->lower[col], ILL_MINDOUBLE) && + EGlpNumIsEqqual (qslp->upper[col], ILL_MAXDOUBLE) && + B->cstat[j] == QS_COL_BSTAT_LOWER) + { + B->cstat[j] = QS_COL_BSTAT_FREE; + } + } + +CLEANUP: + + if (file_in) + EGioClose (file_in); + ILLline_reader_free (in); + + if (rval) + { + ILLlp_basis_free (B); + } + ILL_IFFREE (bname, char); + + EG_RETURN (rval); +} + +int ILLlib_writebasis ( + lpinfo * lp, + ILLlp_basis * B, + const char *fname) +{ + int rval = 0; + EGioFile_t *out = 0; + char *cstat = 0; + char *rstat = 0; + ILLlpdata *qslp; + int i, j, nstruct, nrows; + + /* NOTE: non-basic free variables are encoded as non-basic at lower */ + + if (!lp) + { + fprintf (stderr, "ILLlib_writebasis called without an LP\n"); + rval = 1; + ILL_CLEANUP; + } + if (!B && lp->basisid == -1) + { + fprintf (stderr, "ILLlib_writebasis called with unsolved LP\n"); + rval = 1; + ILL_CLEANUP; + } + + qslp = lp->O; + nstruct = qslp->nstruct; + nrows = qslp->nrows; + + out = EGioOpen (fname, "w"); + if (out == 0) + { + fprintf (stderr, "unable to open %s for writing\n", fname); + rval = 1; + ILL_CLEANUP; + } + + if (B) + { + cstat = B->cstat; + rstat = B->rstat; + } + else + { + ILL_SAFE_MALLOC (cstat, nstruct, char); + ILL_SAFE_MALLOC (rstat, nrows, char); + + rval = ILLlib_getbasis (lp, cstat, rstat); + CHECKRVALG (rval, CLEANUP); + } + + EGioPrintf (out, "NAME %s\n", qslp->probname); + + /* Pick out the non-basic rows and find a matching basic column */ + + i = 0; + j = 0; + do + { + while (i < nrows && rstat[i] == QS_ROW_BSTAT_BASIC) + { + i++; + } + if (i < nrows) + { + while (j < nstruct && cstat[j] != QS_COL_BSTAT_BASIC) + { + j++; + } + if (j == nstruct) + { + /* No basic column to match the non-basic row */ + fprintf (stderr, "No basic column to match non-basic row %d\n", i); + rval = 1; + goto CLEANUP; + } + + if (rstat[i] == QS_ROW_BSTAT_LOWER) + { + EGioPrintf (out, " XL %s %s\n", qslp->colnames[j], qslp->rownames[i]); + } + else + { + EGioPrintf (out, " XU %s %s\n", qslp->colnames[j], qslp->rownames[i]); + } + i++; + j++; + } + } while (i < nrows); + + /* Now go through and output the non-basic cols at upper bound */ + + for (j = 0; j < nstruct; j++) + { + if (cstat[j] == QS_COL_BSTAT_UPPER) + { + EGioPrintf (out, " UL %s\n", qslp->colnames[j]); + } + } + + EGioPrintf (out, "ENDATA\n"); + +CLEANUP: + + if (out) + EGioClose (out); + if (!B) + { + ILL_IFFREE (cstat, char); + ILL_IFFREE (rstat, char); + } + EG_RETURN (rval); +} + +int ILLlib_getrownorms ( + lpinfo * lp, + price_info * pinf, + EGlpNum_t * rownorms) +{ + int rval = 0; + int i, j, basic = 0; + ILLlpdata *qslp = lp->O; + int nstruct = lp->O->nstruct; + int nrows = lp->O->nrows; + + check_pinf (pinf, &rval); + if (rval) + { +/* + fprintf (stderr, "dual steepest edge norms not available\n"); +*/ + ILL_CLEANUP; + } + + for (i = 0; i < nstruct; i++) + { + j = qslp->structmap[i]; + if (lp->vstat[j] == STAT_BASIC) + { + EGlpNumCopy (rownorms[basic++], pinf->dsinfo.norms[lp->vindex[j]]); + } + } + for (i = 0; i < nrows; i++) + { + j = qslp->rowmap[i]; + if (lp->vstat[j] == STAT_BASIC) + { + EGlpNumCopy (rownorms[basic++], pinf->dsinfo.norms[lp->vindex[j]]); + } + } + + if (basic != nrows) + { + fprintf (stderr, "error in ILLlib_getrownorms\n"); + rval = 1; + ILL_CLEANUP; + } + +CLEANUP: + +/* + EG_RETURN(rval); +*/ + return rval; /* Don't want error message */ +} + +int ILLlib_loadrownorms ( + lpinfo * lp, + price_info * pinf, + EGlpNum_t * rownorms) +{ + int rval = 0; + + rval = ILLprice_load_rownorms (lp, rownorms, pinf); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_recompute_rownorms ( + lpinfo * lp, + price_info * pinf) +{ + int rval = 0; + + rval = ILLprice_build_pricing_info (lp, pinf, DUAL_PHASEII); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +int ILLlib_iter ( + lpinfo * lp) +{ + int iter = 0; + + if (lp && lp->cnts) + { + iter = lp->cnts->pI_iter + lp->cnts->pII_iter + + lp->cnts->dI_iter + lp->cnts->dII_iter; + } + + return iter; +} + +//#define PRINT_TOL 0.000001 +#define PRINT_TOL PFEAS_TOLER + +int ILLlib_print_x ( + EGioFile_t * fd, + lpinfo * lp, + ILLlp_cache * C, + EGlpNum_t * x, + int nonZerosOnly) +{ + int rval = 0; + int j; + ILLlpdata *qslp = lp->O; + EGlpNum_t *dx, *myx = 0; + char *strtmp; + + /* If x is not specified, grab the LP solution */ + + if (!x) + { + myx = EGlpNumAllocArray (lp->ncols); + rval = ILLlib_get_x (lp, C, myx); + CHECKRVALG (rval, CLEANUP); + dx = myx; + } + else + { + dx = x; + } + + EGioPrintf (fd, "Solution Values\n"); + for (j = 0; j < qslp->nstruct; j++) + { + /*if (!nonZerosOnly || dx[j] > PRINT_TOL || dx[j] < -PRINT_TOL) */ + if (!nonZerosOnly || EGlpNumIsNeqZero (dx[j], PRINT_TOL)) + { + strtmp = EGlpNumGetStr (dx[j]); + ILL_FAILfalse (qslp->colnames[j] != NULL, "no NULL names PLEASE!"); + EGioPrintf (fd, "%s = %s\n", qslp->colnames[j], strtmp); + EGioFlush (fd); + EGfree (strtmp); + } + } + +CLEANUP: + EGlpNumFreeArray (myx); + EG_RETURN (rval); +} + +int ILLlib_findName ( + ILLlpdata * qslp, + int forRow, + const char *name, + int id, + char buf[ILL_namebufsize]) +{ + ILLsymboltab *tab; + const char *mode; + const char *p1, *p2; + int sind, rval = 0; + + id++; + tab = (forRow) ? &qslp->rowtab : &qslp->coltab; + if (tab->tablesize == 0) + ILLsymboltab_create (tab, 100); + p1 = (forRow) ? "c" : "x"; + p2 = (forRow) ? "c_" : "x_"; + mode = (forRow) ? "row" : "column"; + if (name == 0) + { + ILLsymboltab_unique_name (tab, id, p1, buf); + /* + * fprintf(stderr, "Generating %s name \"%s\".\n", mode, buf); + */ + } + else + { + strcpy (buf, name); + } + if (!ILLsymboltab_lookup (tab, buf, &sind)) + { + rval = ILLsymboltab_uname (&qslp->rowtab, buf, p1, p2); + if (name != NULL) + { + fprintf (stderr, "Changing %s name \"%s\" to \"%s\".\n", mode, name, buf); + } + CHECKRVALG (rval, CLEANUP); + } +CLEANUP: + EG_RETURN (rval); +} + +int ILLwrite_lp_file ( + ILLlpdata * lp, + EGioFile_t * out, + qserror_collector * c) +{ + int rval = 0; + qsstring_reporter rep; + + ILLstring_reporter_copy (&rep, &lp->reporter); + ILLstring_reporter_init (&lp->reporter, (qsreport_string_fct) EGioWrite, out); + rval = ILLwrite_lp (lp, c); + ILLstring_reporter_copy (&lp->reporter, &rep); + return rval; +} + +static void check_pinf ( + price_info * pinf, + int *it_exists) +{ + if (!pinf || pinf->dI_price != QS_PRICE_DSTEEP || + pinf->dII_price != QS_PRICE_DSTEEP || pinf->dsinfo.norms == 0) + { + *it_exists = 1; + } + else + { + *it_exists = 0; + } +} + +#if 0 +static int test_matrix ( + ILLmatrix * A) +{ + int rval = 0; + int i, j, k; + int ncols = A->matcols; + int nrows = A->matrows; + int matsize = A->matsize; + int *mbeg = A->matbeg; + int *mcnt = A->matcnt; + int *mind = A->matind; + int *tempi = 0; + + + if (matsize == 0) + ILL_CLEANUP; + + ILL_SAFE_MALLOC (tempi, matsize, int); + + for (i = 0; i < matsize; i++) + tempi[i] = 0; + + for (i = 0; i < ncols; i++) + { + for (j = 0; j < mcnt[i]; j++) + { + k = mind[mbeg[i] + j]; + if (k < 0 || k >= nrows) + { + printf ("ERROR IN MATRIX: %d\n", k); + printf ("ncols = %d, bad col = %d\n", ncols, i); + printf ("bad cnt = %d, bad index = %d\n", mcnt[i], mbeg[i] + j); + printf ("matcolsize = %d, matsize = %d\n", A->matcolsize, A->matsize); + rval = 1; + ILL_CLEANUP; + } + if (tempi[mbeg[i] + j] != 0) + { + printf ("ERROR: over written matrix\n"); + printf ("ncols = %d, bad col = %d\n", ncols, i); + printf ("nrows = %d\n", nrows); + printf ("bad cnt = %d, bad index = %d\n", mcnt[i], mbeg[i] + j); + rval = 1; + ILL_CLEANUP; + } + else + { + tempi[mbeg[i] + j] = 1; + } + } + } + + for (i = A->matsize - A->matfree; i < A->matsize; i++) + { + if (tempi[i] != 0) + { + printf ("ERROR: free space is being used\n"); + rval = 1; + ILL_CLEANUP; + } + } + +CLEANUP: + + ILL_IFFREE (tempi, int); + + EG_RETURN (rval); +} +#endif diff --git a/src/lib.h b/src/lib.h new file mode 100644 index 0000000..4370a77 --- /dev/null +++ b/src/lib.h @@ -0,0 +1,151 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: lib.h,v 1.4 2003/11/05 17:00:26 meven Exp $ */ +#ifndef ILL_LIB_H +#define ILL_LIB_H + +#include "qs_config.h" +#include "lpdefs.h" +#include "lpdata.h" +#include "price.h" +#include "basicdefs.h" + +/****************************************************************************/ +/* */ +/* Return Status for ILLlib_optimize */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* lib.c */ +/* */ +/****************************************************************************/ + +struct itcnt_t; + +int ILLlib_optimize ( lpinfo * lp, ILLlp_basis * B, price_info * pinf, int algo, + int *status, int simplex_display, struct itcnt_t*itcnt), + ILLlib_cache_solution ( lpinfo * lp, ILLlp_cache * C), + ILLlib_solution ( lpinfo * lp, ILLlp_cache * C, EGlpNum_t * val, + EGlpNum_t * x, EGlpNum_t * pi, EGlpNum_t * slack, EGlpNum_t * rc), + ILLlib_get_x ( lpinfo * lp, ILLlp_cache * C, EGlpNum_t * x), + ILLlib_get_slack ( lpinfo * lp, ILLlp_cache * C, EGlpNum_t * slack), + ILLlib_objval ( lpinfo * lp, ILLlp_cache * C, EGlpNum_t * val), + ILLlib_tableau ( lpinfo * lp, int row, EGlpNum_t * binv, EGlpNum_t * tabrow), + ILLlib_basis_order ( lpinfo * lp, int *header), + ILLlib_newrow ( lpinfo * lp, ILLlp_basis * B,const EGlpNum_t rhs, int sense, + const EGlpNum_t range, const char *name), + ILLlib_newrows ( lpinfo * lp, ILLlp_basis * B, int num,const EGlpNum_t * rhs, + char *sense, const EGlpNum_t * range, const char **names), + ILLlib_addrow ( lpinfo * lp, ILLlp_basis * B, int cnt, int *ind, + const EGlpNum_t * val, const EGlpNum_t rhs, int sense,const EGlpNum_t range, + const char *rowname), + ILLlib_addrows ( lpinfo * lp, ILLlp_basis * B, int num, int *rmatcnt, + int *rmatbeg, int *rmatind,const EGlpNum_t * rmatval,const EGlpNum_t * rhs, + char *sense, const EGlpNum_t * range, const char **names, int *nofactor), + ILLlib_delrows ( lpinfo * lp, ILLlp_basis * B, ILLlp_cache * C, int num, + int *dellist, int *basis_ok, int *cache_ok), + ILLlib_newcol ( lpinfo * lp, ILLlp_basis * B,const EGlpNum_t obj, + const EGlpNum_t lower,const EGlpNum_t upper, const char *name, int factorok), + ILLlib_newcols ( lpinfo * lp, ILLlp_basis * B, int num, EGlpNum_t * obj, + EGlpNum_t * lower, EGlpNum_t * upper, const char **names, int factorok), + ILLlib_addcol ( lpinfo * lp, ILLlp_basis * B, int cnt, int *ind, + EGlpNum_t * val,const EGlpNum_t obj,const EGlpNum_t lower,const EGlpNum_t upper, + const char *name, int factorok), + ILLlib_addcols ( lpinfo * lp, ILLlp_basis * B, int num, int *cmatcnt, + int *cmatbeg, int *cmatind, EGlpNum_t * cmatval, EGlpNum_t * obj, + EGlpNum_t * lower, EGlpNum_t * upper, const char **names, int factorok), + ILLlib_delcols ( lpinfo * lp, ILLlp_basis * B, int num, int *dellist, + int *basis_ok), + ILLlib_chgcoef ( lpinfo * lp, int rowindex, int colindex, EGlpNum_t coef), + ILLlib_getcoef (lpinfo *lp, int rowindex, int colindex, EGlpNum_t* coef), + ILLlib_chgrange (lpinfo *lp, int indx, EGlpNum_t coef), + ILLlib_chgsense ( lpinfo * lp, int num, int *rowlist, char *sense), + ILLlib_getsenses (lpinfo *lp, char *senses), + ILLlib_getrows ( lpinfo * lp, int num, int *rowlist, int **rowcnt, + int **rowbeg, int **rowind, EGlpNum_t ** rowval, EGlpNum_t ** rhs, + char **sense, EGlpNum_t ** range, char ***names), + ILLlib_getcols ( lpinfo * lp, int num, int *collist, int **colcnt, + int **colbeg, int **colind, EGlpNum_t ** colval, EGlpNum_t ** obj, + EGlpNum_t ** lower, EGlpNum_t ** upper, char ***names), + ILLlib_getobj ( lpinfo * lp, EGlpNum_t * obj), + ILLlib_getobj_list (lpinfo *lp, int num, int* collist, EGlpNum_t* obj), + ILLlib_chgobj ( lpinfo * lp, int indx, EGlpNum_t coef), + ILLlib_getrhs ( lpinfo * lp, EGlpNum_t * rhs), + ILLlib_chgrhs ( lpinfo * lp, int indx, EGlpNum_t coef), + ILLlib_getintflags ( lpinfo * lp, int *intflags), + ILLlib_rownames ( lpinfo * lp, char **rownames), + ILLlib_colnames ( lpinfo * lp, char **colnames), + ILLlib_colindex ( lpinfo * lp, const char *name, int *colindex), + ILLlib_rowindex ( lpinfo * lp, const char *name, int *rowindex), + ILLlib_chgbnd ( lpinfo * lp, int indx, int lu,const EGlpNum_t bnd), + ILLlib_chgbnds ( lpinfo * lp, int cnt, int *indx, char *lu, const EGlpNum_t * bnd), + ILLlib_getbnd ( lpinfo * lp, int indx, int lu, EGlpNum_t * bnd), + ILLlib_getbnds ( lpinfo * lp, EGlpNum_t * lower, EGlpNum_t * upper), + ILLlib_getbnds_list ( lpinfo *lp, int num, int*collist, EGlpNum_t *lower, + EGlpNum_t *upper), + ILLlib_strongbranch ( lpinfo * lp, price_info * pinf, int *candidatelist, + int ncand, EGlpNum_t * xlist, EGlpNum_t * downpen, EGlpNum_t * uppen, + int iterations, EGlpNum_t objbound, struct itcnt_t*itcnt), + ILLlib_getbasis ( lpinfo * lp, char *cstat, char *rstat), + ILLlib_loadbasis ( ILLlp_basis * B, int nstruct, int nrows, char *cstat, + char *rstat), + ILLlib_readbasis ( lpinfo * lp, ILLlp_basis * B, const char *fname), + ILLlib_writebasis ( lpinfo * lp, ILLlp_basis * B, const char *fname), + ILLlib_getrownorms ( lpinfo * lp, price_info * pinf, EGlpNum_t * rownorms), + ILLlib_loadrownorms ( lpinfo * lp, price_info * pinf, EGlpNum_t * rownorms), + ILLlib_recompute_rownorms ( lpinfo * lp, price_info * pinf), + ILLlib_iter ( lpinfo * lp), + ILLlib_print_x ( EGioFile_t * fd, lpinfo * lp, ILLlp_cache * C, EGlpNum_t * x, + int nonZerosOnly), + ILLwrite_lp_file ( ILLlpdata * lp, EGioFile_t * eout, qserror_collector * c); + + +extern int ILLlib_findName ( + ILLlpdata * qslp, + int forRow, + const char *name, + int id, + char buf[ILL_namebufsize]); + +/****************************************************************************/ +/* */ +/* presolve.c */ +/* */ +/****************************************************************************/ + +int ILLpresolve_add_logicals ( + ILLlpdata * lp); + + +/****************************************************************************/ +/* */ +/* binary.c */ +/* */ +/****************************************************************************/ + +int ILLmip_binary_dfs ( + lpinfo * lp); + +#endif /* ILL_LIB_H */ diff --git a/src/lp.c b/src/lp.c new file mode 100644 index 0000000..524dc1b --- /dev/null +++ b/src/lp.c @@ -0,0 +1,1268 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: lp.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +/****************************************************************************/ +/* */ +/* Routines for Reading and Writing LP Files */ +/* */ +/* EXPORTED FUNCTIONS */ +/* */ +/* int ILLwrite_lp (EGioFile_t *out, ILLlpdata *lp) */ +/* int ILLread_lp (qsline_reader f, const char *fname, rawlpdata *lp)*/ +/* int ILLis_lp_name_char (char c, int pos) */ +/* int ILLread_constraint_expr(ILLread_lp_state *state, */ +/* rawlpdata *lp, int rowind, int allowNew) */ +/* int ILLread_constraint_name (ILLread_lp_state *state, */ +/* char **rowname) */ +/* int ILLread_one_constraint (ILLread_lp_state *state, */ +/* const char *rowname, rawlpdata *lp, int allowNewCols) */ +/* */ +/****************************************************************************/ + +#include +#include "qs_config.h" +/* from the cplex manual: + + not exceed 16 characters, all of which must be alphanumeric + (a-z, A-Z, 0-9) or one of these symbols: ! " # $ % & ( ) / , + . ; ? @ _ ` ' { } | ~. Longer names will be truncated to 16 + characters. A variable name can not begin with a number or a + period. + + The letter E or e, alone or followed by other valid symbols, + or followed by another E or e, should be avoided as this + notation is reserved for exponential entries. Thus, variables + can not be named e9, E-24, E8cats, or other names that could + be interpreted as an exponent. Even variable names such as + eels or example can cause a read error, depending on their + placement in an input line. + + Also, the following characters are not valid in variable + names (in order to allow for quadratic objective + information): ^, *, [ and ]. +*/ +/* OUR DEFINTION: + * -) variables consist of a-z A-Z 0-9 !"#$%(),;.?@_`'{}|~ + * don't start with a digit or '.' + * return 0 for variable + * return -1 for keyword + * return 1 otherwise + */ + + +int ILLis_lp_name_char ( + int c, + int pos) +{ + return ((('a' <= c) && (c <= 'z')) || + (('A' <= c) && (c <= 'Z')) || + ((pos > 0) && ('0' <= c) && (c <= '9')) || + ((pos > 0) && (c == '.')) || + (strchr ("!\"#$%&()/,;?@_`'{}|~", c) != NULL)); +} + + +/* + * -) anything after '\' is comment + * -) Problem is optional and comes first + * -) Minimize, Maximize, ... comes after Problem + * -) variables consist of a-z A-Z 0-9!"#$%(),;.?@_`'{}|~ + */ + +/* NOTES */ +/* + * don't start with a digit or '.' + */ + +static const int LINE_LEN = 256; + +#include "iqsutil.h" +#include "lp.h" +#include "rawlp.h" +#include "read_lp.h" +#include "write_lp.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif +//extern EGlpNum_t SZERO_TOLER; +static int TRACE = 0; + +static int read_problem_name ( + ILLread_lp_state * state, + rawlpdata * lp); +static int read_minmax ( + ILLread_lp_state * state, + rawlpdata * lp); +static int read_objective ( + ILLread_lp_state * state, + rawlpdata * lp); +static int read_objective ( + ILLread_lp_state * state, + rawlpdata * lp); +static int read_constraints ( + ILLread_lp_state * state, + rawlpdata * lp, + int allowNewCols); +static int read_colname ( + ILLread_lp_state * state, + ILLsymboltab * coltab, + int mustHave); +static int read_integer ( + ILLread_lp_state * state, + rawlpdata * lp); +static int read_bounds ( + ILLread_lp_state * state, + rawlpdata * lp); +static int add_var ( + rawlpdata * lp, + ILLread_lp_state * state, + EGlpNum_t coef, + int row, + int allowNew); + +/*------------------------------------------------------------------------ + * ILLwrite_lp and support routines + */ +static int fix_names ( + qserror_collector * collector, + char **names, + int nnames, + const char *extra, + int prefix, + char ***newnames); +static void write_objective ( + ILLlpdata * lp, + const char *objname, + char **colnames); +static int write_row ( + ILLlpdata * lp, + ILLlp_rows * lprows, + int i, + char **rownames, + char **colnames, + int *colInRow, + EGlpNum_t * colCoef); +static int write_bounds ( + ILLlpdata * lp, + char **colnames); +static void write_intvars ( + ILLlpdata * lp, + char **colnames); + +int ILLwrite_lp ( + ILLlpdata * lp, + qserror_collector * collector) +{ + int rval = 0; + int i; + ILLlp_rows lp_rows, *lprows = NULL; + char **colnames = (char **) NULL; + char **rownames = (char **) NULL; + EGlpNum_t *colCoef = NULL; + int *colInRow = NULL; + const char *objname; + + ILL_FAILfalse (lp, "called without data\n"); + if (lp->nstruct == 0 || lp->nrows == 0) + { + EG_RETURN (rval); + } + ILL_FAILfalse (lp->colnames != NULL, "lp->colnames != NULL"); + ILL_FAILfalse (lp->rownames != NULL, "lp->rownames != NULL"); + ILL_FAILfalse (lp->nstruct == lp->coltab.tablesize, + "lp coltab has nstruct entries"); + if (lp->objname == (char *) NULL) + { + ILL_FAILfalse (lp->nrows == lp->rowtab.tablesize, + "lp rowtab should have nrows entries"); + } + else + { + ILL_FAILfalse (lp->nrows + 1 == lp->rowtab.tablesize, + "lp rowtab should have nrows+1 entries"); + ILL_FAILfalse (ILLsymboltab_contains (&lp->rowtab, lp->objname), + "rowtab must contain objname"); + } + + rval = fix_names (collector, lp->colnames, lp->nstruct, NULL, 'x', &colnames); + CHECKRVALG (rval, CLEANUP); + + rval = fix_names (collector, lp->rownames, lp->nrows, + (lp->objname) ? lp->objname : "obj", 'c', &rownames); + CHECKRVALG (rval, CLEANUP); + objname = rownames[lp->nrows]; + + ILL_FAILtrue (objname == NULL, "OOps, that should never happen"); + CHECKRVALG (rval, CLEANUP); + + if (lp->sos.matcols > 0) + { + rval += + ILLdata_error (collector, "Can't express SOS information in LP format."); + } + + write_objective (lp, objname, colnames); + + /* Note, ILLlp_rows_init returns cols ordered by structmap, so we may use + * colnames[i] when pulling i from the matrix data. */ + + lprows = &lp_rows; + if (ILLlp_rows_init (lprows, lp, 0) != 0) + { + rval += 1; + ILL_FAILtrue (rval, "ILLlp_rows_init failed\n"); + } + + colCoef = EGlpNumAllocArray (lp->nstruct); + ILL_SAFE_MALLOC (colInRow, lp->nstruct, int); + + for (i = 0; i < lp->nstruct; i++) + { + colInRow[i] = -1; + } + + ILLprint_report (lp, "Subject To\n"); + for (i = 0; i < lp->nrows; i++) + { + if (lprows->rowcnt[i] == 0) + { + /* + * ILLdata_warn (collector, "Not printing empty row \"%s\".", rownames[i]); + */ + continue; + } + rval += write_row (lp, lprows, i, rownames, colnames, colInRow, colCoef); + } + + rval += write_bounds (lp, colnames); + + if (lp->intmarker != NULL) + { + write_intvars (lp, colnames); + } + + ILLprint_report (lp, "End\n"); +CLEANUP: + if (lprows != NULL) + { + ILLlp_rows_clear (lprows); + } + ILLfree_names (colnames, lp->nstruct); + ILLfree_names (rownames, lp->nrows + 1); + EGlpNumFreeArray (colCoef); + ILL_IFFREE (colInRow, int); + + EG_RETURN (rval); +} + +static void write_objective ( + ILLlpdata * lp, + const char *objname, + char **colnames) +{ + int ri, i, k, var; + ILLwrite_lp_state ln, *line = &ln; + + if (lp->probname != NULL) + { + ILLprint_report (lp, "Problem\n %s\n", lp->probname); + } + if (lp->objsense == ILL_MIN) + { + ILLprint_report (lp, "Minimize\n"); + } + else + { + ILLprint_report (lp, "Maximize\n"); + } + ILLwrite_lp_state_init (line, NULL); + ILLwrite_lp_state_append (line, " "); + ILLwrite_lp_state_append (line, objname); + ILLwrite_lp_state_append (line, ": "); + ILLwrite_lp_state_save_start (line); + + for (ri = 0, var = 0; ri < lp->nstruct; ri++) + { + i = lp->structmap[ri]; + if (EGlpNumIsNeqqZero (lp->obj[i])) + { + ILLwrite_lp_state_append_coef (line, lp->obj[i], var); + ILLwrite_lp_state_append (line, " "); + ILLwrite_lp_state_append (line, colnames[ri]); + var++; + + /* we put a least 4 terms on a line + * and then we stop after LINE_LEN or more characters + */ + if ((line->total >= LINE_LEN) && (var >= 4)) + { + /* see whether there is another term + * if so append a '+' and print line */ + k = ri + 1; + while (k < lp->nstruct) + { + if (EGlpNumIsLessZero (lp->obj[lp->structmap[k]])) + { + break; + } + else + { + if (EGlpNumIsGreatZero (lp->obj[lp->structmap[k]])) + { + ILLwrite_lp_state_append (line, " +"); + break; + } + } + k++; + } + var = 0; /* next line does not need to prefix coef with '+' */ + ILLprint_report (lp, "%s\n", line->buf); + ILLwrite_lp_state_start (line); + } + } + } + if (var > 0) + { + ILLprint_report (lp, "%s\n", line->buf); + } +} + +static void write_the_expr ( + ILLlpdata * lp, + ILLwrite_lp_state * line, + char *rowname, + ILLlp_rows * lprows, + int row, + char **colnames, + int *colInRow, + EGlpNum_t * colCoef, + int ncols) +{ + int var, firstVar, k, i; + EGlpNum_t *coef; + + ILLwrite_lp_state_init (line, NULL); + if (rowname != NULL) + { + ILLwrite_lp_state_append (line, " "); + ILLwrite_lp_state_append (line, rowname); + ILLwrite_lp_state_append (line, ": "); + } + else + { + ILLwrite_lp_state_append (line, " "); + } + ILLwrite_lp_state_save_start (line); + + for (k = lprows->rowbeg[row]; + k < lprows->rowbeg[row] + lprows->rowcnt[row]; k++) + { + i = lprows->rowind[k]; + colInRow[i] = row; + EGlpNumCopy (colCoef[i], lprows->rowval[k]); + } + var = 0; + firstVar = 1; + for (i = 0; i < ncols; i++) + { + if (colInRow[i] == row) + { + if (EGlpNumIsNeqqZero (colCoef[i])) + { + coef = &(colCoef[i]); + if (line->total >= LINE_LEN) + { + ILLprint_report (lp, "%s\n", line->buf); + ILLwrite_lp_state_start (line); + if ((!firstVar) && !EGlpNumIsLessZero (*coef)) + { + ILLwrite_lp_state_append (line, " +"); + } + var = 0; + } + + ILLwrite_lp_state_append_coef (line, *coef, var); + ILLwrite_lp_state_append (line, " "); + ILLwrite_lp_state_append (line, colnames[i]); + var++; + firstVar = 0; + } + } + } +} + +static int write_row ( + ILLlpdata * lp, + ILLlp_rows * lprows, + int i, + char **rownames, + char **colnames, + int *colInRow, + EGlpNum_t * colCoef) +{ + ILLwrite_lp_state ln, *line = &ln; + int rval = 0; + EGlpNum_t ntmp; + + write_the_expr (lp, line, rownames[i], lprows, i, colnames, + colInRow, colCoef, lp->nstruct); + + switch (lp->sense[i]) + { + case 'G': + ILLwrite_lp_state_append (line, " >= "); + ILLwrite_lp_state_append_number (line, lp->rhs[i]); + break; + case 'L': + ILLwrite_lp_state_append (line, " <= "); + ILLwrite_lp_state_append_number (line, lp->rhs[i]); + break; + case 'E': + ILLwrite_lp_state_append (line, " = "); + ILLwrite_lp_state_append_number (line, lp->rhs[i]); + break; + case 'R': + ILL_FAILtrue (!lp->rangeval, "RANGE constraints without values\n"); + EGlpNumInitVar (ntmp); + ILLwrite_lp_state_append (line, " >= "); + ILLwrite_lp_state_append_number (line, lp->rhs[i]); + + ILLwrite_lp_state_append (line, " \t\\ RANGE ("); + ILLwrite_lp_state_append_number (line, lp->rhs[i]); + ILLwrite_lp_state_append (line, ", "); + EGlpNumCopySum (ntmp, lp->rhs[i], lp->rangeval[i]); + ILLwrite_lp_state_append_number (line, ntmp); + ILLwrite_lp_state_append (line, ")"); + ILLprint_report (lp, "%s\n", line->buf); + + write_the_expr (lp, line, NULL, lprows, i, + colnames, colInRow, colCoef, lp->nstruct); + ILLwrite_lp_state_append (line, " <= "); + ILLwrite_lp_state_append_number (line, ntmp); + EGlpNumClearVar (ntmp); + break; + default: + ILL_FAILtrue (1, "Unknown row sense\n"); + } + + ILLprint_report (lp, "%s\n", line->buf); +CLEANUP: + EG_RETURN (rval); +} + +static int write_bounds ( + ILLlpdata * lp, + char **colnames) +{ + int ri, i, rval = 0; + int prtLower, prtUpper; + ILLwrite_lp_state l, *line = &l; + + ILL_FAILtrue (lp->lower == NULL || lp->upper == NULL, + "Should not call write_bounds when lower or upper are NULL"); + ri = ILLraw_first_nondefault_bound (lp); + if (ri != lp->nstruct) + { + ILLprint_report (lp, "Bounds\n"); + ILLwrite_lp_state_init (line, " "); + ILLwrite_lp_state_save_start (line); + + for (ri = ri; ri < lp->nstruct; ri++) + { + ILLwrite_lp_state_start (line); + i = lp->structmap[ri]; + if (EGlpNumIsEqqual (lp->lower[i], lp->upper[i])) + { + ILLwrite_lp_state_append (line, " "); + ILLwrite_lp_state_append (line, colnames[ri]); + ILLwrite_lp_state_append (line, " = "); + ILLwrite_lp_state_append_number (line, lp->upper[i]); + ILLprint_report (lp, "%s\n", line->buf); + continue; + } + if ((EGlpNumIsEqqual (lp->lower[i], ILL_MINDOUBLE)) && + (EGlpNumIsEqqual (lp->upper[i], ILL_MAXDOUBLE))) + { + ILLwrite_lp_state_append (line, colnames[ri]); + ILLwrite_lp_state_append (line, " free"); + ILLprint_report (lp, "%s\n", line->buf); + continue; + } + prtLower = !ILLraw_default_lower (lp, i); + prtUpper = !ILLraw_default_upper (lp, i, ri); + if (prtLower || prtUpper) + { + if (prtLower) + { + ILLwrite_lp_state_append_number (line, lp->lower[i]); + ILLwrite_lp_state_append (line, " <= "); + } + if (prtLower || prtUpper) + { + ILLwrite_lp_state_append (line, colnames[ri]); + } + if (prtUpper) + { + ILLwrite_lp_state_append (line, " <= "); + ILLwrite_lp_state_append_number (line, lp->upper[i]); + } + ILLprint_report (lp, "%s\n", line->buf); + } + } + } +CLEANUP: + EG_RETURN (rval); +} + +static void write_intvars ( + ILLlpdata * lp, + char **colnames) +{ + ILLwrite_lp_state ln, *line = &ln; + int var, j; + + ILLprint_report (lp, "Integer\n"); + ILLwrite_lp_state_init (line, " "); + ILLwrite_lp_state_save_start (line); + + for (j = 0, var = 0; j < lp->nstruct; j++) + { + if (lp->intmarker[j]) + { + if (var > 0) + { + ILLwrite_lp_state_append (line, " "); + } + ILLwrite_lp_state_append (line, colnames[j]); + var++; + if (line->total >= LINE_LEN) + { + ILLprint_report (lp, "%s\n", line->buf); + ILLwrite_lp_state_init (line, " "); + var = 0; + } + } + } + if (var > 0) + { + ILLprint_report (lp, "%s\n", line->buf); + } +} + +/* ------------------------------------------------------------ */ +/* fix up names that are numbers, i.e. prefix with x X x_ or X_ */ + +/* + * redefine names that start with [0-9]; i.e. give a prefix of + * "x" | "X" | "x_" | "X_" + * or if all these are already taken prefix with "X" + * make sure names contain solely the characters: + * [a-zA-Z0-9] and ! " # $ % & ( ) / , . ; ? @ _ ` ' { } | ~ + * rename names with 'bad' chars to + */ +static int fix_names ( + qserror_collector * collector, + char **names, + int nnames, + const char *extra, + int pref, + char ***newnames) +{ + ILLsymboltab symt, *symtab = NULL; + int rval = 0, i, j, n, ind, hit; + char **n_names = NULL; + const char *old_name; + char buf[ILL_namebufsize]; + char p1[2], p2[3]; + + p1[0] = pref; + p1[1] = '\0'; + p2[0] = pref; + p2[1] = '_'; + p2[2] = '\0'; + + ILL_SAFE_MALLOC (n_names, nnames + 1, char *); + + for (i = 0; i < nnames; i++) + { + n_names[i] = (char *) NULL; + } + + for (i = 0; i <= nnames; i++) + { + if (i == nnames) + { + if (extra == NULL) + break; + old_name = extra; + } + else + old_name = names[i]; + + n = strlen (old_name); + strcpy (buf, old_name); + if (!ILLis_lp_name_char (buf[0], 1)) + { + sprintf (buf, "%d", i); + } + else + { + for (j = 1; j < n; j++) + { + if (!ILLis_lp_name_char (buf[j], j)) + { + sprintf (buf, "%d", i); + break; + } + } + } + + if (!ILLis_lp_name_char (buf[0], 0)) + { + if (symtab == NULL) + { + symtab = &symt; + ILLsymboltab_init (symtab); + ILLsymboltab_create (symtab, nnames + 1); + for (j = 0; j < nnames; j++) + { + ILLsymboltab_register (symtab, names[j], -1, &ind, &hit); + ILL_FAILfalse (ind == j, "ind == j"); + } + if (extra != NULL) + ILLsymboltab_register (symtab, extra, -1, &ind, &hit); + } + rval = ILLsymboltab_uname (symtab, buf, p1, p2); + CHECKRVALG (rval, CLEANUP); + rval = ILLsymboltab_rename (symtab, i, buf); + CHECKRVALG (rval, CLEANUP); + + ILL_UTIL_STR (n_names[i], buf); + ILLdata_warn (collector, + "\"%s\" is not a valid name in LP format; %s\"%s\".", + old_name, "renaiming to ", buf); + } + else + { + ILL_UTIL_STR (n_names[i], old_name); + } + } + +CLEANUP: + if (symtab != NULL) + { + ILLsymboltab_free (symtab); + } + *newnames = n_names; + EG_RETURN (rval); +} + +/* + * end ILLlpdata_lpwrite + * ---------------------------------------------------------------------- */ + +int ILLread_lp ( + qsline_reader * file, + const char *fname, + rawlpdata * lp) +{ +/* file format: + * optional problem name (this is in addition to the bix format) + * min or max + * objective fct + * constraints (mandatory !) + * optional bounds + * optional integer (also new) + * + * as opposed to the official bix-format: + * no blanks in variable names + * there may be several bound defs on the same line; + * bound definitions may cross line boundaries + * constraints that have no name get generated names: + * if constraint i has not name we take the first name from the + * following list that is not in use: + * c, C, or c_0, c_1, c_2, ... + */ + int rval = 0; + ILLread_lp_state lpstate, *state = &lpstate; + + const char *bnds[3], *integer[3], *end[2]; + + bnds[0] = "BOUNDS"; + bnds[1] = "BOUND"; + bnds[2] = NULL; + integer[0] = "INTEGER"; + integer[1] = "INT"; + integer[2] = NULL; + end[0] = "END"; + end[1] = NULL; + + rval = ILLread_lp_state_init (state, file, fname, 0); + CHECKRVALG (rval, CLEANUP); + + ILLinit_rawlpdata (lp, file->error_collector); + rval = ILLsymboltab_create (&lp->rowtab, 100) || + ILLsymboltab_create (&lp->coltab, 100); + CHECKRVALG (rval, CLEANUP); + + if (ILLread_lp_state_next_field (state)) + { + rval = ILLlp_error (state, "Empty file.\n"); + } + if (rval == 0) + rval = read_problem_name (state, lp); + if (rval == 0) + rval = read_minmax (state, lp); + if (rval == 0) + rval = read_objective (state, lp); + if (rval == 0) + rval = read_constraints (state, lp, 1); + if ((rval == 0) && (lp->ncols == 0 || lp->nrows == 0)) + { + rval = ILLlp_error (state, + "Problem must contain at least one %s.\n", + "non empty constraint"); + } + CHECKRVALG (rval, CLEANUP); + + if (ILLread_lp_state_keyword (state, bnds) == 0) + { + rval = read_bounds (state, lp); + } + CHECKRVALG (rval, CLEANUP); + + if (ILLread_lp_state_keyword (state, integer) == 0) + { + rval = read_integer (state, lp); + } + CHECKRVALG (rval, CLEANUP); + + rval = ILLread_lp_state_keyword (state, end); + if (rval != 0) + { + if (state->eof) + { + rval = ILLlp_error (state, "Missing \"End\" at end of file.\n"); + } + else + { + rval = ILLlp_error (state, "\"%s\" unknown keyword\n", state->field); + } + } + if (rval == 0) + { + rval = ILLraw_fill_in_rownames (lp) || ILLraw_fill_in_bounds (lp); + } + +CLEANUP: + EGlpNumClearVar (lpstate.bound_val); + EG_RETURN (rval); +} + +static int read_problem_name ( + ILLread_lp_state * state, + rawlpdata * lp) +{ + int rval = 0; + + if (!state->fieldOnFirstCol) + { + rval = ILLlp_error (state, + "Keyword \"%s\" not at beginning of line.\n", + state->field); + } + if (!ILLutil_strcasecmp (state->field, "PROBLEM") || + !ILLutil_strcasecmp (state->field, "PROB")) + { + if (ILLread_lp_state_next_field (state) != 0) + { + rval = ILLlp_error (state, "No Problem name field.\n"); + } + else + { + ILL_IFFREE (lp->name, char); + + ILL_UTIL_STR (lp->name, state->field); + ILL_IFTRACE ("ProblemName: %s\n", state->field); + (void) ILLread_lp_state_next_field (state); + } + } +CLEANUP: + EG_RETURN (rval); +} + +static int read_minmax ( + ILLread_lp_state * state, + rawlpdata * lp) +{ + int rval = 0; + + if (!state->fieldOnFirstCol) + { + rval = ILLlp_error (state, + "Keyword \"%s\" not at beginning of line.\n", + state->field); + } + if (!ILLutil_strcasecmp (state->field, "MAX") || + !ILLutil_strcasecmp (state->field, "MAXIMUM") || + !ILLutil_strcasecmp (state->field, "MAXIMIZE")) + { + lp->objsense = ILL_MAX; + } + else + { + if (!ILLutil_strcasecmp (state->field, "MIN") || + !ILLutil_strcasecmp (state->field, "MINIMUM") || + !ILLutil_strcasecmp (state->field, "MINIMIZE")) + { + lp->objsense = ILL_MIN; + } + else + { + ILLread_lp_state_prev_field (state); + rval = ILLlp_error (state, "Expecting \"%s\" or \"%s\" keyword.\n", + "Minimize", "Maximize"); + } + } + EG_RETURN (rval); +} + +int ILLread_constraint_expr ( + ILLread_lp_state * state, + rawlpdata * lp, + int rowind, + int allowNew) +{ + int rval = 0; + char firstTerm, haveCoef; + const char *name; + EGlpNum_t sign, coef; + EGlpNum_t ntmp; + + EGlpNumInitVar (ntmp); + EGlpNumInitVar (sign); + EGlpNumInitVar (coef); + + firstTerm = 1; + while (1) + { + if (ILLread_lp_state_sign (state, &sign) != 0) + { + if (!firstTerm) + { + break; /* we've ssen at least one term, + * this is the constraint's end */ + } + } + haveCoef = ILLread_lp_state_possible_coef (state, &coef, oneLpNum); + if (ILLread_lp_state_next_var (state) == 0) + { + EGlpNumCopy (ntmp, coef); + EGlpNumMultTo (ntmp, sign); + rval = add_var (lp, state, ntmp, rowind, allowNew); + CHECKRVALG (rval, CLEANUP); + } + else + { + if (haveCoef == 0) + { + return ILLlp_error (state, "Coefficient without variable.\n"); + } + else + { + break; + } + } + firstTerm = 0; + } +CLEANUP: + if ((rval == 0) && firstTerm) + { + name = ILLraw_rowname (lp, rowind); + if (name != NULL) + { + ILLlp_warn (state, + "No terms in constraint expression for \"%s\".\n", name); + } + else + { + ILLlp_warn (state, "No terms in constraint expression.\n"); + } + } + EGlpNumClearVar (ntmp); + EGlpNumClearVar (sign); + EGlpNumClearVar (coef); + EG_RETURN (rval); +} + +static int read_objective ( + ILLread_lp_state * state, + rawlpdata * lp) +{ + int rval = 0; + char objname[ILL_namebufsize]; + char *name; + + ILL_FAILfalse (lp->nrows == 0, "objective should be first row"); + ILLread_lp_state_skip_blanks (state, 1); + if (ILLread_lp_state_has_colon (state)) + { + if (ILLread_lp_state_next_var (state) != 0) + { + rval = ILLlp_error (state, "Bad objective function name.\n"); + } + name = state->field; + if (rval == 0) + { + if (ILLread_lp_state_colon (state) != 0) + { + rval = ILLlp_error (state, "':' must follow constraint row name.\n"); + } + } + } + else + { + name = NULL; + } + + if (rval == 0) + { + ILL_FAILfalse (lp->rowtab.tablesize == 0, + "objective row is first in symbol tab"); + if (name == NULL) + { + strcpy (objname, "obj"); + ILLlp_warn (state, "Empty obj name; using \"%s\".\n", objname); + } + else + { + strcpy (objname, name); + } + rval = ILLraw_add_row (lp, objname, 'N', zeroLpNum); + lp->objindex = lp->nrows - 1; + CHECKRVALG (rval, CLEANUP); + rval = ILLread_constraint_expr (state, lp, lp->objindex, 1); + } +CLEANUP: + EG_RETURN (rval); +} + +int ILLread_constraint_name ( + ILLread_lp_state * state, + char **rowname) +{ + int rval = 0; + + *rowname = NULL; + + /* if there is a ':' on the line: look for constraint row name */ + if (ILLread_lp_state_has_colon (state)) + { + if (ILLread_lp_state_next_var (state) != 0) + { + rval = ILLlp_error (state, "Bad constraint row name.\n"); + } + else + { + *rowname = state->field; + if (ILLread_lp_state_colon (state) != 0) + { + rval = ILLlp_error (state, "':' must follow constraint row name.\n"); + } + } + } + return rval; +} + +int ILLread_one_constraint ( + ILLread_lp_state * state, + const char *rowname, + rawlpdata * lp, + int allowNewCols) +{ + int rval = 0; + int rowind; + char sense; + EGlpNum_t d; + + EGlpNumInitVar (d); + + if ((rowname != NULL) && + (ILLsymboltab_lookup (&lp->rowtab, rowname, &rowind) == 0)) + { + rval = ILLlp_error (state, "Repeated row name \"%s\".\n", rowname); + CHECKRVALG (rval, CLEANUP); + } + rowind = lp->nrows; + rval = rval || ILLraw_add_row (lp, rowname, 'N', zeroLpNum); + + rval = rval || ILLread_constraint_expr (state, lp, rowind, allowNewCols); + rval = rval || ILLread_lp_state_sense (state); + sense = state->sense_val; + if (rval == 0) + { + rval = ILLread_lp_state_value (state, &d); + if (rval) + { + (void) ILLlp_error (state, "No right hand side value in constraint.\n"); + } + } + if (rval == 0) + { + lp->rowsense[rowind] = sense; + EGlpNumCopy (lp->rhs[rowind], d); + ILL_IFTRACE ("SENSE \"%s\": %c %f\n", + ILLraw_rowname (lp, rowind), sense, EGlpNumToLf (d)); + } +CLEANUP: + EGlpNumClearVar (d); + EG_RETURN (rval); +} + +static int read_constraints ( + ILLread_lp_state * state, + rawlpdata * lp, + int allowNewCols) +{ + int rval = 0; + char *rowname = NULL; + + if (ILLcheck_subject_to (state) != 0) + { + return ILLlp_error (state, "Constraint section expected.\n"); + } + while (rval == 0) + { + rval = ILLread_constraint_name (state, &rowname); + if (rval == 0) + { + rval = ILLread_one_constraint (state, rowname, lp, allowNewCols); + } + if (rval == 0) + { + if (ILLread_lp_state_next_constraint (state) != 0) + { + break; + } + } + } + ILLread_lp_state_next_field (state); + EG_RETURN (rval); +} + +/* + * return -2 iff next is not a variable and not a keyword + * return -1 iff next is a keyword and !mustHave + * return 1 iff unknown column name or mustHave and keyword + * return 0 for success + */ +static int read_colname ( + ILLread_lp_state * state, + ILLsymboltab * coltab, + int mustHave) +{ + int rval = 0; + int colind = ILL_SYM_NOINDEX; + + rval = ILLread_lp_state_next_var (state); + if (mustHave && (rval != 0)) + { + return ILLlp_error (state, "Expecting a column name.\n"); + } + if (rval != 0) + { + return (rval == -1) ? rval : -2; + } + if (ILLsymboltab_lookup (coltab, state->field, &colind)) + { + ILLread_lp_state_prev_field (state); + return ILLlp_error (state, "\"%s\" is not a column name.\n", state->field); + } + state->column_index = colind; + return 0; +} + +static int read_integer ( + ILLread_lp_state * state, + rawlpdata * lp) +{ + int rval = 0; + ILLsymboltab *coltab = &lp->coltab; + + ILL_FAILfalse (lp->intmarker, "Programming error"); + + while ((rval = read_colname (state, coltab, 0)) == 0) + { + ILL_FAILtrue (state->column_index == ILL_SYM_NOINDEX, "Programming error"); + lp->intmarker[state->column_index] = 1; + } +CLEANUP: + if (rval == -1) + { /* last try for a colname gave us a keyword */ + rval = 0; + } + else + { + rval = ILLlp_error (state, "Expecting a column name."); + } + ILLread_lp_state_next_field (state); + EG_RETURN (rval); +} + +static int read_bounds ( + ILLread_lp_state * state, + rawlpdata * lp) +{ + int rval = 0; + int colind, haveBound; + char sense; + const char *msg; + ILLsymboltab *coltab; + + ILLraw_init_bounds (lp); + coltab = &lp->coltab; + + while (1) + { + colind = -1; + haveBound = 0; + if (ILLread_lp_state_possible_bound_value (state)) + { + /* this must be for a lower bound */ + ILLtest_lp_state_bound_sense (state); + if (state->sense_val != 'L') + { + rval = ILLlp_error (state, "Expecting \"<=\".\n"); + break; + } + rval = read_colname (state, coltab, 1); + if (rval != 0) + { + break; + } + colind = state->column_index; + /* add lower bound value */ + msg = ILLraw_set_lowerBound (lp, colind, state->bound_val); + ILLlp_warn (state, msg); + haveBound = 1; + } + if (colind == -1) + { + rval = read_colname (state, coltab, 0); + colind = state->column_index; + if (rval != 0) + { + if (rval == -1) + { + rval = 0; /* found a keyword and that's OK */ + } + else if (rval == -2) + { + rval = ILLlp_error (state, "Expecting a column name.\n"); + } + break; + } + } + ILL_FAILtrue (colind == -1, "must have a valid colname"); + ILLtest_lp_state_bound_sense (state); + if (state->sense_val != ' ') + { + sense = state->sense_val; + if ((sense != 'L') && (sense != 'E')) + { + rval = ILLlp_error (state, "Expecting \"<=\" or \"=\".\n"); + break; + } + if (ILLread_lp_state_possible_bound_value (state)) + { + if (sense == 'E') + { + msg = ILLraw_set_fixedBound (lp, colind, state->bound_val); + } + else + { + msg = ILLraw_set_upperBound (lp, colind, state->bound_val); + } + ILLlp_warn (state, msg); + haveBound = 1; + } + else + { + rval = ILLlp_error (state, "Expecting bound value.\n"); + break; + } + } + else + { + if (ILLtest_lp_state_next_is (state, "FREE")) + { + msg = ILLraw_set_unbound (lp, colind); + ILLlp_warn (state, msg); + haveBound = 1; + } + else + { + if (!haveBound) + { + rval = ILLlp_error (state, "Not a bound expression.\n"); + break; + } + } + } + ILL_IFTRACE ("BOUNDS: %f <= %s <= %f\n", EGlpNumToLf (lp->lower[colind]), + ILLraw_colname (lp, colind), EGlpNumToLf (lp->upper[colind])); + } + ILLread_lp_state_next_field (state); +CLEANUP: + EG_RETURN (rval); +} + +static int add_var ( + rawlpdata * lp, + ILLread_lp_state * state, + EGlpNum_t coef, + int row, + int allowNew) +{ + char *var = state->field; + int rval = 0; + int colind; + + if (ILLsymboltab_lookup (&lp->coltab, var, &colind) != 0) + { + if (!allowNew) + { + rval = ILLlp_error (state, "Unknown col name \"%s\".\n", var); + } + CHECKRVALG (rval, CLEANUP); + rval = ILLraw_add_col (lp, var, 0 /* not an integer var */ ); + colind = lp->ncols - 1; + CHECKRVALG (rval, CLEANUP); + } + ILL_IFTRACE ("add_var: \"%s\" coef=%f row=%s\n", + var, EGlpNumToLf (coef), ILLraw_rowname (lp, row)); + rval = ILLraw_add_col_coef (lp, colind, row, coef); +CLEANUP: + EG_RETURN (rval); +} diff --git a/src/lp.h b/src/lp.h new file mode 100644 index 0000000..b7e0998 --- /dev/null +++ b/src/lp.h @@ -0,0 +1,75 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: lp.h,v 1.2 2003/11/05 16:57:39 meven Exp $ */ +#ifndef LP_H +#define LP_H + +#include "qs_config.h" +#include "readline.h" + +/****************************************************************************/ +/* */ +/* Routines to support Reading and Writing LP Files */ +/* */ +/****************************************************************************/ +/* + * -) anything after '\' is comment + * -) Problem is optional and comes first + * -) Minimize, Maximize, ... comes after Problem + * -) variables consist of a-z A-Z 0-9!"#$%(),;.?@_`'{}|~ + * don't start with a digit or '.' + */ + +#include "lpdata.h" +#include "rawlp.h" +#include "read_lp.h" +#include "write_lp.h" + +extern int ILLread_lp ( + qsline_reader * file, + const char *fname, + rawlpdata * lp); +extern int ILLwrite_lp ( + ILLlpdata * l, + qserror_collector * collector); + + /* write using current lp->reporter */ +extern int ILLis_lp_name_char ( + int c, + int pos); + +extern int ILLread_constraint_name ( + ILLread_lp_state * state, + char **rowname); +extern int ILLread_one_constraint ( + ILLread_lp_state * state, + const char *rowname, + rawlpdata * lp, + int allowNewColsAddRow); +extern int ILLread_constraint_expr ( + ILLread_lp_state * state, + rawlpdata * lp, + int rowind, + int allowNew); + +#endif diff --git a/src/lpdata.c b/src/lpdata.c new file mode 100644 index 0000000..283d365 --- /dev/null +++ b/src/lpdata.c @@ -0,0 +1,724 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: lpdata.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +/****************************************************************************/ +/* */ +/* Routines for Manipulating and Writing LPdata */ +/* */ +/* EXPORTED FUNCTIONS */ +/* */ +/* int ILLlpdata_buildrows (ILLlpdata *lp, int **rowbeg, int **rowcnt, */ +/* int **rowind, double **rowval, int include_logicals) */ +/* - include_logicals: if nonzero, then logical variables will be */ +/* included in the row data */ +/* */ +/* */ +/* All _init routines initialize fields of allocated structure to */ +/* appropiate default values */ +/* The _free routines free structures contained in pareameter structure */ +/* but not the parameter itself. */ +/* The _alloc routines check whether given parameter is NULL; they either*/ +/* print an error message or fill structure with default values or the */ +/* given paremeter values. */ +/* */ +/* void ILLlpdata_init (ILLlpdata *lp) */ +/* void ILLlpdata_free (ILLlpdata *lp) */ +/* */ +/* void ILLlp_basis_init (ILLlp_basis *B) */ +/* void ILLlp_basis_free (ILLlp_basis *B) */ +/* int ILLlp_basis_alloc (ILLlp_basis *B, int nstruct, int nrows) */ +/* */ +/* void ILLlp_cache_init (ILLlp_cache *C) */ +/* void ILLlp_cache_free (ILLlp_cache *C) */ +/* int ILLlp_cache_alloc (ILLlp_cache *C, int nstruct, int nrows) */ +/* */ +/* void ILLlp_sinfo_init (ILLlp_sinfo *sinfo) */ +/* void ILLlp_sinfo_free (ILLlp_sinfo *sinfo) */ +/* */ +/* int ILLlp_rows_init(ILLlp_rows *lprows, ILLlpdata *lp, */ +/* int include_logicals) */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "iqsutil.h" +#include "lpdata.h" +#include "qstruct.h" +#include "qsopt.h" +#include "lp.h" +#include "mps.h" +#include "rawlp.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +//static int TRACE = 0; + +EGlpNum_t PARAM_IBASIS_RPIVOT; +EGlpNum_t PARAM_IBASIS_RTRIANG; +EGlpNum_t PARAM_MIN_DNORM; +EGlpNum_t PFEAS_TOLER; +EGlpNum_t BD_TOLER; +EGlpNum_t DFEAS_TOLER; +EGlpNum_t PIVOT_TOLER; +EGlpNum_t SZERO_TOLER; +EGlpNum_t PIVZ_TOLER; +EGlpNum_t OBJBND_TOLER; +EGlpNum_t DBNDPIV_TOLER; +EGlpNum_t DBNDPIV_RATIO; +EGlpNum_t ALTPIV_TOLER; +//EGlpNum_t DJZERO_TOLER; +EGlpNum_t PROGRESS_ZERO; /* 1e-7 */ +EGlpNum_t PROGRESS_THRESH; /* 1e-5 */ +EGlpNum_t CB_EPS; +EGlpNum_t CB_INF_RATIO; +EGlpNum_t CB_PRI_RLIMIT; +EGlpNum_t ILL_MAXDOUBLE; +EGlpNum_t ILL_MINDOUBLE; + +/* ========================================================================= */ +int __QSEX_SETUP = 0; +/* ========================================================================= */ +void ILLstart ( void) +{ + if (__QSEX_SETUP) + return; + EGlpNumInitVar (PARAM_IBASIS_RPIVOT); + EGlpNumInitVar (PARAM_IBASIS_RTRIANG); + EGlpNumInitVar (PARAM_MIN_DNORM); + EGlpNumInitVar (PFEAS_TOLER); + EGlpNumInitVar (BD_TOLER); + EGlpNumInitVar (DFEAS_TOLER); + EGlpNumInitVar (PIVOT_TOLER); + EGlpNumInitVar (SZERO_TOLER); + EGlpNumInitVar (PIVZ_TOLER); + EGlpNumInitVar (OBJBND_TOLER); + EGlpNumInitVar (DBNDPIV_TOLER); + EGlpNumInitVar (DBNDPIV_RATIO); + EGlpNumInitVar (ALTPIV_TOLER); + //EGlpNumInitVar (DJZERO_TOLER); + EGlpNumInitVar (PROGRESS_ZERO); /* 1e-7 */ + EGlpNumInitVar (PROGRESS_THRESH); /* 1e-5 */ + EGlpNumInitVar (CB_PRI_RLIMIT); + EGlpNumInitVar (CB_INF_RATIO); + EGlpNumInitVar (CB_EPS); + EGlpNumInitVar (ILL_MAXDOUBLE); + EGlpNumInitVar (ILL_MINDOUBLE); + /* parameters that do depend on the tolerance to zero */ + EGlpNumSet (PARAM_MIN_DNORM, 4.5036e-9); + EGlpNumMultTo (PARAM_MIN_DNORM, epsLpNum); + EGlpNumSet (PFEAS_TOLER, 4.5036e9); + EGlpNumMultTo (PFEAS_TOLER, epsLpNum); + EGlpNumSet (BD_TOLER, 4.5036e8); + EGlpNumMultTo (BD_TOLER, epsLpNum); + EGlpNumSet (DFEAS_TOLER, 4.5036e9); + EGlpNumMultTo (DFEAS_TOLER, epsLpNum); + EGlpNumSet (PIVOT_TOLER, 4.5036e5); + EGlpNumMultTo (PIVOT_TOLER, epsLpNum); + EGlpNumSet (SZERO_TOLER, 4.5036); + EGlpNumMultTo (SZERO_TOLER, epsLpNum); + EGlpNumSet (PIVZ_TOLER, 4.5036e3); + EGlpNumMultTo (PIVZ_TOLER, epsLpNum); + EGlpNumSet (OBJBND_TOLER, 4.5036e13); + EGlpNumMultTo (OBJBND_TOLER, epsLpNum); + EGlpNumSet (ALTPIV_TOLER, 4.5036e7); + EGlpNumMultTo (ALTPIV_TOLER, epsLpNum); + EGlpNumSet (PROGRESS_ZERO, 4.5036e8); + EGlpNumMultTo (PROGRESS_ZERO, epsLpNum); + EGlpNumSet (PROGRESS_THRESH, 4.5036e10); + EGlpNumMultTo (PROGRESS_THRESH, epsLpNum); +#if VERBOSE_LEVEL <= DEBUG + MESSAGE (VERBOSE_LEVEL, "Setting PARAM_MIN_DNORM to %lg", EGlpNumToLf (PARAM_MIN_DNORM)); + MESSAGE (VERBOSE_LEVEL, "Setting PFEAS_TOLER to %lg", EGlpNumToLf (PFEAS_TOLER)); + MESSAGE (VERBOSE_LEVEL, "Setting BD_TOLER to %lg", EGlpNumToLf (BD_TOLER)); + MESSAGE (VERBOSE_LEVEL, "Setting DFEAS_TOLER to %lg", EGlpNumToLf (DFEAS_TOLER)); + MESSAGE (VERBOSE_LEVEL, "Setting PIVOT_TOLER to %lg", EGlpNumToLf (PIVOT_TOLER)); + MESSAGE (VERBOSE_LEVEL, "Setting SZERO_TOLER to %lg", EGlpNumToLf (SZERO_TOLER)); + MESSAGE (VERBOSE_LEVEL, "Setting PIVZ_TOLER to %lg", EGlpNumToLf (PIVZ_TOLER)); + MESSAGE (VERBOSE_LEVEL, "Setting OBJBND_TOLER to %lg", EGlpNumToLf (OBJBND_TOLER)); + MESSAGE (VERBOSE_LEVEL, "Setting ALTPIV_TOLER to %lg", EGlpNumToLf (ALTPIV_TOLER)); + MESSAGE (VERBOSE_LEVEL, "Setting PROGRESS_ZERO to %lg", EGlpNumToLf (PROGRESS_ZERO)); + MESSAGE (VERBOSE_LEVEL, "Setting PROGRESS_THRESH to %lg", EGlpNumToLf (PROGRESS_THRESH)); +#endif + /* parameters that do not depend on the tolerance to zero */ + EGlpNumSet (ILL_MAXDOUBLE, 1e150); + EGlpNumSet (ILL_MINDOUBLE, -1e150); + EGlpNumSet (PARAM_IBASIS_RPIVOT, 0.98); + EGlpNumSet (PARAM_IBASIS_RTRIANG, 0.01); + EGlpNumSet (DBNDPIV_TOLER, 1e-3); + EGlpNumSet (DBNDPIV_RATIO, 1e-2); + //EGlpNumSet (DJZERO_TOLER, 1e-8); + EGlpNumSet (CB_EPS, 0.001); + EGlpNumSet (CB_INF_RATIO, 10.0); + EGlpNumSet (CB_PRI_RLIMIT, 0.25); + __QSEX_SETUP = 1; +} + +/* ========================================================================= */ +void ILLchange_precision ( + void) +{ + EGlpNumClearVar (PFEAS_TOLER); + EGlpNumClearVar (BD_TOLER); + EGlpNumClearVar (DFEAS_TOLER); + EGlpNumClearVar (PIVOT_TOLER); + EGlpNumClearVar (SZERO_TOLER); + EGlpNumClearVar (PIVZ_TOLER); + EGlpNumClearVar (OBJBND_TOLER); + EGlpNumClearVar (ALTPIV_TOLER); + EGlpNumClearVar (PARAM_MIN_DNORM); + EGlpNumClearVar (PROGRESS_ZERO); + EGlpNumClearVar (PROGRESS_THRESH); + EGlpNumInitVar (PROGRESS_ZERO); + EGlpNumInitVar (PROGRESS_THRESH); + EGlpNumInitVar (PFEAS_TOLER); + EGlpNumInitVar (BD_TOLER); + EGlpNumInitVar (DFEAS_TOLER); + EGlpNumInitVar (PIVOT_TOLER); + EGlpNumInitVar (SZERO_TOLER); + EGlpNumInitVar (PIVZ_TOLER); + EGlpNumInitVar (OBJBND_TOLER); + EGlpNumInitVar (ALTPIV_TOLER); + EGlpNumInitVar (PARAM_MIN_DNORM); + /* parameters that do depend on the tolerance to zero */ + EGlpNumSet (PARAM_MIN_DNORM, 4.5036e-9); + EGlpNumMultTo (PARAM_MIN_DNORM, epsLpNum); + EGlpNumSet (PFEAS_TOLER, 4.5036e9); + EGlpNumMultTo (PFEAS_TOLER, epsLpNum); + EGlpNumSet (BD_TOLER, 4.5036e8); + EGlpNumMultTo (BD_TOLER, epsLpNum); + EGlpNumSet (DFEAS_TOLER, 4.5036e9); + EGlpNumMultTo (DFEAS_TOLER, epsLpNum); + EGlpNumSet (PIVOT_TOLER, 4.5036e5); + EGlpNumMultTo (PIVOT_TOLER, epsLpNum); + EGlpNumSet (SZERO_TOLER, 4.5036); + EGlpNumMultTo (SZERO_TOLER, epsLpNum); + EGlpNumSet (PIVZ_TOLER, 4.5036e3); + EGlpNumMultTo (PIVZ_TOLER, epsLpNum); + EGlpNumSet (OBJBND_TOLER, 4.5036e13); + EGlpNumMultTo (OBJBND_TOLER, epsLpNum); + EGlpNumSet (ALTPIV_TOLER, 4.5036e7); + EGlpNumMultTo (ALTPIV_TOLER, epsLpNum); + EGlpNumSet (PROGRESS_ZERO, 4.5036e8); + EGlpNumMultTo (PROGRESS_ZERO, epsLpNum); + EGlpNumSet (PROGRESS_THRESH, 4.5036e10); + EGlpNumMultTo (PROGRESS_THRESH, epsLpNum); +} + +/* ========================================================================= */ +void ILLend ( void) +{ + if (!__QSEX_SETUP) + return; + EGlpNumClearVar (PARAM_IBASIS_RPIVOT); + EGlpNumClearVar (PARAM_IBASIS_RTRIANG); + EGlpNumClearVar (PARAM_MIN_DNORM); + EGlpNumClearVar (PFEAS_TOLER); + EGlpNumClearVar (BD_TOLER); + EGlpNumClearVar (DFEAS_TOLER); + EGlpNumClearVar (PIVOT_TOLER); + EGlpNumClearVar (SZERO_TOLER); + EGlpNumClearVar (PIVZ_TOLER); + EGlpNumClearVar (OBJBND_TOLER); + EGlpNumClearVar (DBNDPIV_TOLER); + EGlpNumClearVar (DBNDPIV_RATIO); + EGlpNumClearVar (ALTPIV_TOLER); + //EGlpNumClearVar (DJZERO_TOLER); + EGlpNumClearVar (PROGRESS_ZERO); /* 1e-7 */ + EGlpNumClearVar (PROGRESS_THRESH); /* 1e-5 */ + EGlpNumClearVar (CB_EPS); + EGlpNumClearVar (CB_INF_RATIO); + EGlpNumClearVar (CB_PRI_RLIMIT); + EGlpNumClearVar (ILL_MAXDOUBLE); + EGlpNumClearVar (ILL_MINDOUBLE); + __QSEX_SETUP = 0; +} + +QSdata *ILLread ( + qsline_reader * file, + const char *fname, + int isMps) +{ + int rval = 0; + QSdata *p = 0; + ILLlpdata *lp; + rawlpdata rawlp; + + ILL_FAILfalse (file != NULL, NULL); + ILL_FAILfalse (fname != NULL, NULL); + + p = QScreate_prob (fname, QS_MIN); + ILL_CHECKnull (p, NULL); + ILL_IFFREE (p->qslp->probname, char); + + lp = p->qslp; + + ILLinit_rawlpdata (&rawlp, file->error_collector); + ILLlpdata_init (lp); + + if (isMps != 0) + { + rval = ILLread_mps (file, fname, &rawlp); + } + else + { + rval = ILLread_lp (file, fname, &rawlp); + } + CHECKRVALG (rval, CLEANUP); + + rval = ILLrawlpdata_to_lpdata (&rawlp, lp); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + ILLfree_rawlpdata (&rawlp); + if (rval != 0) + { + QSfree_prob (p); + p = 0; + } + return p; +} + +void ILLlpdata_init ( + ILLlpdata * lp) +{ + if (lp) + { + lp->nrows = 0; + lp->ncols = 0; + lp->nstruct = 0; + lp->nzcount = 0; + lp->rowsize = 0; + lp->colsize = 0; + lp->structsize = 0; + lp->objsense = ILL_MIN; + lp->sense = 0; + lp->obj = 0; + lp->rhs = 0; + lp->rangeval = 0; + lp->lower = 0; + lp->upper = 0; + + ILLmatrix_init (&lp->A); + ILLmatrix_init (&lp->sos); + lp->rA = 0; + lp->is_sos_mem = NULL; + lp->refrowname = NULL; + lp->refind = -1; + + lp->colnames = 0; + ILLsymboltab_init (&lp->coltab); + lp->rownames = 0; + ILLsymboltab_init (&lp->rowtab); + lp->objname = 0; + + lp->probname = 0; + lp->intmarker = 0; + lp->structmap = 0; + lp->rowmap = 0; + lp->basis = 0; + /*lp->presolve = 0; */ + lp->sinfo = 0; + + ILLstring_reporter_init (&lp->reporter, ILL_fprintf, stdout); + } +} + +void ILLlpdata_free ( + ILLlpdata * lp) +{ + int i; + + if (lp) + { + ILL_IFFREE (lp->sense, char); + + EGlpNumFreeArray (lp->obj); + EGlpNumFreeArray (lp->rhs); + EGlpNumFreeArray (lp->rangeval); + EGlpNumFreeArray (lp->lower); + EGlpNumFreeArray (lp->upper); + ILLmatrix_free (&lp->A); + if (lp->rA) + { + ILLlp_rows_clear (lp->rA); + ILL_IFFREE (lp->rA, ILLlp_rows); + } + ILL_IFFREE (lp->is_sos_mem, int); + ILL_IFFREE (lp->refrowname, char); + + ILLmatrix_free (&lp->sos); + if (lp->colnames) + { + for (i = 0; i < lp->nstruct; i++) + { + ILL_IFFREE (lp->colnames[i], char); + } + ILL_IFFREE (lp->colnames, char *); + } + ILLsymboltab_free (&lp->coltab); + if (lp->rownames) + { + for (i = 0; i < lp->nrows; i++) + { + ILL_IFFREE (lp->rownames[i], char); + } + ILL_IFFREE (lp->rownames, char *); + } + ILLsymboltab_free (&lp->rowtab); + ILL_IFFREE (lp->objname, char); + ILL_IFFREE (lp->probname, char); + ILL_IFFREE (lp->intmarker, char); + ILL_IFFREE (lp->structmap, int); + ILL_IFFREE (lp->rowmap, int); + + if (lp->sinfo) + { + ILLlp_sinfo_free (lp->sinfo); + ILL_IFFREE (lp->sinfo, ILLlp_sinfo); + } + ILLlpdata_init (lp); + } +} + +void ILLlp_basis_init ( + ILLlp_basis * B) +{ + if (B) + { + B->cstat = 0; + B->rstat = 0; + B->rownorms = 0; + B->colnorms = 0; + B->nstruct = 0; + B->nrows = 0; + } +} + +void ILLlp_basis_free ( + ILLlp_basis * B) +{ + if (B) + { + ILL_IFFREE (B->cstat, char); + ILL_IFFREE (B->rstat, char); + + EGlpNumFreeArray (B->rownorms); + EGlpNumFreeArray (B->colnorms); + B->nstruct = 0; + B->nrows = 0; + } +} + +int ILLlp_basis_alloc ( + ILLlp_basis * B, + int nstruct, + int nrows) +{ + int rval = 0; + + ILL_FAILtrue (B == NULL, "ILLlp_basis_alloc called without a basis"); + + B->nstruct = nstruct; + B->nrows = nrows; + + if (nstruct > 0) + { + ILL_SAFE_MALLOC (B->cstat, nstruct, char); + } + + if (nrows > 0) + { + ILL_SAFE_MALLOC (B->rstat, nrows, char); + } + +CLEANUP: + + if (rval) + { + ILLlp_basis_free (B); + } + + EG_RETURN (rval); +} + +void ILLlp_cache_init ( + ILLlp_cache * C) +{ + if (C) + { + C->x = 0; + C->rc = 0; + C->pi = 0; + C->slack = 0; + C->nstruct = 0; + C->nrows = 0; + C->status = 0; + EGlpNumZero (C->val); + } +} + +void ILLlp_cache_free ( + ILLlp_cache * C) +{ + if (C) + { + EGlpNumFreeArray (C->x); + EGlpNumFreeArray (C->rc); + EGlpNumFreeArray (C->pi); + EGlpNumFreeArray (C->slack); + C->nstruct = 0; + C->nrows = 0; + C->status = 0; + } +} + +int ILLlp_cache_alloc ( + ILLlp_cache * C, + int nstruct, + int nrows) +{ + int rval = 0; + + ILL_FAILtrue (C == NULL, "ILLlp_cache_alloc called without a cache"); + + C->nstruct = nstruct; + C->nrows = nrows; + + if (nstruct > 0) + { + C->x = EGlpNumAllocArray (nstruct); + C->rc = EGlpNumAllocArray (nstruct); + } + + if (nrows > 0) + { + C->pi = EGlpNumAllocArray (nrows); + C->slack = EGlpNumAllocArray (nrows); + } + +CLEANUP: + + if (rval) + { + ILLlp_cache_free (C); + } + + EG_RETURN (rval); +} + + +int ILLlp_rows_init ( + ILLlp_rows * lprows, + ILLlpdata * lp, + int include_logicals) +{ + int rval = 0; + int i, k, st; + int *beg, *cnt, *ind; + EGlpNum_t *val; + ILLmatrix *A; + char *hit = 0; + int *inv_structmap = 0; + + /* If logicals are not included, then the columns are ordered as in */ + /* lp->structmap. Otherwise, the columns are ordered as in the */ + /* matrix structure. */ + + if (lprows != NULL) + { + lprows->rowbeg = 0; + lprows->rowcnt = 0; + lprows->rowind = 0; + lprows->rowval = 0; + } + + ILL_FAILfalse ((lp != NULL) && (lprows != NULL), + "called with a NULL pointer"); + + A = &lp->A; + + if (lp->nrows > 0) + { + if (include_logicals == 0) + { + ILL_FAILtrue (lp->rowmap == NULL, "Programming error."); + ILL_SAFE_MALLOC (hit, lp->ncols, char); + + for (i = 0; i < lp->ncols; i++) + { + hit[i] = 0; + } + for (i = 0; i < lp->nrows; i++) + { + hit[lp->rowmap[i]] = 1; + } + + ILL_SAFE_MALLOC (inv_structmap, lp->ncols, int); + + for (i = 0; i < lp->nstruct; i++) + { + inv_structmap[lp->structmap[i]] = i; + } + } + + ILL_SAFE_MALLOC (lprows->rowbeg, lp->nrows, int); + ILL_SAFE_MALLOC (lprows->rowcnt, lp->nrows, int); + + if (((include_logicals != 0) && lp->nzcount > 0) || + ((include_logicals == 0) && lp->nzcount > lp->nrows)) + { + if (include_logicals != 0) + { + ILL_SAFE_MALLOC (lprows->rowind, lp->nzcount, int); + + lprows->rowval = EGlpNumAllocArray (lp->nzcount); + } + else + { + ILL_SAFE_MALLOC (lprows->rowind, lp->nzcount - lp->nrows, int); + + lprows->rowval = EGlpNumAllocArray (lp->nzcount - lp->nrows); + } + } + + beg = lprows->rowbeg; + cnt = lprows->rowcnt; + ind = lprows->rowind; + val = lprows->rowval; + + for (i = 0; i < lp->nrows; i++) + { + cnt[i] = 0; + } + + for (i = 0; i < lp->ncols; i++) + { + if ((include_logicals != 0) || hit[i] == 0) + { + k = A->matbeg[i]; + st = k + A->matcnt[i]; + for (; k < st; k++) + { + cnt[A->matind[k]]++; + } + } + } + + for (i = 0, k = 0; i < lp->nrows; i++) + { + beg[i] = k; + k += cnt[i]; + } + + for (i = 0; i < lp->ncols; i++) + { + if ((include_logicals != 0) || hit[i] == 0) + { + k = A->matbeg[i]; + st = k + A->matcnt[i]; + for (; k < st; k++) + { + if (include_logicals != 0) + { + ind[beg[A->matind[k]]] = i; + } + else + { + ind[beg[A->matind[k]]] = inv_structmap[i]; + } + EGlpNumCopy (val[beg[A->matind[k]]], A->matval[k]); + beg[A->matind[k]]++; + } + } + } + + for (i = 0, k = 0; i < lp->nrows; i++) + { + beg[i] = k; + k += cnt[i]; + } + } +CLEANUP: + + if (rval) + { + ILLlp_rows_clear (lprows); + } + ILL_IFFREE (hit, char); + ILL_IFFREE (inv_structmap, int); + + EG_RETURN (rval); +} + +void ILLlp_rows_clear ( + ILLlp_rows * lprows) +{ + if (lprows != NULL) + { + ILL_IFFREE (lprows->rowbeg, int); + ILL_IFFREE (lprows->rowcnt, int); + ILL_IFFREE (lprows->rowind, int); + + EGlpNumFreeArray (lprows->rowval); + } +} + +static int wr_line ( + ILLlpdata * lp, + const char *format, + va_list argptr) +{ + char buffer[ILL_namebufsize]; + int rval = 0; + + rval = vsprintf (buffer, format, argptr); + if (rval > 0) + { + /* Bico -- OPTERON DEBUGGING 051005 */ + /* Replaced ILLstring_report by the explicit call to */ + /* fprintf. */ + /*rval = fprintf (lp->reporter.dest, buffer); + if (rval < 0) rval = 1; + else rval = 0; + */ + /* daespino -- BACK to ILLstring_report to support compresed files 090909 + * */ + rval = ILLstring_report(buffer, &lp->reporter); + } + return rval; +} + +int ILLprint_report ( + ILLlpdata * lp, + const char *format, + ...) +{ + va_list marker; + int rval = 0; + + va_start (marker, format); /* ANSI style */ + rval = wr_line (lp, format, marker); + va_end (marker); /* Reset variable arguments. */ + return rval; +} diff --git a/src/lpdata.h b/src/lpdata.h new file mode 100644 index 0000000..bda6b0f --- /dev/null +++ b/src/lpdata.h @@ -0,0 +1,302 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: lpdata.h,v 1.4 2003/11/05 17:00:56 meven Exp $ */ +#ifndef ILL_LPDATA_H +#define ILL_LPDATA_H + +#include "config.h" +#include "qstruct.h" +#include "iqsutil.h" +#include "readline.h" +#include "reporter.h" +#include "format.h" +#include "dstruct.h" + +extern EGlpNum_t ILL_MAXDOUBLE; /* 1e150 */ +extern EGlpNum_t ILL_MINDOUBLE; /* -1e150 */ + +#define ILL_MAXINT (2147483647) /* this is equal to 2^31-1 */ +#define ILL_MIN (1) /* Must be same as QS_MIN */ +#define ILL_MAX (-1) /* Must be same as QS_MAX */ + +/* Setting Alg in Presolve */ + +#define ILL_PRE_SCALE 1 +#define ILL_PRE_FIXED 2 +#define ILL_PRE_SINGLE_ROW 4 +#define ILL_PRE_FORCING 8 +#define ILL_PRE_SINGLE_COL 16 +#define ILL_PRE_DUPLICATE_ROW 32 +#define ILL_PRE_DUPLICATE_COL 64 +#define ILL_PRE_EMPTY_COL 128 +#define ILL_PRE_ALL (ILL_PRE_SCALE | ILL_PRE_FIXED | ILL_PRE_SINGLE_ROW \ + ILL_PRE_FORCING | ILL_PRE_SINGLE_COL | ILL_PRE_DUPLICATE_ROW \ + ILL_PRE_DUPLICATE_COL | ILL_PRE_EMPTY_COL) +#define ILL_PRE_SIMPLE (ILL_PRE_FIXED | ILL_PRE_EMPTY_COL) + +typedef struct ILLlpdata +{ /* Complete LP data filled in by mpsread. */ + int nrows; + int ncols; + int nstruct; /* Not including logicals. */ + int nzcount; + int rowsize; /* Length of row arrays. */ + int colsize; /* Length of col arrays. */ + int structsize; /* Length of intmarker, structmap, */ + /* colnames */ + int objsense; + char *sense; /* Original sense, not after logicals. */ + EGlpNum_t *obj; + EGlpNum_t *rhs; + EGlpNum_t *rangeval; + EGlpNum_t *lower; + EGlpNum_t *upper; + ILLmatrix A; /* The coef matrix. */ + struct ILLlp_rows *rA; /* Coef matrix in row form. */ + + char **rownames; + ILLsymboltab rowtab; /* contains rownames in no particular order */ + char *objname; /* if colname is not NULL it is entered into + * the rowtab, see reader fcts in lp.c, mps.c*/ + + char **colnames; /* columns of struct variables */ + ILLsymboltab coltab; /* contains colnames in no particular order */ + + char *probname; + char *intmarker; + int *structmap; /* Indices of structural variables */ + int *rowmap; /* Indices of logical and range variables */ + struct ILLlp_basis *basis; + struct ILLlp_predata *presolve; + struct ILLlp_sinfo *sinfo; + + /**************************************************************************/ + /* these fields are currently only set by mps.c reader fcts */ + /**************************************************************************/ + ILLmatrix sos; /* columns are the sets, rows are the + * problem's structural variables + * coefficients are the weights */ + + char *sos_type; /* type of each set */ + int *is_sos_mem; /* for each structural variable contains + * -1 == not a set member + * i == member of sos set i + * where 0 <= i < sos.matcols */ + char *refrowname; /* name of reference row */ + int refind; /* index of reference row + * -1 if refrow was a free row + * and weights are found only in the + * sos matrix + * index >=0 if refrow is also a lp-row */ + + /************************************************************************** + * QSset_reporter initializes reporter + **************************************************************************/ + qsstring_reporter reporter; /* used from within ILL fcts + * to report feedback */ +} +ILLlpdata; + +typedef struct ILLlp_basis +{ + int nstruct; + int nrows; + int rownorms_size; + int colnorms_size; + char *cstat; + char *rstat; + EGlpNum_t *rownorms; + EGlpNum_t *colnorms; +} +ILLlp_basis; + +typedef struct ILLlp_cache +{ + int nstruct; + int nrows; + int status; + EGlpNum_t val; + EGlpNum_t *x; + EGlpNum_t *pi; + EGlpNum_t *rc; + EGlpNum_t *slack; +} +ILLlp_cache; + +typedef struct ILLlp_sinfo +{ /* LP info returned by presolve */ + int ncols; + int nrows; + int nzcount; + int rowsize; + int colsize; + int objsense; + + EGlpNum_t *obj; + EGlpNum_t *rhs; + EGlpNum_t *lower; + EGlpNum_t *upper; + + ILLmatrix A; + + char **colnames; /* Just for debugging - not updated */ +} +ILLlp_sinfo; + +typedef struct ILLlp_preline +{ + EGlpNum_t rhs; + EGlpNum_t obj; + EGlpNum_t lower; + EGlpNum_t upper; + int count; + int *ind; + int row_or_col; /* 0 is row, 1 is col */ + EGlpNum_t *val; +} +ILLlp_preline; + +typedef struct ILLlp_preop +{ + int ptype; + int rowindex; + int colindex; + ILLlp_preline line; +} +ILLlp_preop; + +typedef struct ILLlp_predata +{ /* Data needed in un-presolve. */ + int opcount; + int opsize; + ILLlp_preop *oplist; + int r_nrows; + int r_ncols; + int *colmap; + int *rowmap; + EGlpNum_t *rowscale; + EGlpNum_t *colscale; + EGlpNum_t *colfixval; + EGlpNum_t *rowfixval; +} +ILLlp_predata; + +typedef struct ILLlp_rows +{ + int *rowbeg; + int *rowcnt; + int *rowind; + EGlpNum_t *rowval; +} +ILLlp_rows; + + +/****************************************************************************/ +/* */ +/* lpdata.c */ +/* */ +/****************************************************************************/ + +struct qsdata *ILLread ( + qsline_reader * file, + const char *fname, + int isMps); +void ILLstart ( + void); /**< initialize ILL_MAXDOUBLE and other + + constants, this funtion should be callef AFTER + EGlpNumStart() */ +void ILLend ( + void); /**< free any internal data asociated with variable + + precision numbers */ +void ILLchange_precision ( + void); /**< This function re-compute the internal + + variables precision to the (previously + set) EGLPNUM_PRECISION value (done with + EGlpNumSetPrecision) */ +void ILLlpdata_init ( + ILLlpdata * lp); +void ILLlpdata_free ( + ILLlpdata * lp); +void ILLlp_basis_init ( + ILLlp_basis * B); +void ILLlp_basis_free ( + ILLlp_basis * B); +void ILLlp_cache_init ( + ILLlp_cache * C); +void ILLlp_cache_free ( + ILLlp_cache * C); +int ILLlp_basis_alloc ( + ILLlp_basis * B, + int ncols, + int nrows); +int ILLlp_cache_alloc ( + ILLlp_cache * C, + int ncols, + int nrows); + +int ILLlp_rows_init ( + ILLlp_rows * lp_rows, + ILLlpdata * lp, + int include_logicals); +void ILLlp_rows_clear ( + ILLlp_rows * lp_rows); +int ILLprint_report ( + ILLlpdata * lp, + const char *format, + ...); + + /* print to lp->reporter */ + +/****************************************************************************/ +/* */ +/* presolve.c */ +/* */ +/****************************************************************************/ + +void ILLlp_sinfo_init ( + ILLlp_sinfo * sinfo), + ILLlp_sinfo_free ( + ILLlp_sinfo * sinfo), + ILLlp_predata_init ( + ILLlp_predata * pre), + ILLlp_predata_free ( + ILLlp_predata * pre); + +int ILLlp_add_logicals ( + ILLlpdata * lp), + ILLlp_scale ( + ILLlpdata * lp), + ILLlp_presolve ( + ILLlpdata * lp, + int pre_types); + +/* ========================================================================= */ +/* if non-zero, then internal data has been initialized, and there is some + * memory allocated, if zero, no internal memory has been allocated + * (or it has been freed) */ +extern int __QSEX_SETUP; + +#endif /* __ILL_LPDATA_H */ diff --git a/src/lpdefs.h b/src/lpdefs.h new file mode 100644 index 0000000..0baac67 --- /dev/null +++ b/src/lpdefs.h @@ -0,0 +1,329 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: lpdefs.h,v 1.3 2003/11/05 16:57:39 meven Exp $ */ +#ifndef __QS_LPDEFS_H +#define __QS_LPDEFS_H + +#include "qsopt.h" +#include "lpdata.h" +#include "factor.h" + +/* infinity and negative infinity */ +#define INFTY ILL_MAXDOUBLE +#define NINFTY ILL_MINDOUBLE + +#include "basicdefs.h" +/* tolerances, these are initialized in ILLstart, file lpdata.c */ +//#if EGLPNUM_TYPE != DBL_TYPE && EGLPNUM_TYPE != LDBL_TYPE +/* these three constants are defined in lpdata.c */ +extern EGlpNum_t PARAM_IBASIS_RPIVOT; /* 0.98 */ +extern EGlpNum_t PARAM_IBASIS_RTRIANG;/* 0.01 */ +extern EGlpNum_t PARAM_MIN_DNORM; /* 1e-24 */ +extern EGlpNum_t PFEAS_TOLER; /* 1e-6 */ +extern EGlpNum_t BD_TOLER; /* 1e-7 */ +extern EGlpNum_t DFEAS_TOLER; /* 1e-6 */ +extern EGlpNum_t PIVOT_TOLER; /* 1e-10 */ +extern EGlpNum_t SZERO_TOLER; /* 1e-15 */ +extern EGlpNum_t PIVZ_TOLER; /* 1e-12 */ +extern EGlpNum_t OBJBND_TOLER; /* 1e-2 */ +extern EGlpNum_t DBNDPIV_TOLER; /* 1e-3 */ +extern EGlpNum_t DBNDPIV_RATIO; /* 1e-2 */ +extern EGlpNum_t ALTPIV_TOLER; /* 1e-8 */ +//extern EGlpNum_t DJZERO_TOLER;/* 1e-8 */ +extern EGlpNum_t PROGRESS_ZERO; /* 1e-7 */ +extern EGlpNum_t PROGRESS_THRESH; /* 1e-5 */ +extern EGlpNum_t CB_EPS; /* 0.001 */ +extern EGlpNum_t CB_INF_RATIO; /* 10.0 */ +extern EGlpNum_t CB_PRI_RLIMIT; /* 0.25 */ + +/* structure for statistics */ +typedef struct +{ + int ynz_cnt; /* nz in entering columns */ + int num_y; + EGlpNum_t y_ravg; /* weighted avg. of current & prior y */ + int znz_cnt; /* nz in ith row of B^{-1}, ie z_i */ + int num_z; + EGlpNum_t z_ravg; /* weighted avg. of current & prior z */ + int zanz_cnt; /* nz in z^TA */ + int num_za; + EGlpNum_t za_ravg; /* weighted avg. of current & prior za */ + int pnorm_cnt; /* nz in columns for primal norms */ + int dnorm_cnt; /* nz in rows for dual norms */ + int pinz_cnt; /* nz in phase II pi (solve) */ + int num_pi; /* # of pi solves */ + int pi1nz_cnt; /* nz in phase I pi (solve) */ + int num_pi1; /* # of phase I pi solves */ + int upnz_cnt; /* nz in ftran update vector */ + int num_up; /* # of ftran_updates */ + int pupv_cnt; /* nz in primal steep updates */ + int dupv_cnt; /* nz in dual steep updates */ + + int start_slacks; /* # slacks in beginning */ + int final_slacks; /* # slacks in the end */ + int start_art; /* # arts in beginning */ + int final_art; /* # arts in the end */ + + int pI_iter; /* primal phase I iterations */ + int pII_iter; + int dI_iter; /* dual phase I iterations */ + int dII_iter; + int tot_iter; + + int pivpI[10]; /* sizes of pivots */ + int pivpII[10]; + int pivdI[10]; + int pivdII[10]; +} +count_struct; + +/* structure for tolerances */ +typedef struct +{ + EGlpNum_t pfeas_tol; + EGlpNum_t dfeas_tol; + EGlpNum_t pivot_tol; + EGlpNum_t szero_tol; + EGlpNum_t ip_tol; /* inner primal & dual feas toler */ + EGlpNum_t id_tol; +} +tol_struct; + +/* bound information */ +typedef struct bndinfo +{ + EGlpNum_t pbound; + EGlpNum_t cbound; + int btype; + int varnum; + struct bndinfo *next; +} +bndinfo; + +/* bound information */ +typedef struct coefinfo +{ + EGlpNum_t pcoef; + EGlpNum_t ccoef; + int varnum; + struct coefinfo *next; +} +coefinfo; + +/* feasibility info */ +typedef struct feas_info +{ + int pstatus; + int dstatus; + EGlpNum_t totinfeas; +} +feas_info; + +typedef struct lp_status_info +{ + char optimal; + char primal_feasible; + char primal_infeasible; + char primal_unbounded; + char dual_feasible; + char dual_infeasible; + char dual_unbounded; + char padd; +} +lp_status_info; + +typedef struct pI_uinfo +{ + int tctr; + int i; + int *perm; + int *ix; + int fs; + EGlpNum_t piv; + EGlpNum_t *t; + EGlpNum_t dty; + EGlpNum_t c_obj; + EGlpNum_t tz; +} +pI_uinfo; + +extern void ILLlp_status_info_init ( + lp_status_info * ls); + +/* structure for local lp information + * contains lp obj values - status - dimensions - input data - + * solution vecs - basis info - update vecs - work vecs - bound changes - + * tolerances - time info - statistics + */ +typedef struct lpinfo +{ + + EGlpNum_t objval; /* obj info */ + EGlpNum_t pobjval; /* intermediate status info */ + EGlpNum_t dobjval; + EGlpNum_t pinfeas; + EGlpNum_t dinfeas; + EGlpNum_t objbound; + lp_status_info probstat; /* final status */ + lp_status_info basisstat; /* final status */ + int nrows; /* input info follows; given in col format */ + int ncols; + int *matcnt; + int *matbeg; + int *matind; + EGlpNum_t *matval; + int matfree; + int matsize; + EGlpNum_t *bz; + EGlpNum_t *lz; + EGlpNum_t *uz; + EGlpNum_t *cz; + int localrows; /* set to 1 if these are created locally */ + int *rowcnt; /* row info follows, copy of col info */ + int *rowbeg; + int *rowind; + EGlpNum_t *rowval; + + EGlpNum_t *xbz; /* output info x, pi, reduced cost */ + EGlpNum_t *piz; + EGlpNum_t *dz; + EGlpNum_t *pIxbz; /* output info (phase I) x, pi, reduced cost */ + EGlpNum_t *pIpiz; + EGlpNum_t *pIdz; + + int final_phase; /* final phase, inf & unboundedness info */ + int infub_ix; + + int basisid; /* basis and variable info follows */ + int nnbasic; + int *baz; + int *nbaz; + int *vstat; + int *vindex; + int fbasisid; + factor_work *f; + int *vtype; /* internal var info */ + char *vclass; /* structural or logical */ + + svector zz; /* local ILLfactor_update vectors z, yj, za */ + svector yjz; + svector zA; + svector work; /* local work vector */ + svector srhs; /* local vectors for lin. eq. solves */ + svector ssoln; + int *iwork; /* local work vector */ + pI_uinfo upd; /* phase I update info */ + int *bfeas; /* primal and dual infeasibility info */ + int *dfeas; + + tol_struct *tol; /* tolerances */ + count_struct *cnts; /* counts */ + int nbchange; /* # bound shifts */ + int ncchange; /* # obj coef shifts */ + bndinfo *bchanges; /* list of bound shifts */ + coefinfo *cchanges; /* list of coef shifts */ + int pIratio; /* ratio tests */ + int pIIratio; + int dIratio; + int dIIratio; + + int maxiter; + int iterskip; + double maxtime; + double starttime; + struct ILLlpdata *O; + ILLrandstate rstate; + +} +lpinfo; + +/* pricing structures */ +typedef struct +{ + int ninit; + EGlpNum_t *norms; + int *refframe; +} +p_devex_info; + +typedef struct +{ + EGlpNum_t *norms; +} +p_steep_info; + +typedef struct +{ + int k; + int cgroup; + int ngroups; + int *gstart; + int *gshift; + int *gsize; + int bsize; + int *bucket; + int *perm; + EGlpNum_t *infeas; +} +mpart_info; + +typedef struct +{ + int ninit; + EGlpNum_t *norms; + int *refframe; +} +d_devex_info; + +typedef struct +{ + EGlpNum_t *norms; +} +d_steep_info; + +/* pricing information */ +typedef struct price_info +{ + int p_strategy; + int d_strategy; + int pI_price; + int pII_price; + int dI_price; + int dII_price; + int cur_price; + EGlpNum_t *p_scaleinf; + EGlpNum_t *d_scaleinf; + p_devex_info pdinfo; + p_steep_info psinfo; + mpart_info pmpinfo; + d_devex_info ddinfo; + d_steep_info dsinfo; + mpart_info dmpinfo; + heap h; + EGlpNum_t htrigger; + int hineff; + char init; +} +price_info; + +#endif /* __QS_LPDEFS_H */ diff --git a/src/machdefs.h b/src/machdefs.h new file mode 100644 index 0000000..b2f8c07 --- /dev/null +++ b/src/machdefs.h @@ -0,0 +1,218 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: machdefs.h,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __MACHDEFS_H +#define __MACHDEFS_H +#include "qs_config.h" + +#ifdef HAVE_STDIO_H +# include +#endif + +#ifdef HAVE_STDARG_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_ERRNO_H +# include +#endif +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# ifdef HAVE_TIME_H +# include +# endif +# endif +#endif +#ifdef HAVE_STDDEF_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_MALLOC_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#ifdef HAVE_SOCKET +#define ILL_NETREADY +#endif + +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +#ifdef ILL_ATTRIBUTE +#define ILL_UNUSED __attribute__ ((unused)) +#else +#define ILL_UNUSED +#endif + +#ifdef ILL_PROTO_PRINTF +/* assume that if you're missing printf, you're missing a bunch */ +extern int printf ( + const char *, + ...), + fprintf ( + FILE *, + const char *, + ...), + fflush ( + FILE *), + scanf ( + const char *, + ...), + sscanf ( + const char *, + const char *, + ...), + fscanf ( + FILE *, + const char *, + ...), + fclose ( + FILE *), + ungetc ( + int, + FILE *), + _filbuf ( + FILE *), + time ( + int *); + +#ifdef ILL_NETREADY +extern int socket ( + int, + int, + int), + connect ( + int, + const struct sockaddr *, + int), + accept ( + int, + struct sockaddr *, + int *), + bind ( + int, + const struct sockaddr *, + int), + listen ( + int, + int); +#endif +extern void *memset ( + void *, + int, + size_t), + perror ( + const char *); +#endif + +#ifdef ILL_PROTO_RENAME +extern int rename ( + const char *, + const char *); +#endif + +#ifdef ILL_PROTO_GETHOSTNAME +extern int gethostname ( + char *, + int); +#endif + +#ifdef ILL_PROTO_GETRUSAGE +extern int getrusage ( + int, + struct rusage *); +#endif + +#ifdef ILL_PROTO___VFORK +extern pid_t __vfork ( + void); +#endif + +#ifndef NULL +#define NULL (0) +#endif + +//#ifndef INT_MAX +//#define INT_MAX ((int) (~(((unsigned) 1) << ((8*sizeof(int))-1)))) +//#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#endif /* __MACHDEFS_H */ diff --git a/src/mps.c b/src/mps.c new file mode 100644 index 0000000..efc1a9c --- /dev/null +++ b/src/mps.c @@ -0,0 +1,1335 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: mps.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +/****************************************************************************/ +/* */ +/* Routines for Reading and Writing MPS Files */ +/* */ +/* EXPORTED FUNCTIONS */ +/* */ +/* int ILLlpdata_mpsread (ILLlpdata *lp, const char *filename); */ +/* int ILLlpdata_mpswrite(ILLlpdata *lp, const char *filename); */ +/* */ +/* NOTES */ +/* */ +/* In the MPS reader, integer variables without an explicit bound are */ +/* set to binary; real variables without an explict lower bound and */ +/* either a nonnegative or free upperbound set to nonnegative. (These */ +/* are standard settings.) */ +/* */ +/* If a RHS is not specified for a row, it is set to 0. */ +/* */ +/* The MPS reader allows CPLEX's OBJSENSE extension to specify max or */ +/* min and the OBJNAME extension to specify an objective row. */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "iqsutil.h" +#include "mps.h" +#include "rawlp.h" +#include "lpdata.h" +//extern EGlpNum_t SZERO_TOLER; + +static int TRACE = 0; + +const char *ILLmps_section_name[ILL_MPS_N_SECTIONS + 2] = { + "NAME", "OBJSENSE", "OBJNAME", "ROWS", "COLUMNS", + "RHS", "RANGES", "BOUNDS", "REFROW", "ENDATA", + NULL +}; + +static const char *mps_bound_name[] = { + "LO", "UP", "FX", "FR", "MI", "PL", "BV", "UI", "LI", NULL +}; + +/****************************************************************************/ +/* reading + */ +static int read_mps_section ( + ILLread_mps_state * state, + rawlpdata * lp); + +static int read_mps_name ( + ILLread_mps_state * state, + rawlpdata * lp); +static int read_mps_refrow ( + ILLread_mps_state * state, + rawlpdata * lp); +static int read_mps_objnamesense ( + ILLmps_section sec, + ILLread_mps_state * state, + rawlpdata * lp); +static int read_mps_objname ( + ILLread_mps_state * state); +static int read_mps_objsense ( + ILLread_mps_state * state, + rawlpdata * lp); + +static int read_mps_line_in_section ( + ILLread_mps_state * state, + rawlpdata * lp); + + +static int add_row ( + ILLread_mps_state * state, + rawlpdata * lp); +static int add_col ( + ILLread_mps_state * state, + rawlpdata * lp); +static int add_rhs ( + ILLread_mps_state * state, + rawlpdata * lp); +static int add_ranges ( + ILLread_mps_state * state, + rawlpdata * lp); +static int add_bounds ( + ILLread_mps_state * state, + rawlpdata * lp); + +static int mps_read_marker_line ( + ILLread_mps_state * state, + rawlpdata * lp); +static int is_marker_line ( + ILLread_mps_state * state); +static int mps_read_col_line ( + ILLread_mps_state * state, + rawlpdata * lp); + +static int mps_fill_in ( + rawlpdata * lp, + const char *obj); + + +static void mps_set_bound ( + rawlpdata * lp, + ILLread_mps_state * state, + int colind, + const char *bndtype, + EGlpNum_t bnd); + +int ILLread_mps ( + qsline_reader * file, + const char *f, + rawlpdata * lp) +{ + int rval = 0; + int end = 0; + ILLread_mps_state state; + + ILL_IFTRACE ("\tread_mps\n"); + if (ILLsymboltab_create (&lp->rowtab, 100) || + ILLsymboltab_create (&lp->coltab, 100)) + { + rval = 1; + } + else + { + rval = ILLmps_state_init (&state, file, f); + } + if (rval != 0) + { + goto CLEANUP; + } + + while (ILLmps_next_line (&state) == 0) + { + if (ILLmps_empty_key (&state)) + { + if (read_mps_line_in_section (&state, lp) != 0) + { + rval++; + } + } + else + { + /* found a section indicator in col 1 */ + if (!strcmp (state.key, ILLmps_section_name[ILL_MPS_ENDATA])) + { + end = 1; + break; /* done reading */ + } + if (read_mps_section (&state, lp) != 0) + { + rval++; + } + } + if (rval == 50) + { + (void) ILLmps_error (&state, "Too many errors.\n"); + } + } + + if (!end) + { + ILLmps_warn (&state, "Missing ENDATA."); + } + if (!ILLmps_next_line (&state)) + { + ILLmps_warn (&state, "Ignoring text after ENDATA."); + } + if (rval == 0) + { + rval = mps_fill_in (lp, state.obj); + } + +CLEANUP: + ILL_RESULT (rval, "read_mps"); +} + +static int check_section_order ( + ILLread_mps_state * state, + int sec) +{ + switch (sec) + { + case ILL_MPS_REFROW: + if (state->section[ILL_MPS_ROWS] == 1) + { + return ILLmps_error (state, "%s section after ROWS section.\n", + ILLmps_section_name[sec]); + } + break; + + case ILL_MPS_COLS: + case ILL_MPS_RHS: + case ILL_MPS_RANGES: + if (state->section[ILL_MPS_ROWS] == 0) + { + return ILLmps_error (state, "%s section before ROWS section.\n", + ILLmps_section_name[sec]); + }; + break; + + case ILL_MPS_BOUNDS: + if (state->section[ILL_MPS_COLS] == 0) + { + return ILLmps_error (state, "%s section before COLUMNS section.\n", + ILLmps_section_name[sec]); + } + break; + } + return 0; +} + +static int read_mps_section ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int sec; + int rval = 0, r; + + ILL_FAILtrue (ILLmps_empty_key (state), "must have a key on this line"); + + sec = ILLutil_index (ILLmps_section_name, state->key); + if (sec < 0) + { + return ILLmps_error (state, "\"%s\" is not a key.\n", state->key); + } + rval = ILLmps_set_section (state, sec); + + state->active = ILL_MPS_NONE; + rval = rval || check_section_order (state, sec); + switch (sec) + { + case ILL_MPS_COLS: + case ILL_MPS_ROWS: + state->active = sec; + break; + + case ILL_MPS_NAME: + if (rval == 0) + { + rval = read_mps_name (state, lp); + } + break; + + case ILL_MPS_RHS: + if (rval == 0) + { + rval = ILLraw_init_rhs (lp); + } + state->active = ILL_MPS_RHS; + break; + + case ILL_MPS_RANGES: + if (rval == 0) + { + rval = ILLraw_init_ranges (lp); + } + state->active = ILL_MPS_RANGES; + break; + + case ILL_MPS_BOUNDS: + if (rval == 0) + { + rval = ILLraw_init_bounds (lp); + } + state->active = ILL_MPS_BOUNDS; + break; + + case ILL_MPS_OBJNAME: + case ILL_MPS_OBJSENSE: + r = read_mps_objnamesense (sec, state, lp); + rval = r || rval; + break; + + case ILL_MPS_REFROW: + r = read_mps_refrow (state, lp); + rval = r || rval; + break; + + default: + ILL_REPRT ("should never get here"); + goto CLEANUP; + } +CLEANUP: + ILL_RESULT (rval, "read_mps_section"); +} + +static int read_mps_name ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int rval = 0; + + if (ILLmps_empty_field (state)) + { + ILLmps_warn (state, "Blank NAME."); + } + else + { + ILL_UTIL_STR (lp->name, state->field); + } +CLEANUP: + ILL_RESULT (rval, "read_mps_name"); +} + +static int read_mps_refrow ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int rval = 0; + + rval = ILLmps_next_line (state); + if (state->section[ILL_MPS_REFROW] > 1) + { + /* this is the second time we see this section; + * don't complain about errors */ + return 0; + } + if (ILLmps_empty_key (state) && !ILLmps_empty_field (state)) + { + ILL_UTIL_STR (lp->refrow, state->field); + return 0; + } + else + { + return ILLmps_error (state, "Bad row name in REFROW section.\n"); + } +CLEANUP: + ILL_RETURN (rval, "read_mps_refrow"); +} + +static int read_mps_objnamesense ( + ILLmps_section sec, + ILLread_mps_state * state, + rawlpdata * lp) +{ + if (state->section[sec] > 1) + { + /* this is the second time we see this section; just skip next line */ + (void) ILLmps_next_line (state); + return 0; + } + if (ILLmps_next_line (state) != 0) + { + return ILLmps_error (state, "Missing %s line at end of file.\n", + ILLmps_section_name[sec]); + } + if ((!ILLmps_empty_key (state)) || ILLmps_empty_field (state)) + { + (void) ILLmps_error (state, "Bad %s in %s record.\n", + ((sec == ILL_MPS_OBJNAME) ? "row name" + : "objective sense"), ILLmps_section_name[sec]); + if (!ILLmps_empty_key (state)) + { + (void) read_mps_section (state, lp); + } + return 1; + } + if (sec == ILL_MPS_OBJNAME) + { + if (read_mps_objname (state)) + { + return 1; + } + } + else + { + if (read_mps_objsense (state, lp) != 0) + { + return 1; + } + } + return 0; +} + +static int read_mps_objsense ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int rval = 0; + char *objsense = state->field; + + ILL_FAILfalse (state->section[ILL_MPS_OBJSENSE] == 1, "should never happen"); + if (!strcmp (objsense, "MAX") || + !strcmp (objsense, "Max") || + !strcmp (objsense, "max") || + !strcmp (objsense, "MAXIMIZE") || + !strcmp (objsense, "Maximize") || !strcmp (objsense, "maximize")) + { + lp->objsense = ILL_MAX; + } + else if (!strcmp (objsense, "MIN") || + !strcmp (objsense, "Min") || + !strcmp (objsense, "min") || + !strcmp (objsense, "MINIMIZE") || + !strcmp (objsense, "Minimize") || !strcmp (objsense, "minimize")) + { + lp->objsense = ILL_MIN; + } + else + { + return ILLmps_error (state, "\"%s\" is no OBJSENSE.\n", objsense); + } +CLEANUP: + ILL_RESULT (rval, "read_mps_objsense"); +} + +static int read_mps_objname ( + ILLread_mps_state * state) +{ + int rval = 0; + + ILL_FAILfalse (state->section[ILL_MPS_OBJNAME] == 1, "should never happen"); + ILL_UTIL_STR (state->obj, state->field); +CLEANUP: + ILL_RETURN (rval, "read_mps_objname"); +} + +static int read_mps_line_in_section ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int rval = 0; + + ILL_FAILtrue (!ILLmps_empty_key (state) || ILLmps_empty_field (state), + "no key but at least one field on state->line"); + + if (state->active == ILL_MPS_NONE) + { + return ILLmps_error (state, "Line is in no section.\n"); + } + else + { + if (state->section[state->active] == 1) + { + switch (state->active) + { + case ILL_MPS_ROWS: + rval = add_row (state, lp); + break; + case ILL_MPS_COLS: + rval = add_col (state, lp); + break; + case ILL_MPS_RHS: + rval = add_rhs (state, lp); + break; + case ILL_MPS_RANGES: + rval = add_ranges (state, lp); + break; + case ILL_MPS_BOUNDS: + rval = add_bounds (state, lp); + break; + default: + ILL_REPRT ("should never get here"); + ILL_CLEANUP; + } + if (rval == 0) + { + /* see whether there are extra fields on line */ + ILLmps_check_end_of_line (state); + } + } + } +CLEANUP: + ILL_RESULT (rval, "read_mps_line_in_section"); +} + +static int add_row ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int ind, hit, rval = 0; + char sense; + + ILL_FAILtrue (!ILLmps_empty_key (state) || ILLmps_empty_field (state), + "no key but at least one field on state->line"); + + /* field should contain exactly one character */ + if (state->field[1] == '\0') + { + sense = state->field[0]; + if (sense != 'L' && sense != 'G' && sense != 'E' && sense != 'N') + { + return ILLmps_error (state, + "Unknown rowsense '%c' in ROWS record.\n", sense); + } + if (ILLmps_next_field (state) == 0) + { + hit = ILLsymboltab_lookup (&lp->rowtab, state->field, &ind); + if (!hit) + { + rval = ILLmps_error (state, + "Repeated row definition for \"%s\".\n", + state->field); + } + else + { + rval = ILLraw_add_row (lp, state->field, sense, zeroLpNum); /* default rhs is 0.0 */ + } + } + else + { + rval = ILLmps_error (state, "Missing rowname in ROWS record.\n"); + } + } + else + { + rval = ILLmps_error (state, "Unknown rowsense '%s' in ROWS record.\n", + state->field); + } +CLEANUP: + ILL_RESULT (rval, "add_row"); +} + +static int add_col ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int rval = 0; + + ILL_FAILtrue (!ILLmps_empty_key (state) || ILLmps_empty_field (state), + "no key but at least one field on state->line"); + + if (is_marker_line (state)) + { + return mps_read_marker_line (state, lp); + } + else + { + return mps_read_col_line (state, lp); + } +CLEANUP: + ILL_RETURN (rval, "add_col"); +} + +static int mps_read_col_line ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int hit, colind, rowind, rval = 0, more, ind; + EGlpNum_t ncoef; + + EGlpNumInitVar (ncoef); + + ILL_FAILtrue (!ILLmps_empty_key (state) || ILLmps_empty_field (state), + "no key but at least one field on state->line"); + + hit = ILLsymboltab_lookup (&lp->coltab, state->field, &colind); + if (hit) + { + rval = ILLraw_add_col (lp, state->field, state->intvar); + ILL_CLEANUP_IF (rval); + colind = lp->ncols - 1; + } + else + { + if (state->intvar) + { + /*previously declared variable is in integer section */ + lp->intmarker[colind] = 1; + } + } +#ifndef NDEBUG + hit = ILLsymboltab_lookup (&lp->coltab, state->field, &ind); + ILL_FAILfalse (colind == ind, "colind should be index of state->field"); +#endif + if (state->sosvar == 1) + { + if (ILLraw_is_mem_other_sos (lp, colind)) + { + rval = ILLmps_error (state, + "\"%s\" is a member of SOS set #%d.\n", + ILLraw_colname (lp, colind), + lp->is_sos_member[colind] + 1); + } + else + { + rval = ILLraw_add_sos_member (lp, colind); + } + ILL_CLEANUP_IF (rval); + } + + more = (ILLmps_next_field (state) == 0); + if (!more) + { + return ILLmps_error (state, "Missing fields in COLUMNS record.\n"); + } + for (more = 1; more; more = (ILLmps_next_field (state) == 0)) + { + hit = ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind); + if (hit) + { + return ILLmps_error (state, "\"%s\" is not a row name.\n", state->field); + } + if (ILLmps_next_coef (state, &ncoef) != 0) + { + return ILLmps_error (state, + "Missing/Bad coefficient in COLUMNS record.\n"); + } + rval = ILLraw_add_col_coef (lp, colind, rowind, ncoef); + } +CLEANUP: + EGlpNumClearVar (ncoef); + ILL_RESULT (rval, "mps_read_col_line"); +} + +static int is_marker_line ( + ILLread_mps_state * state) +{ + const char *field = state->line; + + while ((field = ILLutil_strchr (field, '\''))) + { + if (strncmp (field, "'MARKER'", (size_t) 8) == 0) + { + return 1; + } + while ((!ILL_ISBLANK (field)) && (*field != '\0')) + { + field++; + } + } + return 0; +} + +static int mps_read_marker_line ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int rval = 0; + int sos_type = ILL_SOS_TYPE1; + int sos_line = 0; + int cur_sos_mode = state->sosvar; + + if (strcmp (state->field, "S2") == 0) + { + sos_type = ILL_SOS_TYPE2; + sos_line = 1; + } + else if (strcmp (state->field, "S1") == 0) + { + sos_line = 1; + } + if (sos_line) + { + rval = ILLmps_next_field (state); + } + rval = rval || ILLmps_next_field (state); /* swallow marker-id */ + if (strcmp (state->field, "'MARKER'")) + { + return ILLmps_error (state, "Bad 'MARKER' line.\n"); + } + if (ILLmps_next_field (state)) + { + return ILLmps_error (state, "Missing field on 'MARKER' line.\n"); + } + rval = ILLmps_int_sos_mode (state); + if (rval == 0) + { + if (cur_sos_mode != state->sosvar) + { + if (state->sosvar) + { + /* beginning of a new set */ + rval = ILLraw_add_sos (lp, sos_type); + } + } + } + ILL_RESULT (rval, "mps_read_marker_line"); +} + +static int add_rhs ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + int rowind, more_fields, skip; + const char *rhsname; + EGlpNum_t rhs; + + EGlpNumInitVar (rhs); + + rhsname = ILLmps_possibly_blank_name (state->field, state, &lp->rowtab); + if (ILLraw_set_rhs_name (lp, rhsname, &skip)) + { + ILLmps_error (state, "Could not add right hand side.\n"); + } + + if (skip) + { + ILLmps_set_end_of_line (state); /* to avoid warning about extra fields */ + } + else + { + if (strcmp (rhsname, " ")) + { + /* field is non blank rhs name; advance to row name */ + if (ILLmps_next_field (state)) + { + return ILLmps_error (state, "Missing row name in RHS record.\n"); + } + } + for (more_fields = 1; more_fields; more_fields = !ILLmps_next_field (state)) + { + if (ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind)) + { + return ILLmps_error (state, "\"%s\" is not a row name.\n", + state->field); + } + if (ILLmps_next_coef (state, &rhs)) + { + return ILLmps_error (state, "Missing/Bad coefficient in RHS record.\n"); + } + if (lp->rhsind[rowind]) + { + return ILLmps_error (state, "Two rhs values for row \"%s\".\n", + state->field); + } + else + { + if (lp->rowsense[rowind] == 'N') + { + ILLmps_warn (state, + "Ignoring right hand side for N-row \"%s\".", + ILLraw_rowname (lp, rowind)); + } + else + { + EGlpNumCopy (lp->rhs[rowind], rhs); + lp->rhsind[rowind] = 1; + } + } + } + } + EGlpNumClearVar (rhs); + return 0; +} + +static int add_bounds ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + char bndtype[3]; + const char *bounds_name; + int colind, skip, rval = 0; + EGlpNum_t bnd; + + EGlpNumInitVar (bnd); + + ILL_FAILtrue (!ILLmps_empty_key (state) || ILLmps_empty_field (state), + "no key but at least one field on state->line"); + + if (ILLutil_index (mps_bound_name, state->field) < 0) + { + return ILLmps_error (state, "\"%s\" is not a BOUNDS type.\n", state->field); + } + strcpy (bndtype, state->field); + + if (ILLmps_next_field (state) != 0) + { + return ILLmps_error (state, + "No bounds/column identifier in BOUNDS record.\n"); + } + + bounds_name = ILLmps_possibly_blank_name (state->field, state, &lp->coltab); + if (bounds_name == NULL) + { + return 1; + } + if (ILLraw_set_bounds_name (lp, bounds_name, &skip)) + { + return 1; + } + if (skip) + { + ILLmps_set_end_of_line (state); /* to avoid warning about extra fields */ + } + else + { + if (strcmp (bounds_name, " ")) + { + /* non empty bounds_name ==> advance to col name field */ + if (ILLmps_next_field (state)) + { + return ILLmps_error (state, "Missing column field in BOUNDS record.\n"); + } + } + if (ILLsymboltab_lookup (&lp->coltab, state->field, &colind)) + { + return ILLmps_error (state, "\"%s\" is not a column name.\n", + state->field); + } + EGlpNumZero (bnd); + if (strcmp (bndtype, "FR") && strcmp (bndtype, "BV") && + strcmp (bndtype, "MI") && strcmp (bndtype, "PL")) + { + /* neither "FR", "BV", "MI" nor "PL" ==> there should be a bound */ + if (ILLmps_next_bound (state, &bnd)) + { + return ILLmps_error (state, + "Missing/Bad bound field in BOUNDS record.\n"); + } + } + mps_set_bound (lp, state, colind, bndtype, bnd); + } +CLEANUP: + EGlpNumClearVar (bnd); + ILL_RESULT (rval, "add_bounds"); +} + +static void mps_set_bound ( + rawlpdata * lp, + ILLread_mps_state * state, + int colind, + const char *bndtype, + EGlpNum_t bnd) +{ + const char *msg = NULL; + + if (!strcmp (bndtype, "LO")) + { + msg = ILLraw_set_lowerBound (lp, colind, bnd); + } + else if (!strcmp (bndtype, "UP")) + { + msg = ILLraw_set_upperBound (lp, colind, bnd); + } + else if (!strcmp (bndtype, "FX")) + { + msg = ILLraw_set_fixedBound (lp, colind, bnd); + } + else if (!strcmp (bndtype, "FR")) + { + msg = ILLraw_set_unbound (lp, colind); + } + else if (!strcmp (bndtype, "BV")) + { + msg = ILLraw_set_binaryBound (lp, colind); + if (msg == NULL) + { + lp->intmarker[colind] = 1; + } + } + else if (!strcmp (bndtype, "UI")) + { + msg = ILLraw_set_upperBound (lp, colind, bnd); + if (msg == NULL) + { + lp->intmarker[colind] = 1; + } + } + else if (!strcmp (bndtype, "LI")) + { + msg = ILLraw_set_lowerBound (lp, colind, bnd); + if (msg == NULL) + { + lp->intmarker[colind] = 1; + } + } + else if (!strcmp (bndtype, "MI")) + { + msg = ILLraw_set_lowerBound (lp, colind, ILL_MINDOUBLE); + } + else if (!strcmp (bndtype, "PL")) + { + msg = ILLraw_set_upperBound (lp, colind, ILL_MAXDOUBLE); + } + else + { + ILL_REPRT ("should never get here"); + ILL_CLEANUP; + } + ILLmps_warn (state, msg); +CLEANUP: + return; +} + +static int add_ranges ( + ILLread_mps_state * state, + rawlpdata * lp) +{ + const char *rangesname; + int skip, more_fields, rowind; + EGlpNum_t ntmp; + + EGlpNumInitVar (ntmp); + + rangesname = ILLmps_possibly_blank_name (state->field, state, &lp->rowtab); + if (ILLraw_set_ranges_name (lp, rangesname, &skip)) + { + return ILLmps_error (state, "Could not add range.\n"); + } + if (skip) + { + ILLmps_set_end_of_line (state); /* to avoid warning about extra fields */ + } + else + { + if (strcmp (rangesname, " ")) + { + /* field is non blank ranges name; advance to row name */ + if (ILLmps_next_field (state)) + { + return ILLmps_error (state, "Missing row name in RANGES record."); + } + } + for (more_fields = 1; more_fields; more_fields = !ILLmps_next_field (state)) + { + if (ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind)) + { + return ILLmps_error (state, "\"%s\" is not a row name.\n", + state->field); + } + if (ILLmps_next_coef (state, &ntmp)) + { + return ILLmps_error (state, + "Missing/Bad coefficient in RANGES record.\n"); + } + if (lp->rangesind[rowind]) + { + ILLmps_warn (state, "Ignoring second RANGE value %s \"%s\".", + "for row", ILLraw_rowname (lp, rowind)); + } + else + { + if (lp->rowsense[rowind] != 'N') + { + if (ILLraw_add_ranges_coef (lp, rowind, ntmp)) + return 1; + } + else + { + ILLmps_warn (state, "Ignoring RANGE value for N-row \"%s\".", + ILLraw_rowname (lp, rowind)); + } + } + } + } + EGlpNumClearVar (ntmp); + return 0; +} + + +static int mps_fill_in ( + rawlpdata * lp, + const char *obj) +{ + int i, hit, rval = 0; + + /* find the objective function -- the first N row if obj is not defined */ + if (obj) + { + hit = ILLsymboltab_lookup (&lp->rowtab, obj, &lp->objindex); + if (hit) + { + return ILLdata_error (lp->error_collector, + "Bad objective name \"%s\".\n", obj); + } + else if (lp->rowsense[lp->objindex] != 'N') + { + ILLdata_warn (lp->error_collector, + "Making objective row \"%s\" a N-row.", obj); + } + lp->rowsense[lp->objindex] = 'N'; + } + else + { + for (i = 0; i < lp->nrows; i++) + { + if (lp->rowsense[i] == 'N') + { + lp->objindex = i; + break; + } + } + if (i == lp->nrows) + { + return ILLdata_error (lp->error_collector, + "No N-row in lp definition.\n"); + } + } + + if (lp->ncols > 0) + { + rval = ILLraw_fill_in_bounds (lp); + } + + /* set weights of sos set members */ + if (lp->refrow) + { + /* take the values from refrow */ + EGlpNum_t weight; + colptr *cp; + + EGlpNumInitVar (weight); + + hit = ILLsymboltab_lookup (&lp->rowtab, lp->refrow, &lp->refrowind); + if (hit) + { + return ILLdata_error (lp->error_collector, + "REFROW \"%s\" is not a row name.\n", lp->refrow); + } + for (i = 0; i < lp->nsos_member; i++) + { + for (cp = lp->cols[lp->sos_col[i]]; cp != NULL; cp = cp->next) + { + if (cp->this_val == lp->refrowind) + break; + } + if ((cp != NULL) && EGlpNumIsNeqqZero (cp->coef)) + { + EGlpNumCopy (weight, cp->coef); + } + else + { + ILLdata_warn (lp->error_collector, + "\"%s\" has 0.0 coefficient in REFROW \"%s\".", + ILLraw_colname (lp, lp->sos_col[i]), lp->refrow); + EGlpNumZero (weight); + } + EGlpNumCopy (lp->sos_weight[i], weight); + } + EGlpNumClearVar (weight); + } + else + { /* no refrow */ + /* set weights to 1, 2, 3, ... in order of definition */ + int si, w; + sosptr *set; + + for (si = 0; si < lp->nsos; si++) + { + set = lp->sos_set + si; + w = 1; + for (i = set->first; i < set->first + set->nelem; i++) + { + EGlpNumSet (lp->sos_weight[i], (double) w); + w++; + } + } + } + ILL_IFTRACE ("bound %lf <= x1 <= %lf\n", EGlpNumToLf (lp->lower[0]), + EGlpNumToLf (lp->upper[0])); + ILL_IFTRACE ("MAXDOUBLE %lf MINDOUBLE %lf\n", EGlpNumToLf (ILL_MAXDOUBLE), + EGlpNumToLf (ILL_MINDOUBLE)); + ILL_RESULT (rval, "mps_fill_in"); +} + +/****************************************************************************/ +/* writing + */ + +static int mps_write_col ( + int i, + int iorig, + char *colname, + ILLlpdata * lp, + char **rownames, + int intmode, + char *objname); + +int ILLwrite_mps ( + ILLlpdata * lp, + qserror_collector * collector) +{ + int rval = 0; + int marker = 0; + int intmode = 0; + int i, ri, set, el, empty, prtLower, prtUpper; + char **colnames = (char **) NULL; + char **rownames = (char **) NULL; + ILLlp_rows lp_rows, *lprows = NULL; + char buf[ILL_namebufsize]; + char *objname = NULL; + char *str; + + ILL_CHECKnull (lp, "lp must not be null"); + ILL_FAILtrue (lp->probname == NULL, "oops should never happen"); + + ILL_FAILfalse (lp->colnames != NULL, "colnames != NULL"); + ILL_FAILfalse (lp->rownames != NULL, "colnames != NULL"); + colnames = lp->colnames; + rownames = lp->rownames; + + objname = lp->objname; + if (objname == (char *) NULL) + { + strcpy (buf, "obj"); + rval = ILLsymboltab_uname (&lp->rowtab, buf, "", NULL); + ILL_CLEANUP_IF (rval); + ILL_UTIL_STR (objname, buf); + } + ILLprint_report (lp, "NAME %s\n", lp->probname); + ILLprint_report (lp, "OBJSENSE\n %s\n", + (lp->objsense == ILL_MIN) ? "MIN" : "MAX"); + ILLprint_report (lp, "OBJNAME\n %s\n", objname); + if (lp->refrowname) + { + ILLprint_report (lp, "REFROW\n"); + ILLprint_report (lp, " %s\n", lp->refrowname); + } + + + ILLprint_report (lp, "ROWS\n"); + ILLprint_report (lp, " N %s\n", objname); + if (lp->refrowname && (lp->refind == -1)) + { + ILLprint_report (lp, " N %s\n", lp->refrowname); + } + + lprows = &lp_rows; + rval = ILLlp_rows_init (lprows, lp, 0); + ILL_CLEANUP_IF (rval); + for (i = 0; i < lp->nrows; i++) + { + if (lprows->rowcnt[i] == 0) + { + ILLdata_warn (collector, + "Deleting empty row \"%s\" from constraints.", rownames[i]); + continue; + } + switch (lp->sense[i]) + { + case 'G': + ILLprint_report (lp, " G "); + break; + case 'L': + ILLprint_report (lp, " L "); + break; + case 'E': + ILLprint_report (lp, " E "); + break; + case 'R': + ILLprint_report (lp, " G "); + break; + } + ILLprint_report (lp, "%s\n", rownames[i]); + } + + ILLprint_report (lp, "COLUMNS\n"); + for (set = 0; set < lp->sos.matcols; set++) + { + ILL_FAILtrue (lp->sos_type == NULL, "must have non NULL sos_type"); + ILL_FAILtrue (lp->is_sos_mem == NULL, "must have non NULL is_sos_mem"); + empty = 1; + for (el = lp->sos.matbeg[set]; + el < lp->sos.matbeg[set] + lp->sos.matcnt[set]; el++) + { + if (empty) + { + ILLprint_report (lp, " %s SOS%dqs 'MARKER' 'SOSORG'\n", + ((lp->sos_type[set] == ILL_SOS_TYPE1)) ? "S1" : "S2", + marker++); + empty = 0; + } + ri = lp->sos.matind[el]; + i = lp->structmap[ri]; + intmode = mps_write_col (i, ri, colnames[ri], lp, rownames, + intmode, objname); + if (lp->refrowname && (lp->refind == -1)) + { + ILLprint_report (lp, " %s %s %g\n", + colnames[ri], lp->refrowname, lp->sos.matval[el]); + } + } + if (!empty) + { + ILLprint_report (lp, " SOS%dqs 'MARKER' 'SOSEND'\n", marker++); + } + } + for (ri = 0; ri < lp->nstruct; ri++) + { + if (lp->is_sos_mem == (int *) NULL || lp->is_sos_mem[ri] == -1) + { + i = lp->structmap[ri]; + intmode = mps_write_col (i, ri, colnames[ri], lp, rownames, + intmode, objname); + } + } + if (intmode) + { + ILLprint_report (lp, " MARK%dqs 'MARKER' 'INTEND'\n", lp->nstruct); + } + + ILLprint_report (lp, "RHS\n"); + for (i = 0; i < lp->nrows; i++) + { + if ((lprows->rowcnt[i] != 0) && EGlpNumIsNeqqZero (lp->rhs[i])) + { + str = EGlpNumGetStr(lp->rhs[i]); + ILLprint_report (lp, " RHS %s %s\n", rownames[i], str); + EGfree(str); + } + } + + if (lp->rangeval) + { + ILLprint_report (lp, "RANGES\n"); + for (i = 0; i < lp->nrows; i++) + { + if ((lprows->rowcnt[i] != 0) && EGlpNumIsNeqqZero (lp->rangeval[i])) + { + str = EGlpNumGetStr(lp->rangeval[i]); + ILLprint_report (lp, " RANGE %s %s\n", rownames[i], str); + EGfree(str); + } + } + } + + ri = ILLraw_first_nondefault_bound (lp); + if (ri != lp->nstruct) + { + ILLprint_report (lp, "BOUNDS\n"); + for (ri = ri; ri < lp->nstruct; ri++) + { + i = lp->structmap[ri]; + if (EGlpNumIsEqqual (lp->lower[i], lp->upper[i])) + { + str = EGlpNumGetStr(lp->lower[i]); + ILLprint_report (lp, " FX BOUND %s %s\n", colnames[ri], str); + EGfree(str); + continue; + } + if ((EGlpNumIsEqqual (lp->lower[i], ILL_MINDOUBLE)) && + (EGlpNumIsEqqual (lp->upper[i], ILL_MAXDOUBLE))) + { + ILLprint_report (lp, " FR BOUND %s\n", colnames[ri]); + continue; + } + prtLower = !ILLraw_default_lower (lp, i); + prtUpper = !ILLraw_default_upper (lp, i, ri); + if (prtLower) + { + if (EGlpNumIsEqqual (lp->lower[i], ILL_MINDOUBLE)) + { + ILLprint_report (lp, " MI BOUND %s\n", colnames[ri]); + } + else + { + str = EGlpNumGetStr(lp->lower[i]); + ILLprint_report (lp, " LO BOUND %s %s\n", colnames[ri], str); + EGfree(str); + } + } + if (prtUpper) + { + if (EGlpNumIsEqqual (lp->upper[i], ILL_MAXDOUBLE)) + { + ILLprint_report (lp, " PL BOUND %s\n", colnames[ri]); + } + else + { + str = EGlpNumGetStr(lp->upper[i]); + ILLprint_report (lp, " UP BOUND %s %s\n", colnames[ri], str); + EGfree(str); + } + } + } + } + ILLprint_report (lp, "ENDATA\n"); + +CLEANUP: + ILLlp_rows_clear (lprows); + if (!lp->colnames) + { + ILLfree_names (colnames, lp->ncols); + } + if (!lp->rownames) + { + ILLfree_names (rownames, lp->nrows); + } + if (objname != lp->objname) + { + ILL_IFFREE (objname, char); + } + ILL_RESULT (rval, "ILLlpdata_mpswrite"); +} + +static int mps_write_col ( + int i, + int iorig, + char *colname, + ILLlpdata * lp, + char **rownames, + int intmode, + char *objname) +{ + int row, k; + char*str; + ILLmatrix *A; + + A = &lp->A; + if (lp->intmarker && (lp->intmarker[iorig] != intmode)) + { + ILLprint_report (lp, " MARK%dqs 'MARKER' '%s'\n", iorig, + (lp->intmarker[iorig] ? "INTORG" : "INTEND")); + intmode = lp->intmarker[iorig]; + } + if (EGlpNumIsNeqqZero (lp->obj[i])) + { + str = EGlpNumGetStr(lp->obj[i]); + ILLprint_report (lp, " %s %s %s\n", colname, objname, str); + EGfree(str); + } + for (k = A->matbeg[i]; k < A->matbeg[i] + A->matcnt[i]; k++) + { + row = A->matind[k]; + str = EGlpNumGetStr(A->matval[k]); + ILLprint_report (lp, " %s %s %s\n", colname, rownames[row], str); + EGfree(str); + } + return intmode; +} diff --git a/src/mps.h b/src/mps.h new file mode 100644 index 0000000..cd90411 --- /dev/null +++ b/src/mps.h @@ -0,0 +1,53 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: mps.h,v 1.2 2003/11/05 16:57:39 meven Exp $ */ +#ifndef MPS_H +#define MPS_H + +#include "readline.h" +#include "format.h" + +/****************************************************************************/ +/* */ +/* Routines to support Reading and Writing MPS Files */ +/* */ +/****************************************************************************/ +#include "basicdefs.h" +extern const char *ILLmps_section_name[ILL_MPS_N_SECTIONS + 2]; + +#include "lpdata.h" +#include "rawlp.h" +#include "read_mps.h" + +extern int ILLread_mps ( + qsline_reader * file, + const char *filename, + rawlpdata * lp); + +extern int ILLwrite_mps ( + ILLlpdata * lp, + qserror_collector * collector); + + /* use lp->reporter for output */ + +#endif diff --git a/src/names.c b/src/names.c new file mode 100644 index 0000000..a74a9f0 --- /dev/null +++ b/src/names.c @@ -0,0 +1,97 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: names.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +#include "names.h" +#include "util.h" +#include "except.h" +#include "symtab.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +void ILLfree_names ( + char **names, + int count) +{ + int i; + + if (names) + { + for (i = 0; i < count; i++) + { + ILL_IFFREE (names[i], char); + } + ILL_IFFREE (names, char *); + } +} + +int ILLgenerate_names ( + char prefix, + int nnames, + char ***names) +{ + int rval = 0; + int i, len; + char *buf = (char *) NULL; + + *names = (char **) NULL; + if (nnames == 0) + goto CLEANUP; + + ILL_SAFE_MALLOC (buf, ILL_namebufsize, char); + ILL_SAFE_MALLOC (*names, nnames, char *); + + for (i = 0; i < nnames; i++) + { + (*names)[i] = (char *) NULL; + } + + for (i = 0; i < nnames; i++) + { + sprintf (buf, "%c%d", prefix, i); + len = strlen (buf) + 1; + ILL_SAFE_MALLOC ((*names)[i], len, char); + + strcpy ((*names)[i], buf); + } + +CLEANUP: + + if (rval) + { + if (*names) + { + ILLfree_names (*names, nnames); + *names = (char **) NULL; + } + } + + ILL_IFFREE (buf, char); + + if (rval) + { + fprintf (stderr, "ILLsymboltab_generate_names failed\n"); + } + return rval; +} diff --git a/src/names.h b/src/names.h new file mode 100644 index 0000000..d065f7b --- /dev/null +++ b/src/names.h @@ -0,0 +1,35 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: names.h,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +#ifndef ILL_NAMES_H +#define ILL_NAMES_H + +extern void ILLfree_names ( + char **names, + int count); +extern int ILLgenerate_names ( + char prefix, + int nnames, + char ***names); + +#endif diff --git a/src/presolve.c b/src/presolve.c new file mode 100644 index 0000000..92ca20f --- /dev/null +++ b/src/presolve.c @@ -0,0 +1,2677 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: presolve.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +static int TRACE = 0; + +/****************************************************************************/ +/* */ +/* Presolve Routine for Simplex Method */ +/* */ +/* EXPORTED FUNCTIONS */ +/* */ +/* int ILLlp_add_logicals (ILLlpata *lp) */ +/* int ILLlp_presolve (ILLlpdata *lp) */ +/* int ILLlp_scale (ILLlpdata *lp) */ +/* void ILLlp_sinfo_init (ILLlp_sinfo *sinfo) */ +/* void ILLlp_sinfo_free (ILLlp_sinfo *sinfo) */ +/* void ILLlp_predata_init (ILLlp_predata *pre) */ +/* void ILLlp_predata_free (ILLlp_predata *pre) */ +/* */ +/* NOTES */ +/* */ +/* presolve will assume that logicals have been added. */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "iqsutil.h" +#include "lpdata.h" +#include "lpdefs.h" +//extern EGlpNum_t SZERO_TOLER; + +#define ILL_LP_STATUS_OK (0) +#define ILL_PRE_FEAS_TOL PFEAS_TOLER //(1e-6) +#define ILL_PRE_ZERO_TOL PIVOT_TOLER //(1e-10) + +#define ILL_PRE_DELETE_EMPTY_ROW (1) +#define ILL_PRE_DELETE_SINGLETON_ROW (2) +#define ILL_PRE_DELETE_FIXED_VARIABLE (3) +#define ILL_PRE_DELETE_FORCED_VARIABLE (4) +#define ILL_PRE_DELETE_SINGLETON_VARIABLE (5) +#define ILL_PRE_DELETE_FREE_SINGLETON_VARIABLE (6) +#define ILL_PRE_DELETE_EMPTY_COLUMN (7) + +#define ILL_PRE_COL_STRUC (0) +#define ILL_PRE_COL_LOGICAL (1) + +static int debug = 0; + +typedef struct +{ + int row; + int col; + char coltype; + char mark; + char del; + EGlpNum_t coef; +} +edge; + +typedef struct node +{ + edge **adj; + EGlpNum_t obj; + EGlpNum_t lower; + EGlpNum_t upper; + EGlpNum_t rhs; + int deg; + char mark; + char del; + char coltype; + char rowsense; +} +node; + +typedef struct intptr +{ + int this_val; + struct intptr *next; +} +intptr; + +typedef struct graph +{ + edge *edgelist; + struct node *rows; + struct node *cols; + int ecount; + int nrows; + int ncols; + int nzcount; + edge **adjspace; + ILLptrworld intptrworld; + int objsense; +} +graph; + +void ILLlp_sinfo_init ( + ILLlp_sinfo * sinfo), + ILLlp_sinfo_free ( + ILLlp_sinfo * sinfo), + ILLlp_predata_init ( + ILLlp_predata * pre), + ILLlp_predata_free ( + ILLlp_predata * pre), + ILLlp_preop_init ( + ILLlp_preop * op), + ILLlp_preop_free ( + ILLlp_preop * op), + ILLlp_preline_init ( + ILLlp_preline * line), + ILLlp_preline_free ( + ILLlp_preline * line); + +int ILLlp_sinfo_print ( + ILLlp_sinfo * s); + +static void set_fixed_variable ( + graph * G, + int j, + EGlpNum_t val), + get_implied_rhs_bounds ( + graph * G, + int i, + EGlpNum_t * lb, + EGlpNum_t * ub), + get_implied_variable_bounds ( + graph * G, + int j, + edge * a_ij, + EGlpNum_t * lb, + EGlpNum_t * ub), + dump_line ( + ILLlp_preline * line), + init_graph ( + graph * G), + free_graph ( + graph * G), + dump_graph ( + graph * G); + +static int simple_presolve ( + ILLlpdata * lp, + ILLlp_predata * pre, + ILLlp_sinfo * info, + int pre_types, + int *status), + grab_lp_line ( + graph * G, + int indx, + ILLlp_preline * line, + int row_or_col), + grab_lp_info ( + graph * G, + char **colnames, + ILLlp_sinfo * info), + fixed_variables ( + graph * G, + ILLlp_predata * pre), + empty_columns ( + graph * G, + ILLlp_predata * pre), + singleton_rows ( + graph * G, + ILLlp_predata * pre, + int *hit), + forcing_constraints ( + graph * G, + ILLlp_predata * pre, + int *hit), + singleton_columns ( + graph * G, + ILLlp_predata * pre, + int *hit), + duplicate_rows ( + graph * G, + int *hit), + duplicate_cols ( + graph * G, + int *hit), + gather_dup_lists ( + int *s, + int count, + int *duptotal, + int **dupcnt, + int **dupind), + get_next_preop ( + ILLlp_predata * pre, + ILLlp_preop ** op), + add_to_list ( + ILLptrworld * world, + intptr ** list, + int i), + build_graph ( + ILLlpdata * lp, + graph * G); + + +ILL_PTRWORLD_ROUTINES (intptr, intptralloc, intptr_bulkalloc, intptrfree) +ILL_PTRWORLD_LISTFREE_ROUTINE (intptr, intptr_listfree, intptrfree) +ILL_PTRWORLD_LEAKS_ROUTINE (intptr, intptr_check_leaks, this_val, int) + int ILLlp_add_logicals ( + ILLlpdata * lp) +{ + int rval = 0; + int ncols, nrows, nzcount, i, aindex; + char *sense; + ILLmatrix *A; + + if (!lp) + { + fprintf (stderr, "ILLlp_add_logicals called with a NULL pointer\n"); + rval = 1; + goto CLEANUP; + } + + printf ("ILLlp_add_logicals ...\n"); + fflush (stdout); + + A = &lp->A; + sense = lp->sense; + ncols = lp->ncols; + nrows = lp->nrows; + nzcount = lp->nzcount; + + if (nrows == 0) + goto CLEANUP; + EGlpNumReallocArray (&(lp->obj), lp->colsize + nrows); + EGlpNumReallocArray (&(lp->upper), lp->colsize + nrows); + EGlpNumReallocArray (&(lp->lower), lp->colsize + nrows); + lp->colnames = + EGrealloc (lp->colnames, sizeof (char *) * (lp->colsize + nrows)); + //rval = ILLutil_reallocrus_count ((void **) &(lp->colnames), + // lp->colsize + nrows, sizeof (char *)); + //ILL_CLEANUP_IF (rval); + memset (lp->colnames + ncols, 0, sizeof (char *) * nrows); + + ILL_SAFE_MALLOC (lp->rowmap, lp->rowsize, int); + + + A->matcnt = EGrealloc (A->matcnt, sizeof (int) * (A->matcolsize + nrows)); + //rval = ILLutil_reallocrus_count ((void **) &(A->matcnt), + // A->matcolsize + nrows, sizeof (int)); + //ILL_CLEANUP_IF (rval); + + A->matbeg = EGrealloc (A->matbeg, sizeof (int) * (A->matcolsize + nrows)); + //rval = ILLutil_reallocrus_count ((void **) &(A->matbeg), + // A->matcolsize + nrows, sizeof (int)); + //ILL_CLEANUP_IF (rval); + + A->matind = EGrealloc (A->matind, sizeof (int) * (A->matsize + nrows)); + //rval = ILLutil_reallocrus_count ((void **) &(A->matind), + // A->matsize + nrows, sizeof (int)); + //ILL_CLEANUP_IF (rval); + EGlpNumReallocArray (&(A->matval), A->matsize + nrows); + + for (i = 0; i < nrows; i++) + { + A->matind[A->matsize + i] = -1; + } + + aindex = A->matsize - A->matfree; + + for (i = 0; i < nrows; i++) + { + lp->rowmap[i] = ncols; + EGlpNumZero (lp->obj[ncols]); + A->matcnt[ncols] = 1; + A->matbeg[ncols] = aindex; + A->matind[aindex] = i; + switch (sense[i]) + { + case 'E': /* Arificial */ + EGlpNumZero (lp->lower[ncols]); + EGlpNumZero (lp->upper[ncols]); + EGlpNumOne (A->matval[aindex]); + break; + case 'G': /* Surplus */ + EGlpNumZero (lp->lower[ncols]); + EGlpNumCopy (lp->upper[ncols], ILL_MAXDOUBLE); + EGlpNumOne (A->matval[aindex]); + EGlpNumSign (A->matval[aindex]); + break; + case 'L': /* Slack */ + EGlpNumZero (lp->lower[ncols]); + EGlpNumCopy (lp->upper[ncols], ILL_MAXDOUBLE); + EGlpNumOne (A->matval[aindex]); + break; + case 'R': /* Range */ + EGlpNumZero (lp->lower[ncols]); + EGlpNumCopy (lp->upper[ncols], lp->rangeval[i]); + EGlpNumOne (A->matval[aindex]); + EGlpNumSign (A->matval[aindex]); + break; + default: + fprintf (stderr, "unknown sense %c in ILLlp_add_logicals\n", sense[i]); + rval = 1; + goto CLEANUP; + } + ncols++; + nzcount++; + aindex++; + } + + lp->ncols = ncols; + lp->nzcount = nzcount; + A->matcols = ncols; + + lp->colsize += nrows; + A->matsize += nrows; + A->matcolsize += nrows; + + if (lp->rA) + { + ILLlp_rows_clear (lp->rA); + } + else + { + ILL_SAFE_MALLOC (lp->rA, 1, ILLlp_rows); + } + + rval = ILLlp_rows_init (lp->rA, lp, 1); + ILL_CLEANUP_IF (rval); + +CLEANUP: + + ILL_RETURN (rval, "ILLlp_add_logicals"); +} + +int ILLlp_scale ( + ILLlpdata * lp) +{ + int rval = 0; + int i, j, k, col, row, nstruct, start, stop; + ILLmatrix *A; + EGlpNum_t rho; + EGlpNum_t *gama = 0; + + EGlpNumInitVar (rho); + + /* Columns - divide by largest absolute value */ + + if (!lp) + { + ILL_ERROR (rval, "ILLlp_scale called with a NULL pointer"); + } + + if (lp->nrows == 0 || lp->ncols == 0) + goto CLEANUP; + + A = &lp->A; + nstruct = lp->nstruct; + + for (j = 0; j < nstruct; j++) + { + col = lp->structmap[j]; + EGlpNumZero (rho); + + start = A->matbeg[col]; + stop = start + A->matcnt[col]; + + for (k = start; k < stop; k++) + { + EGlpNumSetToMaxAbs (rho, A->matval[k]); + } + + if (EGlpNumIsGreatZero (rho)) + { + for (k = start; k < stop; k++) + { + EGlpNumDivTo (A->matval[k], rho); + } + EGlpNumDivTo (lp->obj[col], rho); + if (EGlpNumIsNeqq (lp->lower[col], ILL_MINDOUBLE)) + EGlpNumMultTo (lp->lower[col], rho); + if (EGlpNumIsNeqq (lp->upper[col], ILL_MAXDOUBLE)) + EGlpNumMultTo (lp->upper[col], rho); + } + } + + gama = EGlpNumAllocArray (lp->nrows); + for (i = 0; i < lp->nrows; i++) + { + EGlpNumZero (gama[i]); + } + + for (j = 0; j < nstruct; j++) + { + col = lp->structmap[j]; + start = A->matbeg[col]; + stop = start + A->matcnt[col]; + + for (k = start; k < stop; k++) + { + row = A->matind[k]; + EGlpNumSetToMaxAbs (gama[row], A->matval[k]); + } + } + + for (j = 0; j < nstruct; j++) + { + col = lp->structmap[j]; + start = A->matbeg[col]; + stop = start + A->matcnt[col]; + + for (k = start; k < stop; k++) + { + row = A->matind[k]; + if (EGlpNumIsGreatZero (gama[row])) + { + EGlpNumDivTo (A->matval[k], gama[row]); + } + } + } + + for (i = 0; i < lp->nrows; i++) + { + if (EGlpNumIsGreatZero ( gama[i])) + { + EGlpNumDivTo (lp->rhs[i], gama[i]); + col = lp->rowmap[i]; + if (EGlpNumIsNeqq (lp->upper[col], ILL_MAXDOUBLE)) + { + EGlpNumDivTo (lp->upper[col], gama[i]); /* Ranged row */ + } + } + } + + if (lp->rA) + { /* Need to clear the row version of data */ + ILLlp_rows_clear (lp->rA); + ILL_IFFREE (lp->rA, ILLlp_rows); + } + + +CLEANUP: + + EGlpNumClearVar (rho); + EGlpNumFreeArray (gama); + ILL_RETURN (rval, "ILLlp_scale"); +} + +int ILLlp_presolve ( + ILLlpdata * lp, + int pre_types) +{ + int rval = 0; + int status = ILL_LP_STATUS_OK; + ILLlp_predata *pre = 0; + ILLlp_sinfo *info = 0; + + if (!lp) + { + fprintf (stderr, "ILLlp_presolve called with a NULL pointer\n"); + rval = 1; + goto CLEANUP; + } + + +/* + ILLlpdata_writelp (lp, 0); + printf ("\n"); fflush (stdout); +*/ + + ILL_SAFE_MALLOC (pre, 1, ILLlp_predata); + ILLlp_predata_init (pre); + + ILL_SAFE_MALLOC (info, 1, ILLlp_sinfo); + ILLlp_sinfo_init (info); + + rval = simple_presolve (lp, pre, info, pre_types, &status); + ILL_CLEANUP_IF (rval); + if (status != ILL_LP_STATUS_OK) + { + printf ("simple_presolve returned with bad status\n"); + rval = 1; + goto CLEANUP; + } + +/* + rval = ILLlp_sinfo_print (info); + ILL_CLEANUP_IF (rval); +*/ + +CLEANUP: + + if (rval) + { + if (pre) + { + ILLlp_predata_free (pre); + ILL_IFFREE (pre, ILLlp_predata); + } + + if (info) + { + ILLlp_sinfo_free (info); + ILL_IFFREE (info, ILLlp_sinfo); + } + } + else + { + lp->presolve = pre; + lp->sinfo = info; + } + + ILL_RETURN (rval, "ILLlp_presolve"); +} + + +#if 0 +int ILLlp_presolve_addrow ( + lpinfo * lp, + int cnt, + int *ind, + double *val, + double rhs) +{ + int rval = 0; + ILLlpdata *qslp; + ILLlp_sinfo *S; + ILLmatrix *A; + + /* This will need to evolve into a function that handles the task */ + /* of working through the presolve data to determine the new LP */ + /* created when a row is added to the original LP. */ + + /* The copies of the obj and bound used in the simplex code are */ + /* also updated in this function. */ + + if (!lp) + { + fprintf (stderr, "ILLlp_presolve_addrow is called without an LP\n"); + rval = 1; + goto CLEANUP; + } + + if (lp->presolve != 0) + { + fprintf (stderr, "Not yet set up to handle addrows after presolve\n"); + rval = 1; + goto CLEANUP; + } + + qslp = lp->O; + S = qslp->sinfo; + A = S->A; + + + rval = ILLlib_matrix_addrow (A, cnt, ind, val, rhs); + ILL_CLEANUP_IF (rval); + + +CLEANUP: + + ILL_RETURN (rval, "ILLlp_presolve_addrow"); +} +#endif + + +static int simple_presolve ( + ILLlpdata * lp, + ILLlp_predata * pre, + ILLlp_sinfo * info, + int pre_types, + int *status) +{ + int rval = 0; + int i, hit, newhit; + graph G; + + if (status) + *status = ILL_LP_STATUS_OK; + init_graph (&G); + + if (!lp) + { + fprintf (stderr, "simple_presolve called with a NULL pointer\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Initial Rows = %d, Cols = %d, Nzcount = %d\n", + lp->nrows, lp->ncols, lp->nzcount); + fflush (stdout); + + rval = build_graph (lp, &G); + ILL_CLEANUP_IF (rval); + if (debug) + dump_graph (&G); + + if (pre_types & ILL_PRE_FIXED) + { + rval = fixed_variables (&G, pre); + ILL_CLEANUP_IF (rval); + } + + do + { + hit = 0; + if (pre_types & ILL_PRE_SINGLE_ROW) + { + rval = singleton_rows (&G, pre, &newhit); + ILL_CLEANUP_IF (rval); + hit += newhit; + } + + if (pre_types & ILL_PRE_FORCING) + { + rval = forcing_constraints (&G, pre, &newhit); + ILL_CLEANUP_IF (rval); + hit += newhit; + } + + if (pre_types & ILL_PRE_SINGLE_COL) + { + rval = singleton_columns (&G, pre, &newhit); + ILL_CLEANUP_IF (rval); + hit += newhit; + } + + if (pre_types & ILL_PRE_DUPLICATE_ROW) + { + rval = duplicate_rows (&G, &newhit); + ILL_CLEANUP_IF (rval); + hit += newhit; + } + + if (pre_types & ILL_PRE_DUPLICATE_COL) + { + rval = duplicate_cols (&G, &newhit); + ILL_CLEANUP_IF (rval); + hit += newhit; + } + + +/* + { + int k, cnt = 0; + for (i = 0; i < G.ncols; i++) { + if (G.cols[i].del == 0) { + for (k = 0; k < G.cols[i].deg; k++) { + if (G.cols[i].adj[k]->del == 0) { + cnt++; + } + } + } + } + printf ("Current NZCOUNT = %d\n", cnt); fflush (stdout); + } +*/ + } while (hit); + + if (ILL_PRE_EMPTY_COL) + { + rval = empty_columns (&G, pre); + ILL_CLEANUP_IF (rval); + } + + if (debug) + { + printf ("Operations\n"); + for (i = 0; i < pre->opcount; i++) + { + switch (pre->oplist[i].ptype) + { + case ILL_PRE_DELETE_EMPTY_ROW: + printf ("Delete Empty Row: %d\n", pre->oplist[i].rowindex); + fflush (stdout); + break; + case ILL_PRE_DELETE_SINGLETON_ROW: + printf ("Delete Singleton Row: %d (col %d)\n", + pre->oplist[i].rowindex, pre->oplist[i].colindex); + fflush (stdout); + dump_line (&pre->oplist[i].line); + break; + case ILL_PRE_DELETE_FIXED_VARIABLE: + printf ("Delete Fixed Variable: %d\n", pre->oplist[i].colindex); + fflush (stdout); + dump_line (&pre->oplist[i].line); + break; + case ILL_PRE_DELETE_FORCED_VARIABLE: + printf ("Delete Forced Variable: %d\n", pre->oplist[i].colindex); + fflush (stdout); + dump_line (&pre->oplist[i].line); + break; + case ILL_PRE_DELETE_SINGLETON_VARIABLE: + printf ("Delete Singleton Variable: %d\n", pre->oplist[i].colindex); + fflush (stdout); + dump_line (&pre->oplist[i].line); + break; + case ILL_PRE_DELETE_FREE_SINGLETON_VARIABLE: + printf ("Delete Free Singleton Variable: %d\n", + pre->oplist[i].colindex); + fflush (stdout); + dump_line (&pre->oplist[i].line); + break; + case ILL_PRE_DELETE_EMPTY_COLUMN: + printf ("Delete Empty Column: %d\n", pre->oplist[i].colindex); + fflush (stdout); + dump_line (&pre->oplist[i].line); + break; + default: + fprintf (stderr, "unknon presolve operation\n"); + rval = 1; + goto CLEANUP; + } + } + printf ("\n"); + } + + rval = grab_lp_info (&G, lp->colnames, info); + ILL_CLEANUP_IF (rval); + +/* + printf ("Final Rows = %d, Cols = %d, Nzcount = %d\n", + info->nrows, info->ncols, info->nzcount); + fflush (stdout); +*/ + + +CLEANUP: + + free_graph (&G); + ILL_RETURN (rval, "simple_presolve"); +} + +static int grab_lp_line ( + graph * G, + int indx, + ILLlp_preline * line, + int row_or_col) +{ + int rval = 0; + int k, cnt; + node *n; + + if (row_or_col == 0) + n = &G->rows[indx]; + else + n = &G->cols[indx]; + + line->count = 0; + + for (k = 0; k < n->deg; k++) + { + if (n->adj[k]->del == 0) + { + line->count++; + } + } + + if (line->count) + { + ILL_SAFE_MALLOC (line->ind, line->count, int); + + line->val = EGlpNumAllocArray (line->count); + if (!line->ind || !line->val) + { + fprintf (stderr, "out of memory in grab_lp_line\n"); + rval = 1; + goto CLEANUP; + } + for (k = 0, cnt = 0; k < n->deg; k++) + { + if (n->adj[k]->del == 0) + { + line->ind[cnt] = n->adj[k]->row; + EGlpNumCopy (line->val[cnt], n->adj[k]->coef); + cnt++; + } + } + } + + if (row_or_col == 0) + { + EGlpNumCopy (line->rhs, n->rhs); + } + else + { + EGlpNumCopy (line->obj, n->obj); + EGlpNumCopy (line->lower, n->lower); + EGlpNumCopy (line->upper, n->upper); + } + + line->row_or_col = row_or_col; + +CLEANUP: + + ILL_RETURN (rval, "grab_lp_line"); +} + +static void dump_line ( + ILLlp_preline * line) +{ + int k; + + printf (" "); + if (line->row_or_col == 0) + { + for (k = 0; k < line->count; k++) + { + printf (" C%d->%g", line->ind[k], EGlpNumToLf (line->val[k])); + } + printf (" RHS->%g\n", EGlpNumToLf (line->rhs)); + } + else + { + for (k = 0; k < line->count; k++) + { + printf (" R%d->%g", line->ind[k], EGlpNumToLf (line->val[k])); + } + printf (" Obj->%g LB->%g UB->%g\n", EGlpNumToLf (line->obj), + EGlpNumToLf (line->lower), EGlpNumToLf (line->upper)); + } + fflush (stdout); +} + +static int grab_lp_info ( + graph * G, + char **colnames, + ILLlp_sinfo * info) +{ + int rval = 0; + int ncols = 0, nrows = 0, nzcount = 0; + int i, j, k, cnt, len; + node *grows = G->rows; + node *gcols = G->cols; + int *tdeg = 0; + int *map = 0; + char *buf = 0; + ILLmatrix *A = &info->A; + + ILL_SAFE_MALLOC (tdeg, G->ncols, int); + ILL_SAFE_MALLOC (map, G->nrows, int); + + if (!tdeg || !map) + { + fprintf (stderr, "out of memory in grab_lp_info\n"); + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < G->nrows; i++) + { + if (grows[i].del == 0) + { + map[i] = nrows; + nrows++; + } + } + + for (j = 0; j < G->ncols; j++) + { + if (gcols[j].del == 0) + { + tdeg[ncols] = 0; + for (k = 0; k < gcols[j].deg; k++) + { + if (gcols[j].adj[k]->del == 0) + { + tdeg[ncols]++; + nzcount++; + } + } + ncols++; + } + } + + info->ncols = ncols; + info->nrows = nrows; + info->nzcount = nzcount; + + info->rowsize = nrows; + info->colsize = ncols; + + info->rhs = EGlpNumAllocArray (nrows); + info->obj = EGlpNumAllocArray (ncols); + info->upper = EGlpNumAllocArray (ncols); + info->lower = EGlpNumAllocArray (ncols); + A->matval = EGlpNumAllocArray (info->nzcount + 1); + ILL_SAFE_MALLOC (A->matind, info->nzcount + 1, int); + ILL_SAFE_MALLOC (A->matcnt, info->colsize, int); + ILL_SAFE_MALLOC (A->matbeg, info->colsize, int); + + if (!info->rhs || !info->obj || !info->lower || !info->upper || + !A->matval || !A->matind || !A->matcnt || !A->matbeg) + { + fprintf (stderr, "out of memory in grab_lp\n"); + rval = 1; + goto CLEANUP; + } + + A->matind[info->nzcount] = -1; + A->matsize = info->nzcount + 1; + A->matcolsize = info->colsize; + A->matfree = 1; + A->matcols = ncols; + A->matrows = nrows; + + + nrows = 0; + for (i = 0; i < G->nrows; i++) + { + if (grows[i].del == 0) + { + EGlpNumCopy (info->rhs[nrows], grows[i].rhs); + nrows++; + } + } + + ncols = 0; + cnt = 0; + for (j = 0; j < G->ncols; j++) + { + if (gcols[j].del == 0) + { + EGlpNumCopy (info->obj[ncols], gcols[j].obj); + EGlpNumCopy (info->lower[ncols], gcols[j].lower); + EGlpNumCopy (info->upper[ncols], gcols[j].upper); + A->matcnt[ncols] = tdeg[ncols]; + A->matbeg[ncols] = cnt; + for (k = 0; k < gcols[j].deg; k++) + { + if (gcols[j].adj[k]->del == 0) + { + EGlpNumCopy (A->matval[cnt], gcols[j].adj[k]->coef); + A->matind[cnt] = map[gcols[j].adj[k]->row]; + cnt++; + } + } + ncols++; + } + } + + if (colnames) + { + ILL_SAFE_MALLOC (info->colnames, info->colsize, char *); + + if (!info->colnames) + { + fprintf (stderr, "out of memory in grab_lp\n"); + rval = 1; + goto CLEANUP; + } + for (j = 0; j < info->colsize; j++) + { + info->colnames[j] = 0; + } + + ILL_SAFE_MALLOC (buf, ILL_namebufsize, char); + + if (!buf) + { + fprintf (stderr, "out of memory in grab_lp\n"); + rval = 1; + goto CLEANUP; + } + ncols = 0; + for (j = 0; j < G->ncols; j++) + { + if (gcols[j].del == 0) + { + if (gcols[j].coltype == ILL_PRE_COL_STRUC) + { + len = strlen (colnames[j]) + 1; + ILL_SAFE_MALLOC (info->colnames[ncols], len, char); + + if (!info->colnames[ncols]) + { + fprintf (stderr, "out of memory in grab_lp\n"); + rval = 1; + goto CLEANUP; + } + strcpy (info->colnames[ncols], colnames[j]); + } + else + { + for (k = 0; k < gcols[j].deg; k++) + { + if (gcols[j].adj[k]->del == 0) + { + i = gcols[j].adj[k]->row; + break; + } + } + if (k == gcols[j].deg) + { + fprintf (stderr, "problem with graph in grab_lp\n"); + rval = 1; + goto CLEANUP; + } + sprintf (buf, "s%d", i); + len = strlen (buf) + 1; + ILL_SAFE_MALLOC (info->colnames[ncols], len, char); + + if (!info->colnames[ncols]) + { + fprintf (stderr, "out of memory in grab_lp\n"); + rval = 1; + goto CLEANUP; + } + strcpy (info->colnames[ncols], buf); + } + ncols++; + } + } + } + +/* ADD STRUCT VARIABLE STUFF */ + + +CLEANUP: + + if (rval) + { + ILLlp_sinfo_free (info); + } + ILL_IFFREE (tdeg, int); + ILL_IFFREE (map, int); + ILL_IFFREE (buf, char); + + ILL_RETURN (rval, "grab_lp_info"); +} + +static int fixed_variables ( + graph * G, + ILLlp_predata * pre) +{ + int rval = 0; + int j; + int ncols = G->ncols; + node *cols = G->cols; + ILLlp_preop *op = 0; + + for (j = 0; j < ncols; j++) + { + if (cols[j].del == 0) + { + if (EGlpNumIsEqqual (cols[j].lower, cols[j].upper)) + { + rval = get_next_preop (pre, &op); + ILL_CLEANUP_IF (rval); + + op->colindex = j; + op->rowindex = -1; + op->ptype = ILL_PRE_DELETE_FIXED_VARIABLE; + + rval = grab_lp_line (G, op->colindex, &op->line, 1); + ILL_CLEANUP_IF (rval); + pre->opcount++; + + set_fixed_variable (G, j, cols[j].lower); + } + } + } + +CLEANUP: + + ILL_RETURN (rval, "fixed_variables"); +} + +static int empty_columns ( + graph * G, + ILLlp_predata * pre) +{ + int rval = 0; + int j, k; + int ncols = G->ncols; + node *cols = G->cols; + ILLlp_preop *op = 0; + EGlpNum_t objtmp; + + EGlpNumInitVar (objtmp); + + for (j = 0; j < ncols; j++) + { + if (cols[j].del == 0) + { + for (k = 0; k < cols[j].deg; k++) + { + if (cols[j].adj[k]->del == 0) + break; + } + if (k == cols[j].deg) + { + rval = get_next_preop (pre, &op); + ILL_CLEANUP_IF (rval); + + op->colindex = j; + op->rowindex = -1; + op->ptype = ILL_PRE_DELETE_EMPTY_COLUMN; + + rval = grab_lp_line (G, op->colindex, &op->line, 1); + ILL_CLEANUP_IF (rval); + pre->opcount++; + EGlpNumCopy (objtmp, cols[j].obj); + if (G->objsense < 0) + EGlpNumSign (objtmp); + if (!EGlpNumIsNeqZero (objtmp, ILL_PRE_FEAS_TOL)) + { + set_fixed_variable (G, j, cols[j].lower); + } + else if (EGlpNumIsGreatZero (objtmp)) + { + if (EGlpNumIsEqqual (cols[j].lower, ILL_MINDOUBLE)) + { + printf ("unbounded prob detected in empty_columns\n"); + printf ("col %d, obj %g\n", j, EGlpNumToLf (cols[j].obj)); + fflush (stdout); + rval = 1; + goto CLEANUP; + } + else + { + set_fixed_variable (G, j, cols[j].lower); + } + } + else if (EGlpNumIsLessZero (objtmp)) + { + if (EGlpNumIsEqqual (cols[j].upper, ILL_MAXDOUBLE)) + { + printf ("unbounded prob detected in empty_columns\n"); + printf ("col %d, obj %g\n", j, EGlpNumToLf (cols[j].obj)); + fflush (stdout); + rval = 1; + goto CLEANUP; + } + else + { + set_fixed_variable (G, j, cols[j].upper); + } + } + else + { + set_fixed_variable (G, j, cols[j].lower); + } + } + } + } + +CLEANUP: + + EGlpNumClearVar (objtmp); + ILL_RETURN (rval, "empty_columns"); +} + +static int singleton_rows ( + graph * G, + ILLlp_predata * pre, + int *hit) +{ + int rval = 0; + int rowindex, i, k, h; + int nrows = G->nrows; + node *rows = G->rows; + node *cols = G->cols; + node *r, *c; + edge *pivot, *f; + intptr *next, *list = 0; + int *tdeg = 0; + EGlpNum_t val; + ILLlp_preop *op = 0; + + EGlpNumInitVar (val); + + *hit = 0; + if (G->nrows == 0) + goto CLEANUP; + + ILL_SAFE_MALLOC (tdeg, G->nrows, int); + + if (!tdeg) + { + fprintf (stderr, "out of memory in singleton_rows\n"); + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < nrows; i++) + { + if (rows[i].del == 0) + { + tdeg[i] = 0; + for (k = 0; k < rows[i].deg; k++) + { + if (rows[i].adj[k]->del == 0) + { + tdeg[i]++; + } + } + if (tdeg[i] <= 1) + { + rval = add_to_list (&G->intptrworld, &list, i); + ILL_CLEANUP_IF (rval); + } + } + } + + while (list) + { + (*hit)++; + rowindex = list->this_val; + next = list->next; + intptrfree (&G->intptrworld, list); + list = next; + + rval = get_next_preop (pre, &op); + ILL_CLEANUP_IF (rval); + + r = &rows[rowindex]; + + if (tdeg[rowindex] == 0) + { + if (EGlpNumIsNeqZero (r->rhs, ILL_PRE_FEAS_TOL)) + { + printf ("infeasible row detected in singleton_row\n"); + printf ("empty row with rhs = %g\n", EGlpNumToLf (r->rhs)); + fflush (stdout); + rval = 1; + goto CLEANUP; + } + op->ptype = ILL_PRE_DELETE_EMPTY_ROW; + op->rowindex = rowindex; + } + else + { + /* Find the "pivot" entry and colum */ + + for (k = 0; k < r->deg; k++) + { + if (r->adj[k]->del == 0) + break; + } + if (k == r->deg) + { + fprintf (stderr, "lost an edge in singleton_rows\n"); + rval = 1; + goto CLEANUP; + } + + pivot = r->adj[k]; + c = &cols[pivot->col]; + + /* Store data from operation (incluing the col coefs) */ + + op->ptype = ILL_PRE_DELETE_SINGLETON_ROW; + op->rowindex = rowindex; + op->colindex = c - cols; + EGlpNumCopy (op->line.rhs, r->rhs); + rval = grab_lp_line (G, op->colindex, &op->line, 1); + ILL_CLEANUP_IF (rval); + + /* Fix the x[c] to its rhs value */ + /*val = r->rhs / pivot->coef; */ + EGlpNumCopyFrac (val, r->rhs, pivot->coef); + /* if (val < c->lower - ILL_PRE_FEAS_TOL || + * val > c->upper + ILL_PRE_FEAS_TOL) */ + if (EGlpNumIsSumLess (val, ILL_PRE_FEAS_TOL, c->lower) || + EGlpNumIsSumLess (c->upper, ILL_PRE_FEAS_TOL, val)) + { + printf ("infeasible bounds detected in singleton_row %d\n", rowindex); + printf ("lower->%g upper->%g val = %g\n", + EGlpNumToLf (c->lower), EGlpNumToLf (c->upper), + EGlpNumToLf (val)); + fflush (stdout); + rval = 1; + goto CLEANUP; + } + else + { + EGlpNumCopy (c->lower, val); + EGlpNumCopy (c->upper, val); + } + + /* Delete x[c] from other rows (and adjust their rhs) */ + + c->del = 1; + + for (h = 0; h < c->deg; h++) + { + f = c->adj[h]; + if (f->del == 0) + { + /*rows[f->row].rhs -= (f->coef * c->lower); */ + EGlpNumSubInnProdTo (rows[f->row].rhs, f->coef, c->lower); + tdeg[f->row]--; + if (tdeg[f->row] == 1) + { + if (f == pivot) + { + fprintf (stderr, "bad pivot element\n"); + rval = 1; + goto CLEANUP; + } + rval = add_to_list (&G->intptrworld, &list, f->row); + ILL_CLEANUP_IF (rval); + } + f->del = 1; + } + } + } + + r->del = 1; + pre->opcount++; + } + +CLEANUP: + + ILL_IFFREE (tdeg, int); + + intptr_listfree (&G->intptrworld, list); + EGlpNumClearVar (val); + ILL_RETURN (rval, "singleton_rows"); +} + +static int forcing_constraints ( + graph * G, + ILLlp_predata * pre, + int *hit) +{ + int rval = 0; + int i, j, k, ts; + node *rows = G->rows; + node *cols = G->cols; + edge *e; + int nrows = G->nrows; + EGlpNum_t ub, lb; + ILLlp_preop *op = 0; + + EGlpNumInitVar (ub); + EGlpNumInitVar (lb); + + *hit = 0; + + for (i = 0; i < nrows; i++) + { + if (rows[i].del == 0) + { + get_implied_rhs_bounds (G, i, &lb, &ub); + if (EGlpNumIsSumLess (rows[i].rhs, ILL_PRE_FEAS_TOL, lb) || + EGlpNumIsSumLess (ub, ILL_PRE_FEAS_TOL, rows[i].rhs)) + { + printf ("infeasible row detected in forcing_constraints\n"); + printf ("Row %d: RHS->%g LBnd->%g UBnd->%g\n", + i, EGlpNumToLf (rows[i].rhs), + EGlpNumToLf (lb), EGlpNumToLf (ub)); + fflush (stdout); + rval = 1; + goto CLEANUP; + } + else if (EGlpNumIsDiffLess (rows[i].rhs, ILL_PRE_FEAS_TOL, lb) || + EGlpNumIsDiffLess (ub, ILL_PRE_FEAS_TOL, rows[i].rhs)) + { + (*hit)++; + ts = (EGlpNumIsDiffLess (rows[i].rhs, ILL_PRE_FEAS_TOL, lb) ? 0 : 1); + for (k = 0; k < rows[i].deg; k++) + { + e = rows[i].adj[k]; + if (e->del == 0) + { + j = e->col; + + rval = get_next_preop (pre, &op); + ILL_CLEANUP_IF (rval); + + op->colindex = j; + op->rowindex = i; + op->ptype = ILL_PRE_DELETE_FORCED_VARIABLE; + + rval = grab_lp_line (G, j, &op->line, 1); + ILL_CLEANUP_IF (rval); + pre->opcount++; + + if ((ts == 0 && EGlpNumIsLessZero (e->coef)) || + (ts == 1 && EGlpNumIsGreatZero (e->coef))) + { + set_fixed_variable (G, j, cols[j].upper); + } + else + { + set_fixed_variable (G, j, cols[j].lower); + } + } + } + } + } + } + +CLEANUP: + + EGlpNumClearVar (ub); + EGlpNumClearVar (lb); + ILL_RETURN (rval, "forcing_constraints"); +} + +static int singleton_columns ( + graph * G, + ILLlp_predata * pre, + int *hit) +{ + int rval = 0; + int ncols = G->ncols; + int j, k, deg, rdeg, single = 0, irow; + EGlpNum_t lb, ub, b, eb; + node *cols = G->cols; + node *rows = G->rows; + edge *b_edge; + ILLlp_preop *op = 0; + EGlpNum_t newub, newlb; + EGlpNum_t a, c, l, u; + + EGlpNumInitVar (lb); + EGlpNumInitVar (ub); + EGlpNumInitVar (eb); + EGlpNumInitVar (b); + EGlpNumInitVar (newlb); + EGlpNumInitVar (newub); + EGlpNumInitVar (a); + EGlpNumInitVar (c); + EGlpNumInitVar (l); + EGlpNumInitVar (u); + + *hit = 0; + if (G->ncols == 0) + goto CLEANUP; + + for (j = 0; j < ncols; j++) + { + if (cols[j].del == 0) + { + deg = 0; + for (k = 0; k < cols[j].deg && deg <= 1; k++) + { + if (cols[j].adj[k]->del == 0) + { + single = k; + deg++; + } + } + if (deg == 1) + { + irow = cols[j].adj[single]->row; + EGlpNumCopy (b, cols[j].adj[single]->coef); + b_edge = cols[j].adj[single]; + + get_implied_variable_bounds (G, j, b_edge, &lb, &ub); + + /*if (lb >= cols[j].lower && ub <= cols[j].upper) */ + if (EGlpNumIsLeq (cols[j].lower, lb) && + EGlpNumIsLeq (ub, cols[j].upper)) + { + edge *a_edge; + + /* The jth variable can be substituted out of problem */ + /* x = (c/b) - (a/b)y */ + + + rval = get_next_preop (pre, &op); + ILL_CLEANUP_IF (rval); + + op->colindex = j; + op->rowindex = irow; + op->ptype = ILL_PRE_DELETE_FREE_SINGLETON_VARIABLE; + + rval = grab_lp_line (G, irow, &op->line, 0); + ILL_CLEANUP_IF (rval); + pre->opcount++; + + /* Adjust the objective function */ + /* dy ==> (d - (e/b))ay (e is obj coef of y) */ + /*eb = cols[j].obj / b; */ + EGlpNumCopyFrac (eb, cols[j].obj, b); + + for (k = 0; k < rows[irow].deg; k++) + { + a_edge = rows[irow].adj[k]; + if (a_edge->del == 0 && a_edge != b_edge) + { + /*cols[a_edge->col].obj -= (eb * a_edge->coef); */ + EGlpNumSubInnProdTo (cols[a_edge->col].obj, eb, a_edge->coef); + } + } + + + /* Delete y from graph */ + + cols[j].del = 1; + + /* Delete equation ay + bx = c */ + + rows[irow].del = 1; + for (k = 0; k < rows[irow].deg; k++) + { + rows[irow].adj[k]->del = 1; + } + + } + else + { + rdeg = 0; + for (k = 0; k < rows[irow].deg && rdeg <= 2; k++) + { + if (rows[irow].adj[k]->del == 0) + { + rdeg++; + } + } + if (rdeg == 2) + { + edge *a_edge = 0; + int col2 = 0; + + EGlpNumCopy (newub, ILL_MAXDOUBLE); + EGlpNumCopy (newlb, ILL_MINDOUBLE); + EGlpNumZero (a); + + /* ay + bx = c */ + /* l <= x <= u */ + /* x - is column singleton */ + /* derive bounds on y and substitute out x */ + + EGlpNumCopy (c, rows[irow].rhs); + EGlpNumCopy (l, cols[j].lower); + EGlpNumCopy (u, cols[j].upper); + + /* Find the ay term */ + + for (k = 0; k < rows[irow].deg; k++) + { + if (rows[irow].adj[k]->del == 0 && rows[irow].adj[k]->col != j) + { + a_edge = rows[irow].adj[k]; + EGlpNumCopy (a, rows[irow].adj[k]->coef); + col2 = rows[irow].adj[k]->col; + break; + } + } + if (k == rows[irow].deg) + { + fprintf (stderr, "graph error in singleton_col\n"); + rval = 1; + goto CLEANUP; + } + + /* Record the operation */ + /* x is column j, y is column col2 */ + + rval = get_next_preop (pre, &op); + ILL_CLEANUP_IF (rval); + + op->colindex = j; + op->rowindex = irow; + op->ptype = ILL_PRE_DELETE_SINGLETON_VARIABLE; + + rval = grab_lp_line (G, irow, &op->line, 0); + ILL_CLEANUP_IF (rval); + pre->opcount++; + + /* Adjust the bounds on y */ + /* Using x = c/b - (a/b)y */ + /* we use eb as temporal variable here */ + /*if (a / b > 0) */ + EGlpNumCopyFrac (eb, a, b); + if (EGlpNumIsGreatZero (eb)) + { + /*if (l > -ILL_MAXDOUBLE) */ + if (EGlpNumIsLess (ILL_MINDOUBLE, l)) + { + /*newub = (c / a) - (l * b) / a; */ + EGlpNumCopy (newub, c); + EGlpNumSubInnProdTo (newub, l, b); + EGlpNumDivTo (newub, a); + } + /*if (u < ILL_MAXDOUBLE) */ + if (EGlpNumIsLess (u, ILL_MAXDOUBLE)) + { + /*newlb = (c / a) - (u * b) / a; */ + EGlpNumCopy (newlb, c); + EGlpNumSubInnProdTo (newlb, u, b); + EGlpNumDivTo (newlb, a); + } + } + else + { + /*if (l > -ILL_MAXDOUBLE) */ + if (EGlpNumIsLess (ILL_MINDOUBLE, l)) + { + /*newlb = (c / a) - (l * b) / a; */ + EGlpNumCopy (newlb, c); + EGlpNumSubInnProdTo (newlb, l, b); + EGlpNumDivTo (newlb, a); + } + /*if (u < ILL_MAXDOUBLE) */ + if (EGlpNumIsLess (u, ILL_MAXDOUBLE)) + { + /*newub = (c / a) - (u * b) / a; */ + EGlpNumCopy (newub, c); + EGlpNumSubInnProdTo (newub, u, b); + EGlpNumDivTo (newub, a); + } + } + + if (EGlpNumIsLess (cols[col2].lower, newlb)) + EGlpNumCopy (cols[col2].lower, newlb); + if (EGlpNumIsLess (newub, cols[col2].upper)) + EGlpNumCopy (cols[col2].upper, newub); + EGlpNumSubTo (cols[col2].obj, eb); + + /* Delete x (and the bx term) from graph */ + + cols[j].del = 1; + b_edge->del = 1; + + /* Delete equation ay + bx = c (and the ax term) */ + + rows[irow].del = 1; + a_edge->del = 1; + } + } + } + } + } + + +CLEANUP: + + EGlpNumClearVar (lb); + EGlpNumClearVar (ub); + EGlpNumClearVar (eb); + EGlpNumClearVar (b); + EGlpNumClearVar (newlb); + EGlpNumClearVar (newub); + EGlpNumClearVar (a); + EGlpNumClearVar (c); + EGlpNumClearVar (l); + EGlpNumClearVar (u); + ILL_RETURN (rval, "singleton_columns"); +} + +static int duplicate_rows ( + graph * G, + int *hit) +{ + int rval = 0; + node *cols = G->cols; + node *rows = G->rows; + int ncols = G->ncols; + int nrows = G->nrows; + int *s = 0; + EGlpNum_t *f = 0; + double szeit = ILLutil_zeit (); + EGlpNum_t q; + int i, j, k, k2, ri, r0 = 0, n, nu = 0, got, t0, t = 1; + node *c; + + EGlpNumInitVar (q); + + + /* Code follows J. Tomlin and J. S. Welch, OR Letters 5 (1986) 7--11 */ + + *hit = 0; + if (nrows == 0) + goto CLEANUP; + + ILL_SAFE_MALLOC (s, nrows, int); + + f = EGlpNumAllocArray (nrows); + + for (i = 0; i < nrows; i++) + { + if (rows[i].del || rows[i].rowsense != 'E') + { + s[i] = ILL_MAXINT; /* ILL_MAXINT means no longer eligible */ + } + else + { + s[i] = 0; /* 0 means eligible, >0 means in a group */ + nu++; /* Tracks the number of eligible rows */ + } + } + + for (j = 0; j < ncols; j++) + { + c = &cols[j]; + if (c->del) + continue; + if (c->coltype != ILL_PRE_COL_STRUC) + continue; + + n = 0; + t0 = t++; + + for (k = 0; k < c->deg; k++) + { + if (c->adj[k]->del) + continue; + + ri = c->adj[k]->row; + if (s[ri] == 0) + { + s[ri] = t0; + EGlpNumCopy (f[ri], c->adj[k]->coef); + r0 = ri; + n++; + } + else if (s[ri] < t0) + { + got = 0; + for (k2 = k + 1; k2 < c->deg; k2++) + { + if (c->adj[k2]->del) + continue; + + i = c->adj[k2]->row; + if (s[i] == s[ri]) + { + /*q = (c->adj[k]->coef * (f[i])) / (f[ri] * (c->adj[k2]->coef)); */ + EGlpNumCopy (q, c->adj[k]->coef); + EGlpNumMultTo (q, f[i]); + EGlpNumDivTo (q, f[ri]); + EGlpNumDivTo (q, c->adj[k2]->coef); + if (EGlpNumIsEqual (q, oneLpNum, ILL_PRE_ZERO_TOL)) + { + s[ri] = t; + s[i] = t; + got++; + } + } + } + if (got) + { + t++; + } + else + { + s[ri] = ILL_MAXINT; + if (--nu == 0) + goto DONE; + } + } + } + + if (n == 1) + { + s[r0] = ILL_MAXINT; + if (--nu == 0) + goto DONE; + } + } + +DONE: + + { + int idup = 0; + + for (i = 0; i < nrows; i++) + { + if (s[i] > 0 && s[i] < ILL_MAXINT) + { + printf ("Row %d: %d\n", i, s[i]); + idup++; + } + } + printf ("Number of duplicate rows: %d\n", idup); + } + + printf ("Time in duplicate_rows: %.2f (seconds)\n", ILLutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + ILL_IFFREE (s, int); + + EGlpNumFreeArray (f); + EGlpNumClearVar (q); + ILL_RETURN (rval, "duplicate_rows"); +} + +static int duplicate_cols ( + graph * G, + int *hit) +{ + int rval = 0; + node *cols = G->cols; + node *rows = G->rows; + int ncols = G->ncols; + int nrows = G->nrows; + int *s = 0; + EGlpNum_t *f = 0; + double szeit = ILLutil_zeit (); + EGlpNum_t q; + int i, j, k, k2, ci, c0 = 0, n, nu = 0, got, t0, t = 1; + node *r; + + EGlpNumInitVar (q); + + + /* Code follows J. Tomlin and J. S. Welch, OR Letters 5 (1986) 7--11 */ + + *hit = 0; + if (ncols == 0) + goto CLEANUP; + + ILL_SAFE_MALLOC (s, ncols, int); + + f = EGlpNumAllocArray (ncols); + + for (j = 0; j < ncols; j++) + { + if (cols[j].del || cols[j].coltype != ILL_PRE_COL_STRUC) + { + s[j] = ILL_MAXINT; /* ILL_MAXINT means no longer eligible */ + } + else + { + s[j] = 0; /* 0 means eligible, >0 means in a group */ + nu++; /* Tracks the number of eligible rows */ + } + } + + for (i = 0; i < nrows; i++) + { + r = &rows[i]; + if (r->del) + continue; + + n = 0; + t0 = t++; + + for (k = 0; k < r->deg; k++) + { + if (r->adj[k]->del) + continue; + + ci = r->adj[k]->col; + if (s[ci] == 0) + { + s[ci] = t0; + EGlpNumCopy (f[ci], r->adj[k]->coef); + c0 = ci; + n++; + } + else if (s[ci] < t0) + { + got = 0; + for (k2 = k + 1; k2 < r->deg; k2++) + { + if (r->adj[k2]->del) + continue; + + j = r->adj[k2]->col; + if (s[j] == s[ci]) + { + /*q = (r->adj[k]->coef * (f[j])) / (f[ci] * (r->adj[k2]->coef)); */ + EGlpNumCopy (q, r->adj[k]->coef); + EGlpNumMultTo (q, f[j]); + EGlpNumDivTo (q, f[ci]); + EGlpNumDivTo (q, r->adj[k2]->coef); + if (EGlpNumIsEqual (q, oneLpNum, ILL_PRE_ZERO_TOL)) + { + s[ci] = t; + s[j] = t; + got++; + } + } + } + if (got) + { + t++; + } + else + { + s[ci] = ILL_MAXINT; + if (--nu == 0) + goto DONE; + } + } + } + + if (n == 1) + { + s[c0] = ILL_MAXINT; + if (--nu == 0) + goto DONE; + } + } + +DONE: + + { + int dcount; + int *dcnt; + int *dlist; + + rval = gather_dup_lists (s, ncols, &dcount, &dcnt, &dlist); + ILL_CLEANUP_IF (rval); + } + + printf ("Time in duplicate_cols: %.2f (seconds)\n", ILLutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + ILL_IFFREE (s, int); + + EGlpNumFreeArray (f); + EGlpNumClearVar (q); + ILL_RETURN (rval, "duplicate_cols"); +} + +static int gather_dup_lists ( + /* graph *G, */ int *s, + /* double *f, */ + int count, + int *duptotal, + int **dupcnt, + int **dupind) +{ + int rval = 0; + int *cnt = 0; + int *ind = 0; + int *beg = 0; + int i, smax = 0, ndup = 0, total = 0; + + *duptotal = 0; + *dupcnt = 0; + *dupind = 0; + + + for (i = 0; i < count; i++) + { + if (s[i] < ILL_MAXINT && s[i] > smax) + smax = s[i]; + } + if (smax == 0) + goto CLEANUP; + + ILL_SAFE_MALLOC (cnt, smax + 1, int); + + ILL_SAFE_MALLOC (ind, smax + 1, int); + + for (i = 0; i < smax + 1; i++) + { + cnt[i] = 0; + } + + for (i = 0; i < count; i++) + { + if (s[i] < ILL_MAXINT) + { + cnt[s[i]]++; + } + } + + if (cnt[0] > 0) + printf ("%d Empty Lines\n", cnt[0]); + + printf ("Duplicate Classes:"); + fflush (stdout); + for (i = 1; i < smax + 1; i++) + { + if (cnt[i] > 1) + { + ndup++; + printf (" %d", cnt[i]); + } + } + printf (" Number %d\n", ndup); + fflush (stdout); + + if (ndup == 0) + goto CLEANUP; + + ILL_SAFE_MALLOC (beg, ndup, int); + + for (i = 1, ndup = 0; i < smax + 1; i++) + { + if (cnt[i] > 1) + { + beg[ndup] = total; + total += cnt[i]; + ind[i] = ndup; + ndup++; + } + } + + if (total == 0) + goto CLEANUP; + + ILL_SAFE_MALLOC (*dupcnt, ndup, int); + + ILL_SAFE_MALLOC (*dupind, total, int); + + for (i = 0; i < ndup; i++) + { + (*dupcnt)[i] = 0; + } + + for (i = 0; i < count; i++) + { + if (s[i] < ILL_MAXINT && s[i] > 0) + { + if (cnt[s[i]] > 1) + { + (*dupind)[beg[ind[s[i]]] + (*dupcnt)[ind[s[i]]]] = i; + (*dupcnt)[ind[s[i]]]++; + } + } + } + + for (i = 0; i < ndup; i++) + { + int j; + + for (j = beg[i]; j < beg[i] + (*dupcnt)[i]; j++) + { + printf (" %d", (*dupind)[j]); + } + printf (" | "); + fflush (stdout); + } + + *duptotal = ndup; + +CLEANUP: + + ILL_IFFREE (cnt, int); + ILL_IFFREE (ind, int); + ILL_IFFREE (beg, int); + + ILL_RETURN (rval, "gather_dup_lists"); +} + +static void set_fixed_variable ( + graph * G, + int j, + EGlpNum_t val) +{ + int k; + edge *e; + + G->cols[j].del = 1; + for (k = 0; k < G->cols[j].deg; k++) + { + e = G->cols[j].adj[k]; + if (e->del == 0) + { + /*G->rows[e->row].rhs -= (e->coef * val); */ + EGlpNumSubInnProdTo (G->rows[e->row].rhs, e->coef, val); + e->del = 1; + } + } +} + +static void get_implied_rhs_bounds ( + graph * G, + int i, + EGlpNum_t * lb, + EGlpNum_t * ub) +{ + int k; + EGlpNum_t l, u; + node *cols = G->cols; + node *rows = G->rows; + edge *e; + + EGlpNumInitVar (u); + EGlpNumInitVar (l); + + EGlpNumZero (l); + for (k = 0; k < rows[i].deg; k++) + { + e = rows[i].adj[k]; + if (e->del == 0) + { + if (EGlpNumIsLessZero (e->coef)) + { + if (EGlpNumIsEqqual (cols[e->col].upper, ILL_MAXDOUBLE)) + { + EGlpNumCopy (l, ILL_MINDOUBLE); + break; + } + else + { + /*l += (e->coef * cols[e->col].upper); */ + EGlpNumAddInnProdTo (l, e->coef, cols[e->col].upper); + } + } + else if (EGlpNumIsGreatZero (e->coef)) + { + if (EGlpNumIsEqqual (cols[e->col].lower, ILL_MINDOUBLE)) + { + EGlpNumCopy (l, ILL_MINDOUBLE); + break; + } + else + { + /*l += (e->coef * cols[e->col].lower); */ + EGlpNumAddInnProdTo (l, e->coef, cols[e->col].lower); + } + } + } + } + + EGlpNumZero (u); + for (k = 0; k < rows[i].deg; k++) + { + e = rows[i].adj[k]; + if (e->del == 0) + { + if (EGlpNumIsLessZero (e->coef )) + { + if (EGlpNumIsEqqual (cols[e->col].lower, ILL_MINDOUBLE)) + { + EGlpNumCopy (u, ILL_MAXDOUBLE); + } + else + { + /*u += (e->coef * cols[e->col].lower); */ + EGlpNumAddInnProdTo (u, e->coef, cols[e->col].lower); + } + } + else if (EGlpNumIsGreatZero (e->coef)) + { + if (EGlpNumIsEqqual (cols[e->col].upper, ILL_MAXDOUBLE)) + { + EGlpNumCopy (u, ILL_MAXDOUBLE); + } + else + { + /*u += (e->coef * cols[e->col].upper); */ + EGlpNumAddInnProdTo (u, e->coef, cols[e->col].upper); + } + } + } + } + + EGlpNumCopy (*lb, l); + EGlpNumCopy (*ub, u); + EGlpNumClearVar (u); + EGlpNumClearVar (l); +} + +static void get_implied_variable_bounds ( + graph * G, + int j, + edge * a_ij, + EGlpNum_t * lb, + EGlpNum_t * ub) +{ + int i = a_ij->row; + EGlpNum_t l, u; + + EGlpNumInitVar (u); + EGlpNumInitVar (l); + + get_implied_rhs_bounds (G, i, &l, &u); + EGlpNumCopy (*lb, ILL_MINDOUBLE); + EGlpNumCopy (*ub, ILL_MAXDOUBLE); + + if (EGlpNumIsLess (ILL_PRE_FEAS_TOL, a_ij->coef)) + { + if (EGlpNumIsLess (u, ILL_MAXDOUBLE)) + { + /**lb = (G->rows[i].rhs - u) / a_ij->coef + G->cols[j].upper;*/ + EGlpNumCopyDiffRatio (*lb, G->rows[i].rhs, u, a_ij->coef); + EGlpNumAddTo (*lb, G->cols[j].upper); + } + if (EGlpNumIsLess (ILL_MINDOUBLE, l)) + { + /**ub = (G->rows[i].rhs - l) / a_ij->coef + G->cols[j].lower;*/ + EGlpNumCopyDiffRatio (*ub, G->rows[i].rhs, l, a_ij->coef); + EGlpNumAddTo (*ub, G->cols[j].lower); + } + } + else if (EGlpNumIsLess (a_ij->coef, ILL_PRE_FEAS_TOL)) + { + if (EGlpNumIsLess (ILL_MINDOUBLE, l)) + { + /**lb = (G->rows[i].rhs - l) / a_ij->coef + G->cols[j].upper;*/ + EGlpNumCopyDiffRatio (*lb, G->rows[i].rhs, l, a_ij->coef); + EGlpNumAddTo (*lb, G->cols[j].upper); + } + if (EGlpNumIsLess (u, ILL_MAXDOUBLE)) + { + /**ub = (G->rows[i].rhs - u) / a_ij->coef + G->cols[j].lower;*/ + EGlpNumCopyDiffRatio (*ub, G->rows[i].rhs, u, a_ij->coef); + EGlpNumAddTo (*ub, G->cols[j].lower); + } + } + EGlpNumClearVar (u); + EGlpNumClearVar (l); +} + +static int get_next_preop ( + ILLlp_predata * pre, + ILLlp_preop ** op) +{ + int rval = 0; + + if (pre->opcount >= pre->opsize) + { + pre->opsize *= 1.3; + pre->opsize += 1000; + if (pre->opsize < pre->opcount + 1) + pre->opsize = pre->opcount + 1; + pre->oplist = EGrealloc (pre->oplist, sizeof (ILLlp_preop) * pre->opsize); + //rval = ILLutil_reallocrus_scale ((void **) &pre->oplist, + // &pre->opsize, pre->opcount + 1, 1.3, + // sizeof (ILLlp_preop)); + //ILL_CLEANUP_IF (rval); + } + *op = &pre->oplist[pre->opcount]; + ILLlp_preop_init (*op); + +//CLEANUP: + + ILL_RETURN (rval, "get_next_preop"); +} + +static int add_to_list ( + ILLptrworld * world, + intptr ** list, + int i) +{ + int rval = 0; + intptr *ip; + + ip = intptralloc (world); + if (!ip) + { + rval = 1; + goto CLEANUP; + } + ip->this_val = i; + ip->next = *list; + *list = ip; + +CLEANUP: + + ILL_RETURN (rval, "add_to_list"); +} + +static int build_graph ( + ILLlpdata * lp, + graph * G) +{ + int rval = 0; + int ncols = lp->ncols; + int nrows = lp->nrows; + int nzcount = lp->nzcount; + int i, j, k, stop, count; + edge *edgelist; + node *rows, *cols; + ILLmatrix *A = &lp->A; + + G->objsense = lp->objsense; + + ILL_SAFE_MALLOC (G->rows, nrows, node); + if (!G->rows) + { + fprintf (stderr, "out of memory in build_graph\n"); + rval = 1; + goto CLEANUP; + } + rows = G->rows; + + for (i = 0; i < nrows; i++) + { + rows[i].rowsense = lp->sense[i]; + rows[i].deg = 0; + } + + ILL_SAFE_MALLOC (G->cols, ncols, node); + ILL_SAFE_MALLOC (G->edgelist, nzcount, edge); + for (i = nzcount; i--;) + EGlpNumInitVar ((G->edgelist[i].coef)); + G->nzcount = nzcount; + ILL_SAFE_MALLOC (G->adjspace, 2 * nzcount, edge *); + + if (!G->cols || !G->edgelist || !G->adjspace) + { + fprintf (stderr, "out of memory in build_graph\n"); + rval = 1; + goto CLEANUP; + } + + cols = G->cols; + edgelist = G->edgelist; + + for (j = 0; j < ncols; j++) + { + stop = A->matbeg[j] + A->matcnt[j]; + for (k = A->matbeg[j]; k < stop; k++) + { + rows[A->matind[k]].deg++; + } + } + + for (i = 0, count = 0; i < nrows; i++) + { + rows[i].adj = G->adjspace + count; + count += rows[i].deg; + rows[i].deg = 0; + } + + for (j = 0; j < ncols; j++) + { + cols[j].adj = G->adjspace + count; + count += A->matcnt[j]; + cols[j].deg = 0; + cols[j].coltype = ILL_PRE_COL_STRUC; + } + for (i = 0; i < nrows; i++) + { + cols[lp->rowmap[i]].coltype = ILL_PRE_COL_LOGICAL; + } + + for (j = 0, count = 0; j < ncols; j++) + { + EGlpNumCopy (cols[j].obj, lp->obj[j]); + EGlpNumCopy (cols[j].lower, lp->lower[j]); + EGlpNumCopy (cols[j].upper, lp->upper[j]); + stop = A->matbeg[j] + A->matcnt[j]; + for (k = A->matbeg[j]; k < stop; k++) + { + i = A->matind[k]; + rows[i].adj[rows[i].deg++] = &(edgelist[count]); + cols[j].adj[cols[j].deg++] = &(edgelist[count]); + edgelist[count].row = i; + edgelist[count].col = j; + EGlpNumCopy (edgelist[count].coef, A->matval[k]); + edgelist[count].mark = 0; + edgelist[count].del = 0; + edgelist[count].coltype = cols[j].coltype; + count++; + } + } + if (count != nzcount) + { + fprintf (stderr, "counts are off in build_graph\n"); + rval = 1; + goto CLEANUP; + } + + G->ecount = count; + G->nrows = nrows; + G->ncols = ncols; + + for (i = 0; i < G->nrows; i++) + { + G->rows[i].del = 0; + EGlpNumCopy (G->rows[i].rhs, lp->rhs[i]); + } + for (j = 0; j < G->ncols; j++) + { + G->cols[j].del = 0; + } + +CLEANUP: + + ILL_RETURN (rval, "build_graph"); +} + +static void dump_graph ( + graph * G) +{ + int i, j, k; + + printf ("ecount = %d, nrows = %d, ncols = %d\n", + G->ecount, G->nrows, G->ncols); + fflush (stdout); + + for (i = 0; i < G->nrows; i++) + { + printf ("Row %d:", i); + for (k = 0; k < G->rows[i].deg; k++) + { + printf (" %d", G->rows[i].adj[k]->col); + if (G->rows[i].adj[k]->coltype == ILL_PRE_COL_LOGICAL) + printf ("S"); + printf ("(%g)", EGlpNumToLf (G->rows[i].adj[k]->coef)); + } + printf (" rhs: %g", EGlpNumToLf (G->rows[i].rhs)); + if (G->rows[i].del) + { + printf (" (deleted)\n"); + } + else + { + printf ("\n"); + } + } + + for (j = 0; j < G->ncols; j++) + { + if (G->cols[j].coltype == ILL_PRE_COL_LOGICAL) + { + printf ("Slk %d:", j); + } + else + { + printf ("Col %d:", j); + } + for (k = 0; k < G->cols[j].deg; k++) + { + printf (" %d", G->cols[j].adj[k]->row); + } + printf (" obj: %g bnd: (%g, %g)", EGlpNumToLf (G->cols[j].obj), + EGlpNumToLf (G->cols[j].lower), EGlpNumToLf (G->cols[j].upper)); + if (G->cols[j].del) + { + printf (" (deleted)\n"); + } + else + { + printf ("\n"); + } + } +} + +static void init_graph ( + graph * G) +{ + if (G) + { + G->edgelist = 0; + G->rows = 0; + G->cols = 0; + G->ecount = 0; + G->nrows = 0; + G->ncols = 0; + G->adjspace = 0; + ILLptrworld_init (&G->intptrworld); + } +} + +static void free_graph ( + graph * G) +{ + register int i; + + if (G) + { + int total, onlist; + + for (i = G->nzcount; i--;) + EGlpNumClearVar ((G->edgelist[i].coef)); + ILL_IFFREE (G->edgelist, edge); + ILL_IFFREE (G->rows, node); + ILL_IFFREE (G->cols, node); + ILL_IFFREE (G->adjspace, edge *); + if (intptr_check_leaks (&G->intptrworld, &total, &onlist)) + { + fprintf (stderr, "WARNING: %d outstanding intptrs\n", total - onlist); + } + ILLptrworld_delete (&G->intptrworld); + init_graph (G); + } +} + +int ILLlp_sinfo_print ( + ILLlp_sinfo * s) +{ + int rval = 0; + int i; + ILLlpdata lp; + char *sense = 0; + + ILLlpdata_init (&lp); + + lp.nrows = s->nrows; + lp.ncols = s->ncols; + lp.nzcount = s->nzcount; + lp.objsense = s->objsense; + lp.obj = s->obj; + lp.rhs = s->rhs; + lp.lower = s->lower; + lp.upper = s->upper; + lp.A.matval = s->A.matval; + lp.A.matcnt = s->A.matcnt; + lp.A.matbeg = s->A.matbeg; + lp.A.matind = s->A.matind; + lp.rownames = 0; + lp.colnames = s->colnames; + lp.objname = 0; + lp.probname = 0; + lp.intmarker = 0; + + ILL_SAFE_MALLOC (sense, s->nrows, char); + + if (!sense) + { + fprintf (stderr, "out of memory in ILLlp_sinfo_print\n"); + rval = 1; + goto CLEANUP; + } + for (i = 0; i < s->nrows; i++) + { + sense[i] = 'E'; + } + lp.sense = sense; + +/* + rval = ILLlpdata_writelp (&lp, 0); + ILL_CLEANUP_IF (rval); +*/ + +CLEANUP: + + ILL_IFFREE (sense, char); + + ILL_RETURN (rval, "ILLlp_sinfo_print"); +} + +void ILLlp_sinfo_init ( + ILLlp_sinfo * sinfo) +{ + if (sinfo) + { + sinfo->ncols = 0; + sinfo->nrows = 0; + sinfo->nzcount = 0; + sinfo->rowsize = 0; + sinfo->colsize = 0; + sinfo->obj = 0; + sinfo->rhs = 0; + sinfo->lower = 0; + sinfo->upper = 0; + sinfo->colnames = 0; + sinfo->objsense = ILL_MIN; + ILLmatrix_init (&sinfo->A); + } +} + +void ILLlp_sinfo_free ( + ILLlp_sinfo * sinfo) +{ + if (sinfo) + { + EGlpNumFreeArray (sinfo->obj); + EGlpNumFreeArray (sinfo->lower); + EGlpNumFreeArray (sinfo->upper); + EGlpNumFreeArray (sinfo->rhs); + ILLmatrix_free (&sinfo->A); + if (sinfo->colnames) + { + int i; + + for (i = 0; i < sinfo->ncols; i++) + { + ILL_IFFREE (sinfo->colnames[i], char); + } + ILL_IFFREE (sinfo->colnames, char *); + } + ILLlp_sinfo_init (sinfo); + } +} + +void ILLlp_predata_init ( + ILLlp_predata * pre) +{ + if (pre) + { + pre->opcount = 0; + pre->opsize = 0; + pre->oplist = 0; + pre->r_nrows = 0; + pre->r_ncols = 0; + pre->colmap = 0; + pre->rowmap = 0; + pre->colscale = 0; + pre->rowscale = 0; + pre->colfixval = 0; + pre->rowfixval = 0; + } +} + +void ILLlp_predata_free ( + ILLlp_predata * pre) +{ + if (pre) + { + int i; + + for (i = 0; i < pre->opcount; i++) + { + ILLlp_preop_free (&pre->oplist[i]); + } + ILL_IFFREE (pre->oplist, ILLlp_preop); + ILL_IFFREE (pre->colmap, int); + ILL_IFFREE (pre->rowmap, int); + + ILL_IFFREE (pre->colscale, EGlpNum_t); + ILL_IFFREE (pre->rowscale, EGlpNum_t); + ILL_IFFREE (pre->colfixval, EGlpNum_t); + ILL_IFFREE (pre->rowfixval, EGlpNum_t); + ILLlp_predata_init (pre); + } +} + +void ILLlp_preop_init ( + ILLlp_preop * op) +{ + if (op) + { + op->ptype = 0; + op->rowindex = -1; + op->colindex = -1; + ILLlp_preline_init (&op->line); + } +} + +void ILLlp_preop_free ( + ILLlp_preop * op) +{ + if (op) + { + ILLlp_preline_free (&op->line); + ILLlp_preop_init (op); + } +} + +void ILLlp_preline_init ( + ILLlp_preline * line) +{ + if (line) + { + EGlpNumInitVar (line->rhs); + EGlpNumInitVar (line->obj); + EGlpNumInitVar (line->upper); + EGlpNumInitVar (line->lower); + EGlpNumZero (line->rhs); + EGlpNumZero (line->obj); + EGlpNumZero (line->upper); + EGlpNumZero (line->lower); + line->count = 0; + line->ind = 0; + line->val = 0; + } +} + +void ILLlp_preline_free ( + ILLlp_preline * line) +{ + if (line) + { + EGlpNumClearVar (line->rhs); + EGlpNumClearVar (line->obj); + EGlpNumClearVar (line->upper); + EGlpNumClearVar (line->lower); + ILL_IFFREE (line->ind, int); + + EGlpNumFreeArray (line->val); + //ILLlp_preline_init (line); + } +} diff --git a/src/presolve.h b/src/presolve.h new file mode 100644 index 0000000..86a0d9b --- /dev/null +++ b/src/presolve.h @@ -0,0 +1,21 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ diff --git a/src/price.c b/src/price.c new file mode 100644 index 0000000..173783b --- /dev/null +++ b/src/price.c @@ -0,0 +1,1631 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: price.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +//static int TRACE = 0; +#include "qs_config.h" +#include "stddefs.h" +#include "qsopt.h" +#include "lpdefs.h" +#include "fct.h" +#include "price.h" +#include "basis.h" +#include "iqsutil.h" +#include "dstruct.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +#define MULTIP 1 +#define PRICE_DEBUG 0 + +static void update_d_scaleinf ( + price_info * const p, + heap * const h, + int const j, + EGlpNum_t inf, + int const prule), + update_p_scaleinf ( + price_info * const p, + heap * const h, + int const i, + EGlpNum_t inf, + int const prule); + +static void compute_dualI_inf ( + lpinfo * const lp, + int const j, + EGlpNum_t * const inf), + compute_dualII_inf ( + lpinfo * const lp, + int const j, + EGlpNum_t * const inf), + compute_primalI_inf ( + lpinfo * const lp, + int const i, + EGlpNum_t * const inf), + compute_primalII_inf ( + lpinfo * const lp, + int const i, + EGlpNum_t * const inf); + +void ILLprice_free_heap ( + price_info * const pinf) +{ + ILLheap_free (&(pinf->h)); +} + +int ILLprice_build_heap ( + price_info * const pinf, + int const nkeys, + EGlpNum_t * keylist) +{ + ILLheap_init (&(pinf->h)); + EGlpNumSet (pinf->htrigger, + 1.0 + + (double) nkeys / (PARAM_HEAP_RATIO * ILLutil_our_log2 (nkeys))); + return ILLheap_build (&(pinf->h), nkeys, keylist); +} + +int ILLprice_test_for_heap ( + lpinfo * const lp, + price_info * const pinf, + int const nkeys, + EGlpNum_t * keylist, + int const algo, + int const upd) +{ + heap *const h = &(pinf->h); + int rval = 0; + EGlpNum_t ravg; + + if (upd != 0) + { + EGlpNumInitVar (ravg); + if (algo == PRIMAL_SIMPLEX) + EGlpNumCopy (ravg, lp->cnts->za_ravg); + else + EGlpNumCopy (ravg, lp->cnts->y_ravg); + if (EGlpNumIsLeq (ravg, pinf->htrigger)) + pinf->hineff--; + else + { + EGlpNumDivUiTo (ravg, 2U); + if (EGlpNumIsLess (pinf->htrigger, ravg)) + pinf->hineff++; + } + EGlpNumClearVar (ravg); + } + if (h->hexist == 0 && pinf->hineff <= 0) + { + rval = ILLprice_build_heap (pinf, nkeys, keylist); + CHECKRVALG (rval, CLEANUP); + } + else if (h->hexist != 0 && pinf->hineff >= PARAM_HEAP_UTRIGGER) + { + ILLprice_free_heap (pinf); + /* + * printf ("freeing heap ..\n"); + * printf ("iter = %d, ravg = %.2f, trigger = %.2f\n", + * lp->cnts->tot_iter, ravg, pinf->htrigger); + */ + } + +CLEANUP: + if (rval) + ILLprice_free_heap (pinf); + return rval; +} + +void ILLprice_init_pricing_info ( + price_info * const pinf) +{ + pinf->p_strategy = -1; + pinf->d_strategy = -1; + pinf->pI_price = -1; + pinf->pII_price = -1; + pinf->dI_price = -1; + pinf->dII_price = -1; + pinf->cur_price = -1; + pinf->p_scaleinf = 0; + pinf->d_scaleinf = 0; + pinf->pdinfo.norms = 0; + pinf->pdinfo.refframe = 0; + pinf->psinfo.norms = 0; + pinf->ddinfo.norms = 0; + pinf->ddinfo.refframe = 0; + pinf->dsinfo.norms = 0; + pinf->dmpinfo.gstart = pinf->pmpinfo.gstart = 0; + pinf->dmpinfo.gshift = pinf->pmpinfo.gshift = 0; + pinf->dmpinfo.gsize = pinf->pmpinfo.gsize = 0; + pinf->dmpinfo.bucket = pinf->pmpinfo.bucket = 0; + pinf->dmpinfo.perm = pinf->pmpinfo.perm = 0; + pinf->dmpinfo.infeas = pinf->pmpinfo.infeas = 0; + ILLheap_init (&(pinf->h)); + EGlpNumZero (pinf->htrigger); + pinf->hineff = 0; +} + +void ILLprice_free_pricing_info ( + price_info * const pinf) +{ + EGlpNumFreeArray (pinf->p_scaleinf); + EGlpNumFreeArray (pinf->d_scaleinf); + EGlpNumFreeArray (pinf->pdinfo.norms); + ILL_IFFREE (pinf->pdinfo.refframe, int); + EGlpNumFreeArray (pinf->psinfo.norms); + EGlpNumFreeArray (pinf->ddinfo.norms); + ILL_IFFREE (pinf->ddinfo.refframe, int); + EGlpNumFreeArray (pinf->dsinfo.norms); + + ILLprice_free_mpartial_info (&(pinf->pmpinfo)); + ILLprice_free_mpartial_info (&(pinf->dmpinfo)); + ILLprice_free_heap (pinf); +} + +int ILLprice_build_pricing_info ( + lpinfo * const lp, + price_info * const pinf, + int const phase) +{ + int rval = 0; + int p_price = -1; + int d_price = -1; + + switch (phase) + { + case PRIMAL_PHASEI: + p_price = pinf->pI_price; + break; + case PRIMAL_PHASEII: + p_price = pinf->pII_price; + break; + case DUAL_PHASEI: + d_price = pinf->dI_price; + break; + case DUAL_PHASEII: + d_price = pinf->dII_price; + break; + } + + if (p_price != -1) + { + pinf->cur_price = p_price; + + if (p_price == QS_PRICE_PDANTZIG || p_price == QS_PRICE_PDEVEX || + p_price == QS_PRICE_PSTEEP) + { + pinf->p_strategy = COMPLETE_PRICING; + EGlpNumFreeArray (pinf->d_scaleinf); + pinf->d_scaleinf = EGlpNumAllocArray (lp->nnbasic); + } + else if (p_price == QS_PRICE_PMULTPARTIAL) + pinf->p_strategy = MULTI_PART_PRICING; + + switch (p_price) + { + case QS_PRICE_PDEVEX: + if (pinf->pdinfo.norms) + return rval; + rval = ILLprice_build_pdevex_norms (lp, &(pinf->pdinfo), 0); + CHECKRVALG(rval,CLEANUP); + break; + case QS_PRICE_PSTEEP: + if (pinf->psinfo.norms) + return rval; + rval = ILLprice_build_psteep_norms (lp, &(pinf->psinfo)); + CHECKRVALG(rval,CLEANUP); + break; + case QS_PRICE_PMULTPARTIAL: + rval = ILLprice_build_mpartial_info (lp, pinf, COL_PRICING); + CHECKRVALG(rval,CLEANUP); + break; + } + } + else if (d_price != -1) + { + pinf->cur_price = d_price; + + if (d_price == QS_PRICE_DDANTZIG || d_price == QS_PRICE_DSTEEP || + d_price == QS_PRICE_DDEVEX) + { + pinf->d_strategy = COMPLETE_PRICING; + EGlpNumFreeArray (pinf->p_scaleinf); + pinf->p_scaleinf = EGlpNumAllocArray (lp->nrows); + } + else if (d_price == QS_PRICE_DMULTPARTIAL) + pinf->d_strategy = MULTI_PART_PRICING; + + switch (d_price) + { + case QS_PRICE_DSTEEP: + if (pinf->dsinfo.norms) + return rval; + rval = ILLprice_build_dsteep_norms (lp, &(pinf->dsinfo)); + CHECKRVALG(rval,CLEANUP); + break; + case QS_PRICE_DMULTPARTIAL: + rval = ILLprice_build_mpartial_info (lp, pinf, ROW_PRICING); + CHECKRVALG(rval,CLEANUP); + break; + case QS_PRICE_DDEVEX: + if (pinf->ddinfo.norms) + return rval; + rval = ILLprice_build_ddevex_norms (lp, &(pinf->ddinfo), 0); + CHECKRVALG(rval,CLEANUP); + break; + } + } + +CLEANUP: + if (rval) + ILLprice_free_pricing_info (pinf); + EG_RETURN(rval); +} + +int ILLprice_update_pricing_info ( + lpinfo * const lp, + price_info * const pinf, + int const phase, + svector * const wz, + int const eindex, + int const lindex, + EGlpNum_t y) +{ + int rval = 0; + int p_price = -1; + int d_price = -1; + + switch (phase) + { + case PRIMAL_PHASEI: + p_price = pinf->pI_price; + break; + case PRIMAL_PHASEII: + p_price = pinf->pII_price; + break; + case DUAL_PHASEI: + d_price = pinf->dI_price; + break; + case DUAL_PHASEII: + d_price = pinf->dII_price; + break; + } + + if (p_price != -1) + { + if (p_price == QS_PRICE_PDEVEX) + { + rval = ILLprice_update_pdevex_norms (lp, &(pinf->pdinfo), eindex, y); + CHECKRVALG(rval,CLEANUP); + } + else if (p_price == QS_PRICE_PSTEEP) + ILLprice_update_psteep_norms (lp, &(pinf->psinfo), wz, eindex, y); + } + else if (d_price != -1) + { + if (d_price == QS_PRICE_DSTEEP) + ILLprice_update_dsteep_norms (lp, &(pinf->dsinfo), wz, lindex, y); + else if (d_price == QS_PRICE_DDEVEX) + { + rval = ILLprice_update_ddevex_norms (lp, &(pinf->ddinfo), lindex, y); + CHECKRVALG(rval,CLEANUP); + } + } +CLEANUP: + EG_RETURN(rval); +} + +int ILLprice_get_price ( + price_info * const p, + int const phase) +{ + int pri = -1; + + switch (phase) + { + case PRIMAL_PHASEI: + return p->pI_price; + case PRIMAL_PHASEII: + return p->pII_price; + case DUAL_PHASEI: + return p->dI_price; + case DUAL_PHASEII: + return p->dII_price; + } + return pri; +} + +void ILLprice_free_mpartial_info ( + mpart_info * p) +{ + ILL_IFFREE (p->gstart, int); + ILL_IFFREE (p->gshift, int); + ILL_IFFREE (p->gsize, int); + ILL_IFFREE (p->bucket, int); + EGlpNumFreeArray (p->infeas); + ILL_IFFREE (p->perm, int); +} + +int ILLprice_build_mpartial_info ( + lpinfo * const lp, + price_info * const pinf, + int const pricetype) +{ + int i = 0; + int rval = 0; + int extra = 0; + int nelems; + mpart_info *p; + + p = (pricetype == COL_PRICING) ? &(pinf->pmpinfo) : &(pinf->dmpinfo); + p->k = 50; + p->cgroup = 0; + nelems = (pricetype == COL_PRICING) ? lp->nnbasic : lp->nrows; + + if (nelems % p->k) + extra = nelems - p->k * (nelems / p->k); + p->ngroups = nelems / p->k; + if (extra != 0) + p->ngroups++; + + ILL_SAFE_MALLOC (p->gstart, p->ngroups, int); + ILL_SAFE_MALLOC (p->gshift, p->ngroups, int); + ILL_SAFE_MALLOC (p->gsize, p->ngroups, int); + ILL_SAFE_MALLOC (p->bucket, 2 * p->k, int); + p->infeas = EGlpNumAllocArray (2 * p->k); + ILL_SAFE_MALLOC (p->perm, 2 * p->k, int); + + p->bsize = 0; + + if (extra != 0) + { + p->gstart[0] = 0; + p->gshift[0] = 1; + p->gsize[0] = extra; + for (i = 1; i < p->ngroups; i++) + { + p->gstart[i] = extra + i - 1; + p->gshift[i] = p->ngroups - 1; + p->gsize[i] = p->k; + } + } + else + { + for (i = 0; i < p->ngroups; i++) + { + p->gstart[i] = i; + p->gshift[i] = p->ngroups; + p->gsize[i] = p->k; + } + } + +CLEANUP: + if (rval) + ILLprice_free_mpartial_info (p); + EG_RETURN(rval); +} + +void ILLprice_init_mpartial_price ( + lpinfo * const lp, + price_info * const pinf, + int const phase, + int const pricetype) +{ + int i; + mpart_info *p; + + p = (pricetype == COL_PRICING) ? &(pinf->pmpinfo) : &(pinf->dmpinfo); + p->bsize = 0; + i = p->cgroup; + do + { + ILLprice_mpartial_group (lp, p, phase, i, pricetype); + i = (i + 1) % p->ngroups; + } while (i != p->cgroup && p->bsize <= p->k); + p->cgroup = i; +} + +void ILLprice_update_mpartial_price ( + lpinfo * const lp, + price_info * const pinf, + int const phase, + int const pricetype) +{ + int i = 0; + int csize = 0; + EGlpNum_t infeas; + mpart_info *p; + price_res pr; + + p = (pricetype == COL_PRICING) ? &(pinf->pmpinfo) : &(pinf->dmpinfo); + EGlpNumInitVar (pr.dinfeas); + EGlpNumInitVar (pr.pinfeas); + EGlpNumInitVar (infeas); + +#ifdef MULTIP + i = 0; + while (i < p->bsize) + { + if (pricetype == COL_PRICING) + { + ILLprice_column (lp, p->bucket[i], phase, &pr); + EGlpNumCopy (infeas, pr.dinfeas); + } + else + { + ILLprice_row (lp, p->bucket[i], phase, &pr); + EGlpNumCopy (infeas, pr.pinfeas); + } + if (!EGlpNumIsNeqqZero (infeas)) + { + p->bucket[i] = p->bucket[p->bsize - 1]; + p->bsize--; + } + else + { + EGlpNumCopy (p->infeas[i], infeas); + i++; + } + } + if (p->bsize > 0) + { + for (i = 0; i < p->bsize; i++) + p->perm[i] = i; + EGutilPermSort ((size_t) (p->bsize), p->perm, + (const EGlpNum_t * const) p->infeas); + + csize = QSMIN (p->bsize, p->k); + for (i = csize - 1; i >= 0; i--) + lp->iwork[p->bucket[p->perm[i]]] = 1; + + for (i = 0, csize = 0; i < p->bsize; i++) + if (lp->iwork[p->bucket[i]] == 1) + { + EGlpNumCopy (p->infeas[csize], p->infeas[i]); + p->bucket[csize] = p->bucket[i]; + csize++; + } + p->bsize = csize; + } +#else + p->bsize = 0; +#endif + + i = p->cgroup; + do + { + ILLprice_mpartial_group (lp, p, phase, i, pricetype); + i = (i + 1) % p->ngroups; + } while (i != p->cgroup && p->bsize <= p->k); + p->cgroup = i; + +#ifdef MULTIP + for (i = 0; i < csize; i++) + lp->iwork[p->bucket[i]] = 0; +#endif + EGlpNumClearVar (infeas); + EGlpNumClearVar (pr.pinfeas); + EGlpNumClearVar (pr.dinfeas); +} + +void ILLprice_delete_onempart_price ( + /*lpinfo * const lp,*/ + price_info * const pinf, + int const indx, + int const pricetype) +{ + int i = 0; + mpart_info *p; + + p = (pricetype == COL_PRICING) ? &(pinf->pmpinfo) : &(pinf->dmpinfo); + + for (i = 0; i < p->bsize; i++) + if (p->bucket[i] == indx) + { + p->bucket[i] = p->bucket[p->bsize - 1]; + EGlpNumCopy (p->infeas[i], p->infeas[p->bsize - 1]); + p->bsize--; + break; + } +} + +void ILLprice_mpartial_group ( + lpinfo * const lp, + mpart_info * const p, + int const phase, + int const g, + int const pricetype) +{ + int i, ix; + int gstart = p->gstart[g]; + int gsize = p->gsize[g]; + int gshift = p->gshift[g]; + EGlpNum_t infeas; + price_res pr; + + EGlpNumInitVar (pr.dinfeas); + EGlpNumInitVar (pr.pinfeas); + EGlpNumInitVar (infeas); + + for (i = 0, ix = gstart; i < gsize; i++, ix += gshift) + { +#ifdef MULTIP + if (lp->iwork[ix]) + continue; +#endif + if (pricetype == COL_PRICING) + { + ILLprice_column (lp, ix, phase, &pr); + EGlpNumCopy (infeas, pr.dinfeas); + } + else + { + ILLprice_row (lp, ix, phase, &pr); + EGlpNumCopy (infeas, pr.pinfeas); + } + if (EGlpNumIsNeqqZero (infeas)) + { + EGlpNumCopy (p->infeas[p->bsize], infeas); + p->bucket[p->bsize] = ix; + p->bsize++; + } + } + EGlpNumClearVar (infeas); + EGlpNumClearVar (pr.dinfeas); + EGlpNumClearVar (pr.pinfeas); +} + +void ILLprice_column ( + lpinfo * const lp, + int const ix, + int const phase, + price_res * const pr) +{ + int i; + int col; + int mcnt; + int mbeg; + EGlpNum_t sum; + + EGlpNumZero (pr->dinfeas); + col = lp->nbaz[ix]; + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED) + return; + EGlpNumInitVar (sum); + EGlpNumZero (sum); + mcnt = lp->matcnt[col]; + mbeg = lp->matbeg[col]; + + if (phase == PRIMAL_PHASEII) + { + for (i = 0; i < mcnt; i++) + EGlpNumAddInnProdTo (sum, lp->piz[lp->matind[mbeg + i]], lp->matval[mbeg + i]); + EGlpNumCopyDiff (lp->dz[ix], lp->cz[col], sum); + compute_dualII_inf (lp, ix, &(pr->dinfeas)); + } + else + { + for (i = 0; i < mcnt; i++) + EGlpNumAddInnProdTo (sum, lp->pIpiz[lp->matind[mbeg + i]], lp->matval[mbeg + i]); + EGlpNumCopyNeg (lp->pIdz[ix], sum); + compute_dualI_inf (lp, ix, &(pr->dinfeas)); + } + EGlpNumClearVar (sum); +} + +void ILLprice_row ( + lpinfo * const lp, + int const ix, + int const phase, + price_res * const pr) +{ + if (phase == DUAL_PHASEII) + compute_primalII_inf (lp, ix, &(pr->pinfeas)); + else + compute_primalI_inf (lp, ix, &(pr->pinfeas)); +} + +int ILLprice_build_pdevex_norms ( + lpinfo * const lp, + p_devex_info * const pdinfo, + int const reinit) +{ + int j; + int rval = 0; + + if (reinit == 0) + { + pdinfo->ninit = 0; + pdinfo->norms = EGlpNumAllocArray (lp->nnbasic); + ILL_SAFE_MALLOC (pdinfo->refframe, lp->ncols, int); + } + + if (reinit != 0) + pdinfo->ninit++; + + for (j = 0; j < lp->ncols; j++) + { + if (lp->vstat[j] == STAT_BASIC) + pdinfo->refframe[j] = 0; + else + { + EGlpNumOne (pdinfo->norms[lp->vindex[j]]); + pdinfo->refframe[j] = 1; + } + } + +CLEANUP: + if (rval) + { + EGlpNumFreeArray (pdinfo->norms); + ILL_IFFREE (pdinfo->refframe, int); + } + EG_RETURN(rval); +} + +int ILLprice_update_pdevex_norms ( + lpinfo * const lp, + p_devex_info * const pdinfo, + int const eindex, + EGlpNum_t yl) +{ + int i, j; + EGlpNum_t normj; + EGlpNum_t zAj; + EGlpNum_t ntmp, ntmp2; + + EGlpNumInitVar (normj); + EGlpNumInitVar (zAj); + EGlpNumInitVar (ntmp); + EGlpNumInitVar (ntmp2); + EGlpNumZero (normj); + + for (i = 0; i < lp->yjz.nzcnt; i++) + if (pdinfo->refframe[lp->baz[lp->yjz.indx[i]]]) + EGlpNumAddInnProdTo (normj, lp->yjz.coef[i], lp->yjz.coef[i]); + + if (pdinfo->refframe[lp->nbaz[eindex]]) + EGlpNumAddTo (normj, oneLpNum); + + EGlpNumSet(ntmp,1000.0); + EGlpNumSet(ntmp2,0.001); + EGlpNumMultTo(ntmp,pdinfo->norms[eindex]); + EGlpNumMultTo(ntmp2,pdinfo->norms[eindex]); + if (EGlpNumIsLess (normj, ntmp2) || EGlpNumIsLess (ntmp, normj)) + { + EGlpNumClearVar (zAj); + EGlpNumClearVar (normj); + EGlpNumClearVar (ntmp); + EGlpNumClearVar (ntmp2); + return ILLprice_build_pdevex_norms (lp, pdinfo, 1); + } + + for (i = 0; i < lp->zA.nzcnt; i++) + { + j = lp->zA.indx[i]; + EGlpNumCopyFrac (zAj, lp->zA.coef[i], yl); + EGlpNumMultTo (zAj, zAj); + EGlpNumMultTo (zAj, normj); + if (EGlpNumIsLess (pdinfo->norms[j], zAj)) + EGlpNumCopy (pdinfo->norms[j], zAj); + } + EGlpNumDivTo (normj, yl); + EGlpNumDivTo (normj, yl); + if (EGlpNumIsLess (normj, oneLpNum)) + EGlpNumCopy (pdinfo->norms[eindex], oneLpNum); + else + EGlpNumCopy (pdinfo->norms[eindex], normj); + EGlpNumClearVar (zAj); + EGlpNumClearVar (normj); + EGlpNumClearVar (ntmp); + EGlpNumClearVar (ntmp2); + return 0; +} + +int ILLprice_build_psteep_norms ( + lpinfo * const lp, + p_steep_info * const psinfo) +{ + int j; + int rval = 0; + svector yz; + + ILLsvector_init (&yz); + rval = ILLsvector_alloc (&yz, lp->nrows); + CHECKRVALG(rval,CLEANUP); + psinfo->norms = EGlpNumAllocArray (lp->nnbasic); + + for (j = 0; j < lp->nnbasic; j++) + { + rval = ILLstring_report (NULL, &lp->O->reporter); + CHECKRVALG(rval,CLEANUP); + ILLfct_compute_yz (lp, &yz, 0, lp->nbaz[j]); + EGlpNumInnProd (psinfo->norms[j], yz.coef, yz.coef, (size_t) yz.nzcnt); + EGlpNumAddTo (psinfo->norms[j], oneLpNum); + } + +CLEANUP: + ILLsvector_free (&yz); + if (rval) + EGlpNumFreeArray (psinfo->norms); + + EG_RETURN(rval); +} + +void ILLprice_update_psteep_norms ( + lpinfo * const lp, + p_steep_info * const psinfo, + svector * const wz, + int const eindex, + EGlpNum_t yl) +{ + int i, j, k; + int mcnt, mbeg; + EGlpNum_t normj,ntmp; + EGlpNum_t zAj, wAj; + EGlpNum_t *v = 0; + + EGlpNumInitVar (normj); + EGlpNumInitVar (zAj); + EGlpNumInitVar (ntmp); + EGlpNumInitVar (wAj); + EGlpNumInnProd (normj, lp->yjz.coef, lp->yjz.coef, (size_t) (lp->yjz.nzcnt)); + EGlpNumAddTo (normj, oneLpNum); + +#if 0 + Bico - remove warnings for dist + if (fabs ((normj - psinfo->norms[eindex]) / normj) > 1000.0 /* 0.01 */ ) + { + printf ("warning: incorrect norm values\n"); + printf ("anorm = %.6f, pnorm = %.6f\n", normj, psinfo->norms[eindex]); + fflush (stdout); + } +#endif + + ILLfct_load_workvector (lp, wz); + v = lp->work.coef; + + for (k = 0; k < lp->zA.nzcnt; k++) + { + j = lp->zA.indx[k]; + EGlpNumCopy (zAj, lp->zA.coef[k]); + EGlpNumZero (wAj); + mcnt = lp->matcnt[lp->nbaz[j]]; + mbeg = lp->matbeg[lp->nbaz[j]]; + for (i = 0; i < mcnt; i++) + EGlpNumAddInnProdTo (wAj, lp->matval[mbeg + i], v[lp->matind[mbeg + i]]); + + /* compute ntmp = (zAj * ((zAj * normj / yl) - (2.0 * wAj))) / yl; */ + EGlpNumCopy(ntmp,zAj); + EGlpNumMultTo(ntmp,normj); + EGlpNumDivTo(ntmp,yl); + EGlpNumSubTo(ntmp,wAj); + EGlpNumSubTo(ntmp,wAj); + EGlpNumMultTo(ntmp,zAj); + EGlpNumDivTo(ntmp,yl); + /* set psinfo->norms[j] += (zAj * ((zAj * normj / yl) - (2.0 * wAj))) / yl; */ + EGlpNumAddTo(psinfo->norms[j],ntmp); + if (EGlpNumIsLess (psinfo->norms[j], oneLpNum)) + EGlpNumOne (psinfo->norms[j]); + } + + EGlpNumCopyFrac (psinfo->norms[eindex], normj, yl); + EGlpNumDivTo (psinfo->norms[eindex], yl); + if (EGlpNumIsLess (psinfo->norms[eindex], oneLpNum)) + EGlpNumOne (psinfo->norms[eindex]); + + ILLfct_zero_workvector (lp); + EGlpNumClearVar (wAj); + EGlpNumClearVar (zAj); + EGlpNumClearVar (normj); + EGlpNumClearVar (ntmp); +} + +int ILLprice_build_ddevex_norms ( + lpinfo * const lp, + d_devex_info * const ddinfo, + int const reinit) +{ + int i; + int rval = 0; + + if (reinit == 0) + { + ddinfo->ninit = 0; + ddinfo->norms = EGlpNumAllocArray (lp->nrows); + ILL_SAFE_MALLOC (ddinfo->refframe, lp->ncols, int); + } + if (reinit != 0) + ddinfo->ninit++; + + for (i = 0; i < lp->ncols; i++) + ddinfo->refframe[i] = (lp->vstat[i] == STAT_BASIC) ? 1 : 0; + + for (i = 0; i < lp->nrows; i++) + EGlpNumOne (ddinfo->norms[i]); + +CLEANUP: + if (rval) + { + EGlpNumFreeArray (ddinfo->norms); + ILL_IFFREE (ddinfo->refframe, int); + } + EG_RETURN(rval); +} + +int ILLprice_update_ddevex_norms ( + lpinfo * const lp, + d_devex_info * const ddinfo, + int const lindex, + EGlpNum_t yl) +{ + int i, r; + EGlpNum_t normi; + EGlpNum_t yr; + EGlpNum_t ntmp,ntmp2; + + EGlpNumInitVar (ntmp); + EGlpNumInitVar (ntmp2); + EGlpNumInitVar (normi); + EGlpNumInitVar (yr); + EGlpNumZero (normi); + + for (i = 0; i < lp->zA.nzcnt; i++) + if (ddinfo->refframe[lp->nbaz[lp->zA.indx[i]]]) + EGlpNumAddInnProdTo (normi, lp->zA.coef[i], lp->zA.coef[i]); + + if (ddinfo->refframe[lp->baz[lindex]]) + EGlpNumAddTo (normi, oneLpNum); + + EGlpNumSet(ntmp,1000.0); + EGlpNumSet(ntmp2,0.001); + EGlpNumMultTo(ntmp,ddinfo->norms[lindex]); + EGlpNumMultTo(ntmp2,ddinfo->norms[lindex]); + if (EGlpNumIsLess(normi, ntmp2) || EGlpNumIsLess(ntmp, normi)) + { + EGlpNumClearVar (normi); + EGlpNumClearVar (yr); + EGlpNumClearVar (ntmp); + EGlpNumClearVar (ntmp2); + return ILLprice_build_ddevex_norms (lp, ddinfo, 1); + } + + for (i = 0; i < lp->yjz.nzcnt; i++) + { + r = lp->yjz.indx[i]; + EGlpNumCopy(yr, lp->yjz.coef[i]); + EGlpNumCopy(ntmp,yr); + EGlpNumMultTo(ntmp,yr); + EGlpNumMultTo(ntmp,normi); + EGlpNumDivTo(ntmp,yl); + EGlpNumDivTo(ntmp,yl); + if (EGlpNumIsLess (ddinfo->norms[r], ntmp)) + EGlpNumCopy (ddinfo->norms[r], ntmp); + } + EGlpNumCopy (ddinfo->norms[lindex], normi); + EGlpNumDivTo(ddinfo->norms[lindex], yl); + EGlpNumDivTo(ddinfo->norms[lindex], yl); + if (EGlpNumIsLess (ddinfo->norms[lindex], oneLpNum)) + EGlpNumOne (ddinfo->norms[lindex]); + EGlpNumClearVar (normi); + EGlpNumClearVar (yr); + EGlpNumClearVar (ntmp); + EGlpNumClearVar (ntmp2); + return 0; +} + +int ILLprice_build_dsteep_norms ( + lpinfo * const lp, + d_steep_info * const dsinfo) +{ + int i; + int rval = 0; + svector z; + + ILLsvector_init (&z); + rval = ILLsvector_alloc (&z, lp->nrows); + CHECKRVALG(rval,CLEANUP); + dsinfo->norms = EGlpNumAllocArray (lp->nrows); + + for (i = 0; i < lp->nrows; i++) + { + rval = ILLstring_report (NULL, &lp->O->reporter); + CHECKRVALG(rval,CLEANUP); + + ILLfct_compute_zz (lp, &z, i); + + EGlpNumInnProd (dsinfo->norms[i], z.coef, z.coef, (size_t) z.nzcnt); + if (EGlpNumIsLess (dsinfo->norms[i], PARAM_MIN_DNORM)) + EGlpNumCopy (dsinfo->norms[i], PARAM_MIN_DNORM); + } + +CLEANUP: + ILLsvector_free (&z); + if (rval) + EGlpNumFreeArray (dsinfo->norms); + + EG_RETURN(rval); +} + +int ILLprice_get_dsteep_norms ( + lpinfo * const lp, + int const count, + int *const rowind, + EGlpNum_t * const norms) +{ + int i; + int rval = 0; + svector z; + + ILLsvector_init (&z); + rval = ILLsvector_alloc (&z, lp->nrows); + CHECKRVALG(rval,CLEANUP); + + for (i = 0; i < count; i++) + { + ILLfct_compute_zz (lp, &z, rowind[i]); + EGlpNumInnProd (norms[i], z.coef, z.coef, (size_t) z.nzcnt); + } + +CLEANUP: + ILLsvector_free (&z); + EG_RETURN(rval); +} + +void ILLprice_update_dsteep_norms ( + lpinfo * const lp, + d_steep_info * const dsinfo, + svector * const wz, + int const lindex, + EGlpNum_t yl) +{ + int i, k; + EGlpNum_t yij; + EGlpNum_t norml; + EGlpNum_t *v = 0; + EGlpNum_t ntmp; + + EGlpNumInitVar (ntmp); + EGlpNumInitVar (norml); + EGlpNumInitVar (yij); + EGlpNumInnProd (norml, lp->zz.coef, lp->zz.coef, (size_t) (lp->zz.nzcnt)); + +#if 0 + Bico - remove warnings for dist + if (fabs ((norml - dsinfo->norms[lindex]) / norml) > 1000.0 /*0.01 */ ) + { + printf ("warning: incorrect dnorm values\n"); + printf ("anorm = %.6f, pnorm = %.6f\n", norml, dsinfo->norms[lindex]); + fflush (stdout); + } +#endif + + ILLfct_load_workvector (lp, wz); + v = lp->work.coef; + + for (k = 0; k < lp->yjz.nzcnt; k++) + { + i = lp->yjz.indx[k]; + EGlpNumCopy (yij, lp->yjz.coef[k]); + /* compute in ntmp (yij * ((yij * norml / yl) - (2.0 * v[i]))) / yl; */ + EGlpNumCopy(ntmp,yij); + EGlpNumMultTo(ntmp,norml); + EGlpNumDivTo(ntmp,yl); + EGlpNumSubTo(ntmp,v[i]); + EGlpNumSubTo(ntmp,v[i]); + EGlpNumMultTo (ntmp, yij); + EGlpNumDivTo (ntmp, yl); + /* set dsinfo->norms[i] += (yij * ((yij * norml / yl) - (2.0 * v[i]))) / yl;*/ + EGlpNumAddTo(dsinfo->norms[i], ntmp); + if (EGlpNumIsLess (dsinfo->norms[i], PARAM_MIN_DNORM)) + EGlpNumCopy (dsinfo->norms[i], PARAM_MIN_DNORM); + } + EGlpNumCopyFrac (dsinfo->norms[lindex], norml, yl); + EGlpNumDivTo (dsinfo->norms[lindex], yl); + if (EGlpNumIsLess (dsinfo->norms[lindex], PARAM_MIN_DNORM)) + EGlpNumCopy (dsinfo->norms[lindex], PARAM_MIN_DNORM); + + ILLfct_zero_workvector (lp); + EGlpNumClearVar (norml); + EGlpNumClearVar (ntmp); + EGlpNumClearVar (yij); +} + +static void update_d_scaleinf ( + price_info * const p, + heap * const h, + int const j, + EGlpNum_t inf, + int const prule) +{ + if (!EGlpNumIsNeqqZero (inf)) + { + EGlpNumZero (p->d_scaleinf[j]); + if (h->hexist != 0 && h->loc[j] != -1) + ILLheap_delete (h, j); + } + else + { + if (prule == QS_PRICE_PDANTZIG) + EGlpNumCopy (p->d_scaleinf[j], inf); + else if (prule == QS_PRICE_PDEVEX) + EGlpNumCopySqrOver (p->d_scaleinf[j], inf, p->pdinfo.norms[j]); + else if (prule == QS_PRICE_PSTEEP) + EGlpNumCopySqrOver (p->d_scaleinf[j], inf, p->psinfo.norms[j]); + + if (h->hexist != 0) + { + if (h->loc[j] == -1) + ILLheap_insert (h, j); + else + ILLheap_modify (h, j); + } + } +} + +static void compute_dualI_inf ( + lpinfo * const lp, + const int j, + EGlpNum_t * const inf) +{ + int col = lp->nbaz[j]; + int vt = lp->vtype[col]; + int vs = lp->vstat[col]; + EGlpNum_t*dj = &(lp->pIdz[j]); + EGlpNum_t*ftol = &(lp->tol->id_tol); + EGlpNumZero (*inf); + if (vt != VARTIFICIAL && vt != VFIXED) + { + if( EGlpNumIsSumLess(*dj,*ftol,zeroLpNum) && (vs == STAT_LOWER || vs == STAT_ZERO)) + EGlpNumCopyNeg(*inf,*dj); + else if (EGlpNumIsLess(*ftol, *dj) && (vs == STAT_UPPER || vs == STAT_ZERO)) + EGlpNumCopy (*inf, *dj); + } +} + +static void compute_dualII_inf ( + lpinfo * const lp, + int const j, + EGlpNum_t * const inf) +{ + int col = lp->nbaz[j]; + int vt = lp->vtype[col]; + int vs = lp->vstat[col]; + EGlpNum_t*dj = &(lp->dz[j]); + EGlpNum_t*ftol = &(lp->tol->dfeas_tol); + EGlpNumZero (*inf); + if (vt != VARTIFICIAL && vt != VFIXED) + { + if( EGlpNumIsSumLess(*dj,*ftol,zeroLpNum) && (vs == STAT_LOWER || vs == STAT_ZERO)) + EGlpNumCopyNeg(*inf,*dj); + else if (EGlpNumIsLess(*ftol,*dj) && (vs == STAT_UPPER || vs == STAT_ZERO)) + EGlpNumCopy (*inf, *dj); + } +} + +void ILLprice_compute_dual_inf ( + lpinfo * const lp, + price_info * const p, + int *const ix, + int const icnt, + int const phase) +{ + int i; + int price; + EGlpNum_t inf; + heap *h = &(p->h); + + price = (phase == PRIMAL_PHASEI) ? p->pI_price : p->pII_price; + EGlpNumInitVar (inf); + EGlpNumZero (inf); + + if (phase == PRIMAL_PHASEI) + { + if (ix == NULL) + for (i = 0; i < lp->nnbasic; i++) + { + compute_dualI_inf (lp, i, &(inf)); + update_d_scaleinf (p, h, i, inf, price); + } + else + for (i = 0; i < icnt; i++) + { + compute_dualI_inf (lp, ix[i], &(inf)); + update_d_scaleinf (p, h, ix[i], inf, price); + } + } + else if (phase == PRIMAL_PHASEII) + { + if (ix == NULL) + for (i = 0; i < lp->nnbasic; i++) + { + compute_dualII_inf (lp, i, &inf); + update_d_scaleinf (p, h, i, inf, price); + } + else + for (i = 0; i < icnt; i++) + { + compute_dualII_inf (lp, ix[i], &inf); + update_d_scaleinf (p, h, ix[i], inf, price); + } + } + EGlpNumClearVar (inf); +} + +void ILLprice_primal ( + lpinfo * const lp, + price_info * const pinf, + price_res * const pr, + int const phase) +{ + int j, vs; + EGlpNum_t d_e, d_max; + EGlpNum_t *ftol = &(lp->tol->dfeas_tol); + heap *const h = &(pinf->h); + + EGlpNumInitVar (d_e); + EGlpNumInitVar (d_max); + pr->eindex = -1; + EGlpNumZero(d_max); + +#if USEHEAP > 0 + ILLprice_test_for_heap (lp, pinf, lp->nnbasic, pinf->d_scaleinf, + PRIMAL_SIMPLEX, 1); +#endif + + if (pinf->p_strategy == COMPLETE_PRICING) + { + if (h->hexist) + { + pr->eindex = ILLheap_findmin (h); + if (pr->eindex != -1) + ILLheap_delete (h, pr->eindex); + } + else + { + for (j = 0; j < lp->nnbasic; j++) + { + if (EGlpNumIsLess (d_max, pinf->d_scaleinf[j])) + { + EGlpNumCopy (d_max, pinf->d_scaleinf[j]); + pr->eindex = j; + } + } + } + } + else if (pinf->p_strategy == MULTI_PART_PRICING) + { + for (j = 0; j < pinf->pmpinfo.bsize; j++) + { + if (EGlpNumIsLess (d_max, pinf->pmpinfo.infeas[j])) + { + EGlpNumCopy (d_max, pinf->pmpinfo.infeas[j]); + pr->eindex = pinf->pmpinfo.bucket[j]; + } + } + } + + if (pr->eindex < 0) + pr->price_stat = PRICE_OPTIMAL; + else + { + if (phase == PRIMAL_PHASEI) + EGlpNumCopy (d_e, lp->pIdz[pr->eindex]); + else + EGlpNumCopy (d_e, lp->dz[pr->eindex]); + vs = lp->vstat[lp->nbaz[pr->eindex]]; + + pr->price_stat = PRICE_NONOPTIMAL; + if (vs == STAT_UPPER || (vs == STAT_ZERO && EGlpNumIsLess (*ftol, d_e))) + pr->dir = VDECREASE; + else + pr->dir = VINCREASE; + } + EGlpNumClearVar (d_e); + EGlpNumClearVar (d_max); +} + +static void update_p_scaleinf ( + price_info * const p, + heap * const h, + int const i, + EGlpNum_t inf, + int const prule) +{ + if (!EGlpNumIsNeqqZero (inf)) + { + EGlpNumZero (p->p_scaleinf[i]); + if (h->hexist != 0 && h->loc[i] != -1) + ILLheap_delete (h, i); + } + else + { + if (prule == QS_PRICE_DDANTZIG) + EGlpNumCopy (p->p_scaleinf[i], inf); + else if (prule == QS_PRICE_DSTEEP) + EGlpNumCopySqrOver (p->p_scaleinf[i], inf, p->dsinfo.norms[i]); + else if (prule == QS_PRICE_DDEVEX) + EGlpNumCopySqrOver (p->p_scaleinf[i], inf, p->ddinfo.norms[i]); + + if (h->hexist != 0) + { + if (h->loc[i] == -1) + ILLheap_insert (h, i); + else + ILLheap_modify (h, i); + } + } +} + +static void compute_primalI_inf ( + lpinfo * const lp, + int const i, + EGlpNum_t * const inf) +{ + int const col = lp->baz[i]; + EGlpNum_t*x = &(lp->xbz[i]); + EGlpNum_t*l = &(lp->lz[col]); + EGlpNum_t*u = &(lp->uz[col]); + EGlpNum_t*ftol = &(lp->tol->ip_tol); + EGlpNumZero (*inf); + + if (EGlpNumIsLess (*ftol, *x) && EGlpNumIsNeqq (*u, INFTY)) + EGlpNumCopy (*inf, *x); + else if (EGlpNumIsNeqq (*l, NINFTY) && EGlpNumIsSumLess (*x, *ftol,zeroLpNum)) + EGlpNumCopy (*inf, *x); +} + +static void compute_primalII_inf ( + lpinfo * const lp, + int const i, + EGlpNum_t * const inf) +{ + int const col = lp->baz[i]; + EGlpNum_t*x = &(lp->xbz[i]); + EGlpNum_t*l = &(lp->lz[col]); + EGlpNum_t*u = &(lp->uz[col]); + EGlpNum_t*ftol = &(lp->tol->pfeas_tol); + EGlpNumZero (*inf); + + if (EGlpNumIsNeqq (*u, INFTY) && EGlpNumIsSumLess (*u, *ftol, *x)) + EGlpNumCopyDiff (*inf, *x, *u); + else if (EGlpNumIsNeqq (*l, NINFTY) && EGlpNumIsSumLess (*x, *ftol, *l)) + EGlpNumCopyDiff (*inf, *l, *x); +} + +void ILLprice_compute_primal_inf ( + lpinfo * const lp, + price_info * const p, + int *const ix, + int const icnt, + int const phase) +{ + int i; + int price; + EGlpNum_t inf; + heap *h = &(p->h); + + price = (phase == DUAL_PHASEI) ? p->dI_price : p->dII_price; + EGlpNumInitVar (inf); + EGlpNumZero (inf); + + if (phase == DUAL_PHASEI) + { + if (ix == NULL) + for (i = 0; i < lp->nrows; i++) + { + compute_primalI_inf (lp, i, &inf); + update_p_scaleinf (p, h, i, inf, price); + } + else + for (i = 0; i < icnt; i++) + { + compute_primalI_inf (lp, ix[i], &inf); + update_p_scaleinf (p, h, ix[i], inf, price); + } + } + else if (phase == DUAL_PHASEII) + { + if (ix == NULL) + for (i = 0; i < lp->nrows; i++) + { + compute_primalII_inf (lp, i, &inf); + update_p_scaleinf (p, h, i, inf, price); + } + else + for (i = 0; i < icnt; i++) + { + compute_primalII_inf (lp, ix[i], &inf); + update_p_scaleinf (p, h, ix[i], inf, price); + } + } + EGlpNumClearVar (inf); +} + +void ILLprice_dual ( + lpinfo * const lp, + price_info * const pinf, + int const phase, + price_res * const pr) +{ + int i; + EGlpNum_t p_max; + EGlpNum_t ubound; + EGlpNum_t*ftol = &(lp->tol->pfeas_tol); + heap *const h = &(pinf->h); + + EGlpNumInitVar (p_max); + EGlpNumInitVar (ubound); + pr->lindex = -1; + EGlpNumZero(p_max); + +#if USEHEAP > 0 + ILLprice_test_for_heap (lp, pinf, lp->nrows, pinf->p_scaleinf, DUAL_SIMPLEX, + 1); +#endif + + if (pinf->d_strategy == COMPLETE_PRICING) + { + if (h->hexist) + { + pr->lindex = ILLheap_findmin (h); + if (pr->lindex != -1) + ILLheap_delete (h, pr->lindex); + } + else + { + for (i = 0; i < lp->nrows; i++) + { + if (EGlpNumIsLess (p_max, pinf->p_scaleinf[i])) + { + EGlpNumCopy (p_max, pinf->p_scaleinf[i]); + pr->lindex = i; + } + } + } + } + else if (pinf->d_strategy == MULTI_PART_PRICING) + { + for (i = 0; i < pinf->dmpinfo.bsize; i++) + { + if (EGlpNumIsLess (p_max, pinf->dmpinfo.infeas[i])) + { + EGlpNumCopy (p_max, pinf->dmpinfo.infeas[i]); + pr->lindex = pinf->dmpinfo.bucket[i]; + } + } + } + + if (pr->lindex < 0) + pr->price_stat = PRICE_OPTIMAL; + else + { + pr->price_stat = NONOPTIMAL; + + if (EGlpNumIsNeqq (lp->uz[lp->baz[pr->lindex]], INFTY)) + { + if (phase == DUAL_PHASEI) + EGlpNumZero(ubound); + else + EGlpNumCopy(ubound,lp->uz[lp->baz[pr->lindex]]); + if (EGlpNumIsSumLess (*ftol, ubound, lp->xbz[pr->lindex])) + pr->lvstat = STAT_UPPER; + else + pr->lvstat = STAT_LOWER; + } + else + pr->lvstat = STAT_LOWER; + } + EGlpNumClearVar (p_max); + EGlpNumClearVar (ubound); +} + +int ILLprice_get_rownorms ( + lpinfo * const lp, + price_info * const pinf, + EGlpNum_t * const rnorms) +{ + int rval = 0; + int i; + + if (pinf->dsinfo.norms == NULL) + { + rval = ILLprice_build_dsteep_norms (lp, &(pinf->dsinfo)); + CHECKRVALG(rval,CLEANUP); + } + for (i = 0; i < lp->nrows; i++) + EGlpNumCopy (rnorms[i], pinf->dsinfo.norms[i]); + +CLEANUP: + if (rval) + EGlpNumFreeArray (pinf->dsinfo.norms); + + return rval; +} + +int ILLprice_get_colnorms ( + lpinfo * const lp, + price_info * const pinf, + EGlpNum_t * const cnorms) +{ + int rval = 0; + int i, j; + + if (pinf->psinfo.norms == NULL) + { + rval = ILLprice_build_psteep_norms (lp, &(pinf->psinfo)); + CHECKRVALG(rval,CLEANUP); + } + for (i = 0; i < lp->nrows; i++) + EGlpNumZero (cnorms[lp->baz[i]]); + for (j = 0; j < lp->nnbasic; j++) + EGlpNumCopy (cnorms[lp->nbaz[j]], pinf->psinfo.norms[j]); + +CLEANUP: + if (rval) + EGlpNumFreeArray (pinf->psinfo.norms); + + return rval; +} + +int ILLprice_get_newnorms ( + lpinfo * const lp, + int const nelems, + EGlpNum_t * const norms, + int *const matcnt, + int *const matbeg, + int *const matind, + EGlpNum_t * const matval, + int const option) +{ + int i, j; + int rval = 0; + svector a; + svector y; + + ILLsvector_init (&y); + rval = ILLsvector_alloc (&y, lp->nrows); + CHECKRVALG(rval,CLEANUP); + + for (j = 0; j < nelems; j++) + { + a.nzcnt = matcnt[j]; + a.indx = &(matind[matbeg[j]]); + a.coef = &(matval[matbeg[j]]); + + if (option == COLUMN_SOLVE) + ILLbasis_column_solve (lp, &a, &y); + else + ILLbasis_row_solve (lp, &a, &y); + + EGlpNumOne (norms[j]); + for (i = 0; i < y.nzcnt; i++) + EGlpNumAddInnProdTo (norms[j], y.coef[i], y.coef[i]); + } + +CLEANUP: + ILLsvector_free (&y); + EG_RETURN(rval); +} + +int ILLprice_get_new_rownorms ( + lpinfo * const lp, + int const newrows, + EGlpNum_t * const rnorms, + int *const rmatcnt, + int *const rmatbeg, + int *const rmatind, + EGlpNum_t * const rmatval) +{ + return ILLprice_get_newnorms (lp, newrows, rnorms, rmatcnt, rmatbeg, rmatind, + rmatval, ROW_SOLVE); +} + +int ILLprice_get_new_colnorms ( + lpinfo * const lp, + int const newrows, + EGlpNum_t * const rnorms, + int *const matcnt, + int *const matbeg, + int *const matind, + EGlpNum_t * const matval) +{ + return ILLprice_get_newnorms (lp, newrows, rnorms, matcnt, matbeg, matind, + matval, COLUMN_SOLVE); +} + +int ILLprice_load_rownorms ( + lpinfo * const lp, + EGlpNum_t * const rnorms, + price_info * const pinf) +{ + int i; + int rval = 0; + + EGlpNumFreeArray (pinf->dsinfo.norms); + pinf->dsinfo.norms = EGlpNumAllocArray (lp->nrows); + + for (i = 0; i < lp->nrows; i++) + { + EGlpNumCopy (pinf->dsinfo.norms[i], rnorms[i]); + if (EGlpNumIsLess (pinf->dsinfo.norms[i], PARAM_MIN_DNORM)) + EGlpNumCopy (pinf->dsinfo.norms[i], PARAM_MIN_DNORM); + } + + EG_RETURN(rval); +} + +int ILLprice_load_colnorms ( + lpinfo * const lp, + EGlpNum_t * const cnorms, + price_info * const pinf) +{ + int j; + int rval = 0; + + EGlpNumFreeArray (pinf->psinfo.norms); + pinf->psinfo.norms = EGlpNumAllocArray (lp->nnbasic); + + for (j = 0; j < lp->nnbasic; j++) + { + EGlpNumCopy (pinf->psinfo.norms[j], cnorms[lp->nbaz[j]]); + if (EGlpNumIsLess (pinf->psinfo.norms[j], oneLpNum)) + EGlpNumOne (pinf->psinfo.norms[j]); + } + + EG_RETURN(rval); +} + +#if PRICE_DEBUG > 0 +void test_dsteep_norms ( + lpinfo * lp, + price_info * p) +{ + int i, errn = 0; + EGlpNum_t *pn = EGlpNumAllocArray(lp->nrows); + EGlpNum_t err, diff; + EGlpNumZero (err); + + EGlpNumInitVar (err); + EGlpNumInitVar (diff); + + ILLprice_get_dsteep_norms (lp, lp->yjz.nzcnt, lp->yjz.indx, pn); + for (i = 0; i < lp->yjz.nzcnt; i++) + { + EGlpNumCopyDiff (diff, pn[i], p->dsinfo.norms[lp->yjz.indx[i]]); + EGlpNumCopyAbs(diff,diff); + if (EGlpNumIsLess (PFEAS_TOLER, diff)) + { + errn++; + EGlpNumAddTo (err, diff); + EGlpNumCopy (p->dsinfo.norms[lp->yjz.indx[i]], pn[i]); + } + } + if (errn) + printf ("%d: dnorm errn = %d, err = %.6f\n", lp->cnts->tot_iter, errn, + EGlpNumToLf (err)); + EGlpNumFreeArray (pn); + EGlpNumClearVar (diff); + EGlpNumClearVar (err); +} +#endif diff --git a/src/price.h b/src/price.h new file mode 100644 index 0000000..11b50be --- /dev/null +++ b/src/price.h @@ -0,0 +1,222 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: price.h,v $ $Revision: 1.3 $ $Date: 2003/11/05 16:57:39 $" */ +#ifndef __PRICE_H +#define __PRICE_H + +#include "dstruct.h" +#include "basicdefs.h" + +typedef struct price_res +{ + int eindex; + int dir; + int lindex; + int lvstat; + int price_stat; + EGlpNum_t dinfeas; + EGlpNum_t pinfeas; +} +price_res; + +int ILLprice_test_for_heap ( + lpinfo * const lp, + price_info * const pinf, + int const nkeys, + EGlpNum_t * keylist, + int const algo, + int const upd), + ILLprice_build_heap ( + price_info * const pinf, + int const nkeys, + EGlpNum_t * keylist), + ILLprice_build_pricing_info ( + lpinfo * const lp, + price_info * const pinf, + int const phase), + ILLprice_update_pricing_info ( + lpinfo * const lp, + price_info * const pinf, + int const phase, + svector * const wz, + int const eindex, + int const lindex, + EGlpNum_t y), + ILLprice_get_price ( + price_info * const p, + int const phase), + ILLprice_build_mpartial_info ( + lpinfo * const lp, + price_info * const pinf, + int const pricetype), + ILLprice_build_pdevex_norms ( + lpinfo * const lp, + p_devex_info * const pdinfo, + int const reinit), + ILLprice_update_pdevex_norms ( + lpinfo * const lp, + p_devex_info * const pdinfo, + int const eindex, + EGlpNum_t yl), + ILLprice_build_psteep_norms ( + lpinfo * const lp, + p_steep_info * const psinfo), + ILLprice_build_ddevex_norms ( + lpinfo * const lp, + d_devex_info * const ddinfo, + int const reinit), + ILLprice_update_ddevex_norms ( + lpinfo * const lp, + d_devex_info * const ddinfo, + int const eindex, + EGlpNum_t yl), + ILLprice_build_dsteep_norms ( + lpinfo * const lp, + d_steep_info * const dsinfo), + ILLprice_get_dsteep_norms ( + lpinfo * const lp, + int const count, + int *constrowind, + EGlpNum_t * const norms), + ILLprice_get_rownorms ( + lpinfo * const lp, + price_info * const pinf, + EGlpNum_t * const rnorms), + ILLprice_get_colnorms ( + lpinfo * const lp, + price_info * const pinf, + EGlpNum_t * const cnorms), + ILLprice_get_newnorms ( + lpinfo * const lp, + int const nelems, + EGlpNum_t * const norms, + int *const matcnt, + int *const matbeg, + int *const matind, + EGlpNum_t * const matval, + int const option), + ILLprice_get_new_rownorms ( + lpinfo * const lp, + int const newrows, + EGlpNum_t * const rnorms, + int *const rmatcnt, + int *const rmatbeg, + int *const rmatind, + EGlpNum_t * const rmatval), + ILLprice_get_new_colnorms ( + lpinfo * const lp, + int const newrows, + EGlpNum_t * const rnorms, + int *const matcnt, + int *const matbeg, + int *const matind, + EGlpNum_t * const matval), + ILLprice_load_rownorms ( + lpinfo * const lp, + EGlpNum_t * const rnorms, + price_info * const pinf), + ILLprice_load_colnorms ( + lpinfo * const lp, + EGlpNum_t * const cnorms, + price_info * const pinf); + + +void ILLprice_free_heap ( + price_info * const pinf), + ILLprice_init_pricing_info ( + price_info * const pinf), + ILLprice_free_pricing_info ( + price_info * const pinf), + ILLprice_free_mpartial_info ( + mpart_info * p), + ILLprice_init_mpartial_price ( + lpinfo * const lp, + price_info * const pinf, + int const phase, + int const pricetype), + ILLprice_update_mpartial_price ( + lpinfo * const lp, + price_info * const pinf, + int const phase, + int const pricetype), + ILLprice_delete_onempart_price ( + /*lpinfo * const lp,*/ + price_info * const pinf, + int const indx, + int const pricetype), + ILLprice_mpartial_group ( + lpinfo * const lp, + mpart_info * const p, + int const phase, + int const g, + int const pricetype), + ILLprice_column ( + lpinfo * const lp, + int const ix, + int const phase, + price_res * const pr), + ILLprice_row ( + lpinfo * const lp, + int const ix, + int const phase, + price_res * const pr), + ILLprice_update_psteep_norms ( + lpinfo * lp, + p_steep_info * psinfo, + svector * wz, + int eindex, + EGlpNum_t yl), + ILLprice_update_dsteep_norms ( + lpinfo * const lp, + d_steep_info * const dsinfo, + svector * const wz, + int const lindex, + EGlpNum_t yl), + ILLprice_compute_dual_inf ( + lpinfo * const lp, + price_info * const p, + int *const ix, + int const icnt, + int const phase), + ILLprice_primal ( + lpinfo * const lp, + price_info * const pinf, + price_res * const pr, + int const phase), + ILLprice_compute_primal_inf ( + lpinfo * const lp, + price_info * const p, + int *const ix, + int const icnt, + int const phase), + ILLprice_dual ( + lpinfo * const lp, + price_info * const pinf, + int const phase, + price_res * const pr); + +void test_dsteep_norms ( + lpinfo * const lp, + price_info * const p); + +#endif /* __PRICE_H */ diff --git a/src/priority.c b/src/priority.c new file mode 100644 index 0000000..2d29a92 --- /dev/null +++ b/src/priority.c @@ -0,0 +1,255 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: priority.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* PRIORITY QUEUE ROUTINES */ +/* */ +/* */ +/* TSP CODE */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 3, 1997 */ +/* March 13, 2002 - Cook Modified for QS) */ +/* Reference: R.E. Tarjan, Data Structures and Network Algorithms */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int ILLutil_priority_init (ILLpriority *pri, int k) */ +/* -h should point to a ILLpriority struct. */ +/* -k an initial allocation for the priority queue. */ +/* */ +/* void ILLutil_priority_free (ILLpriority *pri) */ +/* -frees the spaces allocated for the ILLpriority queue. */ +/* */ +/* void ILLutil_priority_findmin (ILLpriority *pri, double *keyval */ +/* void **en) */ +/* -en the entry with least key value (NULL if no entries in heap). */ +/* -if (keyval != NULL), *keyval will be the minimum key value. */ +/* */ +/* int ILLutil_priority_insert (ILLpriority *pri, void *data, */ +/* double keyval, int *handle) */ +/* -adds (data, keyval) to h. */ +/* -handle returns a handle (>= 0) to use when deleting or changing the */ +/* entry */ +/* */ +/* void ILLutil_priority_delete (ILLpriority *pri, int handle) */ +/* -deletes an entry from the queue. handle is the value returned by */ +/* ILLutil_priority_insert. */ +/* */ +/* void ILLutil_priority_deletemin (ILLpriority *pri, double *keyval, */ +/* void **en) */ +/* -like ILLutil_priority_findmin, but also deletes the entry. */ +/* */ +/* void ILLutil_priority_changekey (ILLpriority *pri, int handle, */ +/* double newkey) */ +/* -changes the key of an entry in the queue. handle is the value */ +/* returned by ILLutil_priority_insert. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* NOTES: */ +/* These priority queue routines use the ILLdheap routines to maintain */ +/* the priority queue. */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "machdefs.h" +#include "priority.h" +#include "allocrus.h" +#include "except.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +int ILLutil_priority_init ( + ILLpriority * pri, + int k) +{ + int i; + int list; + int rval = 0; + + pri->space = k; + ILL_SAFE_MALLOC (pri->pri_info, k, union ILLpri_data); + + rval = ILLutil_dheap_init (&pri->heap, k); + ILL_CLEANUP_IF (rval); + + list = -1; + for (i = k - 1; i >= 0; i--) + { + pri->pri_info[i].next = list; + list = i; + } + pri->freelist = list; + +CLEANUP: + + if (rval) + { + ILL_IFFREE (pri->pri_info, union ILLpri_data); + } + return rval; +} + +void ILLutil_priority_free ( + ILLpriority * pri) +{ + ILLutil_dheap_free (&pri->heap); + ILL_IFFREE (pri->pri_info, union ILLpri_data); + + pri->space = 0; +} + +void ILLutil_priority_findmin ( + ILLpriority * pri, + EGlpNum_t * keyval, + void **en) +{ + int handle; + + ILLutil_dheap_findmin (&pri->heap, &handle); + + if (handle < 0) + { + *en = (void *) NULL; + } + else + { + if (keyval) + EGlpNumCopy (*keyval, pri->heap.key[handle]); + *en = pri->pri_info[handle].data; + } +} + +int ILLutil_priority_insert ( + ILLpriority * pri, + void *data, + EGlpNum_t * keyval, + int *handle) +{ + int newsize; + int i; + int list; + int rval = 0; + + if (pri->freelist == -1) + { + /* Change from 1.3 * pri->space to avoid a warning */ + newsize = pri->space + (pri->space / 3); + if (newsize < pri->space + 1000) + newsize = pri->space + 1000; + rval = ILLutil_dheap_resize (&pri->heap, newsize); + ILL_CLEANUP_IF (rval); + + pri->pri_info = + EGrealloc (pri->pri_info, sizeof (union ILLpri_data) * newsize); + //rval = ILLutil_reallocrus_count ((void **) &pri->pri_info, newsize, + // sizeof (union ILLpri_data)); + //ILL_CLEANUP_IF (rval); + + list = -1; + for (i = newsize - 1; i >= pri->space; i--) + { + pri->pri_info[i].next = list; + list = i; + } + pri->space = newsize; + pri->freelist = list; + } + + i = pri->freelist; + pri->freelist = pri->pri_info[i].next; + pri->pri_info[i].data = data; + EGlpNumCopy (pri->heap.key[i], *keyval); + rval = ILLutil_dheap_insert (&pri->heap, i); + ILL_CLEANUP_IF (rval); + + if (handle) + *handle = i; + +CLEANUP: + + return rval; +} + +void ILLutil_priority_delete ( + ILLpriority * pri, + int handle) +{ + ILLutil_dheap_delete (&pri->heap, handle); + pri->pri_info[handle].next = pri->freelist; + pri->freelist = handle; +} + +void ILLutil_priority_deletemin ( + ILLpriority * pri, + EGlpNum_t * keyval, + void **en) +{ + int handle; + void *data; + + ILLutil_dheap_deletemin (&pri->heap, &handle); + + if (handle < 0) + { + *en = (void *) NULL; + } + else + { + if (keyval) + EGlpNumCopy (*keyval, pri->heap.key[handle]); + data = pri->pri_info[handle].data; + pri->pri_info[handle].next = pri->freelist; + pri->freelist = handle; + *en = data; + } +} + +void ILLutil_priority_changekey ( + ILLpriority * pri, + int handle, + EGlpNum_t * newkey) +{ + ILLutil_dheap_changekey (&pri->heap, handle, newkey); +} diff --git a/src/priority.h b/src/priority.h new file mode 100644 index 0000000..f58e1f0 --- /dev/null +++ b/src/priority.h @@ -0,0 +1,75 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __PRIORITY_H__ +#define __PRIORITY_H__ +#include "dheaps_i.h" +/****************************************************************************/ +/* */ +/* priority.c */ +/* */ +/****************************************************************************/ + +typedef struct ILLpriority +{ + ILLdheap heap; + union ILLpri_data + { + void *data; + int next; + } + *pri_info; + int space; + int freelist; +} +ILLpriority; + +void ILLutil_priority_free ( + ILLpriority * pri), + ILLutil_priority_delete ( + ILLpriority * pri, + int handle), + ILLutil_priority_changekey ( + ILLpriority * pri, + int handle, + EGlpNum_t * newkey), + ILLutil_priority_findmin ( + ILLpriority * pri, + EGlpNum_t * keyval, + void **en), + ILLutil_priority_deletemin ( + ILLpriority * pri, + EGlpNum_t * keyval, + void **en); + +int ILLutil_priority_init ( + ILLpriority * pri, + int k), + ILLutil_priority_insert ( + ILLpriority * pri, + void *data, + EGlpNum_t * keyval, + int *handle); + + + +#endif diff --git a/src/qs_config.h b/src/qs_config.h new file mode 100644 index 0000000..5789782 --- /dev/null +++ b/src/qs_config.h @@ -0,0 +1,180 @@ +/* Taken from EGlib 10-09-26 */ +/* EGlib "Efficient General Library" provides some basic structures and + * algorithms commons in many optimization algorithms. + * + * Copyright (C) 2005 Daniel Espinoza and Marcos Goycoolea. + * + * This library 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.1 of the License, or (at your + * option) any later version. + * + * This library 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 library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * */ +/* ========================================================================= */ +/** Main Configuration for the library, as debug levels and so on + * + * @par History: + * - 2010-09-26 + * - Addapted for QSopt_ex + * - 2010-08-13 + * - Add suport for autoconf and configure for header and feature + * selection + * - 2006-01-27 + * - Handle some problems with stdint.h in SUN + * - 2005-08-17 + * - Set memory aligment to 8 bits + * - 2003-06-02 + * - First Implementation + * @version 1.1.1 + * */ +/* ========================================================================= */ +#ifndef __QS_CONFIG_H__ +#define __QS_CONFIG_H__ +#include "config.h" +#ifdef HAVE_STDIO_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_ERRNO_H +# include +#endif +#ifdef HAVE_LIMITS_H +# include +#endif +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_FLOAT_H +# include +#endif +#ifdef HAVE_GETOPT_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETINET_TCP_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#ifdef HAVE_SYS_TIMES_H +# include +#endif +#ifdef HAVE_STDARG_H +# include +#endif +#ifdef HAVE_SYS_UTSNAME_H +# include +#endif +#ifdef HAVE_SIGNAL_H +# include +#endif +#ifdef HAVE_SETJMP_H +# include +#endif +/* ========================================================================= */ +/** @brief if no gmp support, we do not include gmp.h, if on the otherhand, we + * have libgmp, we MUST have gmp.h */ +#ifdef HAVE_LIBGMP +# if HAVE_LIBGMP +# ifdef HAVE_GMP_H +# include +# else +# error Must have gmp.h for compiling QSopt_ex +# endif +# else +# error Must have gmp.h for compiling QSopt_ex +# endif +# else +# error Must have gmp.h for compiling QSopt_ex +#endif +/* ========================================================================= */ +/** @brief assert Debug options definitions, by defoult set on */ +#ifndef DEBUG +#warning you should define DEBUG, assuming it to be 1 +#define DEBUG 1 +#endif + +/* ========================================================================= */ +/** @brief assert Verbose options definition, by default set on */ +#ifndef VERBOSE_LEVEL +#warning you should define VERBOSE_LEVEL, assuming it to be 1 +#define VERBOSE_LEVEL 1 +#endif +/* ========================================================================= */ +#ifdef HAVE_EGLIB_H +# if HAVE_EGLIB_H +# include "EGlib.h" +# else +# error You must have EGlib.h for compilation +# endif +#else +# error You must have EGlib.h for compilation +#endif +/* ========================================================================= */ +/** @brief define version function name */ +void QSopt_ex_version(void); +#endif diff --git a/src/qsopt.c b/src/qsopt.c new file mode 100644 index 0000000..0564cc7 --- /dev/null +++ b/src/qsopt.c @@ -0,0 +1,3921 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: qsopt.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +static int TRACE = 0; + +/****************************************************************************/ +/* */ +/* User-level Functions */ +/* */ +/* EXPORTED FUNCTIONS */ +/* */ +/* int QSopt_primal (QSdata *p, int *status) */ +/* int QSopt_dual (QSdata *p, int *status) */ +/* QSdata *QScreate_prob (const char *name, int objsense) */ +/* QSdata *QSread_prob (const char *filename, const char *filetype) */ +/* QSdata *QSload_prob (const char *probname, int ncols, int nrows, */ +/* int *cmatcnt, int *cmatbeg, int *cmatind, double *cmatval, */ +/* int objsense, double *obj, double *rhs, char *sense, */ +/* double *lower, double *upper, const char **colnames, */ +/* const char **rownames) */ +/* QSdata *QScopy_prob (QSdata *p, const char *newname) */ +/* int QSchange_objsense (QSdata *p, int newsense) */ +/* int QSget_objsense (QSdata *p, int *objsense) */ +/* int QSnew_col (QSdata *p, double obj, double lower, double upper, */ +/* const char *name) */ +/* int QSadd_cols (QSdata *p, int num, int *cmatcnt, int *cmatbeg, */ +/* int *cmatind, double *cmatval, double *obj, double *lower, */ +/* double *upper, const char **names) */ +/* int QSadd_col (QSdata *p, int cnt, int *cmatind, double *cmatval, */ +/* double obj, double lower, double upper, const char *name) */ +/* int QSnew_row (QSdata *p, double rhs, const char sense, char *name) */ +/* int QSadd_rows (QSdata *p, int num, int *rmatcnt, int *rmatbeg, */ +/* int *rmatind, double *rmatval, double *rhs, char *sense, */ +/* char **names) */ +/* int QSadd_row (QSdata *p, int cnt, int *rmatind, double *rmatval, */ +/* double rhs, char sense, const char *name) */ +/* int QSdelete_rows (QSdata *p, int num, int *dellist) */ +/* int QSdelete_row (QSdata *p, int rowindex) */ +/* int QSdelete_setrows (QSdata *p, int *flags) */ +/* int QSdelete_cols (QSdata *p, int num, int *dellist) */ +/* int QSdelete_col (QSdata *p, int colindex) */ +/* int QSdelete_setcols (QSdata *p, int *flags) */ +/* int QSdelete_named_column (QSdata *p, const char *colname) */ +/* int QSdelete_named_columns_list (QSdata *p, int num, */ +/* const char **colnames) */ +/* int QSdelete_named_row (QSdata *p, const char *rowname) */ +/* int QSdelete_named_rows_list (QSdata *p, int num, */ +/* const char **rownames) */ +/* int QSchange_senses (QSdata *p, int num, int *rowlist, char *sense) */ +/* int QSchange_sense (QSdata *p, int rowindex, char sense) */ +/* int QSchange_coef (QSdata *p, int rowindex, int colindex, */ +/* double coef) */ +/* int QSchange_objcoef (QSdata *p, int indx, double coef) */ +/* int QSchange_rhscoef (QSdata *p, int indx, double coef) */ +/* int QSchange_bounds (QSdata *p, int num, int *collist, char *lu, */ +/* double *bounds) */ +/* int QSchange_bound (QSdata *p, int indx, char lu, double bound) */ +/* int QSwrite_basis (QSdata *p, QSbasis *B, const char *filename) */ +/* QSbasis *QSget_basis (QSdata *p) */ +/* QSbasis *QSread_basis (QSdata *p, const char *filename) */ +/* int QSload_basis (QSdata *p, QSbasis *B) */ +/* int QSread_and_load_basis (QSdata *p, const char *filename) */ +/* int QSload_basis_array (QSdata *p, char *cstat, char *rstat) */ +/* int QSload_basis_and_row_norms_array (QSdata *p, char *cstat, */ +/* char *rstat, double *rownorms) */ +/* int QSget_basis_array (QSdata *p, char *cstat, char *rstat) */ +/* int QSget_basis_and_row_norms_array (QSdata *p, char *cstat, */ +/* char *rstat, double *rownorms) */ +/* int QSget_binv_row (QSdata *p, int indx, double *binvrow) */ +/* int QSget_tableau_row (QSdata *p, int indx, double *tableaurow) */ +/* int QSget_basis_order (QSdata *p, int *basorder) */ +/* int QSget_status (QSdata *p, int *status) */ +/* int QSget_solution (QSdata *p, double *value, double *x, */ +/* double *pi, double *slack, double *rc), */ +/* int QSget_objval (QSdata *p, double *value) */ +/* int QSget_x_array (QSdata *p, double *x) */ +/* int QSget_rc_array (QSdata *p, double *rc) */ +/* int QSget_pi_array (QSdata *p, double *pi) */ +/* int QSget_slack_array (QSdata *p, double *slack) */ +/* int QSget_infeas_array (QSdata *p, double *pi) */ +/* int QSget_named_x (QSdata *p, const char *colname, double *val) */ +/* int QSget_named_rc (QSdata *p, const char *colname, double *val) */ +/* int QSget_named_pi (QSdata *p, const char *rowname, double *val) */ +/* int QSget_named_slack (QSdata *p, const char *rowname, double *val) */ +/* int QSget_colcount (QSdata *p) */ +/* int QSget_rowcount (QSdata *p) */ +/* int QSget_nzcount (QSdata *p) */ +/* int QSget_obj (QSdata *p, double *obj), */ +/* int QSget_rhs (QSdata *p, double *rhs) */ +/* char* QSget_probname (QSdata *p) */ +/* char* QSget_objname (QSdata *p) */ +/* int QSget_columns (QSdata *p, int **colcnt, int **colbeg, */ +/* int **colind, double **colval, double **obj, double **lower, */ +/* double **upper, char ***names) */ +/* int QSget_columns_list (QSdata *p, int num, int *collist, */ +/* int **colcnt, int **colbeg, int **colind, double **colval, */ +/* double **obj, double **lower, double **upper, char ***names) */ +/* int QSget_rows (QSdata *p, int **rowcnt, int **rowbeg, int **rowind, */ +/* double **rowval, double **rhs, char **sense, char ***names) */ +/* int QSget_rows_list (QSdata *p, int num, int *rowlist, int **rowcnt, */ +/* int **rowbeg, int **rowind, double **rowval, double **rhs, */ +/* char **sense, char ***names) */ +/* int QSget_column_index (QSdata *p, const char *name, int *colindex) */ +/* int QSget_row_index (QSdata *p, const char *name, int *rowindex) */ +/* int QSget_rownames (QSdata *p, char **rownames) */ +/* int QSget_colnames (QSdata *p, char **colnames) */ +/* int QSget_bound (QSdata *p, int colindex, char lu, double *bound) */ +/* int QSget_bounds (QSdata *p, double *lower, double *upper) */ +/* int QSget_intcount (QSdata *p, int *count) */ +/* int QSget_intflags (QSdata *p, int *intflags) */ +/* int QScompute_row_norms (QSdata *p) */ +/* void QSfree_prob (QSdata *p) */ +/* void QSfree_basis (QSbasis *B) */ +/* int QSwrite_prob (QSdata *p, const char *filename, */ +/* const char *filetype) */ +/* int QSwrite_prob_file (QSdata *p, FILE *file, const char *filetype) */ +/* int QSset_param (QSdata *p, int whichparam, int newvalue) */ +/* int QSset_param_double (QSdata *p, int whichparam, double newvalue) */ +/* int QSget_param (QSdata *p, int whichparam, int *value) */ +/* int QSget_param_double (QSdata *p, int whichparam, double *value) */ +/* int QStest_row_norms (QSdata *p) */ +/* int QSopt_strongbranch (QSdata *p, int ncand, int *candidatelist, */ +/* double *xlist, double *down_vals, double *up_vals, */ +/* int iterations, double objbound) */ +/* int QSopt_pivotin_row (QSdata *p, int rcnt, int *rlist) */ +/* int QSopt_pivotin_col (QSdata *p, int ccnt, int *clist) */ +/* void QSfree (void *ptr) */ +/* void QSstart (void) */ +/* void QSend (void) */ +/* char *QSversion (void)) */ +/* */ +/* NEW FUNCTIONS - Add to Docs */ +/* */ +/* char *QSversion (void)) */ +/* int QSget_objsense (QSdata *p, int *objsense) */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "iqsutil.h" +#include "lpdata.h" +#include "lpdefs.h" +#include "simplex.h" +#include "price.h" +#include "qstruct.h" +#include "qsopt.h" +#include "lib.h" +#include "mps.h" +#include "lp.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif +void QSset_precision ( + const unsigned prec) +{ + EGlpNumSetPrecision (prec); + ILLchange_precision (); + /* change the numbers */ +} + +static void init_basis ( + QSbasis * B), + free_cache ( + QSdata * p); + +int grab_cache ( QSdata * p, int status); +static int opt_work ( QSdata * p, int *status, int primal_or_dual), + qsbasis_to_illbasis ( QSbasis * qB, ILLlp_basis * B), + illbasis_to_qsbasis ( ILLlp_basis * B, QSbasis * qB), + grab_basis ( QSdata * p), + check_qsdata_pointer ( QSdata * p); + + +QSLIB_INTERFACE int QSopt_primal ( + QSdata * p, + int *status) +{ + int rval = 0; + + if (status) + *status = QS_LP_UNSOLVED; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + /* If both the basis and the cache exist, then skip the optimization */ + + if (!p->basis || !p->cache) + { + rval = opt_work (p, status, 0); + CHECKRVALG (rval, CLEANUP); + } + else + { + if (status) + *status = p->cache->status; + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSopt_dual ( + QSdata * p, + int *status) +{ + int rval = 0; + + if (status) + *status = QS_LP_UNSOLVED; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (!p->basis || !p->cache || !p->factorok) + { + rval = opt_work (p, status, 1); + CHECKRVALG (rval, CLEANUP); + } + else + { + if (status) + *status = p->cache->status; + } + +CLEANUP: + + if (rval == QS_LP_CHANGE_PREC) + { + MESSAGE (__QS_SB_VERB, "Changing precision"); + return rval; + } + EG_RETURN (rval); +} + +static int opt_work ( + QSdata * p, + int *status, + int primal_or_dual) +{ + int rval = 0; + int rstatus = QS_LP_UNSOLVED; + QSdata *p2 = 0; + + if (p->basis) + { + if (p->basis->nstruct != p->qslp->nstruct || + p->basis->nrows != p->qslp->nrows) + { + fprintf (stderr, "Size of basis does not match LP\n"); + rval = 1; + goto CLEANUP; + } + } + + if (!p->basis && p->lp->basisid == -1 && p->simplex_scaling == 1) + { + /* Try scaling by copying the LP and solving */ + + ILLprice_free_pricing_info (p->pricing); /* Just to be sure */ + p->factorok = 0; /* that p is clean. */ + + p2 = QScopy_prob (p, "scaled_lp"); + if (p2 == 0) + goto CLEANUP; + + rval = ILLlp_scale (p2->qslp); + CHECKRVALG (rval, CLEANUP); + + if (primal_or_dual == 0) + { + rval = ILLlib_optimize (p2->lp, p2->basis, p2->pricing, + PRIMAL_SIMPLEX, 0, p2->simplex_display, + &(p->itcnt)); + } + else + { + rval = ILLlib_optimize (p2->lp, p2->basis, p2->pricing, + DUAL_SIMPLEX, 0, p2->simplex_display, + &(p->itcnt)); + } + CHECKRVALG (rval, CLEANUP); + + rval = grab_basis (p2); + CHECKRVALG (rval, CLEANUP); + + if (p->basis) + { + ILLlp_basis_free (p->basis); + ILL_IFFREE (p->basis, ILLlp_basis); + } + p->basis = p2->basis; + p2->basis = 0; + QSfree_prob (p2); + p2 = 0; + } + + if (primal_or_dual == 0) + { + if (p->factorok == 0) + { + if (p->basis == 0) + p->lp->basisid = -1; + rval = ILLlib_optimize (p->lp, p->basis, p->pricing, PRIMAL_SIMPLEX, + &rstatus, p->simplex_display, &(p->itcnt)); + } + else + { + ILLprice_free_pricing_info (p->pricing); + if (p->lp->basisid != -1) + p->lp->fbasisid = p->lp->basisid; + rval = ILLlib_optimize (p->lp, 0, p->pricing, + PRIMAL_SIMPLEX, &rstatus, p->simplex_display, + &(p->itcnt)); + } + } + else + { + if (p->factorok == 0) + { + if (p->basis == 0) + p->lp->basisid = -1; + rval = ILLlib_optimize (p->lp, p->basis, p->pricing, DUAL_SIMPLEX, + &rstatus, p->simplex_display, &(p->itcnt)); + } + else + { + /* The factorization and rownorms should be up-to-date */ + if (p->lp->basisid != -1) + { + p->lp->fbasisid = p->lp->basisid; + } + else + { + ILLprice_free_pricing_info (p->pricing); + } + rval = ILLlib_optimize (p->lp, 0, p->pricing, + DUAL_SIMPLEX, &rstatus, p->simplex_display, + &(p->itcnt)); + } + } + CHECKRVALG (rval, CLEANUP); + + rval = grab_basis (p); + CHECKRVALG (rval, CLEANUP); + + if (rstatus == QS_LP_OPTIMAL) + { + rval = grab_cache (p, rstatus); + CHECKRVALG (rval, CLEANUP); + } + else + { + free_cache (p); + } + + p->factorok = 1; + +#if 0 + p->lp->basisid = -1; /* This will cause the basis to be reloaded at the */ + /* next optimization - it could be moved into the */ + /* add/del routines if we want to cache the */ + /* factored basis. */ + -switched to having qs_simplex load a basis whenever it is passed; + the trouble with keeping basisid == -1 is that the QS - level routines + will not know if the + current lp has been optimized (so, for example, + getbasis will not work) + . +#endif + CLEANUP:p->qstatus = rstatus; + + if (status) + *status = rstatus; + + if (p2) + QSfree_prob (p2); + if (rval == QS_LP_CHANGE_PREC) + { + MESSAGE (__QS_SB_VERB, "Changing precision"); + return rval; + } + MESSAGE (rval ? 0 : 1000, "Error code %d", rval); + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSopt_pivotin_row ( + QSdata * p, + int rcnt, + int *rlist) +{ + int basismod = 0; + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->pricing == 0) + { + ILL_ERROR (rval, "pricing info not available in QSopt_pivotin_row\n"); + } + + rval = ILLsimplex_pivotin (p->lp, p->pricing, rcnt, rlist, + SIMPLEX_PIVOTINROW, &basismod); + CHECKRVALG (rval, CLEANUP); + + rval = grab_basis (p); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSopt_pivotin_col ( + QSdata * p, + int ccnt, + int *clist) +{ + int basismod = 0; + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->pricing == 0) + { + ILL_ERROR (rval, "pricing info not available in QSopt_pivotin\n"); + } + + rval = ILLsimplex_pivotin (p->lp, p->pricing, ccnt, clist, + SIMPLEX_PIVOTINCOL, &basismod); + CHECKRVALG (rval, CLEANUP); + + rval = grab_basis (p); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + + +QSLIB_INTERFACE int QSopt_strongbranch ( + QSdata * p, + int ncand, + int *candidatelist, + EGlpNum_t * xlist, + EGlpNum_t * down_vals, + EGlpNum_t * up_vals, + int iterations, + EGlpNum_t objbound) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->pricing == 0) + { + rval = 1; + CHECKRVALG (rval, CLEANUP); + } + + rval = ILLlib_strongbranch (p->lp, p->pricing, candidatelist, ncand, + xlist, down_vals, up_vals, iterations, objbound, + &(p->itcnt)); + CHECKRVALG (rval, CLEANUP); + + p->factorok = 0; + free_cache (p); + p->qstatus = QS_LP_UNSOLVED; /* Was set to MODIFIED in free_cache () */ + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE QSdata *QScreate_prob ( + const char *name, + int objsense) +{ + int rval = 0; + QSdata *p = 0; + int len; + + ILL_SAFE_MALLOC (p, 1, QSdata); + if (!p) + { + fprintf (stderr, "out of memory in QScreate_prob\n"); + rval = 1; + goto CLEANUP; + } + + p->qslp = 0; + p->lp = 0; + p->pricing = 0; + p->basis = 0; + p->cache = 0; + p->qstatus = QS_LP_UNSOLVED; + p->factorok = 0; + + p->itcnt.pI_iter = 0; + p->itcnt.pII_iter = 0; + p->itcnt.dI_iter = 0; + p->itcnt.dII_iter = 0; + p->itcnt.tot_iter = 0; + EGlpNumInitVar(p->uobjlim); + EGlpNumInitVar(p->lobjlim); + EGlpNumCopy(p->uobjlim, ILL_MAXDOUBLE); + EGlpNumCopy(p->lobjlim, ILL_MINDOUBLE); + + p->simplex_display = 0; + p->simplex_scaling = 1; + + ILL_SAFE_MALLOC (p->qslp, 1, ILLlpdata); + if (!p->qslp) + { + fprintf (stderr, "out of memory in QScreate_prob\n"); + rval = 1; + goto CLEANUP; + } + ILLlpdata_init (p->qslp); + + ILL_SAFE_MALLOC (p->lp, 1, lpinfo); + if (!p->lp) + { + fprintf (stderr, "out of memory in QScreate_prob\n"); + rval = 1; + goto CLEANUP; + } + EGlpNumInitVar (p->lp->objval); + EGlpNumInitVar (p->lp->pobjval); + EGlpNumInitVar (p->lp->dobjval); + EGlpNumInitVar (p->lp->pinfeas); + EGlpNumInitVar (p->lp->dinfeas); + EGlpNumInitVar (p->lp->objbound); + EGlpNumInitVar (p->lp->upd.piv); + EGlpNumInitVar (p->lp->upd.dty); + EGlpNumInitVar (p->lp->upd.c_obj); + EGlpNumInitVar (p->lp->upd.tz); + ILLsimplex_init_lpinfo (p->lp); + ILLsimplex_load_lpinfo (p->qslp, p->lp); + + ILL_SAFE_MALLOC (p->pricing, 1, price_info); + if (!p->pricing) + { + fprintf (stderr, "out of memory in QScreate_prob\n"); + rval = 1; + goto CLEANUP; + } + EGlpNumInitVar (p->pricing->htrigger); + ILLprice_init_pricing_info (p->pricing); + p->pricing->pI_price = QS_DEFAULT_PRICE_PI; + p->pricing->pII_price = QS_DEFAULT_PRICE_PII; + p->pricing->dI_price = QS_DEFAULT_PRICE_DI; + p->pricing->dII_price = QS_DEFAULT_PRICE_DII; + + if (name) + { + len = strlen (name) + 1; + ILL_SAFE_MALLOC (p->name, len, char); + + strcpy (p->name, name); + } + else + { + ILL_SAFE_MALLOC (p->name, 7, char); + + sprintf (p->name, "noname"); + } + + len = strlen (p->name) + 1; + ILL_SAFE_MALLOC (p->qslp->probname, len, char); + + strcpy (p->qslp->probname, p->name); + + if (objsense == QS_MAX) + { + p->qslp->objsense = QS_MAX; + } + +CLEANUP: + + if (rval) + { + QSfree_prob (p); + p = 0; + } + + return p; +} + +QSLIB_INTERFACE QSdata *QSread_prob ( + const char *filename, + const char *filetype) +{ + QSdata *p = 0; + EGioFile_t *file = 0; + QSline_reader reader; + + if ((file = EGioOpen (filename, "r")) == 0) + { + perror (filename); + fprintf (stderr, "Unable to open \"%s\" for input.\n", filename); + } + if (file == NULL) + goto CLEANUP; + + reader = ILLline_reader_new ((qsread_line_fct) EGioGets, file); + p = QSget_prob (reader, filename, filetype); + QSline_reader_free (reader); /* Bico - 040723 */ + +CLEANUP: + if (file != NULL) + { + EGioClose (file); + } + return p; +} + +QSLIB_INTERFACE QSdata *QSload_prob ( + const char *probname, + int ncols, + int nrows, + int *cmatcnt, + int *cmatbeg, + int *cmatind, + EGlpNum_t * cmatval, + int objsense, + EGlpNum_t * obj, + EGlpNum_t * rhs, + char *sense, + EGlpNum_t * lower, + EGlpNum_t * upper, + const char **colnames, + const char **rownames) +{ + int rval = 0; + QSdata *p = 0; + + p = QScreate_prob (probname, objsense); + if (p == 0) + goto CLEANUP; + + rval = ILLlib_newrows (p->lp, 0, nrows, rhs, sense, 0, rownames); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_addcols (p->lp, 0, ncols, cmatcnt, cmatbeg, cmatind, + cmatval, obj, lower, upper, colnames, 0); + CHECKRVALG (rval, CLEANUP); + + p->factorok = 0; + +CLEANUP: + + if (rval) + { + QSfree_prob (p); + p = 0; + } + + return p; +} + +QSLIB_INTERFACE QSdata *QScopy_prob ( + QSdata * p, + const char *newname) +{ + int rval = 0; + int j, col, beg, pindex, hit; + QSdata *p2 = 0; + char *coln; + char buf[ILL_namebufsize]; + + /* printf ("QScopy_prob ...\n"); fflush (stdout); */ + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + p2 = QScreate_prob (newname, p->qslp->objsense); + if (p2 == 0) + goto CLEANUP; + + rval = ILLlib_newrows (p2->lp, 0, p->qslp->nrows, + p->qslp->rhs, p->qslp->sense, p->qslp->rangeval, + (const char **) p->qslp->rownames); + CHECKRVALG (rval, CLEANUP); + + for (j = 0; j < p->qslp->nstruct; j++) + { + col = p->qslp->structmap[j]; + if (p->qslp->colnames) + coln = p->qslp->colnames[j]; + else + coln = 0; + beg = p->qslp->A.matbeg[col]; + + /* Monika: Note that Java will need to handle these arrays */ + /* without using the beg offset. The easiest way */ + /* may be to copy the arrays, as in the getcols() */ + /* code in lib.c. */ + + rval = ILLlib_addcol (p2->lp, 0, + p->qslp->A.matcnt[col], + p->qslp->A.matind + beg, p->qslp->A.matval + beg, + p->qslp->obj[col], p->qslp->lower[col], + p->qslp->upper[col], coln, 0); + CHECKRVALG (rval, CLEANUP); + } + + p2->qslp->objsense = p->qslp->objsense; + + p2->factorok = 0; + p2->simplex_display = p->simplex_display; + p2->simplex_scaling = p->simplex_scaling; + EGlpNumClearVar (p2->pricing->htrigger); + *(p2->pricing) = *(p->pricing); + /* I added this line because copying the heap (as a pointer) doesn't make any + * sense ! */ + ILLheap_init (&(p2->pricing->h)); + EGlpNumInitVar (p2->pricing->htrigger); + EGlpNumCopy (p2->pricing->htrigger, p->pricing->htrigger); + + if (p->qslp->intmarker != 0) + { + ILL_SAFE_MALLOC (p2->qslp->intmarker, p->qslp->nstruct, char); + + for (j = 0; j < p->qslp->nstruct; j++) + { + p2->qslp->intmarker[j] = p->qslp->intmarker[j]; + } + } + + if (p->qslp->objname != 0) + { + ILL_UTIL_STR (p2->qslp->objname, p->qslp->objname); + } + else + { + strcpy (buf, "obj"); + rval = ILLsymboltab_uname (&p2->qslp->rowtab, buf, "", NULL); + CHECKRVALG (rval, CLEANUP); + ILL_UTIL_STR (p2->qslp->objname, buf); + } + rval = ILLsymboltab_register (&p2->qslp->rowtab, p2->qslp->objname, + -1, &pindex, &hit); + rval = rval || hit; + CHECKRVALG (rval, CLEANUP); + + ILLstring_reporter_copy (&p2->qslp->reporter, &p->qslp->reporter); + +CLEANUP: + + if (rval) + { + QSfree_prob (p2); + p2 = 0; + } + + return p2; +} + +QSLIB_INTERFACE int QSchange_objsense ( + QSdata * p, + int newsense) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (newsense != QS_MIN && newsense != QS_MAX) + { + fprintf (stderr, "Illegal objective sense %d\n", newsense); + rval = 1; + goto CLEANUP; + } + + if (p->qslp->objsense != newsense) + { + if(newsense == QS_MAX) ILLsimplex_set_bound(p->lp,(const EGlpNum_t *)(&(p->lobjlim)), newsense); + else ILLsimplex_set_bound(p->lp,(const EGlpNum_t*)(&(p->uobjlim)), newsense); + p->qslp->objsense = newsense; + free_cache (p); + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int +QSget_itcnt( + QSdata* p, + int *pI_iter, + int *pII_iter, + int *dI_iter, + int *dII_iter, + int *tot_iter) +{ + int rval = 0; + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + if(pI_iter) *pI_iter = p->itcnt.pI_iter; + if(pII_iter) *pII_iter = p->itcnt.pII_iter; + if(dI_iter) *dI_iter = p->itcnt.dI_iter; + if(dII_iter) *dII_iter = p->itcnt.dII_iter; + if(tot_iter) *tot_iter = p->itcnt.tot_iter; + +CLEANUP: + + EG_RETURN(rval); +} + +QSLIB_INTERFACE int QSget_objsense ( + QSdata * p, + int *objsense) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (objsense) + *objsense = p->qslp->objsense; + +CLEANUP: + + EG_RETURN (rval); +} + + +QSLIB_INTERFACE int QSnew_col ( + QSdata * p, + const EGlpNum_t obj, + const EGlpNum_t lower, + const EGlpNum_t upper, + const char *name) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_newcol (p->lp, p->basis, obj, lower, upper, name, p->factorok); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSadd_cols ( + QSdata * p, + int num, + int *cmatcnt, + int *cmatbeg, + int *cmatind, + EGlpNum_t * cmatval, + EGlpNum_t * obj, + EGlpNum_t * lower, + EGlpNum_t * upper, + const char **names) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_addcols (p->lp, p->basis, num, cmatcnt, cmatbeg, + cmatind, cmatval, obj, lower, upper, names, + p->factorok); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSadd_col ( + QSdata * p, + int cnt, + int *cmatind, + EGlpNum_t * cmatval, + EGlpNum_t obj, + EGlpNum_t lower, + EGlpNum_t upper, + const char *name) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_addcol (p->lp, p->basis, cnt, cmatind, cmatval, + obj, lower, upper, name, p->factorok); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSnew_row ( + QSdata * p, + const EGlpNum_t rhs, + int sense, + const char *name) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_newrow (p->lp, p->basis, rhs, sense, zeroLpNum, name); + CHECKRVALG (rval, CLEANUP); + + p->factorok = 0; + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSadd_ranged_rows ( + QSdata * p, + int num, + int *rmatcnt, + int *rmatbeg, + int *rmatind, + const EGlpNum_t * rmatval, + const EGlpNum_t * rhs, + char *sense, + const EGlpNum_t * range, + const char **names) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_addrows (p->lp, p->basis, num, rmatcnt, rmatbeg, + rmatind, rmatval, rhs, sense, range, + names, &(p->factorok)); + CHECKRVALG (rval, CLEANUP); + + if (p->factorok == 1 && p->basis->rownorms) + { + rval = ILLlib_loadrownorms (p->lp, p->pricing, p->basis->rownorms); + CHECKRVALG (rval, CLEANUP); + /* This really should go inside of ILLlib_addrows, once pinf is */ + /* is moved into the lp struct. */ + } + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSadd_ranged_row ( + QSdata * p, + int cnt, + int *rmatind, + const EGlpNum_t * rmatval, + const EGlpNum_t * rhs, + int sense, + const EGlpNum_t * range, + const char *name) +{ + int rval = 0; + int vmatcnt[1]; + int vmatbeg[1]; + char vsense[1]; + const char *vnames[1]; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + vmatcnt[0] = cnt; + vmatbeg[0] = 0; + vsense[0] = sense; + vnames[0] = name; + + rval = QSadd_ranged_rows (p, 1, vmatcnt, vmatbeg, rmatind, rmatval, rhs, + vsense, range, vnames); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSadd_rows ( + QSdata * p, + int num, + int *rmatcnt, + int *rmatbeg, + int *rmatind, + const EGlpNum_t * rmatval, + const EGlpNum_t * rhs, + char *sense, + const char **names) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_addrows (p->lp, p->basis, num, rmatcnt, rmatbeg, + rmatind, rmatval, rhs, sense, 0, names, + &(p->factorok)); + CHECKRVALG (rval, CLEANUP); + + if (p->factorok == 1 && p->basis->rownorms) + { + rval = ILLlib_loadrownorms (p->lp, p->pricing, p->basis->rownorms); + CHECKRVALG (rval, CLEANUP); + /* This really should go inside of ILLlib_addrows, once pinf is */ + /* is moved into the lp struct. */ + } + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSadd_row ( + QSdata * p, + int cnt, + int *rmatind, + const EGlpNum_t * rmatval, + const EGlpNum_t * rhs, + int sense, + const char *name) +{ + int rval = 0; + int vmatcnt[1]; + int vmatbeg[1]; + char vsense[1]; + const char *vnames[1]; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + vmatcnt[0] = cnt; + vmatbeg[0] = 0; + vsense[0] = sense; + vnames[0] = name; + + rval = QSadd_rows (p, 1, vmatcnt, vmatbeg, rmatind, rmatval, rhs, vsense, + vnames); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_rows ( + QSdata * p, + int num, + int *dellist) +{ + int rval = 0; + int basis_ok = 0; + int cache_ok = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_delrows (p->lp, p->basis, p->cache, num, dellist, &basis_ok, + &cache_ok); + CHECKRVALG (rval, CLEANUP); + + /* For now, just remove the basis - wait for pivotin */ + + if (p->basis && !basis_ok) + { + ILLlp_basis_free (p->basis); + ILL_IFFREE (p->basis, ILLlp_basis); + } + + p->factorok = 0; + + if (!p->basis || !basis_ok || !cache_ok) + { + /* Note: If we only delete basic rows then cached soln is valid */ + free_cache (p); + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_row ( + QSdata * p, + int rowindex) +{ + int rval = 0; + int vdellist[1]; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + vdellist[0] = rowindex; + + rval = QSdelete_rows (p, 1, vdellist); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_setrows ( + QSdata * p, + int *flags) +{ + int rval = 0; + int j, num = 0; + int *dellist = 0; + int nrows; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + nrows = p->qslp->nrows; + + for (j = 0; j < nrows; j++) + { + if (flags[j] == 1) + num++; + } + + if (num > 0) + { + ILL_SAFE_MALLOC (dellist, num, int); + + for (j = 0, num = 0; j < nrows; j++) + { + if (flags[j] == 1) + { + dellist[num++] = j; + } + } + + rval = QSdelete_rows (p, num, dellist); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + ILL_IFFREE (dellist, int); + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_named_row ( + QSdata * p, + const char *rowname) +{ + int rval = 0; + int i, vdellist[1]; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = QSget_row_index (p, rowname, &i); + CHECKRVALG (rval, CLEANUP); + + vdellist[0] = i; + + rval = QSdelete_rows (p, 1, vdellist); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_named_rows_list ( + QSdata * p, + int num, + const char **rownames) +{ + int rval = 0; + int i, k; + int *vdellist = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (num > 0) + { + ILL_SAFE_MALLOC (vdellist, num, int); + + for (k = 0; k < num; k++) + { + rval = QSget_row_index (p, rownames[k], &i); + CHECKRVALG (rval, CLEANUP); + vdellist[k] = i; + } + + rval = QSdelete_rows (p, num, vdellist); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + ILL_IFFREE (vdellist, int); + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_cols ( + QSdata * p, + int num, + int *dellist) +{ + int rval = 0; + int basis_ok; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_delcols (p->lp, p->basis, num, dellist, &basis_ok); + CHECKRVALG (rval, CLEANUP); + + /* For now, just remove the basis - wait for pivotout */ + + if (p->basis && !basis_ok) + { + ILLlp_basis_free (p->basis); + ILL_IFFREE (p->basis, ILLlp_basis); + } + + p->factorok = 0; + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_col ( + QSdata * p, + int colindex) +{ + int rval = 0; + int vdellist[1]; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + vdellist[0] = colindex; + + rval = QSdelete_cols (p, 1, vdellist); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_setcols ( + QSdata * p, + int *flags) +{ + int rval = 0; + int j, num = 0; + int *dellist = 0; + int ncols; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + ncols = p->qslp->nstruct; + + for (j = 0; j < ncols; j++) + { + if (flags[j] == 1) + num++; + } + + if (num > 0) + { + ILL_SAFE_MALLOC (dellist, num, int); + + for (j = 0, num = 0; j < ncols; j++) + { + if (flags[j] == 1) + { + dellist[num++] = j; + } + } + + rval = QSdelete_cols (p, num, dellist); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + ILL_IFFREE (dellist, int); + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_named_column ( + QSdata * p, + const char *colname) +{ + int rval = 0; + int j, vdellist[1]; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = QSget_column_index (p, colname, &j); + CHECKRVALG (rval, CLEANUP); + + vdellist[0] = j; + + rval = QSdelete_cols (p, 1, vdellist); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSdelete_named_columns_list ( + QSdata * p, + int num, + const char **colnames) +{ + int rval = 0; + int i, j; + int *vdellist = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (num > 0) + { + ILL_SAFE_MALLOC (vdellist, num, int); + + for (i = 0; i < num; i++) + { + rval = QSget_column_index (p, colnames[i], &j); + CHECKRVALG (rval, CLEANUP); + vdellist[i] = j; + } + + rval = QSdelete_cols (p, num, vdellist); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + ILL_IFFREE (vdellist, int); + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSchange_senses ( + QSdata * p, + int num, + int *rowlist, + char *sense) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_chgsense (p->lp, num, rowlist, sense); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSchange_range ( + QSdata*p, + int rowindex, + EGlpNum_t range) +{ + int rval = 0; + rval = check_qsdata_pointer (p); + CHECKRVALG(rval, CLEANUP); + + rval = ILLlib_chgrange (p->lp, rowindex, range); + CHECKRVALG(rval, CLEANUP); + + p->factorok = 0; /* Sanjeeb -- 050911 */ + free_cache (p); + +CLEANUP: + + EG_RETURN(rval); + +} + +QSLIB_INTERFACE int QSchange_sense ( + QSdata * p, + int rowindex, + int sense) +{ + int rval = 0; + int vrowlist[1]; + char vsenselist[1]; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + vrowlist[0] = rowindex; + vsenselist[0] = sense; + + rval = QSchange_senses (p, 1, vrowlist, vsenselist); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_coef ( + QSdata *p, + int rowindex, + int colindex, + EGlpNum_t* coef) +{ + int rval = 0; + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + rval = ILLlib_getcoef (p->lp, rowindex, colindex, coef); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSchange_coef ( + QSdata * p, + int rowindex, + int colindex, + EGlpNum_t coef) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_chgcoef (p->lp, rowindex, colindex, coef); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSchange_objcoef ( + QSdata * p, + int indx, + EGlpNum_t coef) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_chgobj (p->lp, indx, coef); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSchange_rhscoef ( + QSdata * p, + int indx, + EGlpNum_t coef) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_chgrhs (p->lp, indx, coef); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSchange_bounds ( + QSdata * p, + int num, + int *collist, + char *lu, + const EGlpNum_t * bounds) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_chgbnds (p->lp, num, collist, lu, bounds); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSchange_bound ( + QSdata * p, + int indx, + int lu, + const EGlpNum_t bound) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_chgbnd (p->lp, indx, lu, bound); + CHECKRVALG (rval, CLEANUP); + + free_cache (p); + +CLEANUP: + + EG_RETURN (rval); +} + +#if 0 + /* + * Bico - I removed this on 02.04.22. I don't think we need to support + * this type of interface (the loading via arrays can do the job) + */ +QSLIB_INTERFACE QSbasis *QScreate_basis ( + int nstruct, + int nrows) +{ + int rval = 0; + int i; + QSbasis *B = 0; + + ILL_SAFE_MALLOC (B, 1, QSbasis); + + B->nstruct = nstruct; + B->nrows = nrows; + B->cstat = 0; + B->rstat = 0; + + if (nstruct) + { + ILL_SAFE_MALLOC (B->cstat, nstruct, char); + } + + if (nrows) + { + ILL_SAFE_MALLOC (B->rstat, nrows, char); + } + + for (i = 0; i < nstruct; i++) + B->cstat[i] = 0; + for (i = 0; i < nrows; i++) + B->rstat[i] = 0; + +CLEANUP: + + if (rval) + { + QSfree_basis (B); + B = 0; + } + + return B; +} +#endif + +QSLIB_INTERFACE QSbasis *QSread_basis ( + QSdata * p, + const char *filename) +{ + int rval = 0; + QSbasis *qB = 0; + ILLlp_basis B; + + ILLlp_basis_init (&B); + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + ILL_NEW (qB, QSbasis); + init_basis (qB); + + rval = ILLlib_readbasis (p->lp, &B, filename); + CHECKRVALG (rval, CLEANUP); + + rval = illbasis_to_qsbasis (&B, qB); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + if (rval && qB) + { + QSfree_basis (qB); + qB = 0; + } + ILLlp_basis_free (&B); + + return qB; +} + +QSLIB_INTERFACE int QSload_basis ( + QSdata * p, + QSbasis * B) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (B->nstruct != p->qslp->nstruct || B->nrows != p->qslp->nrows) + { + fprintf (stderr, "size of basis does not match lp\n"); + rval = 1; + goto CLEANUP; + } + + if (p->basis == 0) + { + ILL_SAFE_MALLOC (p->basis, 1, ILLlp_basis); + ILLlp_basis_init (p->basis); + } + else + { + ILLlp_basis_free (p->basis); + } + + rval = qsbasis_to_illbasis (B, p->basis); + CHECKRVALG (rval, CLEANUP); + + p->factorok = 0; + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSread_and_load_basis ( + QSdata * p, + const char *filename) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->basis == 0) + { + ILL_SAFE_MALLOC (p->basis, 1, ILLlp_basis); + ILLlp_basis_init (p->basis); + } + else + { + ILLlp_basis_free (p->basis); + } + + rval = ILLlib_readbasis (p->lp, p->basis, filename); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + return rval; +} + +QSLIB_INTERFACE int QSload_basis_array ( + QSdata * p, + char *cstat, + char *rstat) +{ + int rval = 0; + int i; + ILLlp_basis *B; + ILLlpdata *qslp; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + qslp = p->qslp; + + if (qslp->nstruct > 0 && cstat == 0) + { + fprintf (stderr, "QSload_basis_array called without cstat\n"); + rval = 1; + goto CLEANUP; + } + + if (qslp->nrows > 0 && rstat == 0) + { + fprintf (stderr, "QSload_basis_array called without rstat\n"); + rval = 1; + goto CLEANUP; + } + + if (p->basis == 0) + { + ILL_SAFE_MALLOC (p->basis, 1, ILLlp_basis); + ILLlp_basis_init (p->basis); + } + else + { + ILLlp_basis_free (p->basis); + } + + B = p->basis; + + B->nstruct = qslp->nstruct; + B->nrows = qslp->nrows; + ILL_SAFE_MALLOC (B->cstat, qslp->nstruct, char); + ILL_SAFE_MALLOC (B->rstat, qslp->nrows, char); + + for (i = 0; i < qslp->nstruct; i++) + { + B->cstat[i] = cstat[i]; + } + + for (i = 0; i < qslp->nrows; i++) + { + B->rstat[i] = rstat[i]; + } + + p->factorok = 0; + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSload_basis_and_row_norms_array ( + QSdata * p, + char *cstat, + char *rstat, + EGlpNum_t * rownorms) +{ + int rval = 0; + int i, nrows; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + nrows = p->qslp->nrows; + + rval = QSload_basis_array (p, cstat, rstat); + CHECKRVALG (rval, CLEANUP); + p->basis->rownorms = EGlpNumAllocArray (nrows); + + for (i = 0; i < nrows; i++) + { + EGlpNumCopy (p->basis->rownorms[i], rownorms[i]); + } + + p->factorok = 0; + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSwrite_basis ( + QSdata * p, + QSbasis * B, + const char *filename) +{ + int rval = 0; + ILLlp_basis iB, *basis = 0; + + ILLlp_basis_init (&iB); + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (B) + { + rval = qsbasis_to_illbasis (B, &iB); + CHECKRVALG (rval, CLEANUP); + basis = &iB; + } + else + { + if (p->basis == 0) + { + fprintf (stderr, "no basis available in QSwrite_basis\n"); + rval = 1; + goto CLEANUP; + } + basis = p->basis; + } + + rval = ILLlib_writebasis (p->lp, basis, filename); + CHECKRVALG (rval, CLEANUP); + + +CLEANUP: + + ILLlp_basis_free (basis); + EG_RETURN (rval); +} + +QSLIB_INTERFACE QSbasis *QSget_basis ( + QSdata * p) +{ + int rval = 0; + QSbasis *B = 0; + + if (p->basis == 0) + { + fprintf (stderr, "no basis available in QSget_basis\n"); + rval = 1; + goto CLEANUP; + } + + ILL_SAFE_MALLOC (B, 1, QSbasis); + init_basis (B); + rval = illbasis_to_qsbasis (p->basis, B); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + if (rval) + { + QSfree_basis (B); + B = 0; + } + + return B; +} + +QSLIB_INTERFACE int QSget_basis_array ( + QSdata * p, + char *cstat, + char *rstat) +{ + int rval = 0; + int i; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->basis == 0) + { + fprintf (stderr, "no basis available in QSget_basis_array\n"); + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < p->basis->nstruct; i++) + cstat[i] = p->basis->cstat[i]; + for (i = 0; i < p->basis->nrows; i++) + rstat[i] = p->basis->rstat[i]; + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_basis_and_row_norms_array ( + QSdata * p, + char *cstat, + char *rstat, + EGlpNum_t * rownorms) +{ + int rval = 0; + int i; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->basis == 0) + { + fprintf (stderr, "no basis available\n"); + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < p->basis->nstruct; i++) + cstat[i] = p->basis->cstat[i]; + for (i = 0; i < p->basis->nrows; i++) + rstat[i] = p->basis->rstat[i]; + + if (p->basis->rownorms == 0) + { + fprintf (stderr, "no row norms available\n"); + rval = 1; + goto CLEANUP; + } + else + { + for (i = 0; i < p->basis->nrows; i++) + { + EGlpNumCopy (rownorms[i], p->basis->rownorms[i]); + } + } + +CLEANUP: + + EG_RETURN (rval); +} + +static int illbasis_to_qsbasis ( + ILLlp_basis * B, + QSbasis * qB) +{ + int rval = 0; + int i; + + qB->nstruct = B->nstruct; + qB->nrows = B->nrows; + ILL_SAFE_MALLOC (qB->cstat, B->nstruct, char); + ILL_SAFE_MALLOC (qB->rstat, B->nrows, char); + + for (i = 0; i < B->nstruct; i++) + { + qB->cstat[i] = B->cstat[i]; + } + + for (i = 0; i < B->nrows; i++) + { + qB->rstat[i] = B->rstat[i]; + } + +CLEANUP: + + EG_RETURN (rval); +} + +static int qsbasis_to_illbasis ( + QSbasis * qB, + ILLlp_basis * B) +{ + int rval = 0; + int i; + int nbas = 0; + + B->nstruct = qB->nstruct; + B->nrows = qB->nrows; + ILL_SAFE_MALLOC (B->cstat, qB->nstruct, char); + ILL_SAFE_MALLOC (B->rstat, qB->nrows, char); + + for (i = 0; i < qB->nstruct; i++) + { + if(qB->cstat[i] == QS_COL_BSTAT_BASIC) nbas++; + B->cstat[i] = qB->cstat[i]; + } + + for (i = 0; i < qB->nrows; i++) + { + if(qB->rstat[i] == QS_ROW_BSTAT_BASIC) nbas++; + B->rstat[i] = qB->rstat[i]; + } + + if(nbas != qB->nrows) + { + fprintf(stderr,"Received basis is not valid, in qsbasis_to_illbasis\n"); + rval = 1; + ILL_CLEANUP; + } + +CLEANUP: + + EG_RETURN (rval); +} + +int grab_basis ( + QSdata * p) +{ + int rval = 0; + ILLlp_basis *B = p->basis; + int nstruct = p->qslp->nstruct; + int nrows = p->qslp->nrows; + + if (!B) + { + ILL_SAFE_MALLOC (p->basis, 1, ILLlp_basis); + ILLlp_basis_init (p->basis); + B = p->basis; + } + + if (nstruct != B->nstruct) + { + ILL_IFFREE (B->cstat, char); + ILL_SAFE_MALLOC (B->cstat, nstruct, char); + + B->nstruct = nstruct; + } + + if (nrows != B->nrows) + { + ILL_IFFREE (B->rstat, char); + ILL_SAFE_MALLOC (B->rstat, nrows, char); + + B->nrows = nrows; + } + + rval = ILLlib_getbasis (p->lp, B->cstat, B->rstat); + CHECKRVALG (rval, CLEANUP); + + EGlpNumFreeArray (B->rownorms); + EGlpNumFreeArray (B->colnorms); + + if (p->pricing->dII_price == QS_PRICE_DSTEEP) + { + B->rownorms = EGlpNumAllocArray (nrows); + rval = ILLlib_getrownorms (p->lp, p->pricing, B->rownorms); + if (rval) + { +/* + fprintf (stderr, "no edge norms, continue anyway\n"); +*/ + EGlpNumFreeArray (B->rownorms); + rval = 0; + } + } + +CLEANUP: + + if (rval) + { + if (B) + { + ILLlp_basis_free (B); + ILL_IFFREE (p->basis, ILLlp_basis); + } + } + + EG_RETURN (rval); +} + +int grab_cache ( + QSdata * p, + int status) +{ + int rval = 0; + ILLlp_cache *C = p->cache; + int nstruct = p->qslp->nstruct; + int nrows = p->qslp->nrows; + #if 0 + /* we may need to fix basic status for fixed variables */ + register int i; + char *const cstat = p->basis->cstat; + const int *const structmap = p->lp->O->structmap; + const int sense = p->lp->O->objsense; + const int *const vtype = p->lp->vtype; + int *const vstat = p->lp->vstat; + /* end extra variables needed */ + #endif + + if (C == 0) + { + ILL_SAFE_MALLOC (p->cache, 1, ILLlp_cache); + EGlpNumInitVar (p->cache->val); + ILLlp_cache_init (p->cache); + C = p->cache; + } + + if (nstruct != C->nstruct || nrows != C->nrows) + { + ILLlp_cache_free (C); + rval = ILLlp_cache_alloc (C, nstruct, nrows); + CHECKRVALG (rval, CLEANUP); + } + + rval = ILLlib_cache_solution (p->lp, C); + CHECKRVALG (rval, CLEANUP); + + #if 0 + /* we fix basis status and vstat */ + for( i = nstruct ; i-- ; ) + { + if(vtype[structmap[i]] != VFIXED) continue; + if(cstat[i] == QS_COL_BSTAT_BASIC) continue; + if(( sense > 0 && EGlpNumIsLess(SZERO_TOLER,C->rc[i])) || + ( sense < 0 && !EGlpNumIsLess(SZERO_TOLER,C->rc[i]))) + { + vstat[structmap[i]] = STAT_LOWER; + cstat[i] = QS_COL_BSTAT_LOWER; + } + else + { + vstat[structmap[i]] = STAT_UPPER; + cstat[i] = QS_COL_BSTAT_UPPER; + } + }/* end fix */ + #endif + C->status = status; + +CLEANUP: + + if (rval) + { + if (C) + { + ILLlp_cache_free (C); + EGlpNumClearVar (p->cache->val); + ILL_IFFREE (p->cache, ILLlp_cache); + } + } + + EG_RETURN (rval); +} + +void free_cache ( + QSdata * p) +{ + if (p->cache) + { + ILLlp_cache_free (p->cache); + EGlpNumClearVar (p->cache->val); + ILL_IFFREE (p->cache, ILLlp_cache); + } + p->qstatus = QS_LP_MODIFIED; +} + +QSLIB_INTERFACE int QSget_binv_row ( + QSdata * p, + int indx, + EGlpNum_t * binvrow) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if(!p->basis) + { + fprintf(stderr, "no active basis in store\n"); + rval = 1; + goto CLEANUP; + } + if(0>indx || indx >= QSget_rowcount(p)) + { + fprintf(stderr, "row index %d outside valid bounds [%d:%d]\n", + indx, 0, QSget_rowcount(p)-1); + rval = 1; + goto CLEANUP; + } + if (p->cache == 0) + { + fprintf (stderr, "LP has not been optimized in QSget_binv_row\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_tableau (p->lp, indx, binvrow, 0); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_tableau_row ( + QSdata * p, + int indx, + EGlpNum_t * tableaurow) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "LP has not been optimized in QSget_tableau_row\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_tableau (p->lp, indx, 0, tableaurow); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_basis_order ( + QSdata * p, + int *basorder) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "LP has not been optimized in QSget_basis_order\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_basis_order (p->lp, basorder); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QScompute_row_norms ( + QSdata * p) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->pricing->dII_price != QS_PRICE_DSTEEP) + { + fprintf (stderr, "not using dual steepest edge\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_recompute_rownorms (p->lp, p->pricing); + CHECKRVALG (rval, CLEANUP); + + rval = grab_basis (p); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE void QSfree_prob ( + QSdata * p) +{ + if (p) + { + EGlpNumClearVar(p->uobjlim); + EGlpNumClearVar(p->lobjlim); + if (p->qslp) + { + ILLlpdata_free (p->qslp); + ILL_IFFREE (p->qslp, ILLlpdata); + } + if (p->lp) + { + ILLsimplex_free_lpinfo (p->lp); + EGlpNumClearVar (p->lp->objval); + EGlpNumClearVar (p->lp->pobjval); + EGlpNumClearVar (p->lp->dobjval); + EGlpNumClearVar (p->lp->pinfeas); + EGlpNumClearVar (p->lp->dinfeas); + EGlpNumClearVar (p->lp->objbound); + EGlpNumClearVar (p->lp->upd.piv); + EGlpNumClearVar (p->lp->upd.dty); + EGlpNumClearVar (p->lp->upd.c_obj); + EGlpNumClearVar (p->lp->upd.tz); + ILL_IFFREE (p->lp, lpinfo); + } + if (p->basis) + { + ILLlp_basis_free (p->basis); + ILL_IFFREE (p->basis, ILLlp_basis); + } + if (p->cache) + { + ILLlp_cache_free (p->cache); + EGlpNumClearVar (p->cache->val); + ILL_IFFREE (p->cache, ILLlp_cache); + } + if (p->pricing) + { + EGlpNumClearVar (p->pricing->htrigger); + ILLprice_free_pricing_info (p->pricing); + ILL_IFFREE (p->pricing, price_info); + } + ILL_IFFREE (p->name, char); + + ILL_IFFREE (p, QSdata); + } +} + +QSLIB_INTERFACE void QSfree_basis ( + QSbasis * B) +{ + if (B) + { + ILL_IFFREE (B->rstat, char); + ILL_IFFREE (B->cstat, char); + + ILL_IFFREE (B, QSbasis); + } +} + +static void init_basis ( + QSbasis * B) +{ + if (B) + { + B->nstruct = 0; + B->nrows = 0; + B->cstat = 0; + B->rstat = 0; + } +} + +QSLIB_INTERFACE int QSget_status ( + QSdata * p, + int *status) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (status) + *status = p->qstatus; + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_solution ( + QSdata * p, + EGlpNum_t * value, + EGlpNum_t * x, + EGlpNum_t * pi, + EGlpNum_t * slack, + EGlpNum_t * rc) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_solution\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_solution (p->lp, p->cache, value, x, pi, slack, rc); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_objval ( + QSdata * p, + EGlpNum_t * value) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + +/* Want to get objval after limited number of pivots. */ + + if (p->qstatus == QS_LP_MODIFIED) + { + fprintf (stderr, "QSmsg: LP has been modified since last solve.\n"); + rval = 1; + ILL_CLEANUP; + } + + rval = ILLlib_objval (p->lp, p->cache, value); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_x_array ( + QSdata * p, + EGlpNum_t * x) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_x_array\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_get_x (p->lp, p->cache, x); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_slack_array ( + QSdata * p, + EGlpNum_t * slack) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_slack_array\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_get_slack (p->lp, p->cache, slack); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_rc_array ( + QSdata * p, + EGlpNum_t * rc) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_rc_array\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_solution (p->lp, p->cache, 0, 0, 0, 0, rc); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_pi_array ( + QSdata * p, + EGlpNum_t * pi) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_pi_array\n"); + rval = 1; + goto CLEANUP; + } + + rval = ILLlib_solution (p->lp, p->cache, 0, 0, pi, 0, 0); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_infeas_array ( + QSdata * p, + EGlpNum_t * pi) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (pi == 0) + { + ILL_ERROR (rval, "QS_get_infeas_array called with NULL pi vector\n"); + } + + rval = ILLsimplex_infcertificate (p->lp, pi); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_named_x ( + QSdata * p, + const char *colname, + EGlpNum_t * val) +{ + int rval = 0; + int j; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_named_x\n"); + rval = 1; + goto CLEANUP; + } + + rval = QSget_column_index (p, colname, &j); + CHECKRVALG (rval, CLEANUP); + + if (j != -1) + { + EGlpNumCopy (*val, p->cache->x[j]); + } + else + { + rval = 1; + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_named_rc ( + QSdata * p, + const char *colname, + EGlpNum_t * val) +{ + int rval = 0; + int j; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_named_rc\n"); + rval = 1; + goto CLEANUP; + } + + rval = QSget_column_index (p, colname, &j); + CHECKRVALG (rval, CLEANUP); + + if (j != -1) + { + EGlpNumCopy (*val, p->cache->rc[j]); + } + else + { + rval = 1; + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_named_pi ( + QSdata * p, + const char *rowname, + EGlpNum_t * val) +{ + int rval = 0; + int i; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_named_pi\n"); + rval = 1; + goto CLEANUP; + } + + rval = QSget_row_index (p, rowname, &i); + CHECKRVALG (rval, CLEANUP); + + if (i != -1) + { + EGlpNumCopy (*val, p->cache->pi[i]); + } + else + { + rval = 1; + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_named_slack ( + QSdata * p, + const char *rowname, + EGlpNum_t * val) +{ + int rval = 0; + int i; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->cache == 0) + { + fprintf (stderr, "no solution available in QSget_named_slack\n"); + rval = 1; + goto CLEANUP; + } + + rval = QSget_row_index (p, rowname, &i); + CHECKRVALG (rval, CLEANUP); + + if (i != -1) + { + EGlpNumCopy (*val, p->cache->slack[i]); + } + else + { + rval = 1; + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_colcount ( + QSdata * p) +{ + int cnt; + + if (check_qsdata_pointer (p)) + cnt = 0; + else + cnt = p->qslp->nstruct; + + return cnt; +} + +QSLIB_INTERFACE int QSget_rowcount ( + QSdata * p) +{ + int cnt; + + if (check_qsdata_pointer (p)) + cnt = 0; + else + cnt = p->qslp->nrows; + + return cnt; +} + +QSLIB_INTERFACE int QSget_nzcount ( + QSdata * p) +{ + int cnt; + + if (check_qsdata_pointer (p)) + cnt = 0; + else + cnt = p->qslp->nzcount - p->qslp->nrows; + + return cnt; +} + +QSLIB_INTERFACE int QStest_row_norms ( + QSdata * p) +{ + int yesno; + + if (check_qsdata_pointer (p)) + { + yesno = 0; + } + else + { + if (p->basis && p->basis->rownorms) + { + yesno = 1; + } + else + { + yesno = 0; + } + } + + return yesno; +} + +QSLIB_INTERFACE int QSget_obj_list(QSprob p, + int num, + int*collist, + EGlpNum_t*obj) +{ + int rval = 0; + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + rval = ILLlib_getobj_list (p->lp, num, collist, obj); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_obj ( + QSdata * p, + EGlpNum_t * obj) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getobj (p->lp, obj); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_rhs ( + QSdata * p, + EGlpNum_t * rhs) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getrhs (p->lp, rhs); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_ranged_rows_list ( + QSdata * p, + int num, + int *rowlist, + int **rowcnt, + int **rowbeg, + int **rowind, + EGlpNum_t ** rowval, + EGlpNum_t ** rhs, + char **sense, + EGlpNum_t ** range, + char ***names) +{ + int rval = 0; + int i, nrows; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + nrows = QSget_rowcount (p); + for (i = 0; i < num; i++) + { + if (rowlist[i] < 0 || rowlist[i] >= nrows) + { + fprintf (stderr, "entry %d in rowlist out of range\n", i); + rval = 1; + goto CLEANUP; + } + } + + rval = ILLlib_getrows (p->lp, num, rowlist, rowcnt, rowbeg, rowind, + rowval, rhs, sense, range, names); + CHECKRVALG (rval, CLEANUP); + + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_ranged_rows ( + QSdata * p, + int **rowcnt, + int **rowbeg, + int **rowind, + EGlpNum_t ** rowval, + EGlpNum_t ** rhs, + char **sense, + EGlpNum_t ** range, + char ***names) +{ + int rval = 0; + int i, nrows; + int *rowlist = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + nrows = QSget_rowcount (p); + if (nrows > 0) + { + ILL_SAFE_MALLOC (rowlist, nrows, int); + + for (i = 0; i < nrows; i++) + { + rowlist[i] = i; + } + rval = ILLlib_getrows (p->lp, nrows, rowlist, rowcnt, rowbeg, rowind, + rowval, rhs, sense, range, names); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + ILL_IFFREE (rowlist, int); + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_senses ( + QSdata *p, + char *senses) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getsenses (p->lp, senses); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + + + +QSLIB_INTERFACE int QSget_rows_list ( + QSdata * p, + int num, + int *rowlist, + int **rowcnt, + int **rowbeg, + int **rowind, + EGlpNum_t ** rowval, + EGlpNum_t ** rhs, + char **sense, + char ***names) +{ + int rval = 0; + int i, nrows; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + nrows = QSget_rowcount (p); + for (i = 0; i < num; i++) + { + if (rowlist[i] < 0 || rowlist[i] >= nrows) + { + fprintf (stderr, "entry %d in rowlist out of range\n", i); + rval = 1; + goto CLEANUP; + } + } + + rval = ILLlib_getrows (p->lp, num, rowlist, rowcnt, rowbeg, rowind, + rowval, rhs, sense, 0, names); + CHECKRVALG (rval, CLEANUP); + + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_rows ( + QSdata * p, + int **rowcnt, + int **rowbeg, + int **rowind, + EGlpNum_t ** rowval, + EGlpNum_t ** rhs, + char **sense, + char ***names) +{ + int rval = 0; + int i, nrows; + int *rowlist = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + nrows = QSget_rowcount (p); + if (nrows > 0) + { + ILL_SAFE_MALLOC (rowlist, nrows, int); + + for (i = 0; i < nrows; i++) + { + rowlist[i] = i; + } + rval = ILLlib_getrows (p->lp, nrows, rowlist, rowcnt, rowbeg, rowind, + rowval, rhs, sense, 0, names); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + ILL_IFFREE (rowlist, int); + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_columns_list ( + QSdata * p, + int num, + int *collist, + int **colcnt, + int **colbeg, + int **colind, + EGlpNum_t ** colval, + EGlpNum_t ** obj, + EGlpNum_t ** lower, + EGlpNum_t ** upper, + char ***names) +{ + int rval = 0; + int j, ncols; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + ncols = QSget_colcount (p); + for (j = 0; j < num; j++) + { + if (collist[j] < 0 || collist[j] >= ncols) + { + fprintf (stderr, "entry %d in collist out of range\n", j); + rval = 1; + goto CLEANUP; + } + } + + rval = ILLlib_getcols (p->lp, num, collist, colcnt, colbeg, colind, + colval, obj, lower, upper, names); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_columns ( + QSdata * p, + int **colcnt, + int **colbeg, + int **colind, + EGlpNum_t ** colval, + EGlpNum_t ** obj, + EGlpNum_t ** lower, + EGlpNum_t ** upper, + char ***names) +{ + int rval = 0; + int j, ncols; + int *collist = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + ncols = QSget_colcount (p); + if (ncols > 0) + { + ILL_SAFE_MALLOC (collist, ncols, int); + + for (j = 0; j < ncols; j++) + { + collist[j] = j; + } + rval = ILLlib_getcols (p->lp, ncols, collist, colcnt, colbeg, colind, + colval, obj, lower, upper, names); + CHECKRVALG (rval, CLEANUP); + } + +CLEANUP: + + ILL_IFFREE (collist, int); + + EG_RETURN (rval); +} + +QSLIB_INTERFACE char *QSget_probname ( + QSdata * p) +{ + int rval = 0; + char *name = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + ILL_UTIL_STR (name, p->name); + +CLEANUP: + ILL_RETURN_PTR (name, "QSget_probname"); +} + +QSLIB_INTERFACE char *QSget_objname ( + QSdata * p) +{ + int rval = 0; + char *name = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (p->qslp->objname != 0) + { + ILL_UTIL_STR (name, p->qslp->objname); + } + +CLEANUP: + ILL_RETURN_PTR (name, "QSget_objname"); +} + +QSLIB_INTERFACE int QSget_rownames ( + QSdata * p, + char **rownames) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_rownames (p->lp, rownames); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_colnames ( + QSdata * p, + char **colnames) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_colnames (p->lp, colnames); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_bound ( + QSdata * p, + int colindex, + int lu, + EGlpNum_t * bound) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getbnd (p->lp, colindex, lu, bound); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_bounds_list( + QSdata* p, + int num, + int*collist, + EGlpNum_t*lb, + EGlpNum_t*ub) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getbnds_list (p->lp, num, collist, lb, ub); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_bounds ( + QSdata * p, + EGlpNum_t * lower, + EGlpNum_t * upper) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_getbnds (p->lp, lower, upper); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_intflags ( + QSdata * p, + int *intflags) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (intflags == 0) + { + rval = 1; + ILL_CLEANUP; + } + + rval = ILLlib_getintflags (p->lp, intflags); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_intcount ( + QSdata * p, + int *count) +{ + int j, ncols, cnt = 0, rval = 0; + int *intflags = 0; + + *count = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + ncols = QSget_colcount (p); + + if (ncols > 0) + { + ILL_SAFE_MALLOC (intflags, ncols, int); + + rval = ILLlib_getintflags (p->lp, intflags); + CHECKRVALG (rval, CLEANUP); + + for (j = 0; j < ncols; j++) + { + if (intflags[j] > 0) + cnt++; + } + } + +CLEANUP: + + *count = cnt; + ILL_IFFREE (intflags, int); + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_column_index ( + QSdata * p, + const char *name, + int *colindex) +{ + int rval = 0; + + *colindex = -1; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_colindex (p->lp, name, colindex); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_row_index ( + QSdata * p, + const char *name, + int *rowindex) +{ + int rval = 0; + + *rowindex = -1; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + rval = ILLlib_rowindex (p->lp, name, rowindex); + CHECKRVALG (rval, CLEANUP); + +CLEANUP: + + EG_RETURN (rval); +} + +static int QSwrite_prob_EGioFile( + QSdata*p, + EGioFile_t*out, + const char*filetype) +{ + int rval = 0; + qsstring_reporter rep; + + ILLstring_reporter_copy(&rep, &p->qslp->reporter); + ILLstring_reporter_init(&p->qslp->reporter, + (qsreport_string_fct) EGioWrite, out); + rval = QSreport_prob(p, filetype, NULL); + ILLstring_reporter_copy(&p->qslp->reporter, &rep); + ILL_RESULT(rval, "QSwrite_prob_EGioFile"); +} + +QSLIB_INTERFACE int QSwrite_prob ( + QSdata * p, + const char *filename, + const char *filetype) +{ + EGioFile_t *file = NULL; + int rval = 0; + + if (filename == NULL) + { + file = EGioOpenFILE(stdout); + } + else + { + if ((file = EGioOpen (filename, "w")) == 0) + { + perror (filename); + fprintf (stderr, "Unable to open \"%s\" for output.\n", filename); + } + } + ILL_CHECKnull (file, NULL); + rval = QSwrite_prob_EGioFile (p, file, filetype); + if (file) + { + EGioClose (file); + } +CLEANUP: + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSwrite_prob_file ( + QSdata * p, + FILE * out, + const char *filetype) +{ + int rval = 0; + EGioFile_t*lout = EGioOpenFILE(out); + rval = QSwrite_prob_EGioFile(p,lout,filetype); + CHECKRVALG(rval,CLEANUP); + CLEANUP: + free(lout); + EG_RETURN (rval); +} + +QSLIB_INTERFACE void QSfree ( + void *ptr) +{ + ILL_IFFREE (ptr, void); +} + +QSLIB_INTERFACE int QSset_param ( + QSdata * p, + int whichparam, + int newvalue) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + switch (whichparam) + { + case QS_PARAM_PRIMAL_PRICING: + if (newvalue == QS_PRICE_PDANTZIG || + newvalue == QS_PRICE_PDEVEX || + newvalue == QS_PRICE_PSTEEP || newvalue == QS_PRICE_PMULTPARTIAL) + { + p->pricing->pI_price = newvalue; + p->pricing->pII_price = newvalue; + } + else + { + fprintf (stderr, "illegal value for QS_PARAM_PRIMAL_PRICING\n"); + rval = 1; + goto CLEANUP; + } + break; + case QS_PARAM_DUAL_PRICING: + if (newvalue == QS_PRICE_DDANTZIG || + newvalue == QS_PRICE_DSTEEP || + newvalue == QS_PRICE_DMULTPARTIAL || newvalue == QS_PRICE_DDEVEX) + { + p->pricing->dI_price = newvalue; + p->pricing->dII_price = newvalue; + } + else + { + fprintf (stderr, "illegal value for QS_PARAM_DUAL_PRICING\n"); + rval = 1; + goto CLEANUP; + } + break; + case QS_PARAM_SIMPLEX_DISPLAY: + if (newvalue == 0 || (newvalue > 0 && newvalue < 4)) + { + p->simplex_display = newvalue; + } + else + { + fprintf (stderr, "illegal value for QS_PARAM_SIMPLEX_DISPLAY\n"); + rval = 1; + goto CLEANUP; + } + break; + case QS_PARAM_SIMPLEX_MAX_ITERATIONS: + if (newvalue > 0) + { + p->lp->maxiter = newvalue; + } + else + { + fprintf (stderr, "illegal value for QS_PARAM_SIMPLEX_MAX_ITERATIONS\n"); + rval = 1; + goto CLEANUP; + } + break; + case QS_PARAM_SIMPLEX_SCALING: + if (newvalue == 0 || newvalue == 1) + { + p->simplex_scaling = newvalue; + } + else + { + fprintf (stderr, "illegal value for QS_PARAM_SIMPLEX_SCALING\n"); + rval = 1; + goto CLEANUP; + } + break; + default: + fprintf (stderr, "unknown parameter: %d\n", whichparam); + rval = 1; + goto CLEANUP; + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSset_param_EGlpNum ( + QSdata * p, + int whichparam, + EGlpNum_t newvalue) +{ + int rval = 0; + int sense; + EGlpNum_t lvar; + + EGlpNumInitVar(lvar); + EGlpNumCopy(lvar,newvalue); + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + switch (whichparam) + { + case QS_PARAM_SIMPLEX_MAX_TIME: + if (EGlpNumIsGreatZero (lvar)) + { + p->lp->maxtime = EGlpNumToLf (lvar); + } + else + { + fprintf (stderr, "illegal value for QS_PARAM_SIMPLEX_MAX_TIME\n"); + rval = 1; + goto CLEANUP; + } + break; + case QS_PARAM_OBJULIM: + QSget_objsense(p,&sense); + if(EGlpNumIsLeq(ILL_MAXDOUBLE,lvar)) EGlpNumCopy(lvar,ILL_MAXDOUBLE); + EGlpNumCopy(p->uobjlim,lvar); + if(sense == QS_MIN) ILLsimplex_set_bound(p->lp,(const EGlpNum_t*)(&lvar), sense); + break; + case QS_PARAM_OBJLLIM: + QSget_objsense(p,&sense); + if(EGlpNumIsLeq(newvalue,ILL_MINDOUBLE)) EGlpNumCopy(lvar,ILL_MINDOUBLE); + EGlpNumCopy(p->lobjlim,lvar); + if(sense == QS_MAX) ILLsimplex_set_bound(p->lp,(const EGlpNum_t*)(&lvar), sense); + break; + default: + fprintf (stderr, "unknown parameter: %d\n", whichparam); + rval = 1; + goto CLEANUP; + } + +CLEANUP: + + EGlpNumClearVar(lvar); + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_param ( + QSdata * p, + int whichparam, + int *value) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (!value) + { + fprintf (stderr, "QSget_param call without a value pointer\n"); + rval = 1; + goto CLEANUP; + } + + switch (whichparam) + { + case QS_PARAM_PRIMAL_PRICING: + *value = p->pricing->pII_price; + break; + case QS_PARAM_DUAL_PRICING: + *value = p->pricing->dII_price; + break; + case QS_PARAM_SIMPLEX_DISPLAY: + *value = p->simplex_display; + break; + case QS_PARAM_SIMPLEX_MAX_ITERATIONS: + *value = p->lp->maxiter; + break; + case QS_PARAM_SIMPLEX_SCALING: + *value = p->simplex_scaling; + break; + default: + fprintf (stderr, "unknown parameter: %d\n", whichparam); + rval = 1; + goto CLEANUP; + } + +CLEANUP: + + EG_RETURN (rval); +} + +QSLIB_INTERFACE int QSget_param_EGlpNum ( + QSdata * p, + int whichparam, + EGlpNum_t * value) +{ + int rval = 0; + + rval = check_qsdata_pointer (p); + CHECKRVALG (rval, CLEANUP); + + if (!value) + { + fprintf (stderr, "QSget_param_double call without a value pointer\n"); + rval = 1; + goto CLEANUP; + } + + switch (whichparam) + { + case QS_PARAM_SIMPLEX_MAX_TIME: + EGlpNumSet (*value, p->lp->maxtime); + break; + case QS_PARAM_OBJULIM: + EGlpNumCopy(*value,p->uobjlim); + break; + case QS_PARAM_OBJLLIM: + EGlpNumCopy(*value,p->lobjlim); + break; + default: + fprintf (stderr, "unknown parameter: %d\n", whichparam); + rval = 1; + goto CLEANUP; + } + +CLEANUP: + + EG_RETURN (rval); +} + +static int check_qsdata_pointer ( + QSdata * p) +{ + if (p == NULL) + { + fprintf (stderr, "NULL QSprob pointer\n"); + return 1; + } + else + { + return 0; + } +} + +static int formatIsMps ( + const char *filetype, + int *isMps) +{ + int rval = 0; + + if (!strcasecmp (filetype, "MPS")) + { + *isMps = 1; + } + else if (!strcasecmp (filetype, "LP")) + { + *isMps = 0; + } + else + { + fprintf (stderr, "Unknown prob-file type: %s\n", filetype); + rval = 1; + ILL_CLEANUP; + } +CLEANUP: + return rval; +} + + +/****************************************************************************/ +/* + * undocumentyed functions + */ + +static void check_pointer ( + void *p, + const char *fct, + const char *param) +{ + if (p == NULL) + fprintf (stderr, "NULL %s argument to %s\n", param, fct); +} + +/* QSline_reader: + * used by mps/lp reader to get input lines + * by default input is read froma FILE* via fgets + */ +QSLIB_INTERFACE QSline_reader QSline_reader_new ( + void *fct, + void *data_src) +{ + check_pointer (fct, "QSline_reader_new", "fct"); + check_pointer (data_src, "QSline_reader_new", "data_src"); + return ILLline_reader_new ((qsread_line_fct) fct, data_src); +} + +QSLIB_INTERFACE void QSline_reader_set_error_collector ( + QSline_reader reader, + QSerror_collector collector) +{ + check_pointer (reader, "QSline_reader_set_error_collector", "reader"); + check_pointer (collector, "QSline_reader_set_error_collector", "collector"); + reader->error_collector = collector; +} + +QSLIB_INTERFACE void QSline_reader_free ( + QSline_reader reader) +{ + ILLline_reader_free (reader); +} + +QSLIB_INTERFACE char *QSline_reader_get ( + QSline_reader reader, + char *s, + int size) +{ + check_pointer (reader, "QSline_reader_get", "reader"); + check_pointer (s, "QSline_reader_get", "s"); + return ILLline_reader_get (s, size, reader); +} + + +QSLIB_INTERFACE QSerror_collector QSerror_collector_new ( + void *fct, + void *dest) +{ + check_pointer (fct, "QSerror_collector_new", "fct"); + return ILLerror_collector_new ((qsadd_error_fct) fct, dest); +} + +QSLIB_INTERFACE + QSerror_collector QSerror_memory_collector_new (QSerror_memory mem) +{ + check_pointer (mem, "QSerror_memory_collector_new", "mem"); + return ILLerror_memory_collector_new (mem); +} + +QSLIB_INTERFACE void QSerror_collector_free ( + QSerror_collector c) +{ + ILLerror_collector_free (c); +} + +QSLIB_INTERFACE QSdata *QSget_prob ( + QSline_reader reader, + const char *probname, + const char *filetype) +{ + int isMps, rval = 0; + QSdata *p = 0; + + if ((filetype != NULL) && !strcasecmp (filetype, "MPS")) + { + isMps = 1; + } + else if ((filetype != NULL) && !strcasecmp (filetype, "LP")) + { + isMps = 0; + } + else + { + fprintf (stderr, "Unknown prob-file type: %s\n", + (filetype != NULL) ? filetype : "NULL"); + rval = 1; + ILL_CLEANUP; + } + + p = ILLread (reader, probname, isMps); + ILL_CHECKnull (p, NULL); + + ILL_FAILfalse (p->qslp != NULL, "If there's a p there must be a p-qslp"); + ILL_IFFREE (p->name, char); + + ILL_UTIL_STR (p->name, p->qslp->probname); + ILLsimplex_load_lpinfo (p->qslp, p->lp); + +CLEANUP: + + if (rval != 0) + { + QSfree_prob (p); + p = 0; + } + return p; +} + +QSLIB_INTERFACE int QSreport_prob ( + QSdata * p, + const char *filetype, + qserror_collector * c) +{ + int isMps, rval = 0; + + rval = formatIsMps (filetype, &isMps); + CHECKRVALG (rval, CLEANUP); + if (isMps) + { + rval = ILLwrite_mps (p->qslp, c); + } + else + { + rval = ILLwrite_lp (p->qslp, c); + } +CLEANUP: + EG_RETURN (rval); +} + +QSLIB_INTERFACE char *QSversion ( + void) +{ + char *name = 0; + name = EGsMalloc (char, 256); + + snprintf (name, (size_t) 255, "%s (build %s-%s)",PACKAGE_STRING, __DATE__, + __TIME__); + return name; +} + +/* QSstring_reporter: + * used by solver code to report feedback + * by default feedback is sent to stdout via fprintf + */ +QSLIB_INTERFACE void QSset_reporter ( + QSprob prob, + int skip, + void *fct, + void *dest) +{ + int rval = 0; + + rval = check_qsdata_pointer (prob); + if (rval != 0) + return; + + check_pointer (fct, "QSset_reporter", "fct"); + + ILL_FAILtrue (prob->lp == NULL, "QSprob internal error: prob->lp == NULL"); + ILLstring_reporter_init (&prob->qslp->reporter, + (qsreport_string_fct) fct, dest); + + prob->lp->iterskip = skip; +CLEANUP: + return; +} + +QSLIB_INTERFACE const char *QSformat_error_type_string ( + int tp) +{ + const char *type = "Error"; + + if (tp == QS_DATA_ERROR) + { + type = "Data Error"; + } + if (tp == QS_DATA_WARN) + { + type = "Data Warning"; + } + if (tp == QS_MPS_FORMAT_ERROR) + { + type = "MPS Error"; + } + if (tp == QS_MPS_FORMAT_WARN) + { + type = "MPS Warning"; + } + if (tp == QS_LP_FORMAT_ERROR) + { + type = "LP Error"; + } + if (tp == QS_LP_FORMAT_WARN) + { + type = "LP Warning"; + } + return type; +} + +QSLIB_INTERFACE int QSerror_get_type ( + QSformat_error error) +{ + check_pointer (error, "QSerror_get_type", "error"); + return error->type; +} + +QSLIB_INTERFACE const char *QSerror_get_desc ( + QSformat_error error) +{ + check_pointer (error, "QSerror_get_desc", "error"); + return error->desc; +} + +QSLIB_INTERFACE int QSerror_get_line_number ( + QSformat_error error) +{ + check_pointer (error, "QSerror_get_line_number", "error"); + return error->lineNumber; +} + +QSLIB_INTERFACE int QSerror_get_pos ( + QSformat_error error) +{ + check_pointer (error, "QSerror_get_pos", "error"); + return error->at; +} + +QSLIB_INTERFACE const char *QSerror_get_line ( + QSformat_error error) +{ + check_pointer (error, "QSerror_get_line", "error"); + return error->theLine; +} + +QSLIB_INTERFACE void QSerror_print ( + FILE * f, + QSformat_error error) +{ + check_pointer (f, "QSerror_print", "f"); + if (error == NULL) + { + fprintf (stderr, "0\n"); + } + else + { + EGioFile_t*out = EGioOpenFILE(f); + ILLformat_error_print (out, error); + EGioClose(out); + } +} + +QSLIB_INTERFACE QSerror_memory QSerror_memory_create ( + int takeErrorLines) +{ + return ILLerror_memory_create (takeErrorLines); +} + +QSLIB_INTERFACE void QSerror_memory_free ( + QSerror_memory mem) +{ + if (mem != NULL) + { + ILLerror_memory_free (mem); + } +} + +QSLIB_INTERFACE int QSerror_memory_get_nerrors ( + QSerror_memory mem) +{ + check_pointer (mem, "QSerror_memory_get_nerrors", "mem"); + return mem->nerror; +} + +QSLIB_INTERFACE int QSerror_memory_get_nof ( + QSerror_memory mem, + int type) +{ + check_pointer (mem, "QSerror_memory_get_nerrors", "mem"); + if (0 <= type && type < QS_INPUT_NERROR) + { + return mem->has_error[type]; + } + else + { + ILL_REPRT ("bad error type"); + return 0; + } +} + +QSLIB_INTERFACE QSformat_error QSerror_memory_get_last_error ( + QSerror_memory mem) +{ + check_pointer (mem, "QSerror_memory_get_last_errors", "mem"); + return mem->error_list; +} + +QSLIB_INTERFACE QSformat_error QSerror_memory_get_prev_error ( + QSformat_error e) +{ + check_pointer (e, "QSerror_memory_get_prev_errors", "e"); + if (e != NULL) + e = e->next; + return e; +} diff --git a/src/qsopt.h b/src/qsopt.h new file mode 100644 index 0000000..65dfc9c --- /dev/null +++ b/src/qsopt.h @@ -0,0 +1,353 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: qsopt.h,v $ $Revision: 1.3 $ $Date: 2003/11/05 16:57:39 $" */ +#ifndef __QS_QSOPT_H +#define __QS_QSOPT_H + +#include +#include "qs_config.h" + +#ifdef WIN32 + +#ifdef QSLIB_EXPORTS +#define QSLIB_INTERFACE __declspec(dllexport) +#else +#define QSLIB_INTERFACE __declspec(dllimport) +#endif + +#else +#define QSLIB_INTERFACE extern +#endif + +#ifdef WIN32 +typedef struct QSLIB_INTERFACE qsdata *QSprob; +typedef struct QSLIB_INTERFACE qsbasis *QSbas; +#else +typedef struct qsdata *QSprob; +typedef struct qsbasis *QSbas; +#endif + +/****************************************************************************/ +/* */ +/* PARAMETERS TO SPECIFY OBJECTIVE SENSE */ +/* */ +/****************************************************************************/ +#include "basicdefs.h" +/* +#define QS_LP_PRIMAL_FEASIBLE 11 +#define QS_LP_PRIMAL_INFEASIBLE 12 +#define QS_LP_PRIMAL_UNBOUNDED 13 +#define QS_LP_DUAL_FEASIBLE 14 +#define QS_LP_DUAL_INFEASIBLE 15 +#define QS_LP_DUAL_UNBOUNDED 16 +*/ + +/****************************************************************************/ +/* */ +/* QSopt Library Functions */ +/* */ +/****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef WIN32 +/* + * in WINDOWS we make + * solver_main/reader_main part of DLL + */ +QSLIB_INTERFACE int solver_main ( int argc, char **argv); +QSLIB_INTERFACE int reader_main ( int argc, char **argv); +#endif + +QSLIB_INTERFACE void QSfree ( void *ptr), + QSfree_prob ( QSprob p), + QSfree_basis ( QSbas B), + QSset_precision ( const unsigned prec),/**< set the precision for floating + point numbers to the given + number of bits */ + QSstart ( void),/**< whe we use non native numbers, we need to make + some initializations before operating with the + library */ + QSend ( void); /**< just to free any internal static data needed by + the variable precision numbers */ + +QSLIB_INTERFACE int QSopt_primal ( QSprob p, int *status), + QSopt_dual ( QSprob p, int *status), + QSopt_pivotin_col ( QSprob p, int ccnt, int *clist), + QSopt_pivotin_row ( QSprob p, int rcnt, int *rlist), + QSopt_strongbranch ( QSprob p, int ncand, int *candidatelist, + EGlpNum_t * xlist, EGlpNum_t * down_vals, EGlpNum_t * up_vals, + int iterations, EGlpNum_t objbound), + QSchange_objsense ( QSprob p, int newsense), + QSget_objsense ( QSprob p, int *newsense), + QSnew_col ( QSprob p,const EGlpNum_t obj,const EGlpNum_t lower,const EGlpNum_t upper, + const char *name), + QSadd_cols ( QSprob p, int num, int *cmatcnt, int *cmatbeg, int *cmatind, + EGlpNum_t * cmatval, EGlpNum_t * obj, EGlpNum_t * lower, + EGlpNum_t * upper, const char **names), + QSadd_col ( QSprob p, int cnt, int *cmatind, EGlpNum_t * cmatval, + EGlpNum_t obj, EGlpNum_t lower, EGlpNum_t upper, const char *name), + QSnew_row ( QSprob p,const EGlpNum_t rhs, int sense, const char *name), + QSadd_ranged_rows ( QSprob p, int num, int *rmatcnt, int *rmatbeg, + int *rmatind,const EGlpNum_t * rmatval,const EGlpNum_t * rhs, char *sense, + const EGlpNum_t* range, const char **names), + QSadd_ranged_row ( QSprob p, int cnt, int *rmatind,const EGlpNum_t * rmatval, + const EGlpNum_t * rhs, int sense,const EGlpNum_t * range, const char *name), + QSadd_rows ( QSprob p, int num, int *rmatcnt, int *rmatbeg, int *rmatind, + const EGlpNum_t * rmatval,const EGlpNum_t * rhs, char *sense, const char **names), + QSadd_row ( QSprob p, int cnt, int *rmatind,const EGlpNum_t * rmatval, + const EGlpNum_t * rhs, int sense, const char *name), + QSdelete_rows ( QSprob p, int num, int *dellist), + QSdelete_row ( QSprob p, int rowindex), + QSdelete_setrows ( QSprob p, int *flags), + QSdelete_named_row ( QSprob p, const char *rowname), + QSdelete_named_rows_list ( QSprob p, int num, const char **rownames), + QSdelete_cols ( QSprob p, int num, int *dellist), + QSdelete_col ( QSprob p, int colindex), + QSdelete_setcols ( QSprob p, int *flags), + QSdelete_named_column ( QSprob p, const char *colname), + QSdelete_named_columns_list ( QSprob p, int num, const char **colnames), + QSchange_senses ( QSprob p, int num, int *rowlist, char *sense), + QSchange_sense ( QSprob p, int rowindex, int sense), + QSchange_coef ( QSprob p, int rowindex, int colindex, EGlpNum_t coef), + QSchange_objcoef ( QSprob p, int indx, EGlpNum_t coef), + QSchange_rhscoef ( QSprob p, int indx, EGlpNum_t coef), + QSchange_range(QSprob p, int rowindex, EGlpNum_t range), + QSchange_bounds ( QSprob p, int num, int *collist, char *lu, + const EGlpNum_t * bounds), + QSchange_bound ( QSprob p, int indx, int lu,const EGlpNum_t bound), + QSload_basis ( QSprob p, QSbas B), + QSread_and_load_basis ( QSprob p, const char *filename), + QSload_basis_array ( QSprob p, char *cstat, char *rstat), + QSload_basis_and_row_norms_array ( QSprob p, char *cstat, char *rstat, + EGlpNum_t * rownorms), + QSget_basis_array ( QSprob p, char *cstat, char *rstat), + QSget_basis_and_row_norms_array ( QSprob p, char *cstat, char *rstat, + EGlpNum_t * rownorms), + QSget_binv_row ( QSprob p, int indx, EGlpNum_t * binvrow), + QSget_tableau_row ( QSprob p, int indx, EGlpNum_t * tableaurow), + QSget_basis_order ( QSprob p, int *basorder), + QSget_coef (QSprob p, int rowindex, int colindex, EGlpNum_t*coef), + QSget_status ( QSprob p, int *status), + QSget_solution ( QSprob p, EGlpNum_t * value, EGlpNum_t * x, + EGlpNum_t * pi, EGlpNum_t * slack, EGlpNum_t * rc), + QSget_objval ( QSprob p, EGlpNum_t * value), + QSget_pi_array ( QSprob p, EGlpNum_t * pi), + QSget_rc_array ( QSprob p, EGlpNum_t * rc), + QSget_x_array ( QSprob p, EGlpNum_t * x), + QSget_slack_array ( QSprob p, EGlpNum_t * slack), + QSget_infeas_array ( QSprob p, EGlpNum_t * pi), + QSget_colcount ( QSprob p), + QSget_rowcount ( QSprob p), + QSget_nzcount ( QSprob p), + QSget_obj_list(QSprob p, int num, int*collist, EGlpNum_t*obj), + QSget_obj ( QSprob p, EGlpNum_t * obj), + QSget_rhs ( QSprob p, EGlpNum_t * rhs), + QSget_ranged_rows_list ( QSprob p, int num, int *rowlist, int **rowcnt, + int **rowbeg, int **rowind, EGlpNum_t ** rowval, EGlpNum_t ** rhs, + char **sense, EGlpNum_t **range, char ***names), + QSget_ranged_rows ( QSprob p, int **rowcnt, int **rowbeg, int **rowind, + EGlpNum_t ** rowval, EGlpNum_t ** rhs, char **sense, + EGlpNum_t ** range, char ***names), + QSget_senses ( QSprob p, char*senses), + QSget_rows_list ( QSprob p, int num, int *rowlist, int **rowcnt, + int **rowbeg, int **rowind, EGlpNum_t ** rowval, EGlpNum_t ** rhs, + char **sense, char ***names), + QSget_rows ( QSprob p, int **rowcnt, int **rowbeg, int **rowind, + EGlpNum_t ** rowval, EGlpNum_t ** rhs, char **sense, char ***names), + QSget_columns_list ( QSprob p, int num, int *collist, int **colcnt, + int **colbeg, int **colind, EGlpNum_t ** colval, EGlpNum_t ** obj, + EGlpNum_t ** lower, EGlpNum_t ** upper, char ***names), + QSget_columns ( QSprob p, int **colcnt, int **colbeg, int **colind, + EGlpNum_t ** colval, EGlpNum_t ** obj, EGlpNum_t ** lower, + EGlpNum_t ** upper, char ***names), + QSget_rownames ( QSprob p, char **rownames), + QSget_colnames ( QSprob p, char **colnames), + QSget_bound ( QSprob p, int colindex, int lu, EGlpNum_t * bound), + QSget_bounds ( QSprob p, EGlpNum_t * lower, EGlpNum_t * upper), + QSget_bounds_list(QSprob p, int num, int*collist, EGlpNum_t*lb, + EGlpNum_t*ub), + QSget_intflags ( QSprob p, int *intflags), + QSget_intcount ( QSprob p, int *count), + QSget_column_index ( QSprob p, const char *name, int *colindex), + QSget_row_index ( QSprob p, const char *name, int *rowindex), + QSget_named_x ( QSprob p, const char *colname, EGlpNum_t * val), + QSget_named_rc ( QSprob p, const char *colname, EGlpNum_t * val), + QSget_named_pi ( QSprob p, const char *rowname, EGlpNum_t * val), + QSget_named_slack ( QSprob p, const char *rowname, EGlpNum_t * val), + QScompute_row_norms ( QSprob p), + QSwrite_prob ( QSprob p, const char *filename, const char *filetype), + QSwrite_prob_file ( QSprob p, FILE * file, const char *filetype), + QSwrite_basis ( QSprob p, QSbas B, const char *filename), + QStest_row_norms ( QSprob p), + QSget_itcnt(QSprob p, int *pI_iter, int *pII_iter, int *dI_iter, + int *dII_iter, int *tot_iter), + QSset_param ( QSprob p, int whichparam, int newvalue), + QSset_param_EGlpNum ( QSprob p, int whichparam, EGlpNum_t newvalue), + QSget_param ( QSprob p, int whichparam, int *value), + QSget_param_EGlpNum ( QSprob p, int whichparam, EGlpNum_t * value); + +QSLIB_INTERFACE char *QSget_probname ( QSprob p); +QSLIB_INTERFACE char *QSget_objname ( QSprob p); +QSLIB_INTERFACE char *QSversion ( void); + +QSLIB_INTERFACE QSprob QScreate_prob ( const char *name, int objsense), + QSread_prob ( const char *filename, const char *filetype), + QSload_prob ( const char *probname, int ncols, int nrows, int *cmatcnt, + int *cmatbeg, int *cmatind, EGlpNum_t * cmatval, int objsense, + EGlpNum_t * obj, EGlpNum_t * rhs, char *sense, EGlpNum_t * lower, + EGlpNum_t * upper, const char **colnames, const char **rownames), + QScopy_prob ( QSprob p, const char *newname); + +QSLIB_INTERFACE QSbas QSget_basis ( QSprob p), + QSread_basis ( QSprob p, const char *filename); + +#ifdef __cplusplus +} +#endif + +/**************************************************************************** + * + * This is the undocumented part of the QSlib interface + * + ****************************************************************************/ +/* + * functions to facilitate line by line reading from other sources than + * files from within MPS/LP parsers + * + * functions to facilitate the collection of error information instead of + * having the parsers print messages to stderr + * by mps/lp format writers + * + * a problem's reporter is used by the solver code to provide important + * feedback/progress information + */ + +#ifdef WIN32 +typedef struct QSLIB_INTERFACE qsline_reader *QSline_reader; +typedef struct QSLIB_INTERFACE qsformat_error *QSformat_error; +typedef struct QSLIB_INTERFACE qserror_collector *QSerror_collector; +typedef struct QSLIB_INTERFACE qserror_memory *QSerror_memory; +#else +typedef struct qsline_reader *QSline_reader; +typedef struct qsformat_error *QSformat_error; +typedef struct qserror_collector *QSerror_collector; +typedef struct qserror_memory *QSerror_memory; +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + QSLIB_INTERFACE const char *QSformat_error_type_string ( + int tp); + + QSLIB_INTERFACE int QSerror_get_type ( + QSformat_error error); + QSLIB_INTERFACE const char *QSerror_get_desc ( + QSformat_error error); + QSLIB_INTERFACE int QSerror_get_line_number ( + QSformat_error error); + QSLIB_INTERFACE int QSerror_get_pos ( + QSformat_error error); + QSLIB_INTERFACE const char *QSerror_get_line ( + QSformat_error error); + QSLIB_INTERFACE void QSerror_print ( + FILE * f, + QSformat_error error); + + QSLIB_INTERFACE QSerror_collector QSerror_collector_new ( + void *fct, + void *dest); + QSLIB_INTERFACE QSerror_collector QSerror_memory_collector_new ( + QSerror_memory mem); + QSLIB_INTERFACE void QSerror_collector_free ( + QSerror_collector c); + +/**************************************************************************** + * line reader + */ + QSLIB_INTERFACE QSline_reader QSline_reader_new ( + void *fct, + void *data_src); + /* reader->read_line_fct defaults to fgets */ + + QSLIB_INTERFACE void QSline_reader_free ( + QSline_reader reader); + + QSLIB_INTERFACE void QSline_reader_set_error_collector ( + QSline_reader reader, + QSerror_collector collector); + + QSLIB_INTERFACE char *QSline_reader_get ( + QSline_reader reader, + char *s, + int size); + + QSLIB_INTERFACE QSprob QSget_prob ( + QSline_reader reader, + const char *probname, + const char *filetype); + /* the MPS and LP parsers uses the fct from reader + * to get to next input line */ + + +/**************************************************************************** + * error memory + */ + QSLIB_INTERFACE QSerror_memory QSerror_memory_create ( + int takeErrorLines); + QSLIB_INTERFACE void QSerror_memory_free ( + QSerror_memory mem); + + QSLIB_INTERFACE int QSerror_memory_get_nof ( + QSerror_memory mem, + int error_type); + QSLIB_INTERFACE int QSerror_memory_get_nerrors ( + QSerror_memory mem); + + QSLIB_INTERFACE QSformat_error QSerror_memory_get_last_error ( + QSerror_memory mem); + QSLIB_INTERFACE QSformat_error QSerror_memory_get_prev_error ( + QSformat_error e); + +/**************************************************************************** + * reporter for solver feedback + */ + QSLIB_INTERFACE void QSset_reporter ( + QSprob prob, + int iterskip, + void *fct, + void *dest); + + QSLIB_INTERFACE int QSreport_prob ( + QSprob p, + const char *filetype, + QSerror_collector c); + +#ifdef __cplusplus +} +#endif +#endif /* __QS_QSOPT_H */ diff --git a/src/qstruct.h b/src/qstruct.h new file mode 100644 index 0000000..fd5e6a7 --- /dev/null +++ b/src/qstruct.h @@ -0,0 +1,46 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: qstruct.h,v $ $Revision: 1.3 $ $Date: 2003/11/05 16:57:39 $" */ +#ifndef __QS_QSTRUCT_H +#define __QS_QSTRUCT_H +#include "basicdefs.h" + +typedef struct qsdata +{ + struct ILLlpdata *qslp; + struct lpinfo *lp; + struct price_info *pricing; + struct ILLlp_basis *basis; + struct ILLlp_cache *cache; + char *name; + int qstatus; /* QS_LP_UNSOLVED or an opt status */ + int factorok; /* set to 0 if factorization is old */ + int simplex_display; /* 0 off, 1 on */ + int simplex_scaling; /* 0 off, 1 on */ + itcnt_t itcnt; + EGlpNum_t uobjlim; + EGlpNum_t lobjlim; +} +QSdata; + +#endif /* __QS_QSTRUCT_H */ diff --git a/src/ratio.c b/src/ratio.c new file mode 100644 index 0000000..186edf7 --- /dev/null +++ b/src/ratio.c @@ -0,0 +1,1290 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* "$RCSfile: ratio.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +static int TRACE = 0; + +#include "config.h" +#include "sortrus.h" +#include "stddefs.h" +#include "iqsutil.h" +#include "lpdefs.h" +#include "ratio.h" +#include "fct.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +void ILLratio_pI_test ( + lpinfo * lp, + int eindex, + int dir, + ratio_res * rs) +{ + int i = 0, k = 0; + int col, ecol; + int cbnd, indx = 0; + int tctr = 0; + int *perm = lp->upd.perm; + int *ix = lp->upd.ix; + EGlpNum_t *pivtol = &(lp->tol->pivot_tol); + EGlpNum_t *dftol = &(lp->tol->id_tol); + + /*HHH*/ EGlpNum_t * t = lp->upd.t; + EGlpNum_t t_i, delta, y_ij, rcost, nrcost, ntmp; + EGlpNum_t *x, *l, *u; + + /*HHH*/ EGlpNumInitVar (t_i); + EGlpNumInitVar (delta); + EGlpNumInitVar (y_ij); + EGlpNumInitVar (rcost); + EGlpNumInitVar (nrcost); + EGlpNumInitVar (ntmp); + EGlpNumZero (t_i); + EGlpNumZero (y_ij); + EGlpNumZero (delta); + rs->lindex = -1; + EGlpNumZero (rs->tz); + EGlpNumZero (rs->pivotval); + rs->ratio_stat = RATIO_FAILED; + rs->lvstat = -1; + ecol = lp->nbaz[eindex]; + ILL_IFTRACE2 ("%s:%d:%d:%d:%d", __func__, eindex, dir, ecol, + (VBOUNDED == lp->vtype[ecol])); + if (lp->vtype[ecol] == VBOUNDED) + { + EGlpNumCopyDiff (t[0], lp->uz[ecol], lp->lz[ecol]); + ix[0] = BBOUND; + ILL_IFTRACE2 (":%d[%d](%la,%la,%la)\n", ix[tctr], tctr, + EGlpNumToLf (t[tctr]), EGlpNumToLf (lp->uz[ecol]), + EGlpNumToLf (lp->lz[ecol])); + tctr++; + } + ILL_IFTRACE2 (":%d", lp->yjz.nzcnt); + for (k = 0; k < lp->yjz.nzcnt; k++) + { + EGlpNumCopy (y_ij, lp->yjz.coef[k]); + if (!EGlpNumIsNeqZero (y_ij, *pivtol)) + continue; + + i = lp->yjz.indx[k]; + x = &(lp->xbz[i]); + col = lp->baz[i]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + + if ((dir == VINCREASE && EGlpNumIsGreatZero (y_ij)) || + (dir == VDECREASE && EGlpNumIsLessZero (y_ij))) + { + if (EGlpNumIsLessZero (y_ij)) + EGlpNumSign (y_ij); + ILL_IFTRACE2 (":%d", lp->bfeas[i]); + if (lp->bfeas[i] > 0) + { + EGlpNumCopyDiffRatio (t[tctr], *x, *u, y_ij); + ix[tctr] = 10 * k + BATOUPPER; + ILL_IFTRACE2 (":%d[%d](%la)\n", ix[tctr], tctr, EGlpNumToLf (t[tctr])); + tctr++; + if (EGlpNumIsNeqq (*l, NINFTY)) + { + EGlpNumCopyDiffRatio (t[tctr], *x, *l, y_ij); + ix[tctr] = 10 * k + BATOLOWER; + ILL_IFTRACE2 (":%d[%d](%la)\n", ix[tctr], tctr, + EGlpNumToLf (t[tctr])); + tctr++; + } + } + else if (lp->bfeas[i] == 0) + { + if (EGlpNumIsNeqq (*l, NINFTY)) + { + EGlpNumCopyDiffRatio (t[tctr], *x, *l, y_ij); + ix[tctr] = 10 * k + BATOLOWER; + ILL_IFTRACE2 (":%d[%d](%la)\n", ix[tctr], tctr, + EGlpNumToLf (t[tctr])); + tctr++; + } + } + } + else if ((dir == VINCREASE && EGlpNumIsLessZero (y_ij)) || + (dir == VDECREASE && EGlpNumIsGreatZero (y_ij))) + { + if (EGlpNumIsLessZero (y_ij)) + EGlpNumSign (y_ij); + ILL_IFTRACE2 (":%d", lp->bfeas[i]); + if (lp->bfeas[i] < 0) + { + EGlpNumCopyDiffRatio (t[tctr], *l, *x, y_ij); + ix[tctr] = 10 * k + BBTOLOWER; + ILL_IFTRACE2 (":%d[%d](%la)\n", ix[tctr], tctr, EGlpNumToLf (t[tctr])); + tctr++; + if (EGlpNumIsNeqq (*u, INFTY)) + { + EGlpNumCopyDiffRatio (t[tctr], *u, *x, y_ij); + ix[tctr] = 10 * k + BBTOUPPER; + ILL_IFTRACE2 (":%d[%d](%la)\n", ix[tctr], tctr, + EGlpNumToLf (t[tctr])); + tctr++; + } + } + else if (lp->bfeas[i] == 0) + { + if (EGlpNumIsNeqq (*u, INFTY)) + { + EGlpNumCopyDiffRatio (t[tctr], *u, *x, y_ij); + ix[tctr] = 10 * k + BBTOUPPER; + ILL_IFTRACE2 (":%d[%d](%la)\n", ix[tctr], tctr, + EGlpNumToLf (t[tctr])); + tctr++; + } + } + } + } + if (tctr == 0) + { + rs->ratio_stat = RATIO_FAILED; + ILL_CLEANUP; + } + + for (i = 0; i < tctr; i++) + perm[i] = i; + ILLutil_EGlpNum_perm_quicksort (perm, t, tctr); + + EGlpNumZero (lp->upd.c_obj); + EGlpNumCopy (rcost, lp->pIdz[eindex]); + ILL_IFTRACE2 ("\n%s:%d:%lf", __func__, tctr, EGlpNumToLf (rcost)); + for (i = 0; i < tctr; i++) + { + EGlpNumCopy (t_i, t[perm[i]]); + EGlpNumCopy (ntmp, t_i); + EGlpNumSubTo (ntmp, delta); + EGlpNumAddInnProdTo (lp->upd.c_obj, ntmp, rcost); + EGlpNumCopy (delta, t_i); + ILL_IFTRACE2 (":%d:%lf", perm[i], EGlpNumToLf (delta)); + /*HHH*/ cbnd = ix[perm[i]] % 10; + if (cbnd != BBOUND) + { + k = ix[perm[i]] / 10; + EGlpNumCopy (y_ij, lp->yjz.coef[k]); + indx = lp->yjz.indx[k]; + ILL_IFTRACE2 (":%d", indx); + } + + switch (cbnd) + { + case BBOUND: + rs->ratio_stat = RATIO_NOBCHANGE; + EGlpNumCopy (rs->tz, t_i); + if (dir != VINCREASE) + EGlpNumSign (rs->tz); + ILL_CLEANUP; + + case BATOLOWER: + case BATOUPPER: + EGlpNumAddTo (rcost, y_ij); + break; + case BBTOLOWER: + case BBTOUPPER: + EGlpNumSubTo (rcost, y_ij); + break; + } + EGlpNumCopyNeg (nrcost, rcost); + if ((dir == VINCREASE && EGlpNumIsLeq (nrcost, *dftol)) || + (dir == VDECREASE && EGlpNumIsLeq (rcost, *dftol))) + { + /* change 5 to -1 if t_i > 0 is required below */ + if (EGlpNumIsLessZero (t_i) && i > 5) + { + /* printf ("pIhell %.5f %d\n", t_i, i); */ + EGlpNumDivUiTo (t_i, 2); + rs->ratio_stat = RATIO_NEGATIVE; + EGlpNumZero (rs->tz); + ILL_CLEANUP; + } + rs->lindex = indx; + rs->ratio_stat = RATIO_BCHANGE; + if (cbnd == BATOLOWER || cbnd == BBTOLOWER) + rs->lvstat = STAT_LOWER; + else + rs->lvstat = STAT_UPPER; + + EGlpNumCopy (rs->pivotval, y_ij); + EGlpNumCopy (rs->tz, t_i); + if (dir != VINCREASE) + EGlpNumSign (rs->tz); + ILL_CLEANUP; + } + } + +CLEANUP: + ILLfct_update_counts (lp, CNT_PIPIV, 0, rs->pivotval); + ILL_IFTRACE2 (":tctr %d:%d\n", tctr, rs->ratio_stat); + lp->upd.tctr = tctr; + lp->upd.i = i; + EGlpNumCopy (lp->upd.tz, t_i); + EGlpNumCopy (lp->upd.piv, rs->pivotval); + if (dir == VDECREASE) + EGlpNumSign (lp->upd.c_obj); + if (rs->lindex != -1) + lp->upd.fs = lp->bfeas[rs->lindex]; + EGlpNumClearVar (t_i); + EGlpNumClearVar (delta); + EGlpNumClearVar (y_ij); + EGlpNumClearVar (rcost); + EGlpNumClearVar (nrcost); + EGlpNumClearVar (ntmp); +} + +void ILLratio_pII_test ( + lpinfo * lp, + int eindex, + int dir, + ratio_res * rs) +{ + int i, k, indx, col, ecol; + EGlpNum_t *x, *l, *u, t_max, ayi_max, yi_max, ay_ij, y_ij, t_i, t_z; + EGlpNum_t *pivtol = &(lp->tol->pivot_tol); + EGlpNum_t *pftol = &(lp->tol->pfeas_tol); + + EGlpNumInitVar (y_ij); + EGlpNumInitVar (ay_ij); + EGlpNumInitVar (t_i); + EGlpNumInitVar (t_z); + EGlpNumInitVar (t_max); + EGlpNumInitVar (yi_max); + EGlpNumInitVar (ayi_max); + /*HHH*/ rs->boundch = 0; + rs->lindex = -1; + EGlpNumZero (rs->tz); + rs->ratio_stat = RATIO_FAILED; + rs->lvstat = -1; + EGlpNumZero (rs->pivotval); + EGlpNumZero (rs->lbound); + ecol = lp->nbaz[eindex]; + + for (k = 0, EGlpNumCopy (t_max, INFTY); k < lp->yjz.nzcnt; k++) + { + EGlpNumCopy (y_ij, lp->yjz.coef[k]); + EGlpNumCopyAbs (ay_ij, y_ij); + if (!EGlpNumIsNeqZero (y_ij, *pivtol)) + continue; + + EGlpNumCopy (t_i, INFTY); + i = lp->yjz.indx[k]; + x = &(lp->xbz[i]); + col = lp->baz[i]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + + if ((dir == VINCREASE && EGlpNumIsGreatZero (y_ij)) || + (dir == VDECREASE && EGlpNumIsLessZero (y_ij))) + { + if (EGlpNumIsNeqq (*l, NINFTY)) + { + EGlpNumCopyDiff (t_i, *x, *l); + EGlpNumAddTo (t_i, *pftol); + EGlpNumDivTo (t_i, ay_ij); + } + } + else if ((dir == VINCREASE && EGlpNumIsLessZero (y_ij)) || + (dir == VDECREASE && EGlpNumIsGreatZero (y_ij))) + { + if (EGlpNumIsNeqq (*u, INFTY)) + { + EGlpNumCopySum (t_i, *u, *pftol); + EGlpNumSubTo (t_i, *x); + EGlpNumDivTo (t_i, ay_ij); + } + } + if (EGlpNumIsEqqual (t_i, INFTY)) + continue; + + if (EGlpNumIsLess (t_i, t_max)) + { + /*HHH tind = i; yval = fabs (y_ij); tval = t_i - pftol/fabs(y_ij); */ + EGlpNumCopy (t_max, t_i); + } + } + /* we use yi_max as temporal variable here */ + EGlpNumCopyDiff (yi_max, lp->uz[ecol], lp->lz[ecol]); + if (lp->vtype[ecol] == VBOUNDED && EGlpNumIsLeq (yi_max, t_max)) + { + + EGlpNumCopy (t_max, yi_max); + rs->ratio_stat = RATIO_NOBCHANGE; + EGlpNumCopy (rs->tz, t_max); + if (dir != VINCREASE) + EGlpNumSign (rs->tz); + ILL_CLEANUP; + } + + if (EGlpNumIsLeq (INFTY, t_max)) + { + rs->ratio_stat = RATIO_UNBOUNDED; + ILL_CLEANUP; + } + /*if (EGlpNumIsLess (t_max, zeroLpNum)) + * printf ("pIIhell\n"); + */ + indx = -1; + EGlpNumZero (t_z); + EGlpNumZero (yi_max); + EGlpNumZero (ayi_max); + ILL_IFTRACE2 (":%d", lp->yjz.nzcnt); + for (k = 0; k < lp->yjz.nzcnt; k++) + { + EGlpNumCopy (y_ij, lp->yjz.coef[k]); + EGlpNumCopyAbs (ay_ij, y_ij); + if (!EGlpNumIsNeqZero (y_ij, *pivtol)) + continue; + + EGlpNumCopy (t_i, INFTY); + i = lp->yjz.indx[k]; + x = &(lp->xbz[i]); + col = lp->baz[i]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + + if ((dir == VINCREASE && EGlpNumIsGreatZero (y_ij)) || + (dir == VDECREASE && EGlpNumIsLessZero (y_ij))) + { + if (EGlpNumIsNeqq (*l, NINFTY)) + EGlpNumCopyDiffRatio (t_i, *x, *l, ay_ij); + } + else if ((dir == VINCREASE && EGlpNumIsLessZero (y_ij)) || + (dir == VDECREASE && EGlpNumIsGreatZero (y_ij))) + { + if (EGlpNumIsNeqq (*u, INFTY)) + EGlpNumCopyDiffRatio (t_i, *u, *x, ay_ij); + } + + if (EGlpNumIsLeq (t_i, t_max)) + { + if (EGlpNumIsLess (ayi_max, ay_ij)) + { + EGlpNumCopy (yi_max, y_ij); + EGlpNumCopy (ayi_max, ay_ij); + indx = i; + EGlpNumCopy (t_z, t_i); + ILL_IFTRACE2 (":%d:%lf:%lf:%lf:%lf", indx, EGlpNumToLf (t_i), + EGlpNumToLf (t_max), EGlpNumToLf (ayi_max), + EGlpNumToLf (ay_ij)); + } + } + } + + if (indx < 0) + { + rs->ratio_stat = RATIO_FAILED; + } + else + { + /* + * if (tind != rs->lindex){ + * HHHprintf ("tmax %e tval = %e yval = %e tind = %d\n", t_max, tval, yval, tind); + * HHHprintf ("h tval = %e yval = %e tind = %d\n",rs->tz, yi_max, rs->lindex); + * } + */ + ILL_IFTRACE2 (":%d", indx); + rs->lindex = indx; + EGlpNumCopy (rs->tz, t_z); + EGlpNumCopy (rs->pivotval, yi_max); + rs->ratio_stat = RATIO_BCHANGE; + + if (dir == VINCREASE) + rs->lvstat = + (EGlpNumIsGreatZero (yi_max)) ? STAT_LOWER : STAT_UPPER; + else + rs->lvstat = + (EGlpNumIsGreatZero (yi_max)) ? STAT_UPPER : STAT_LOWER; + + if (EGlpNumIsLessZero (rs->tz)) + { + ILL_IFTRACE2 ("need to change bound, tz=%la\n", EGlpNumToLf (rs->tz)); + EGlpNumCopyAbs (rs->tz, t_max); + EGlpNumDivUiTo (rs->tz, 10); + rs->boundch = 1; + EGlpNumCopy (rs->lbound, lp->xbz[rs->lindex]); + if (rs->lvstat == STAT_LOWER) + EGlpNumSubInnProdTo (rs->lbound, rs->tz, ayi_max); + else + EGlpNumAddInnProdTo (rs->lbound, rs->tz, ayi_max); + } + if (dir == VDECREASE) + EGlpNumSign (rs->tz); + } +CLEANUP: + ILLfct_update_counts (lp, CNT_PIIPIV, 0, rs->pivotval); + EGlpNumClearVar (y_ij); + EGlpNumClearVar (ay_ij); + EGlpNumClearVar (t_i); + EGlpNumClearVar (t_z); + EGlpNumClearVar (t_max); + EGlpNumClearVar (yi_max); + EGlpNumClearVar (ayi_max); +} + +#define GET_XY_DRATIOTEST \ + if (lp->vstat[col] == STAT_UPPER){ \ + EGlpNumCopyNeg(x,lp->dz[j]);\ + EGlpNumCopy(y, *zAj);\ + } \ + else{ \ + EGlpNumCopy(x, lp->dz[j]); \ + EGlpNumCopyNeg(y, *zAj);\ + } \ + if (lvstat == STAT_UPPER) \ + EGlpNumSign(y); + + +void ILLratio_dI_test ( + lpinfo * lp, + int lindex, + int lvstat, + ratio_res * rs) +{ + int j = 0, k; + int col; + int cbnd, indx; + int tctr = 0; + int *perm = lp->upd.perm; + int *ix = lp->upd.ix; + EGlpNum_t *t = lp->upd.t; + EGlpNum_t *zAj, x, y, t_j, theta, rcost, delta; + EGlpNum_t *pftol = &(lp->tol->ip_tol); + EGlpNum_t *pivtol = &(lp->tol->pivot_tol); + + EGlpNumInitVar (x); + EGlpNumInitVar (y); + EGlpNumInitVar (t_j); + EGlpNumInitVar (theta); + EGlpNumInitVar (rcost); + EGlpNumInitVar (delta); + EGlpNumZero (delta); + EGlpNumZero (t_j); + EGlpNumZero (rs->tz); + /*HHH*/ rs->eindex = -1; + rs->ratio_stat = RATIO_FAILED; + EGlpNumZero (rs->pivotval); + + for (k = 0; k < lp->zA.nzcnt; k++) + { + zAj = &(lp->zA.coef[k]); + if (!EGlpNumIsNeqZero (*zAj, *pivtol)) + continue; + + EGlpNumCopy (t_j, INFTY); + j = lp->zA.indx[k]; + col = lp->nbaz[j]; + + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED) + continue; + + GET_XY_DRATIOTEST; + + if (EGlpNumIsLessZero (y)) + { + if (lp->dfeas[j] != 0 && lp->vstat[col] != STAT_ZERO) + { + EGlpNumCopyFrac (t[tctr], x, y); + ix[tctr] = 10 * k + BBTOLOWER; + tctr++; + } + else if (lp->vstat[col] == STAT_ZERO) + { + if (lp->dfeas[j] < 0) + { + EGlpNumCopyFrac (t[tctr], x, y); + ix[tctr] = 10 * k + BBTOLOWER; + tctr++; + } + if (lp->dfeas[j] <= 0) + { + EGlpNumCopyFrac (t[tctr], x, y); + ix[tctr] = 10 * k + BBTOUPPER; + tctr++; + } + } + } + else + { + if (lp->dfeas[j] > 0) + { + if (lp->vstat[col] == STAT_ZERO) + { + EGlpNumCopyFrac (t[tctr], x, y); + ix[tctr] = 10 * k + BATOUPPER; + tctr++; + EGlpNumCopyFrac (t[tctr], x, y); + ix[tctr] = 10 * k + BATOLOWER; + tctr++; + } + } + else if (lp->dfeas[j] == 0) + { + EGlpNumCopyFrac (t[tctr], x, y); + if (lp->vtype[col] == VBOUNDED) + ix[tctr] = 10 * k + BSKIP; + else + ix[tctr] = 10 * k + BATOLOWER; + tctr++; + } + } + } + + if (tctr == 0) + { + rs->ratio_stat = RATIO_FAILED; + ILL_CLEANUP; + } + + for (j = 0; j < tctr; j++) + perm[j] = j; + ILLutil_EGlpNum_perm_quicksort (perm, t, tctr); + + EGlpNumZero (lp->upd.c_obj); + EGlpNumCopy (rcost, lp->xbz[lindex]); + if (lvstat == STAT_LOWER) + EGlpNumSign (rcost); + for (j = 0; j < tctr; j++) + { + cbnd = ix[perm[j]] % 10; + if (cbnd == BSKIP) + continue; + + EGlpNumCopy (t_j, t[perm[j]]); + EGlpNumCopy (x, t_j); + EGlpNumSubTo (x, delta); + EGlpNumAddInnProdTo (lp->upd.c_obj, x, rcost); + EGlpNumCopy (delta, t_j); + k = ix[perm[j]] / 10; + zAj = &(lp->zA.coef[k]); + indx = lp->zA.indx[k]; + + if (lp->vstat[lp->nbaz[indx]] == STAT_LOWER + || lp->vstat[lp->nbaz[indx]] == STAT_ZERO) + EGlpNumCopyNeg (theta, *zAj); + else + EGlpNumCopy (theta, *zAj); + + if (lvstat == STAT_UPPER) + EGlpNumSign (theta); + + switch (cbnd) + { + case BATOLOWER: + case BATOUPPER: + EGlpNumSubTo (rcost, theta); + break; + case BBTOLOWER: + case BBTOUPPER: + EGlpNumAddTo (rcost, theta); + break; + } + if (EGlpNumIsLeq (rcost, *pftol)) + { + /* if (t_j < 0.0) printf ("dIhell\n"); */ + rs->eindex = indx; + EGlpNumCopy (rs->tz, t_j); + EGlpNumCopy (rs->pivotval, *zAj); + rs->ratio_stat = RATIO_BCHANGE; + ILL_CLEANUP; + } + } + +CLEANUP: + ILLfct_update_counts (lp, CNT_DIPIV, 0, rs->pivotval); + ILL_IFTRACE2 ("%s:tctr %d\n", __func__, tctr); + lp->upd.tctr = tctr; + lp->upd.i = j; + EGlpNumCopyAbs (lp->upd.tz, t_j); + EGlpNumCopy (lp->upd.piv, rs->pivotval); + if (rs->eindex != -1) + lp->upd.fs = lp->dfeas[rs->eindex]; + EGlpNumClearVar (x); + EGlpNumClearVar (y); + EGlpNumClearVar (t_j); + EGlpNumClearVar (theta); + EGlpNumClearVar (rcost); + EGlpNumClearVar (delta); +} + +void ILLratio_dII_test ( + lpinfo * lp, + /*int lindex,*/ + int lvstat, + ratio_res * rs) +{ + int j, k, indx; + int col, ecol; + EGlpNum_t *zAj, azAj, az_max, x, y, t_j, z_max, t_max, t_z; + EGlpNum_t *dftol = &(lp->tol->dfeas_tol); + EGlpNum_t *pivtol = &(lp->tol->pivot_tol); + + EGlpNumInitVar (x); + EGlpNumInitVar (y); + EGlpNumInitVar (t_j); + EGlpNumInitVar (z_max); + EGlpNumInitVar (t_max); + EGlpNumInitVar (az_max); + EGlpNumInitVar (azAj); + EGlpNumInitVar (t_z); + EGlpNumZero (t_j); + rs->coeffch = 0; + EGlpNumZero (rs->ecoeff); + rs->eindex = -1; + rs->ratio_stat = RATIO_FAILED; + ILL_IFTRACE2 ("%s:tctr %d\n", __func__, 0); + lp->upd.tctr = 0; + EGlpNumZero (lp->upd.dty); + for (k = 0, EGlpNumCopy (t_max, INFTY); k < lp->zA.nzcnt; k++) + { + zAj = &(lp->zA.coef[k]); + if (!EGlpNumIsNeqZero (*zAj, *pivtol)) + continue; + + EGlpNumCopy (t_j, INFTY); + j = lp->zA.indx[k]; + col = lp->nbaz[j]; + + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED) + continue; + + GET_XY_DRATIOTEST; + +//#warning adding/substracting tolerances to used value, is it rigght? + if (EGlpNumIsGreatZero (y)) + { + //t_j = (x + dftol) / y; + EGlpNumCopySum (t_j, x, *dftol); + EGlpNumDivTo (t_j, y); + } + else + { +//#warning adding/substracting tolerances to used value, is it rigght? + if (lp->vstat[col] == STAT_ZERO) + EGlpNumCopyDiffRatio (t_j, x, *dftol, y); + } + //if (t_j == INFTY) + if (EGlpNumIsEqqual (t_j, INFTY)) + continue; + + if (EGlpNumIsLess (t_j, t_max)) + EGlpNumCopy (t_max, t_j); + } + + if (EGlpNumIsLeq (INFTY, t_max)) + { + rs->ratio_stat = RATIO_UNBOUNDED; + ILL_CLEANUP; + } + /* if (t_max < 0.0) printf ("dIIhell\n"); */ + + indx = -1; + EGlpNumZero (t_z); + EGlpNumZero (z_max); + EGlpNumZero (az_max); + + for (k = 0; k < lp->zA.nzcnt; k++) + { + zAj = &(lp->zA.coef[k]); + EGlpNumCopyAbs (azAj, *zAj); + if (!EGlpNumIsNeqZero (*zAj, *pivtol)) + continue; + + EGlpNumCopy (t_j, INFTY); + j = lp->zA.indx[k]; + col = lp->nbaz[j]; + + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED) + continue; + + GET_XY_DRATIOTEST; + + if (EGlpNumIsGreatZero (y) || lp->vstat[col] == STAT_ZERO) + EGlpNumCopyFrac (t_j, x, y); + + if (EGlpNumIsLeq (t_j, t_max) && (EGlpNumIsLess (az_max, azAj))) + { + EGlpNumCopy (z_max, *zAj); + EGlpNumCopy (az_max, azAj); + indx = j; + EGlpNumCopy (t_z, t_j); + } + } + + + if (indx < 0) + { + rs->ratio_stat = RATIO_FAILED; + } + else + { + rs->eindex = indx; + EGlpNumCopy (rs->tz, t_z); + EGlpNumCopy (rs->pivotval, z_max); + rs->ratio_stat = RATIO_BCHANGE; + + if (EGlpNumIsLessZero (rs->tz)) + { + EGlpNumCopyAbs (rs->tz, t_max); + EGlpNumDivUiTo (rs->tz, 20); + rs->coeffch = 1; + ecol = lp->nbaz[indx]; + EGlpNumCopyDiff (rs->ecoeff, lp->cz[ecol], lp->dz[indx]); + switch (lp->vstat[ecol]) + { + case STAT_LOWER: + EGlpNumAddInnProdTo (rs->ecoeff, rs->tz, az_max); + break; + case STAT_UPPER: + EGlpNumSubInnProdTo (rs->ecoeff, rs->tz, az_max); + break; + default: + EGlpNumZero (rs->tz); + break; + } + } + } + +CLEANUP: + ILLfct_update_counts (lp, CNT_DIIPIV, 0, rs->pivotval); + EGlpNumCopy (lp->upd.piv, rs->pivotval); + EGlpNumClearVar (x); + EGlpNumClearVar (y); + EGlpNumClearVar (t_j); + EGlpNumClearVar (z_max); + EGlpNumClearVar (t_max); + EGlpNumClearVar (t_z); + EGlpNumClearVar (az_max); + EGlpNumClearVar (azAj); +} + +void ILLratio_longdII_test ( + lpinfo * lp, + int lindex, + int lvstat, + ratio_res * rs) +{ + int j, k, indx = 0, tctr = 0; + int col, ecol; + int vs, bnd_exist = 0; + int *perm = lp->upd.perm; + int *ix = lp->upd.ix; + int b_indx = -1; + EGlpNum_t *t = lp->upd.t; + EGlpNum_t *l, + *u, + *xb, + *zAj = 0, + x, + y, + t_j, + z_max, + t_max, t_z, theta, rcost, delta, zb_val, tb_val, az_max, azb_val, azAj; + EGlpNum_t *pftol = &(lp->tol->pfeas_tol); + EGlpNum_t *dftol = &(lp->tol->dfeas_tol); + EGlpNum_t *pivtol = &(lp->tol->pivot_tol); + + EGlpNumInitVar (x); + EGlpNumInitVar (azAj); + EGlpNumInitVar (y); + EGlpNumInitVar (t_j); + EGlpNumInitVar (z_max); + EGlpNumInitVar (az_max); + EGlpNumInitVar (t_max); + EGlpNumInitVar (t_z); + EGlpNumInitVar (theta); + EGlpNumInitVar (rcost); + EGlpNumInitVar (delta); + EGlpNumInitVar (zb_val); + EGlpNumInitVar (azb_val); + EGlpNumInitVar (tb_val); + EGlpNumZero (t_j); + EGlpNumZero (delta); + EGlpNumZero (zb_val); + EGlpNumZero (azb_val); + EGlpNumCopy (tb_val, NINFTY); +//#warning not sure about THIS line + EGlpNumZero (rs->pivotval); + + rs->coeffch = 0; + rs->eindex = -1; + rs->ratio_stat = RATIO_FAILED; + + ILL_IFTRACE2 ("%s:tctr %d\n", __func__, 0); + lp->upd.tctr = 0; + lp->upd.i = 0; + EGlpNumZero (lp->upd.tz); + EGlpNumZero (lp->upd.piv); + EGlpNumZero (lp->upd.c_obj); + EGlpNumZero (lp->upd.dty); + + xb = &(lp->xbz[lindex]); + col = lp->baz[lindex]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + //rcost = (lvstat == STAT_LOWER) ? l - xb : xb - u; + if (lvstat == STAT_LOWER) + EGlpNumCopyDiff (rcost, *l, *xb); + else + EGlpNumCopyDiff (rcost, *xb, *u); + + for (k = 0, EGlpNumCopy (t_max, INFTY); k < lp->zA.nzcnt; k++) + { + zAj = &(lp->zA.coef[k]); + if (!EGlpNumIsNeqZero (*zAj, *pivtol)) + continue; + + EGlpNumCopy (t_j, INFTY); + j = lp->zA.indx[k]; + col = lp->nbaz[j]; + + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED) + continue; + if (lp->vtype[col] == VBOUNDED) + { + bnd_exist++; + continue; + } + + GET_XY_DRATIOTEST; + + if (EGlpNumIsGreatZero (y)) + { + //t_j = (x + dftol) / y; +//#warning Using tolerances to add to result, is it right? + EGlpNumCopySum (t_j, x, *dftol); + EGlpNumDivTo (t_j, y); + } + else + { + if (lp->vstat[col] == STAT_ZERO) + EGlpNumCopyDiffRatio (t_j, x, *dftol, y); + } + if (EGlpNumIsEqqual (t_j, INFTY)) + continue; + + if (EGlpNumIsLess (t_j, t_max)) + EGlpNumCopy (t_max, t_j); + } + if (EGlpNumIsLessZero (t_max)) + { + /*printf ("dIIhell, %.4f\n", t_max); */ + rs->ratio_stat = RATIO_NEGATIVE; + ILL_CLEANUP; + } + + if (bnd_exist == 0 && EGlpNumIsLeq (INFTY, t_max)) + { + rs->ratio_stat = RATIO_UNBOUNDED; + /* + * printf ("x = %.8f, b = %.2f \n", lp->xbz[lindex], (lvstat == STAT_LOWER ) ? lp->lz[lp->baz[lindex]] : lp->uz[lp->baz[lindex]]); + */ + ILL_CLEANUP; + } + + if (bnd_exist != 0) + { + for (k = 0; k < lp->zA.nzcnt; k++) + { + zAj = &(lp->zA.coef[k]); + if (!EGlpNumIsNeqZero (*zAj, *pivtol)) + continue; + + EGlpNumCopy (t_j, INFTY); + j = lp->zA.indx[k]; + col = lp->nbaz[j]; + + if (lp->vtype[col] != VBOUNDED) + continue; + + GET_XY_DRATIOTEST; + + if (EGlpNumIsGreatZero (y)) + { + EGlpNumCopyFrac (t_j, x, y); + if (EGlpNumIsLeq (t_j, t_max)) + { + EGlpNumCopy (t[tctr], t_j); + ix[tctr] = k; + tctr++; + } + } + } + } + + if (tctr != 0) + { + for (j = 0; j < tctr; j++) + perm[j] = j; + ILLutil_EGlpNum_perm_quicksort (perm, t, tctr); + + for (j = 0; j < tctr; j++) + { + + EGlpNumCopy (t_j, t[perm[j]]); + /* we use x as temporal storage */ + //lp->upd.c_obj += (t_j - delta) * rcost; + EGlpNumCopy (x, t_j); + EGlpNumSubTo (x, delta); + EGlpNumAddInnProdTo (lp->upd.c_obj, x, rcost); + EGlpNumCopy (delta, t_j); + /*HHH*/ k = ix[perm[j]]; + zAj = &(lp->zA.coef[k]); + indx = lp->zA.indx[k]; + col = lp->nbaz[indx]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + vs = lp->vstat[col]; + //theta = (vs == STAT_UPPER) ? (l - u) * zAj : (u - l) * zAj; + EGlpNumCopyDiff (theta, *l, *u); + EGlpNumMultTo (theta, *zAj); + if (vs != STAT_UPPER) + EGlpNumSign (theta); + if (lvstat == STAT_LOWER) + EGlpNumAddTo (rcost, theta); + else + EGlpNumSubTo (rcost, theta); + + if (EGlpNumIsLeq (rcost, *pftol)) + { + rs->eindex = indx; + EGlpNumCopy (rs->tz, t_j); + EGlpNumCopy (rs->pivotval, *zAj); + rs->ratio_stat = RATIO_BCHANGE; + + if (EGlpNumIsLessZero (rs->tz)) + { + EGlpNumZero (rs->tz); + rs->coeffch = 1; + //rs->ecoeff = lp->cz[col] - lp->dz[indx]; + EGlpNumCopyDiff (rs->ecoeff, lp->cz[col], lp->dz[indx]); + //lp->upd.c_obj += (rs->tz - delta) * rcost; note ts->tz == 0; + EGlpNumSubInnProdTo (lp->upd.c_obj, delta, rcost); + } + ILL_IFTRACE2 ("%s:tctr %d\n", __func__, tctr); + lp->upd.tctr = tctr; + lp->upd.i = j; + EGlpNumCopy (lp->upd.tz, rs->tz); + ILL_CLEANUP; + } + } + ILL_IFTRACE2 ("%s:tctr %d\n", __func__, tctr); + lp->upd.tctr = tctr; + lp->upd.i = tctr; + EGlpNumCopy (lp->upd.tz, t_j); + EGlpNumCopy (zb_val, *zAj); + EGlpNumCopyAbs (azb_val, zb_val); + EGlpNumCopy (tb_val, t_j); + b_indx = indx; + } + + if (bnd_exist != 0 && EGlpNumIsLeq (INFTY, t_max)) + { + rs->ratio_stat = RATIO_UNBOUNDED; + /* printf ("rcost: %.8f\n", rcost); */ + ILL_CLEANUP; + } + + EGlpNumZero (z_max); + EGlpNumZero (az_max); + indx = -1; + EGlpNumZero (t_z); + for (k = 0; k < lp->zA.nzcnt; k++) + { + zAj = &(lp->zA.coef[k]); + EGlpNumCopyAbs (azAj, *zAj); + if (!EGlpNumIsNeqZero (*zAj, *pivtol)) + continue; + + EGlpNumCopy (t_j, INFTY); + j = lp->zA.indx[k]; + col = lp->nbaz[j]; + + if (lp->vtype[col] == VARTIFICIAL || lp->vtype[col] == VFIXED || + lp->vtype[col] == VBOUNDED) + continue; + + GET_XY_DRATIOTEST; + + if (EGlpNumIsGreatZero (y) || lp->vstat[col] == STAT_ZERO) + EGlpNumCopyFrac (t_j, x, y); + + if (EGlpNumIsLeq (t_j, t_max)) + { + if (EGlpNumIsLess (az_max, azAj)) + { + EGlpNumCopy (z_max, *zAj); + EGlpNumCopy (az_max, azAj); + indx = j; + EGlpNumCopy (t_z, t_j); + } + } + } + + if (indx < 0) + { + rs->ratio_stat = RATIO_FAILED; + ILL_CLEANUP; + } + if ((tctr == 0) || (EGlpNumIsLessZero (tb_val)) || + (tctr != 0 && EGlpNumIsLeq (tb_val, t_z) && + EGlpNumIsLeq (azb_val, az_max))) + { + /* we use x as temporal vvariable */ + /* lp->upd.c_obj += (t_z - delta) * rcost; */ + EGlpNumCopyDiff (x, t_z, delta); + EGlpNumAddInnProdTo (lp->upd.c_obj, x, rcost); + EGlpNumCopy (delta, t_z); + rs->eindex = indx; + EGlpNumCopy (rs->tz, t_z); + EGlpNumCopy (rs->pivotval, z_max); + rs->ratio_stat = RATIO_BCHANGE; + } + /* For now */ + else if (tctr != 0) + { + rs->eindex = b_indx; + EGlpNumCopy (rs->tz, tb_val); + EGlpNumCopy (rs->pivotval, zb_val); + rs->ratio_stat = RATIO_BCHANGE; + lp->upd.i -= 1; + } + + if (EGlpNumIsLessZero (rs->tz)) + { + /* if (tctr != 0) printf ("despite long step\n"); */ + /* rs->tz = fabs (t_max / 20.0); */ + EGlpNumCopyAbs (rs->tz, t_max); + EGlpNumDivUiTo (rs->tz, 20); + rs->coeffch = 1; + + ecol = lp->nbaz[indx]; + if (lp->vstat[ecol] == STAT_LOWER) + { + /*rs->ecoeff = lp->cz[ecol] - lp->dz[indx] + rs->tz * fabs (z_max); */ + EGlpNumCopy (rs->ecoeff, az_max); + EGlpNumMultTo (rs->ecoeff, rs->tz); + EGlpNumAddTo (rs->ecoeff, lp->cz[ecol]); + EGlpNumSubTo (rs->ecoeff, lp->dz[indx]); + } + else if (lp->vstat[ecol] == STAT_UPPER) + { + /*rs->ecoeff = lp->cz[ecol] - lp->dz[indx] - rs->tz * fabs (z_max); */ + EGlpNumCopy (rs->ecoeff, az_max); + EGlpNumMultTo (rs->ecoeff, rs->tz); + EGlpNumSign (rs->ecoeff); + EGlpNumAddTo (rs->ecoeff, lp->cz[ecol]); + EGlpNumSubTo (rs->ecoeff, lp->dz[indx]); + } + else + { + /*rs->ecoeff = lp->cz[ecol] - lp->dz[indx]; */ + EGlpNumCopyDiff (rs->ecoeff, lp->cz[ecol], lp->dz[indx]); + EGlpNumZero (rs->tz); + } + /* we use x as temporal storage */ + /*lp->upd.c_obj += (rs->tz - delta) * rcost; */ + EGlpNumCopy (x, rs->tz); + EGlpNumSubTo (x, delta); + EGlpNumAddInnProdTo (lp->upd.c_obj, x, rcost); + } + +CLEANUP: + ILLfct_update_counts (lp, CNT_DIIPIV, 0, rs->pivotval); + EGlpNumCopy (lp->upd.piv, rs->pivotval); + EGlpNumClearVar (x); + EGlpNumClearVar (y); + EGlpNumClearVar (t_j); + EGlpNumClearVar (z_max); + EGlpNumClearVar (az_max); + EGlpNumClearVar (t_max); + EGlpNumClearVar (t_z); + EGlpNumClearVar (theta); + EGlpNumClearVar (rcost); + EGlpNumClearVar (delta); + EGlpNumClearVar (zb_val); + EGlpNumClearVar (azb_val); + EGlpNumClearVar (tb_val); + EGlpNumClearVar (azAj); +} + +void ILLratio_pivotin_test ( + lpinfo * lp, + int *rlist, + int rcnt, + ratio_res * rs) +{ + int i, k, col; + EGlpNum_t *x, *l, *u; + EGlpNum_t ay_ij, + at_i, at_l, at_u, ayi_max, y_ij, t_i, t_l, t_u, t_max, yi_max; + EGlpNum_t *pivtol = &(lp->tol->pivot_tol); + + if (rcnt <= 0 || rs == NULL) + return; + EGlpNumInitVar (ay_ij); + EGlpNumInitVar (at_i); + EGlpNumInitVar (at_l); + EGlpNumInitVar (at_u); + EGlpNumInitVar (ayi_max); + EGlpNumInitVar (t_max); + EGlpNumInitVar (y_ij); + EGlpNumInitVar (t_i); + EGlpNumInitVar (t_l); + EGlpNumInitVar (t_u); + EGlpNumInitVar (yi_max); + rs->boundch = 0; + rs->lindex = -1; + EGlpNumZero (rs->tz); + rs->ratio_stat = RATIO_FAILED; + rs->lvstat = -1; + EGlpNumZero (rs->pivotval); + EGlpNumZero (rs->lbound); + + for (i = 0; i < rcnt; i++) + lp->iwork[rlist[i]] = 1; + + for (k = 0, EGlpNumCopy (t_max, INFTY); k < lp->yjz.nzcnt; k++) + { + EGlpNumCopy (y_ij, lp->yjz.coef[k]); + if (!EGlpNumIsNeqZero (y_ij, *pivtol)) + continue; + + i = lp->yjz.indx[k]; + if (lp->iwork[lp->baz[i]] == 1) + continue; + x = &(lp->xbz[i]); + col = lp->baz[i]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + EGlpNumCopy (t_u, INFTY); + EGlpNumCopy (at_u, INFTY); + EGlpNumCopy (t_l, NINFTY); + EGlpNumCopy (at_l, INFTY); + + if (EGlpNumIsNeqq (*l, NINFTY)) + { + EGlpNumCopyDiffRatio (t_l, *x, *l, y_ij); + EGlpNumCopyAbs (at_l, t_l); + if (EGlpNumIsLess (at_l, t_max)) + EGlpNumCopy (t_max, at_l); + } + if (EGlpNumIsNeqq (*u, INFTY)) + { + EGlpNumCopyDiffRatio (t_u, *x, *u, y_ij); + EGlpNumCopyAbs (at_u, t_u); + if (EGlpNumIsLess (at_u, t_max)) + EGlpNumCopy (t_max, at_u); + } + } + + if (EGlpNumIsLeq (INFTY, t_max)) + { + rs->ratio_stat = RATIO_UNBOUNDED; + ILL_CLEANUP; + } + + EGlpNumZero (yi_max); + EGlpNumZero (ayi_max); + EGlpNumMultUiTo (t_max, 101); + EGlpNumDivUiTo (t_max, 100); + for (k = 0; k < lp->yjz.nzcnt; k++) + { + EGlpNumCopy (y_ij, lp->yjz.coef[k]); + EGlpNumCopyAbs (ay_ij, y_ij); + if (!EGlpNumIsNeqZero (y_ij, *pivtol)) + continue; + + i = lp->yjz.indx[k]; + if (lp->iwork[lp->baz[i]] == 1) + continue; + x = &(lp->xbz[i]); + col = lp->baz[i]; + l = &(lp->lz[col]); + u = &(lp->uz[col]); + + EGlpNumCopy (t_u, INFTY); + EGlpNumCopy (at_u, t_u); + EGlpNumCopy (t_l, NINFTY); + EGlpNumCopy (at_l, t_u); + if (EGlpNumIsNeqq (*l, NINFTY)) + { + EGlpNumCopyDiffRatio (t_l, *x, *l, y_ij); + EGlpNumCopyAbs (at_l, t_l); + } + if (EGlpNumIsNeqq (*u, INFTY)) + { + EGlpNumCopyDiffRatio (t_u, *x, *u, y_ij); + EGlpNumCopyAbs (at_u, t_u); + } + //t_i = (fabs (t_l) < fabs (t_u)) ? t_l : t_u; + if (EGlpNumIsLess (at_l, at_u)) + { + EGlpNumCopy (t_i, t_l); + EGlpNumCopy (at_i, at_l); + } + else + { + EGlpNumCopy (t_i, t_u); + EGlpNumCopy (at_i, at_u); + } + /*if (fabs (t_i) <= t_max + t_max * (1.0e-2)) */ + if (EGlpNumIsLeq (at_i, t_max)) + { + if (EGlpNumIsLess (ayi_max, ay_ij)) + { + EGlpNumCopy (yi_max, y_ij); + EGlpNumCopy (ayi_max, ay_ij); + rs->lindex = i; + EGlpNumCopy (rs->tz, t_i); + rs->lvstat = (EGlpNumIsLess (at_l, at_u)) ? STAT_LOWER : STAT_UPPER; + } + } + } + + if (rs->lindex < 0) + { + rs->ratio_stat = RATIO_FAILED; + } + else + { + rs->ratio_stat = RATIO_BCHANGE; + EGlpNumCopy (rs->pivotval, yi_max); + } +CLEANUP: + for (i = 0; i < rcnt; i++) + lp->iwork[rlist[i]] = 0; + EGlpNumClearVar (t_max); + EGlpNumClearVar (ay_ij); + EGlpNumClearVar (at_i); + EGlpNumClearVar (at_l); + EGlpNumClearVar (at_u); + EGlpNumClearVar (ayi_max); + EGlpNumClearVar (y_ij); + EGlpNumClearVar (t_i); + EGlpNumClearVar (t_l); + EGlpNumClearVar (t_u); + EGlpNumClearVar (yi_max); + return; +} diff --git a/src/ratio.h b/src/ratio.h new file mode 100644 index 0000000..2e8cafa --- /dev/null +++ b/src/ratio.h @@ -0,0 +1,73 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: ratio.h,v $ $Revision: 1.3 $ $Date: 2003/11/05 16:57:39 $" */ +#ifndef __RATIO_H +#define __RATIO_H +#include "basicdefs.h" +typedef struct ratio_res +{ + EGlpNum_t tz; + int eindex; + int lindex; + int lvstat; + int ratio_stat; + int boundch; + int coeffch; + EGlpNum_t lbound; + EGlpNum_t ecoeff; + EGlpNum_t pivotval; +} +ratio_res; + +void ILLratio_pI_test ( + lpinfo * const lp, + int const eindex, + int const dir, + ratio_res * const rs), + ILLratio_pII_test ( + lpinfo * const lp, + int const eindex, + int const dir, + ratio_res * const rs), + ILLratio_dI_test ( + lpinfo * const lp, + int const lindex, + int const lvstat, + ratio_res * const rs), + ILLratio_dII_test ( + lpinfo * const lp, + /*int const lindex,*/ + int const lvstat, + ratio_res * const rs), + ILLratio_longdII_test ( + lpinfo * const lp, + int const lindex, + int const lvstat, + ratio_res * const rs), + ILLratio_pivotin_test ( + lpinfo * const lp, + int *const rlist, + int const rcnt, + ratio_res * const rs); + +#endif /* __RATIO_H */ diff --git a/src/rawlp.c b/src/rawlp.c new file mode 100644 index 0000000..a05ccde --- /dev/null +++ b/src/rawlp.c @@ -0,0 +1,1760 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: rawlp.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +/****************************************************************************/ +/* DataStructure and routines to deal with raw lp information as read */ +/* from mps or lp files. */ +/****************************************************************************/ + +#include "qs_config.h" +#include "config.h" +#include "sortrus.h" +#include "iqsutil.h" +#include "rawlp.h" +#include "allocrus.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif +static int TRACE = 0; + +ILL_PTRWORLD_ROUTINES (colptr, colptralloc, colptr_bulkalloc, colptrfree) +ILL_PTRWORLD_LISTFREE_ROUTINE (colptr, colptr_listfree, colptrfree) +ILL_PTRWORLD_LEAKS_ROUTINE (colptr, colptr_check_leaks, this_val, int) + const int ILL_SOS_TYPE1 = 1; + const int ILL_SOS_TYPE2 = 2; + + static void ILLprt_EGlpNum ( + FILE * f, + EGlpNum_t * d) +{ + if (EGlpNumIsLeq (ILL_MAXDOUBLE, *d)) + { + fprintf (f, "MAX_DOUBLE"); + } + else + { + if (EGlpNumIsLeq (*d, ILL_MINDOUBLE)) + { + fprintf (f, "-MAX_DOUBLE"); + } + else + { + fprintf (f, "%f", EGlpNumToLf (*d)); + } + } +} + +static int ILLraw_check_bounds ( + rawlpdata * lp); + +void ILLinit_rawlpdata ( + rawlpdata * lp, + qserror_collector * collector) +{ + if (lp) + { + lp->name = 0; + lp->ncols = 0; + lp->nrows = 0; + lp->cols = 0; + lp->rowsense = 0; + lp->rhsname = 0; + lp->rhs = 0; + lp->rhsind = 0; + lp->rangesname = 0; + lp->rangesind = 0; + lp->ranges = 0; + lp->boundsname = 0; + lp->lbind = 0; + lp->ubind = 0; + lp->lower = 0; + lp->upper = 0; + lp->intmarker = 0; + lp->colsize = 0; + lp->sensesize = 0; + lp->intsize = 0; + lp->rhssize = 0; + lp->refrow = NULL; + lp->is_sos_size = 0; + lp->is_sos_member = NULL; + lp->nsos_member = 0; + lp->sos_weight_size = 0; + lp->sos_weight = NULL; + lp->sos_col_size = 0; + lp->sos_col = NULL; + lp->nsos = 0; + lp->sos_setsize = 0; + lp->sos_set = NULL; + ILLsymboltab_init (&lp->coltab); + ILLsymboltab_init (&lp->rowtab); + lp->objindex = -1; + lp->objsense = ILL_MIN; + lp->refrowind = -1; /* undefined */ + ILLptrworld_init (&lp->ptrworld); + lp->error_collector = collector; + } +} + +void ILLraw_clear_matrix ( + rawlpdata * lp) +{ + int i; + colptr *next, *curr; + + if ((lp != NULL) && (lp->cols != NULL)) + { + for (i = 0; i < lp->ncols; i++) + { + { + curr = lp->cols[i]; + while (curr) + { + next = curr->next; + EGlpNumClearVar ((curr->coef)); + colptrfree (&(lp->ptrworld), curr); + curr = next; + } + } + //colptr_listfree (&lp->ptrworld, lp->cols[i]); + lp->cols[i] = NULL; + } + } +} + +void ILLfree_rawlpdata ( + rawlpdata * lp) +{ + int total, onlist; + colptr *next, *curr; + + if (lp) + { + ILL_IFFREE (lp->name, char); + + ILLsymboltab_free (&lp->rowtab); + ILLsymboltab_free (&lp->coltab); + ILL_IFFREE (lp->rowsense, char); + + ILLraw_clear_matrix (lp); + ILL_IFFREE (lp->cols, colptr *); + { + curr = lp->ranges; + while (curr) + { + next = curr->next; + EGlpNumClearVar ((curr->coef)); + colptrfree (&(lp->ptrworld), curr); + curr = next; + } + } + //colptr_listfree (&lp->ptrworld, lp->ranges); + if (colptr_check_leaks (&lp->ptrworld, &total, &onlist)) + { + fprintf (stderr, "WARNING: %d outstanding colptrs\n", total - onlist); + } + ILLptrworld_delete (&lp->ptrworld); + ILL_IFFREE (lp->rhsname, char); + + EGlpNumFreeArray (lp->rhs); + ILL_IFFREE (lp->rhsind, char); + ILL_IFFREE (lp->rangesname, char); + ILL_IFFREE (lp->rangesind, char); + ILL_IFFREE (lp->boundsname, char); + ILL_IFFREE (lp->lbind, char); + ILL_IFFREE (lp->ubind, char); + + EGlpNumFreeArray (lp->lower); + EGlpNumFreeArray (lp->upper); + ILL_IFFREE (lp->intmarker, char); + ILL_IFFREE (lp->refrow, char); + ILL_IFFREE (lp->is_sos_member, int); + + EGlpNumFreeArray (lp->sos_weight); + ILL_IFFREE (lp->sos_col, int); + + ILL_IFFREE (lp->sos_set, sosptr); + ILLinit_rawlpdata (lp, NULL); + } +} + +const char *ILLraw_rowname ( + rawlpdata * lp, + int i) +{ + const char *name = NULL; + + ILL_FAILfalse_no_rval ((i >= 0) && (i < lp->nrows), "index out of range"); + ILL_FAILfalse_no_rval (lp->nrows == lp->rowtab.tablesize, + "tab and lp must be in synch"); + name = ILLsymboltab_get (&lp->rowtab, i); +CLEANUP: + return name; +} +const char *ILLraw_colname ( + rawlpdata * lp, + int i) +{ + const char *name = NULL; + + ILL_FAILfalse_no_rval ((i >= 0) && (i < lp->ncols), "index out of range"); + ILL_FAILfalse_no_rval (lp->ncols == lp->coltab.tablesize, + "tab and lp must be in synch"); + name = ILLsymboltab_get (&lp->coltab, i); +CLEANUP: + return name; +} + +int ILLraw_add_col ( + rawlpdata * lp, + const char *name, + int intmarker) +{ + int rval = 0; + int pindex, hit; + + rval = ILLsymboltab_register (&lp->coltab, name, -1, &pindex, &hit); + rval = rval || hit; + ILL_CLEANUP_IF (rval); + if (lp->ncols >= lp->colsize) + { + lp->colsize *= 1.3; + lp->colsize += 1000; + if (lp->colsize < lp->ncols + 1) + lp->colsize = lp->ncols + 1; + lp->cols = EGrealloc (lp->cols, lp->colsize * sizeof (colptr *)); + //rval = rval || ILLutil_reallocrus_scale (&lp->cols, + // &lp->colsize, lp->ncols + 1, 1.3, + // sizeof (colptr *)); + } + if (lp->ncols >= lp->intsize) + { + lp->intsize *= 1.3; + lp->intsize += 1000; + if (lp->intsize < lp->ncols + 1) + lp->intsize = lp->ncols + 1; + lp->intmarker = EGrealloc (lp->intmarker, lp->intsize * sizeof (char)); + //rval = rval || ILLutil_reallocrus_scale ((void **) &lp->intmarker, + // &lp->intsize, lp->ncols + 1, + // 1.3, sizeof (char)); + } + if (lp->ncols >= lp->is_sos_size) + { + lp->is_sos_size *= 1.3; + lp->is_sos_size += 1000; + if (lp->is_sos_size < lp->ncols + 1) + lp->is_sos_size = lp->ncols + 1; + lp->is_sos_member = EGrealloc (lp->is_sos_member, + sizeof (int) * lp->is_sos_size); + //rval = rval || ILLutil_reallocrus_scale ((void **) &lp->is_sos_member, + // &lp->is_sos_size, lp->ncols + 1, + // 1.3, sizeof (int)); + } + ILL_CLEANUP_IF (rval); + lp->cols[lp->ncols] = 0; + lp->is_sos_member[lp->ncols] = -1; + lp->intmarker[lp->ncols] = intmarker; + lp->ncols++; +CLEANUP: + ILL_RETURN (rval, "ILLraw_add_col"); +} + +int ILLraw_init_rhs ( + rawlpdata * lp) +{ + int i, rval = 0; + + ILL_FAILfalse (lp->rhsind == NULL, "Should be called exactly once"); + if (lp->nrows > 0) + { + ILL_SAFE_MALLOC (lp->rhsind, lp->nrows, char); + + for (i = 0; i < lp->nrows; i++) + { + lp->rhsind[i] = (char) 0; + } + } +CLEANUP: + ILL_RETURN (rval, "ILLraw_init_rhs"); +} + +int ILLraw_init_ranges ( + rawlpdata * lp) +{ + int i, rval = 0; + + ILL_FAILfalse (lp->rangesind == NULL, "Should be called exactly once"); + if (lp->nrows > 0) + { + ILL_SAFE_MALLOC (lp->rangesind, lp->nrows, char); + + for (i = 0; i < lp->nrows; i++) + { + lp->rangesind[i] = (char) 0; + } + } +CLEANUP: + ILL_RETURN (rval, "ILLraw_init_ranges"); +} + +int ILLraw_add_col_coef ( + rawlpdata * lp, + int colind, + int rowind, + EGlpNum_t coef) +{ + colptr *cp = ILLcolptralloc (&lp->ptrworld); + + if (!cp) + { + return 1; + } + cp->this_val = rowind; + EGlpNumCopy (cp->coef, coef); + cp->next = lp->cols[colind]; + lp->cols[colind] = cp; + return 0; +} + + +int ILLraw_add_ranges_coef ( + rawlpdata * lp, + int rowind, + EGlpNum_t coef) +{ + colptr *cp = ILLcolptralloc (&lp->ptrworld); + + if (!cp) + { + return 1; + } + cp->this_val = rowind; + EGlpNumCopy (cp->coef, coef); + cp->next = lp->ranges; + lp->ranges = cp; + lp->rangesind[rowind] = (char) 1; + return 0; +} + +int ILLraw_add_sos ( + rawlpdata * lp, + int tp) +{ + int rval = 0; + sosptr *sos, *bef; + + if (lp->nsos >= lp->sos_setsize) + { + lp->sos_setsize *= 1.3; + lp->sos_setsize += 1000; + if (lp->sos_setsize < lp->nsos + 1) + lp->sos_setsize = lp->nsos + 1; + lp->sos_set = EGrealloc (lp->sos_set, sizeof (sosptr *) * lp->sos_setsize); + //if (ILLutil_reallocrus_scale ((void **) &lp->sos_set, + // &lp->sos_setsize, lp->nsos + 1, 1.3, + // sizeof (sosptr *))) + //{ + // ILL_CLEANUP_IF (rval); + //} + } + sos = lp->sos_set + lp->nsos; + sos->nelem = 0; + sos->type = tp; + if (lp->nsos == 0) + { + sos->first = 0; + } + else + { + bef = &(lp->sos_set[lp->nsos - 1]); + sos->first = bef->first + bef->nelem; + } + lp->nsos++; +//CLEANUP: + ILL_RETURN (rval, "ILLraw_add_sos"); +} + +int ILLraw_is_mem_other_sos ( + rawlpdata * lp, + int colind) +{ + return (lp->is_sos_member[colind] >= 0) && + (lp->is_sos_member[colind] != (lp->nsos - 1)); +} + +int ILLraw_add_sos_member ( + rawlpdata * lp, + int colind) +{ + int rval = 0; + + ILL_FAILfalse (lp->nsos > 0, "we should have called ILLraw_add_sos earlier"); + ILL_FAILtrue (ILLraw_is_mem_other_sos (lp, colind), + "colind is member of another sos set"); + + if (lp->is_sos_member[colind] == -1) + { + if (lp->nsos_member >= lp->sos_weight_size) + { + lp->sos_weight_size *= 1.3; + lp->sos_weight_size += 1000; + if (lp->sos_weight_size < lp->nsos_member + 1) + lp->sos_weight_size = lp->nsos_member + 1; + lp->sos_weight = EGrealloc (lp->sos_weight, + lp->sos_weight_size * sizeof (double)); + //if (ILLutil_reallocrus_scale ((void **) &lp->sos_weight, + // &lp->sos_weight_size, + // lp->nsos_member + 1, 1.3, sizeof (double))) + //{ + // ILL_CLEANUP_IF (rval); + //} + } + if (lp->nsos_member >= lp->sos_col_size) + { + lp->sos_col_size *= 1.3; + lp->sos_col_size += 1000; + if (lp->sos_col_size < lp->nsos_member + 1) + lp->sos_col_size = lp->nsos_member + 1; + lp->sos_col = EGrealloc (lp->sos_col, sizeof (int) * lp->sos_col_size); + //if (ILLutil_reallocrus_scale ((void **) &lp->sos_col, + // &lp->sos_col_size, + // lp->nsos_member + 1, 1.3, sizeof (int))) + //{ + // ILL_CLEANUP_IF (rval); + //} + } + lp->sos_col[lp->nsos_member] = colind; + lp->sos_set[lp->nsos - 1].nelem++; + lp->is_sos_member[colind] = lp->nsos - 1; + lp->nsos_member++; + } +CLEANUP: + ILL_RETURN (rval, "ILLraw_add_sos_member"); +} + + +int ILLraw_add_row ( + rawlpdata * lp, + const char *name, + int sense, + const EGlpNum_t rhs) +{ + int pindex, hit, rval = 0; + + rval = ILLsymboltab_register (&lp->rowtab, name, -1, &pindex, &hit); + rval = rval || hit; + ILL_CLEANUP_IF (rval); + if (lp->nrows >= lp->sensesize) + { + lp->sensesize *= 1.3; + lp->sensesize += 1000; + if (lp->sensesize < lp->nrows + 1) + lp->sensesize = lp->nrows + 1; + lp->rowsense = EGrealloc (lp->rowsense, sizeof (char) * lp->sensesize); + //if (ILLutil_reallocrus_scale ((void **) &lp->rowsense, + // &lp->sensesize, lp->nrows + 1, + // 1.3, sizeof (char))) + //{ + // ILL_CLEANUP_IF (rval); + //} + } + if (lp->nrows >= lp->rhssize) + { + if (lp->rhssize + 1000 < (lp->nrows + 1) * 1.3) + lp->rhssize = (lp->nrows + 1) * 1.3; + else + lp->rhssize += 1000; + EGlpNumReallocArray (&(lp->rhs), lp->rhssize); + } + lp->rowsense[lp->nrows] = sense; + EGlpNumCopy (lp->rhs[lp->nrows], rhs); + lp->nrows++; + +CLEANUP: + ILL_RETURN (rval, "ILLraw_add_row"); +} + +static int ILLcheck_rawlpdata ( + rawlpdata * lp) +{ + int i, col, rval = 0; + int si, *perm = NULL; + const char *c1, *c2; + sosptr *set; + + ILL_FAILfalse (lp, "lp must not be NULL"); + + /* check + * *) that there is at least one variable + * *) that the weights in all SOS sets are distinct + * *) all sos members are non integer variables + * *) sos set members have distint weights + * *) objindex is not -1 + * *) INVARIANT: rowname[objindex] != NULL + * *) INVARIANT: upper/lower arrays are filled in + * *) INVARIANT: if col or rownames != NULL then + * all their elements are not NULL + */ + if (lp->ncols < 1) + { + return ILLdata_error (lp->error_collector, "There are no variables."); + } + if (lp->objindex == -1) + { + return ILLdata_error (lp->error_collector, "There is no objective fct."); + } + ILL_FAILfalse (ILLraw_rowname (lp, lp->objindex) != NULL, + "must have objective name"); + if (lp->nsos_member > 1) + { + ILL_SAFE_MALLOC (perm, lp->nsos_member, int); + + for (si = 0; si < lp->nsos; si++) + { + set = lp->sos_set + si; + for (i = 0; i < set->nelem; i++) + { + col = lp->sos_col[set->first + i]; + if (lp->intmarker[col]) + { + rval = ILLdata_error (lp->error_collector, + "SOS set member \"%s\" is an %s.\n", + ILLraw_colname (lp, col), + "integer/binary variable"); + } + } + if (set->nelem > 1) + { + for (i = 0; i < set->nelem; i++) + { + perm[i] = set->first + i; + } + ILLutil_EGlpNum_perm_quicksort (perm, lp->sos_weight, set->nelem); + for (i = 1; i < set->nelem; i++) + { + if (EGlpNumIsEqqual + (lp->sos_weight[perm[i - 1]], lp->sos_weight[perm[i]])) + { + c1 = ILLraw_colname (lp, lp->sos_col[perm[i]]); + c2 = ILLraw_colname (lp, lp->sos_col[perm[i - 1]]); + ILLdata_error (lp->error_collector, + "\"%s\" and \"%s\" both have %s %f.\n", c1, c2, + "SOS weight", lp->sos_weight[perm[i]]); + rval = 1; + } + } + } + } + } + for (i = 0; i < lp->ncols; i++) + { + ILL_CHECKnull (ILLraw_colname (lp, i), "There is a NULL col name"); + } + for (i = 0; i < lp->nrows; i++) + { + ILL_CHECKnull (ILLraw_rowname (lp, i), "There is a NULL row name"); + } + ILL_FAILtrue ((lp->upper == NULL) | (lp->lower == NULL), + "Upper/Lower arrays must be filled in."); + + rval += ILLraw_check_bounds (lp); +CLEANUP: + ILL_IFFREE (perm, int); + + ILL_RESULT (rval, "ILLcheck_rawlpdata"); +} + +int ILLraw_init_bounds ( + rawlpdata * lp) +{ + int i, rval = 0; + + ILL_FAILfalse (lp->upper == NULL, "Should be called exactly once"); + ILL_FAILfalse (lp->lower == NULL, "Should be called exactly once"); + ILL_FAILfalse (lp->lbind == NULL, "Should be called exactly once"); + ILL_FAILfalse (lp->ubind == NULL, "Should be called exactly once"); + lp->upper = EGlpNumAllocArray (lp->ncols); + lp->lower = EGlpNumAllocArray (lp->ncols); + ILL_SAFE_MALLOC (lp->lbind, lp->ncols, char); + ILL_SAFE_MALLOC (lp->ubind, lp->ncols, char); + + for (i = 0; i < lp->ncols; i++) + { + lp->lbind[i] = (char) 0; + lp->ubind[i] = (char) 0; + EGlpNumZero (lp->lower[i]); + } +CLEANUP: + ILL_RETURN (rval, "ILLraw_init_bounds"); +} + +const char *ILLraw_set_lowerBound ( + rawlpdata * lp, + int i, + EGlpNum_t bnd) +{ + ILL_FAILtrue_no_rval (i >= lp->ncols, "proper colind"); + if (lp->lbind[i]) + { + return "Using previous bound definition."; + } + EGlpNumCopy (lp->lower[i], bnd); + lp->lbind[i] = (char) 1; +CLEANUP: + return NULL; +} + +const char *ILLraw_set_upperBound ( + rawlpdata * lp, + int i, + EGlpNum_t bnd) +{ + ILL_FAILtrue_no_rval (i >= lp->ncols, "proper colind"); + if (lp->ubind[i]) + { + return "Using previous bound definition."; + } + EGlpNumCopy (lp->upper[i], bnd); + lp->ubind[i] = (char) 1; + if (!EGlpNumIsNeqqZero (lp->lower[i]) && + !EGlpNumIsNeqqZero (bnd)) + { + return "0.0 upper bound fixes variable."; + } +CLEANUP: + return NULL; +} + +const char *ILLraw_set_fixedBound ( + rawlpdata * lp, + int i, + EGlpNum_t bnd) +{ + ILL_FAILtrue_no_rval (i >= lp->ncols, "proper colind"); + if (lp->ubind[i] || lp->lbind[i]) + { + return "Using previous bound definition."; + } + EGlpNumCopy (lp->lower[i], bnd); + lp->lbind[i] = (char) 1; + EGlpNumCopy (lp->upper[i], bnd); + lp->ubind[i] = (char) 1; +CLEANUP: + return NULL; +} + +const char *ILLraw_set_unbound ( + rawlpdata * lp, + int i) +{ + ILL_FAILtrue_no_rval (i >= lp->ncols, "proper colind"); + if (lp->lbind[i] || lp->ubind[i]) + { + return "Using previous bound definition."; + } + EGlpNumCopy (lp->lower[i], ILL_MINDOUBLE); + EGlpNumCopy (lp->upper[i], ILL_MAXDOUBLE); + lp->lbind[i] = 1; + lp->ubind[i] = 1; +CLEANUP: + return NULL; +} + +const char *ILLraw_set_binaryBound ( + rawlpdata * lp, + int i) +{ + ILL_FAILtrue_no_rval (i >= lp->ncols, "proper colind"); + if (lp->lbind[i] || lp->ubind[i]) + { + return "Using previous bound definition."; + } + EGlpNumZero (lp->lower[i]); + EGlpNumOne (lp->upper[i]); + lp->lbind[i] = 1; + lp->ubind[i] = 1; +CLEANUP: + return NULL; +} + +int ILLraw_fill_in_bounds ( + rawlpdata * lp) +{ + int rval = 0, i; + + if (lp->lbind == NULL) + { + ILLraw_init_bounds (lp); + } + ILL_FAILtrue (lp->upper == NULL, "must all be there now"); + ILL_FAILtrue (lp->lower == NULL, "must all be there now"); + ILL_FAILtrue (lp->lbind == NULL, "must all be there now"); + ILL_FAILtrue (lp->ubind == NULL, "must all be there now"); + for (i = 0; i < lp->ncols; i++) + { + if (!lp->lbind[i]) + { + if (lp->ubind[i] && EGlpNumIsLessZero (lp->upper[i])) + { + EGlpNumCopy (lp->lower[i], ILL_MINDOUBLE); + } + } + if (!lp->ubind[i]) + { + /* int vars without bounds are binary */ + /* all, also int vars */ + /* with explicit lower bound 0.0 are in [0.0,+inf] */ + if (((lp->intmarker != NULL) && lp->intmarker[i]) && !lp->lbind[i]) + { + EGlpNumOne (lp->upper[i]); + } + else + { + EGlpNumCopy (lp->upper[i], ILL_MAXDOUBLE); + } + } + } + +CLEANUP: + if (rval) + { + EGlpNumFreeArray (lp->lower); + EGlpNumFreeArray (lp->upper); + } + ILL_RETURN (rval, "ILLraw_fill_in_bounds"); +} + +static int ILLraw_check_bounds ( + rawlpdata * lp) +{ + int rval = 0, i; + + ILL_FAILtrue (lp->upper == NULL, "must all be there now"); + ILL_FAILtrue (lp->lower == NULL, "must all be there now"); + ILL_FAILtrue (lp->lbind == NULL, "must all be there now"); + ILL_FAILtrue (lp->ubind == NULL, "must all be there now"); + for (i = 0; i < lp->ncols; i++) + { + if (EGlpNumIsLess (lp->upper[i], lp->lower[i])) + { + rval += ILLdata_error (lp->error_collector, + "Lower bound is bigger than %s \"%s\".\n", + "upper bound for", ILLraw_colname (lp, i)); + } + } + ILL_RESULT (rval, "ILLraw_check_bounds"); +CLEANUP: + ILL_RETURN (rval, "ILLraw_check_bounds"); +} + +int ILLraw_first_nondefault_bound ( + ILLlpdata * lp) +{ + int ri = lp->nstruct, i; + + ILL_FAILtrue_no_rval (lp->lower == NULL || lp->upper == NULL, + "Should not call write_bounds when lower or upper are NULL"); + for (ri = 0; ri < lp->nstruct; ri++) + { + i = lp->structmap[ri]; + if (!ILLraw_default_lower (lp, i) || !ILLraw_default_upper (lp, i, ri)) + break; + } +CLEANUP: + return ri; +} + +int ILLraw_default_lower ( + ILLlpdata * lp, + int i) +{ + ILL_FAILtrue_no_rval (lp->lower == NULL || lp->upper == NULL, + "Should not call write_bounds when lower or upper are NULL"); + ILL_FAILfalse_no_rval (lp->ncols > i, "i is not col index"); + if (!EGlpNumIsNeqqZero (lp->lower[i]) && + !EGlpNumIsLessZero (lp->upper[i])) + { + return 1; + } + if (EGlpNumIsEqqual (lp->lower[i], ILL_MINDOUBLE) && + EGlpNumIsLessZero (lp->upper[i])) + { + return 1; + } +CLEANUP: + return 0; +} + +int ILLraw_default_upper ( + ILLlpdata * lp, + int i, + int ri) +{ + int isInt; + + ILL_FAILtrue_no_rval (lp->lower == NULL || lp->upper == NULL, + "Should not call write_bounds when lower or upper are NULL"); + ILL_FAILfalse_no_rval (lp->ncols >= i, "i is not col index"); + isInt = (lp->intmarker != NULL) && lp->intmarker[ri]; + if (isInt) + { + if (!EGlpNumIsNeqqZero (lp->lower[i])) + { + return (EGlpNumIsEqqual (lp->upper[i], oneLpNum)); + } + } + + if (EGlpNumIsEqqual (lp->upper[i], ILL_MAXDOUBLE)) + { + return 1; + } +CLEANUP: + return 0; +} + +int ILLraw_fill_in_rownames ( + rawlpdata * lp) +{ + int i, rval = 0; + char uname2[ILL_namebufsize]; + ILLsymboltab *rowtab; + char first = 1; + + rowtab = &lp->rowtab; + ILL_FAILtrue (lp->nrows != rowtab->tablesize, "must have same #entries"); + for (i = 0; (rval == 0) && i < lp->nrows; i++) + { + if (ILLsymboltab_get (rowtab, i) == NULL) + { + if (first) + { + ILLdata_warn (lp->error_collector, + "Generating names for unnamed rows."); + first = 0; + } + + ILLsymboltab_unique_name (rowtab, i, "c", uname2); + rval = ILLsymboltab_rename (rowtab, i, uname2); + ILL_CLEANUP_IF (rval); + } + } +CLEANUP: + ILL_RESULT (rval, "ILLraw_fill_in_rownames"); +} + +static int whichColsAreUsed ( + rawlpdata * raw, + ILLlpdata * lp, + int *colindex) +{ + int rval = 0; + int i, objind = raw->objindex; + colptr *cp; + char *colUsed = NULL; + + /* colUsed[i] variable raw->colnames[i] is used in obj fct + * and/or equation(s) */ + ILL_SAFE_MALLOC (colUsed, raw->ncols, char); + + for (i = 0; i < raw->ncols; i++) + { + colUsed[i] = 0; + } + for (i = 0; i < raw->ncols; i++) + { + for (cp = raw->cols[i]; cp; cp = cp->next) + { + if ((cp->this_val == objind) || (raw->rowsense[cp->this_val] != 'N')) + { + colUsed[i] = 1; + break; + } + } + } + + /* colindex[i] = -1 for undefined, 0, 1, ... lp->ncol-1 + * lp->ncols <= raw->ncols */ + for (i = 0; i < raw->ncols; i++) + { + if (colUsed[i]) + { + colindex[i] = lp->ncols++; + } + else + { + colindex[i] = -1; + ILLdata_warn (raw->error_collector, + "\"%s\" is used in non objective 'N' rows only.", + ILLraw_colname (raw, i)); + } + } + if (lp->ncols < 1) + { + rval = ILLdata_error (raw->error_collector, "There are no variables."); + ILL_CLEANUP_IF (rval); + } +CLEANUP: + ILL_IFFREE (colUsed, char); + + ILL_RESULT (rval, "whichColsAreUsed"); +} + +static int whichRowsAreUsed ( + rawlpdata * raw, + ILLlpdata * lp, + int *rowindex) +{ + int i, rval = 0; + + /* only use non 'N' rows */ + for (i = 0; i < raw->nrows; i++) + { + if (raw->rowsense[i] != 'N') + { + rowindex[i] = lp->nrows++; + } + else + { + rowindex[i] = -1; + } + } + if (lp->nrows == 0) + { + rval = ILLdata_error (raw->error_collector, "There are no constraints."); + } + ILL_RESULT (rval, "whichRowsAreUsed"); +} + + +static int transferObjective ( + rawlpdata * raw, + ILLlpdata * lp, + int *colindex) +{ + int rval = 0, i, ci, objind = raw->objindex; + colptr *cp; + int *coefWarn = NULL; + + /* transfer objective fct */ + lp->obj = EGlpNumAllocArray (lp->ncols); + ILL_SAFE_MALLOC (coefWarn, lp->ncols, int); + + for (i = 0; i < lp->ncols; i++) + { + EGlpNumZero (lp->obj[i]); + coefWarn[i] = 0; + } + for (i = 0; i < raw->ncols; i++) + { + for (cp = raw->cols[i]; cp; cp = cp->next) + { + if (cp->this_val == objind) + { + ci = colindex[i]; + TESTG ((rval = + (ci < 0 + || ci >= lp->ncols)), CLEANUP, "ci %d is out of range [0,%d[", + ci, lp->ncols); + ILL_FAILfalse (ci != -1, + "all vars in obj fct should be marked as useful"); + coefWarn[ci]++; + if (EGlpNumIsNeqqZero (cp->coef)) + EGlpNumAddTo (lp->obj[ci], cp->coef); + if (coefWarn[ci] == 2) + { + ILLdata_warn (raw->error_collector, + "Multiple coefficients for \"%s\" in %s.", + ILLraw_colname (raw, i), "objective function"); + } + } + } + } +CLEANUP: + ILL_IFFREE (coefWarn, int); + + ILL_RETURN (rval, "transferObjective"); +} + +static int transferColNamesLowerUpperIntMarker ( + rawlpdata * raw, + ILLlpdata * lp, + int *colindex) +{ + int i, ci, ind, pre, rval = 0; + int hasIntVar; + ILL_SAFE_MALLOC (lp->colnames, lp->ncols, char *); + + if (raw->upper) + lp->upper = EGlpNumAllocArray (lp->ncols); + if (raw->lower) + lp->lower = EGlpNumAllocArray (lp->ncols); + ILL_SAFE_MALLOC (lp->intmarker, lp->ncols, char); + + hasIntVar = 0; + for (i = 0; i < raw->ncols; i++) + { + ci = colindex[i]; + if (ci != -1) + { + ILL_FAILfalse ((ci >= 0) && (ci < lp->ncols), "colindex problem"); + ILL_UTIL_STR (lp->colnames[ci], ILLraw_colname (raw, i)); + rval = ILLsymboltab_register (&lp->coltab, + lp->colnames[ci], -1, &ind, &pre); + ILL_FAILfalse ((rval == 0) && (ind == ci) && (pre == 0), + "should have new entry"); + if (raw->upper) + { + EGlpNumCopy (lp->upper[ci], raw->upper[i]); + } + if (raw->lower) + { + EGlpNumCopy (lp->lower[ci], raw->lower[i]); + } + lp->intmarker[ci] = raw->intmarker[i]; + hasIntVar = hasIntVar || lp->intmarker[ci]; + ILL_IFDOTRACE + { + if (lp->lower) + { + ILLprt_EGlpNum (stdout, &(lp->lower[ci])); + ILL_IFTRACE (" <= "); + } + ILL_IFTRACE ("%s", lp->colnames[ci]); + if (lp->upper) + { + ILL_IFTRACE (" <= "); + ILLprt_EGlpNum (stdout, &(lp->upper[ci])); + } + if (lp->intmarker[ci]) + { + ILL_IFTRACE (" INTEGER "); + } + ILL_IFTRACE ("\n"); + } + } + } + if (!hasIntVar) + { + ILL_IFFREE (lp->intmarker, char); + } +CLEANUP: + ILL_RETURN (rval, "transferColNamesLowerUpperIntMarker"); +} + +static void safeRegister ( + ILLsymboltab * tab, + const char *name, + int i) +{ + int ind, pre, rval; + + rval = ILLsymboltab_register (tab, name, -1, &ind, &pre); + ILL_FAILfalse ((rval == 0) && (ind == i) && (pre == 0), + "Pgming Error: should have new entry"); +CLEANUP: + return; +} + +static int transferSenseRhsRowNames ( + rawlpdata * raw, + ILLlpdata * lp, + int *rowindex) +{ + int i, ri, rval = 0; + int objind = raw->objindex; + + /* transfer sense/rhs/rownames */ + if (lp->nrows > 0) + { + ILL_SAFE_MALLOC (lp->sense, lp->nrows, char); + + lp->rhs = EGlpNumAllocArray (lp->nrows); + ILL_SAFE_MALLOC (lp->rownames, lp->nrows, char *); + + ILL_FAILfalse (ILLraw_rowname (raw, raw->objindex), "NULL objname"); + safeRegister (&lp->rowtab, ILLraw_rowname (raw, raw->objindex), 0); + + ri = 0; + for (i = 0; i < raw->nrows; i++) + { + ri = rowindex[i]; + if (i == raw->refrowind) + { + ILL_UTIL_STR (lp->refrowname, ILLraw_rowname (raw, i)); + lp->refind = ri; + } + if (raw->rowsense[i] != 'N') + { + ILL_FAILfalse (ILLraw_rowname (raw, i) != NULL, + "all rownames should be non NULL"); + ILL_UTIL_STR (lp->rownames[ri], ILLraw_rowname (raw, i)); + safeRegister (&lp->rowtab, lp->rownames[ri], ri + 1); + lp->sense[ri] = raw->rowsense[i]; + EGlpNumCopy (lp->rhs[ri], raw->rhs[i]); + } + else if (i == objind) + { + ILL_FAILfalse (lp->objname == NULL, "objname == NULL"); + ILL_UTIL_STR (lp->objname, ILLraw_rowname (raw, i)); + } + else + { + /* unused 'N' row */ + } + } + ILL_FAILfalse ((lp->nrows + 1) == lp->rowtab.tablesize, + "problem with rowtab structure"); + } +CLEANUP: + ILL_RETURN (rval, "transferSenseRhsRowNames"); +} + +static int buildMatrix ( + rawlpdata * raw, + ILLlpdata * lp, + int *rowindex, + int *colindex) +{ + int i, ri, ci, k, nempty = 0, rval = 0; + int *nRowsUsed = 0; + int *coefSet = 0; + int *coefWarn = 0; + ILLmatrix *A = &lp->A; + colptr *cp = NULL; + + /* put subjective fcts into matrix */ + ILL_SAFE_MALLOC (A->matcnt, lp->ncols, int); + ILL_SAFE_MALLOC (A->matbeg, lp->ncols, int); + ILL_SAFE_MALLOC (nRowsUsed, lp->nrows, int); + + ILL_SAFE_MALLOC (coefWarn, lp->ncols, int); + + for (i = 0; i < lp->ncols; i++) + { + coefWarn[i] = 0; + } + for (i = 0; i < lp->nrows; i++) + { + nRowsUsed[i] = -1; + } + for (i = 0; i < raw->ncols; i++) + { + ci = colindex[i]; + if (ci == -1) + continue; + k = 0; + for (cp = raw->cols[i]; cp; cp = cp->next) + { + ri = rowindex[cp->this_val]; + if (ri >= 0) + { + if (nRowsUsed[ri] != i) + { + nRowsUsed[ri] = i; + k++; + } + else + { + if (!coefWarn[ci]) + { + ILLdata_warn (raw->error_collector, + "Multiple coefficients for \"%s\" %s.", + lp->colnames[i], "in a row"); + coefWarn[ci] = 1; + } + } + } + } + A->matcnt[ci] = k; + A->matbeg[ci] = lp->nzcount + nempty; /* mark empty cols */ + lp->nzcount += k; + if (k == 0) + nempty++; + } + + A->matrows = lp->nrows; + A->matcols = lp->ncols; + A->matcolsize = lp->ncols; + A->matsize = lp->nzcount + nempty + 1; + A->matfree = 1; + ILL_SAFE_MALLOC (A->matind, A->matsize, int); + + A->matval = EGlpNumAllocArray (A->matsize); + ILL_SAFE_MALLOC (coefSet, lp->nrows, int); + + for (k = 0; k < lp->nrows; k++) + { + coefSet[k] = -1; + } + + for (i = 0; i < raw->ncols; i++) + { + ci = colindex[i]; + if (ci == -1) + continue; /* unused variable */ + k = A->matbeg[ci]; + if (A->matcnt[ci] == 0) + { + A->matind[k] = 1; /* Used in addcols and addrows */ + } + else + { + for (cp = raw->cols[i]; cp; cp = cp->next) + { + ri = rowindex[cp->this_val]; + if (ri >= 0) + { + if (coefSet[ri] == -1) + { + A->matind[k] = ri; + EGlpNumCopy (A->matval[k], cp->coef); + coefSet[ri] = k; + k++; + } + else + { + EGlpNumAddTo (A->matval[coefSet[ri]], cp->coef); + } + } + } + if (k != A->matbeg[ci] + A->matcnt[ci]) + { + ILL_ERROR (rval, "problem with matrix"); + } + for (k--; k >= A->matbeg[ci]; k--) + { + coefSet[A->matind[k]] = -1; + } + } + } + A->matind[lp->nzcount + nempty] = -1; +CLEANUP: + ILL_IFFREE (nRowsUsed, int); + ILL_IFFREE (coefWarn, int); + ILL_IFFREE (coefSet, int); + + ILL_RETURN (rval, "buildMatrix"); +} + +static int transferRanges ( + rawlpdata * raw, + ILLlpdata * lp, + int *rowindex) +{ + int i, ri, rval = 0; + colptr *cp; + + /*****************************************************/ + /* */ + /* Interpretation of RANGE values in MPS files */ + /* */ + /* G rhs <= row <= rhs + |range| */ + /* L rhs - |range| <= row <= rhs */ + /* E + rhs <= row <= rhs + range */ + /* E - rhs + range <= row <= rhs */ + /* */ + /* - where + and - refer to the sign of range */ + /* and the letters refer to sense of the row. */ + /* */ + /* We will store ranged rows as */ + /* */ + /* rhs <= row <= rhs + range */ + /* */ + /*****************************************************/ + + + lp->rangeval = EGlpNumAllocArray (lp->nrows); + for (i = 0; i < lp->nrows; i++) + { + EGlpNumZero (lp->rangeval[i]); + } + for (cp = raw->ranges; cp; cp = cp->next) + { + i = cp->this_val; + ri = rowindex[cp->this_val]; + switch (raw->rowsense[i]) + { + case 'N': + ILLdata_error (raw->error_collector, "No range for N-row.\n"); + rval = 1; + goto CLEANUP; + case 'G': + lp->sense[ri] = 'R'; + EGlpNumCopyAbs (lp->rangeval[ri], cp->coef); + break; + case 'L': + lp->sense[ri] = 'R'; + EGlpNumCopyAbs (lp->rangeval[ri], cp->coef); + EGlpNumSubTo (lp->rhs[ri], lp->rangeval[ri]); + break; + case 'E': + lp->sense[ri] = 'R'; + if (!EGlpNumIsLessZero (cp->coef)) + { + EGlpNumCopy (lp->rangeval[ri], cp->coef); + } + else + { + EGlpNumAddTo (lp->rhs[ri], cp->coef); + EGlpNumCopyNeg (lp->rangeval[ri], cp->coef); + } + break; + } + } +CLEANUP: + ILL_RETURN (rval, "transferRanges"); +} + +static int initStructmap ( + ILLlpdata * lp) +{ + int i, rval = 0; + + /* all vars are structural */ + ILL_SAFE_MALLOC (lp->structmap, lp->nstruct, int); + + for (i = 0; i < lp->nstruct; i++) + { + lp->structmap[i] = i; + } + +CLEANUP: + ILL_RETURN (rval, "initStructmap"); +} + +static int buildSosInfo ( + rawlpdata * raw, + ILLlpdata * lp, + int *colindex) +{ + int i, ci, set, rval = 0; + int nSosMem, nSetMem; + + /* build sos info */ + /* see comment in lpdata.h about ILLlpdata's sos and is_sos_mem + * fields and section of ILLprint_rawlpdata that prints SOS sets */ + + ILL_SAFE_MALLOC (lp->is_sos_mem, lp->ncols, int); + + nSosMem = 0; + for (i = 0; i < raw->ncols; i++) + { + ci = colindex[i]; + if (ci != -1) + { + lp->is_sos_mem[ci] = raw->is_sos_member[i]; + if (raw->is_sos_member[i] != -1) + nSosMem++; + } + } + if (nSosMem > 0) + { + lp->sos.matsize = nSosMem; + lp->sos.matcols = raw->nsos; + lp->sos.matcolsize = raw->nsos; + lp->sos.matrows = lp->ncols; + lp->sos.matfree = 0; + lp->sos.matval = EGlpNumAllocArray (nSosMem); + ILL_SAFE_MALLOC (lp->sos.matind, nSosMem, int); + ILL_SAFE_MALLOC (lp->sos.matbeg, raw->nsos, int); + ILL_SAFE_MALLOC (lp->sos.matcnt, raw->nsos, int); + ILL_SAFE_MALLOC (lp->sos_type, raw->nsos, char); + + nSosMem = 0; + for (set = 0; set < raw->nsos; set++) + { + lp->sos_type[set] = raw->sos_set[set].type; + lp->sos.matbeg[set] = nSosMem; + nSetMem = 0; + for (i = raw->sos_set[set].first; + i < raw->sos_set[set].first + raw->sos_set[set].nelem; i++) + { + ci = colindex[raw->sos_col[i]]; + if (ci != -1) + { + lp->sos.matind[nSosMem + nSetMem] = ci; + EGlpNumCopy (lp->sos.matval[nSosMem + nSetMem], raw->sos_weight[i]); + nSetMem++; + } + } + lp->sos.matcnt[set] = nSetMem; + nSosMem += nSetMem; + } + } +CLEANUP: + ILL_RETURN (rval, "buildSosInfo"); +} + +static int convert_rawlpdata_to_lpdata ( + rawlpdata * raw, + ILLlpdata * lp) +/* + * only raw's non 'N' rows are converted to matrix entries in lp + * columns that are used in non objective 'N' rows only are not + * converted. That is they don't end up in lp's matrix, row/colnames, + * upper/lower bounds or SOS information. + */ +{ + int rval = 0; + int *rowindex = 0; + int *colindex = 0; + + ILL_FAILfalse ((raw && lp), "rawlpdata_to_lpdata called without input"); + if (raw->name == NULL) + { + ILLdata_warn (raw->error_collector, "Setting problem name to \"unnamed\"."); + ILL_UTIL_STR (raw->name, "unnamed"); + } + rval = ILLcheck_rawlpdata (raw); + ILL_CLEANUP_IF (rval); + + ILL_FAILfalse (raw->objindex != -1, "rawlpdata must have objective fct."); + ILLlpdata_init (lp); + + ILL_IFFREE (lp->probname, char); + + lp->probname = raw->name; + raw->name = 0; + + /* MINIMIZE or MAXIMIZE ? */ + lp->objsense = raw->objsense; + if (lp->objsense != ILL_MIN && lp->objsense != ILL_MAX) + { + ILLdata_error (raw->error_collector, "Bad objsense.\n"); + rval = 1; + goto CLEANUP; + } + + ILL_SAFE_MALLOC (colindex, raw->ncols, int); + ILL_SAFE_MALLOC (rowindex, raw->nrows, int); + + rval = whichColsAreUsed (raw, lp, colindex) || + whichRowsAreUsed (raw, lp, rowindex); + ILL_CLEANUP_IF (rval); + ILL_FAILtrue (lp->ncols == 0 || lp->nrows == 0, "we need rows and cols"); + + /* array sizes */ + lp->rowsize = lp->nrows; + lp->colsize = lp->ncols; + lp->nstruct = lp->ncols; + lp->structsize = lp->ncols; + ILLsymboltab_create (&lp->rowtab, lp->nrows); + ILLsymboltab_create (&lp->coltab, lp->ncols); + + rval = transferObjective (raw, lp, colindex); + rval = rval || transferColNamesLowerUpperIntMarker (raw, lp, colindex); + rval = rval || buildMatrix (raw, lp, rowindex, colindex); + rval = rval || buildSosInfo (raw, lp, colindex); + ILL_CLEANUP_IF (rval); + ILL_IFDOTRACE + { + EGioFile_t*lout = EGioOpenFILE(stdout); + ILLmatrix_prt (lout, &lp->A); + EGioClose(lout); + } + + rval = transferSenseRhsRowNames (raw, lp, rowindex); + if ((lp->nrows > 0) && raw->ranges) + { + rval = rval || transferRanges (raw, lp, rowindex); + } + ILL_CLEANUP_IF (rval); + + rval = initStructmap (lp); + ILL_CLEANUP_IF (rval); + +CLEANUP: + + ILL_IFFREE (rowindex, int); + ILL_IFFREE (colindex, int); + + ILLfree_rawlpdata (raw); + + ILL_RESULT (rval, "convert_rawlpdata_to_lpdata"); +} + +int ILLrawlpdata_to_lpdata ( + rawlpdata * raw, + ILLlpdata * lp) +{ + int rval = 0; + + ILL_IFDOTRACE + { + printf ("%s\n", __func__); + ILLprint_rawlpdata (raw); + } + rval = convert_rawlpdata_to_lpdata (raw, lp); + if (rval == 0) + { + rval = ILLlp_add_logicals (lp); + } + ILL_RESULT (rval, "ILLrawlpdata_to_lpdata"); +} + +static int set_field_name ( + char **field, + const char *name, + int *skip) +{ + int rval = 0; + + /* name is bounds/rhs/rangesname field from rawlpdata */ + *skip = 0; + if (!*field) + { + ILL_UTIL_STR (*field, name); + } + + if (strcmp (*field, name)) + { + /* not first specified RHS/BOUNDS - skip it */ + *skip = 1; + } +CLEANUP: + ILL_RETURN (rval, "set_field_name"); +} + +int ILLraw_set_rhs_name ( + rawlpdata * lp, + const char *name, + int *skip) +{ + return set_field_name (&lp->rhsname, name, skip); +} + +int ILLraw_set_bounds_name ( + rawlpdata * lp, + const char *name, + int *skip) +{ + return set_field_name (&lp->boundsname, name, skip); +} + +int ILLraw_set_ranges_name ( + rawlpdata * lp, + const char *name, + int *skip) +{ + return set_field_name (&lp->rangesname, name, skip); +} + +void ILLprint_rawlpdata ( + rawlpdata * lp) +{ + int i, cnt, si, m; + char c; + EGlpNum_t d; + colptr *cp; + sosptr *set; + + EGlpNumInitVar (d); + + if (lp) + { + if (lp->name) + { + printf ("PROBLEM %s\n", lp->name); + fflush (stdout); + } + if (lp->rowsense && lp->rhs) + { + printf ("Subject To\n"); + for (i = 0; i < lp->nrows; i++) + { + switch (lp->rowsense[i]) + { + case 'E': + c = '='; + break; + case 'L': + c = '<'; + break; + case 'G': + c = '>'; + break; + default: + c = '?'; + break; + } + printf ("%s: %c %f\n", ILLraw_rowname (lp, i), c, + EGlpNumToLf (lp->rhs[i])); + } + printf ("\n"); + fflush (stdout); + } + if (lp->ncols > 0) + { + printf ("Columns\n"); + for (i = 0; i < lp->ncols; i++) + { + for (cp = lp->cols[i]; cp; cp = cp->next) + { + printf ("%s: ", ILLraw_rowname (lp, cp->this_val)); + printf ("%c ", (EGlpNumIsLessZero (cp->coef)) ? '-' : '+'); + EGlpNumCopyAbs (d, cp->coef); + if (EGlpNumIsNeqq (d, oneLpNum)) + { + printf (" %f ", EGlpNumToLf (d)); + } + printf ("%s\n", ILLraw_colname (lp, i)); + } + printf ("\n"); + fflush (stdout); + } + } + if (lp->rangesname) + { + printf ("RANGES %s\n", lp->rangesname); + for (cp = lp->ranges; cp; cp = cp->next) + { + printf ("(%s, %f) ", ILLraw_rowname (lp, cp->this_val), + EGlpNumToLf (cp->coef)); + } + printf ("\n"); + fflush (stdout); + } + if (lp->boundsname) + { + printf ("BOUNDS %s\n", lp->boundsname); + fflush (stdout); + } + else + { + printf ("BOUNDS \n"); + fflush (stdout); + } + if (lp->lower && lp->upper) + { + for (i = 0; i < lp->ncols; i++) + { + ILLprt_EGlpNum (stdout, &(lp->lower[i])); + printf (" <= %s <= ", ILLraw_colname (lp, i)); + ILLprt_EGlpNum (stdout, &(lp->upper[i])); + printf ("\n"); + } + } + if (lp->intmarker) + { + printf ("Integer\n"); + cnt = 0; + for (i = 0; i < lp->ncols; i++) + { + if (lp->intmarker[i]) + { + printf ("%s", ILLraw_colname (lp, i)); + cnt++; + if (cnt == 8) + { + printf ("\n "); + cnt = 0; + } + } + } + printf ("\n"); + fflush (stdout); + } + printf ("SOS-SETS\n"); + for (si = 0; si < lp->nsos; si++) + { + set = lp->sos_set + si; + printf ("SOS-SET %d: %s; nelem=%d; first=%d;\n", + si, ((set->type == ILL_SOS_TYPE1) ? "TYPE1" : "TYPE2"), + set->nelem, set->first); + printf ("\t"); + for (m = set->first; m < set->first + set->nelem; m++) + { + printf (" %s %f; ", ILLraw_colname (lp, lp->sos_col[m]), + EGlpNumToLf (lp->sos_weight[m])); + } + printf ("\n"); + } + printf ("\n"); + fflush (stdout); + } + EGlpNumClearVar (d); +} + +static int ILLmsg ( + qserror_collector * collector, + int isError, + const char *format, + va_list args) +{ + const char *pre; + int slen, errtype; + qsformat_error error; + char error_desc[256]; + + vsprintf (error_desc, format, args); + slen = strlen (error_desc); + if ((slen > 0) && error_desc[slen - 1] != '\n') + { + error_desc[slen] = '\n'; + error_desc[slen + 1] = '\0'; + } + + if (collector != NULL) + { + errtype = (isError) ? QS_DATA_ERROR : QS_DATA_WARN; + ILLformat_error_create (&error, errtype, error_desc, -1, NULL, -1); + ILLformat_error (collector, &error); + ILLformat_error_delete (&error); + } + else + { + pre = (isError) ? "Data Error" : "Data Warning"; + fprintf (stderr, "%s: %s", pre, error_desc); + } + return 1; +} + +int ILLdata_error ( + qserror_collector * collector, + const char *format, + ...) +{ + va_list args; + + va_start (args, format); + return ILLmsg (collector, TRUE, format, args); +} + +void ILLdata_warn ( + qserror_collector * collector, + const char *format, + ...) +{ + va_list args; + + va_start (args, format); + (void) ILLmsg (collector, FALSE, format, args); +} + +colptr *ILLcolptralloc ( + ILLptrworld * p) +{ + colptr *sol = colptralloc (p); + + EGlpNumInitVar ((sol->coef)); + return sol; +} diff --git a/src/rawlp.h b/src/rawlp.h new file mode 100644 index 0000000..097c659 --- /dev/null +++ b/src/rawlp.h @@ -0,0 +1,256 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: rawlp.h,v $ $Revision: 1.3 $ $Date: 2003/11/05 16:57:39 $"; */ +#ifndef __ILL_RAWLP_H_ +#define __ILL_RAWLP_H_ + +/****************************************************************************/ +/* DataStructure and Routines */ +/* to deal with raw lp information as read from mps or lp files */ +/* support scanning of input */ +/* error reporting */ +/****************************************************************************/ + +#include "trace.h" +#include "lpdata.h" +#include "iqsutil.h" +#include "format.h" +#include "lpdefs.h" + +#define ILL_ISBLANK(p) \ + (((*(p))==' '||(*(p))=='\t'||(*(p))=='\r'||(*(p))=='\f') ? 1 : 0) + +/* + * we rely on ILLsymboltab property: + * the ith name added can be retrieved by ILLsymboltab_get(table, i) + * as long as we never delete names from the symbol table + */ +typedef struct rawlpdata +{ + char *name; + + char *rhsname; + char *rangesname; + char *boundsname; + + int objsense; /* maximize or minimize */ + int objindex; /* index of objective row */ + + int nrows; /* number of rows in problem */ + ILLsymboltab rowtab; /* ILLsymboltab_get(rowtab, i) name of ith row */ + + int sensesize; /* size of rowsense */ + char *rowsense; /* rowsense[i] snese of row[i] */ + + char *rhsind; /* rhsind[i] == 1 we saw an rhs for row[i] */ + /* size is nrows */ + int rhssize; /* size of rhs array */ + EGlpNum_t *rhs; /* rhs values for rows; size is nrows */ + char *rangesind; /* ranges[i] == 1 we saw a range def for row[i] */ + struct colptr *ranges; /* list of range values */ + + int ncols; /* number of cols in problem */ + ILLsymboltab coltab; /* ILLsymboltab_get(coltab, i) name of ith col */ + int colsize; /* size of cols array */ + struct colptr **cols; + + char *lbind; /* lbind[i] == 1 we saw a lower bound for col[i] */ + char *ubind; /* ubind[i] == 1 we saw a upper bound for col[i] */ + EGlpNum_t *lower; /* lower[i] = lower bound for col[i] */ + EGlpNum_t *upper; /* upper[i] = upper bound for col[i] */ + + int intsize; /* size of intmarker array */ + char *intmarker; /* intmarker[i] == 1 col[i] is an int var */ + + /* sos information is tranfered into ILLmatrix lpdata->sos */ + char *refrow; /* name of reference row */ + int refrowind; /* index of refrow or -1 */ + + int is_sos_size; /* size of is_sos_member array */ + int *is_sos_member; /* for each col contains either + * -1 == no sos memeber + * i == member of set #i */ + + int nsos_member; /* total number of sos set members */ + int sos_weight_size; /* size of sos_weight array */ + EGlpNum_t *sos_weight; /* sos set elem i has weight of sos_weight[i] + * value comes from refrow coeficients */ + int sos_col_size; /* size of sos_col array */ + int *sos_col; /* sos elem i is column sos_col[i] */ + + int nsos; /* number of sos sets */ + int sos_setsize; /* size of sosset array */ + struct sosptr *sos_set; /* type, size, first element of sos sets + * first is index into sos_weight and sos_col + * arrays */ + qserror_collector *error_collector; + ILLptrworld ptrworld; +} +rawlpdata; + +typedef struct colptr +{ + EGlpNum_t coef; + struct colptr *next; + int this_val; /* row index */ +} +colptr; +extern colptr *ILLcolptralloc ( + ILLptrworld * p); + +typedef struct sosptr +{ + int nelem; /* number of set elements */ + int first; /* index of first set element in sosmemeber */ + char type; /* set type */ +} +sosptr; +extern const int ILL_SOS_TYPE1; +extern const int ILL_SOS_TYPE2; + +extern void ILLinit_rawlpdata ( + rawlpdata * lp, + qserror_collector * collector); +extern void ILLfree_rawlpdata ( + rawlpdata * lp); +extern void ILLraw_clear_matrix ( + rawlpdata * lp); + +extern const char *ILLraw_rowname ( + rawlpdata * lp, + int i); +extern const char *ILLraw_colname ( + rawlpdata * lp, + int i); + +extern int ILLraw_add_col ( + rawlpdata * lp, + const char *name, + int intmarker); +extern int ILLraw_add_row ( + rawlpdata * lp, + const char *name, + int sense, + const EGlpNum_t rhs); + +extern int ILLraw_add_col_coef ( + rawlpdata * lp, + int colind, + int rowind, + EGlpNum_t coef); + +extern int ILLraw_init_ranges ( + rawlpdata * lp); +extern int ILLraw_init_rhs ( + rawlpdata * lp); + +extern int ILLraw_add_ranges_coef ( + rawlpdata * lp, + int rowind, + EGlpNum_t coef); + + +extern int ILLraw_add_sos ( + rawlpdata * lp, + int sos_type); + + /* add empty set with type */ +extern int ILLraw_add_sos_member ( + rawlpdata * lp, + int colind); + + /* add col to last set */ +extern int ILLraw_is_mem_other_sos ( + rawlpdata * lp, + int colind); + +extern int ILLraw_set_rhs_name ( + rawlpdata * lp, + const char *name, + int *skip); +extern int ILLraw_set_bounds_name ( + rawlpdata * lp, + const char *name, + int *skip); +extern int ILLraw_set_ranges_name ( + rawlpdata * lp, + const char *name, + int *skip); +extern void ILLprint_rawlpdata ( + rawlpdata * lp); + +extern char *ILLraw_unique_name ( + ILLsymboltab * tab, + char *prefix, + int i); +extern int ILLraw_fill_in_rownames ( + rawlpdata * lp); + +extern int ILLraw_init_bounds ( + rawlpdata * lp); + +extern const char *ILLraw_set_lowerBound ( + rawlpdata * lp, + int i, + EGlpNum_t bnd); +extern const char *ILLraw_set_upperBound ( + rawlpdata * lp, + int i, + EGlpNum_t bnd); +extern const char *ILLraw_set_fixedBound ( + rawlpdata * lp, + int i, + EGlpNum_t bnd); +extern const char *ILLraw_set_binaryBound ( + rawlpdata * lp, + int i); +extern const char *ILLraw_set_unbound ( + rawlpdata * lp, + int colind); +extern int ILLraw_fill_in_bounds ( + rawlpdata * lp); + +extern int ILLraw_first_nondefault_bound ( + ILLlpdata * lp); +extern int ILLraw_default_lower ( + ILLlpdata * lp, + int i); +extern int ILLraw_default_upper ( + ILLlpdata * lp, + int i, + int ri); + +extern int ILLrawlpdata_to_lpdata ( + rawlpdata * raw, + ILLlpdata * lp); + +extern int ILLdata_error ( + qserror_collector * collector, + const char *format, + ...); +extern void ILLdata_warn ( + qserror_collector * collector, + const char *format, + ...); + +#endif diff --git a/src/read_lp.c b/src/read_lp.c new file mode 100644 index 0000000..de79d3a --- /dev/null +++ b/src/read_lp.c @@ -0,0 +1,826 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: read_lp_state.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +/****************************************************************************/ +/* */ +/* Routines to support Reading LP Files */ +/* */ +/****************************************************************************/ + +/* + * -) anything after '\' is comment + * -) variables consist of a-z A-Z 0-9!"#$%(),;.?@_`'{}|~ + * don't start with a digit or '.' + */ + +#include "qs_config.h" +#include "iqsutil.h" +#include "read_lp.h" +#include "lp.h" +#include "rawlp.h" +#include "lpdefs.h" +#include "format.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif +static int TRACE = 0; + +#define END_LINE(p) (((*p) == '\\' || (*p) == '\n' || (*p) == '\0') ? 1 : 0) + +static const char *all_keyword[] = { + "MIN", "MINIMUM", "MINIMIZE", + "MAX", "MAXIMUM", "MAXIMIZE", + "SUBJECT", "ST", "PROBLEM", "PROB", + "BOUNDS", "BOUND", "INTEGER", "END", NULL +}; +static int all_keyword_len[] = { + 3, 7, 8, + 3, 7, 8, + 7, 2, 7, 4, + 6, 5, 7, 3, -1 +}; + +int ILLread_lp_state_init ( + ILLread_lp_state * state, + qsline_reader * file, + const char *fname, + int inter) +{ + int rval = 0; + + ILL_FAILtrue (file == NULL, "need a file"); + state->eof = 0; + state->file_name = fname; + state->interactive = inter; + state->file = file; + state->line_num = 0; + state->p = state->line; + state->line[0] = '\0'; + state->realline[0] = '\0'; + state->field[0] = '\0'; + state->fieldOnFirstCol = 0; + EGlpNumInitVar (state->bound_val); + ILLread_lp_state_skip_blanks (state, 1); +CLEANUP: + ILL_RETURN (rval, "ILLread_lp_state_init"); +} + +int ILLread_lp_state_next_line ( + ILLread_lp_state * state) +{ + char *slash; + + if (state->eof) + { + return 1; + } + state->line[0] = '\0'; + if (state->interactive) + { + fprintf (stdout, "> "); + fflush (stdout); + } + while (ILLline_reader_get (state->realline, ILL_namebufsize - 2, state->file) + != (char *) NULL) + { + state->p = state->line; + state->line_num++; + strcpy (state->line, state->realline); + slash = strchr (state->line, '\\'); + if (slash != NULL) + { + *slash = '\0'; + } + while (ILL_ISBLANK (state->p)) + { + state->p++; + } + if (!END_LINE (state->p)) + { + ILL_IFTRACE ("NEWLINE %s %d: %s", + state->file_name, state->line_num, state->line); + return 0; + } + if (state->interactive) + { + fprintf (stdout, "> "); + fflush (stdout); + } + } + state->eof = 1; + state->line_num++; + state->field[0] = '\0'; + state->line[0] = '\0'; + strcpy (state->realline, "\n"); + state->p = state->line; + state->fieldOnFirstCol = 0; + return 1; +} + +int ILLread_lp_state_skip_blanks ( + ILLread_lp_state * state, + int wrapLines) +{ + while (1) + { + while (ILL_ISBLANK (state->p)) + { + state->p++; + } + if (END_LINE (state->p)) + { + if (wrapLines) + { + if (ILLread_lp_state_next_line (state) != 0) + { + return 1; + } + } + else + { + return 0; /* done */ + } + } + else + { + return 0; /* foud non blank */ + } + } +} + +static int next_field ( + ILLread_lp_state * state, + int acrossLines) +{ + (void) ILLread_lp_state_skip_blanks (state, (char) acrossLines); + if (state->eof) + { + return 1; + } + state->fieldOnFirstCol = (state->line == state->p); + if (sscanf (state->p, "%s", state->field) != EOF) + { + state->p += strlen (state->field); + return 0; + } + return 1; +} + +int ILLread_lp_state_next_field_on_line ( + ILLread_lp_state * state) +{ + return next_field (state, 0); +} + +int ILLread_lp_state_next_field ( + ILLread_lp_state * state) +{ + return next_field (state, 1); +} + +void ILLread_lp_state_prev_field ( + ILLread_lp_state * state) +{ + if (state->p > state->line) + { + state->p--; + } + while (ILL_ISBLANK (state->p) && (state->p > state->line)) + { + state->p--; + } + while (!ILL_ISBLANK (state->p) && (state->p > state->line)) + { + state->p--; + } + state->fieldOnFirstCol = (state->line == state->p); +} + +int ILLread_lp_state_next_var ( + ILLread_lp_state * state) +{ + char *p; + int var_len, i; + + if (ILLread_lp_state_skip_blanks (state, 1)) + { + return 1; + } + state->fieldOnFirstCol = (state->line == state->p); + var_len = 0; + p = state->p; + while (1) + { + if (ILLis_lp_name_char (*p, var_len)) + { + p++; + var_len++; + } + else + { + break; + } + } + if (var_len == 0) + { + return 1; + } + if (state->fieldOnFirstCol) + { + /* see whether we founbd a reserved keyword */ + for (i = 0; all_keyword[i] != NULL; i++) + { + if ((var_len == all_keyword_len[i]) && + (strncasecmp (all_keyword[i], state->p, (size_t) (all_keyword_len[i])) + == 0)) + { + return -1; /* yes we did */ + } + } + } + strncpy (state->field, state->p, (size_t) var_len); + state->field[var_len] = '\0'; + state->p = p; + return 0; +} + +int ILLread_lp_state_bad_keyword ( + ILLread_lp_state * state) +{ + if (!state->fieldOnFirstCol) + { + return ILLlp_error (state, + "Keyword \"%s\" not at beginning of line.\n", + state->field); + } + return 0; +} + +int ILLtest_lp_state_keyword ( + ILLread_lp_state * state, + const char *kwd[]) +{ + int i = 0; + + if (!state->eof && state->fieldOnFirstCol) + { + for (i = 0; kwd[i] != NULL; i++) + { + if (strcasecmp (state->field, kwd[i]) == 0) + { + return 0; + } + } + } + return 1; +} + +int ILLread_lp_state_keyword ( + ILLread_lp_state * state, + const char *kwd[]) +{ + if (state->eof || ILLread_lp_state_bad_keyword (state)) + { + return 1; + } + return ILLtest_lp_state_keyword (state, kwd); +} + + +int ILLread_lp_state_colon ( + ILLread_lp_state * state) +{ + if ((ILLread_lp_state_skip_blanks (state, 1) == 0) && (*state->p == ':')) + { + state->p++; + return 0; + } + return 1; +} + +int ILLread_lp_state_has_colon ( + ILLread_lp_state * state) +{ + char *pp; + + ILLread_lp_state_skip_blanks (state, 0); + for (pp = state->p; *pp != '\n'; pp++) + { + if (*pp == ':') + { + return 1; + } + } + return 0; +} + +int ILLread_lp_state_next_constraint ( + ILLread_lp_state * state) +{ + int rval; + int ln = state->line_num; + + ILLread_lp_state_skip_blanks (state, 1); + if (state->eof) + { + return 1; + } + if (ln == state->line_num) + { + return ILLlp_error (state, "Constraints must start on a new line.\n"); + } + if (ILLread_lp_state_next_field (state) == 0) + { + rval = ILLtest_lp_state_keyword (state, all_keyword); + ILLread_lp_state_prev_field (state); + return !rval; + } + return 0; +} + +/* return 0 if there is a sign */ +int ILLread_lp_state_sign ( + ILLread_lp_state * state, + EGlpNum_t * sign) +{ + char found = 0; + + EGlpNumOne (*sign); + if (ILLread_lp_state_skip_blanks (state, 1) == 0) + { + if ((*state->p == '+') || (*state->p == '-')) + { + if (*state->p != '+') + EGlpNumSign (*sign); + state->p++; + found = 1; + } + } + return 1 - found; +} + +int ILLtest_lp_state_next_is ( + ILLread_lp_state * state, + const char *str) +{ + ILLread_lp_state_skip_blanks (state, 0); + if (strncasecmp (state->p, str, strlen (str)) == 0) + { + state->p += strlen (str); + return 1; + } + return 0; +} + +int ILLread_lp_state_value ( + ILLread_lp_state * state, + EGlpNum_t * coef) +{ + int len = 0; + + if (ILLread_lp_state_skip_blanks (state, 1) != 0) + { + ILL_RESULT (1, "ILLread_lp_state_value"); + } + else + { + state->fieldOnFirstCol = (state->line == state->p); + len = ILLget_value (state->p, coef); + if (len > 0) + { + state->p += len; + ILL_RESULT (0, "ILLread_lp_state_value"); + } + ILL_RESULT (1, "ILLread_lp_state_value"); + } +} + +int ILLread_lp_state_possible_coef ( + ILLread_lp_state * state, + EGlpNum_t * coef, + const EGlpNum_t defValue) +{ + EGlpNumCopy (*coef, defValue); + return ILLread_lp_state_value (state, coef); +} + + +int ILLread_lp_state_possible_bound_value ( + ILLread_lp_state * state) +{ + EGlpNum_t sign; + int len = 0; + char *p = NULL; + int rval = 0; + + EGlpNumInitVar (sign); + (void) ILLread_lp_state_sign (state, &sign); + + if (!strncasecmp (state->p, "INFINITY", (size_t) 8)) + { + len = 8; + } + else + { + if (!strncasecmp (state->p, "INF", (size_t) 3)) + { + len = 3; + } + } + if (len > 0) + { + state->p += len; + p = state->p; + ILLread_lp_state_skip_blanks (state, 0); + if (!END_LINE (p) && p == state->p) + { + /* found no blanks so this INF/INFINITY is the prefix + * of something else */ + state->p -= len; + goto CLEANUP; + return 0; /* no coef found */ + } + else + { + if (EGlpNumIsLessZero (sign)) + EGlpNumCopy (state->bound_val, ILL_MINDOUBLE); + else if (EGlpNumIsGreatZero (sign)) + EGlpNumCopy (state->bound_val, ILL_MAXDOUBLE); + else + EGlpNumZero (state->bound_val); + rval = 1; + goto CLEANUP; + } + } + if (ILLread_lp_state_value (state, &(state->bound_val)) == 0) + { + EGlpNumMultTo (state->bound_val, sign); + rval = 1; + goto CLEANUP; + } +CLEANUP: + EGlpNumClearVar (sign); + return rval; /* no coef found */ +} + +int ILLtest_lp_state_sense ( + ILLread_lp_state * state, + int all) +{ + char c; + + state->sense_val = ' '; + if (ILLread_lp_state_skip_blanks (state, 1) == 0) + { + c = *state->p; + if (!all) + { /* look for '=' and '<=' */ + if (c == '=') + { + state->p++; + state->sense_val = 'E'; + } + else + { + if ((c == '<') && (*(state->p + 1) == '=')) + { + state->p += 2; + state->sense_val = 'L'; + } + } + } + else + { + c = *state->p; + if ((c == '<') || (c == '>')) + { + state->sense_val = (c == '<') ? 'L' : 'G'; + state->p++; + c = *state->p; + if (*state->p == '=') + { + state->p++; + } + } + else + { + if (c == '=') + { + state->p++; + c = *state->p; + if ((c == '<') || (c == '>')) + { + state->sense_val = (c == '<') ? 'L' : 'G'; + state->p++; + } + else + { + state->sense_val = 'E'; + } + } + } + } + } + return (state->sense_val != ' '); +} + +void ILLtest_lp_state_bound_sense ( + ILLread_lp_state * state) +{ + (void) ILLtest_lp_state_sense (state, 0); +} + +int ILLread_lp_state_sense ( + ILLread_lp_state * state) +{ + if (!ILLtest_lp_state_sense (state, 1)) + { + if (END_LINE (state->p)) + { + return ILLlp_error (state, "Missing row sense at end of line.\n"); + } + else + { + if (*state->p != '\0') + { + return ILLlp_error (state, "\"%c\" is not a row sense.\n", *state->p); + } + else + { + return ILLlp_error (state, "Missing row sense at end of line.\n"); + } + } + } + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* error printing + */ + +static void ILLread_lp_state_print_at ( + ILLread_lp_state * state) +{ + char *p; + + if (state->eof) + { + fprintf (stderr, "end of file"); + } + else + { + if (*state->p == '\n') + { + fprintf (stderr, "end of line"); + } + else + { + p = state->p; + while (ILL_ISBLANK (p)) + { + p++; + } + fprintf (stderr, "%c", '"'); + for (; !ILL_ISBLANK (p) && !END_LINE (p); p++) + { + fprintf (stderr, "%c", *p); + } + fprintf (stderr, "\""); + } + } +} + +static void lp_err ( + ILLread_lp_state * state, + int isError, + const char *format, + va_list args) +{ + int rval = 0; + int errtype, slen, at; + qsformat_error error; + char error_desc[256]; + + ILL_FAILfalse (state != NULL, "state != NULL"); + ILL_FAILfalse (state->file != NULL, "state->file != NULL"); + ILL_FAILfalse (format != NULL, "format != NULL"); + ILL_FAILfalse (format[0] != '\0', "format[0] != '0'"); + + ILLread_lp_state_skip_blanks (state, 0); + at = state->p - state->line; + vsprintf (error_desc, format, args); + slen = strlen (error_desc); + if ((slen > 0) && error_desc[slen - 1] != '\n') + { + error_desc[slen] = '\n'; + error_desc[slen + 1] = '\0'; + } + + if (state->file->error_collector != NULL) + { + errtype = (isError) ? QS_LP_FORMAT_ERROR : QS_LP_FORMAT_WARN; + ILLformat_error_create (&error, errtype, error_desc, + state->line_num, state->realline, at); + ILLformat_error (state->file->error_collector, &error); + ILLformat_error_delete (&error); + } + else + { + if (!state->interactive) + { + fprintf (stderr, "%s %d: %s\t", state->file_name, state->line_num, + state->realline); + fprintf (stderr, "%s at ", (isError) ? "LP Error" : "LP Warning"); + ILLread_lp_state_print_at (state); + fprintf (stderr, ": "); + } + else + { + fprintf (stderr, "%s : ", (isError) ? "LP Error" : "LP Warning"); + } + fprintf (stderr, error_desc); + fflush (stderr); + } +CLEANUP:; +} + +int ILLlp_error ( + ILLread_lp_state * state, + const char *format, + ...) +{ + va_list args; + + va_start (args, format); + lp_err (state, TRUE, format, args); + return 1; +} + +void ILLlp_warn ( + ILLread_lp_state * state, + const char *format, + ...) +{ + va_list args; + + va_start (args, format); + if (format != NULL) + { + lp_err (state, FALSE, format, args); + } +} + +/* shared with read_mps_state.c */ +int ILLget_value ( + char *line, + EGlpNum_t * coef) +{ +#ifdef mpq_READ_LP_STATE_H + mpq_t res; + int rval = 0; + + mpq_init (res); + rval = mpq_EGlpNumReadStrXc (res, line); + if (rval == 0) + mpq_set_ui (*coef, 1UL, 1UL); + else + mpq_set (*coef, res); + mpq_clear (res); + return rval; + //return mpq_EGlpNumReadStrXc (*coef, line); +#else + char field[ILL_namebufsize]; + int rval = 0, i; + char c, lastC, *p; + int allowDot, allowExp, allowSign; + double dtmp; + + p = line; + c = *p; + i = 0; + lastC = ' '; + allowSign = 1; + allowExp = 0; + allowDot = 1; + while ((('0' <= c) && (c <= '9')) || + (allowDot && (c == '.')) || + ((allowExp == 1) && ((c == 'e') || (c == 'E'))) || + ((allowSign || lastC == 'e' || lastC == 'E') && + ((c == '+') || (c == '-')))) + { + if (c == '.') + allowDot = 0; + allowSign = 0; + + if ((allowExp == 0) && (c >= '0') && (c <= '9')) + { + allowExp = 1; + } + if ((c == 'e') || (c == 'E')) + { + allowExp++; + allowDot = 0; + } + p++; + lastC = c; + c = *p; + i++; + } + if ((lastC == '+') || (lastC == '-')) + { + p--; + i--; + if (p > line) + lastC = *(p - 1); + else + lastC = ' '; + } + if ((lastC == 'e') || (lastC == 'E')) + { + p--; + i--; + } + if (i > 0) + { + strncpy (field, line, (size_t) i); + field[i] = '\0'; + rval = !sscanf (field, "%lf%n", &dtmp, &i); + EGlpNumSet (*coef, dtmp); + ILL_IFTRACE ("%la\n", EGlpNumToLf (*coef)); + if (rval != 0) + { + ILL_RESULT (0, "ILLget_value"); + } + } + //ILL_RESULT (i, "ILLget_value"); + return i; +#endif +} + +int ILLcheck_subject_to ( + ILLread_lp_state * state) +{ + int rval; + char *p; + + if ((rval = ILLread_lp_state_next_field (state)) == 0) + { + if (strcasecmp (state->field, "ST") == 0) + { + rval = ILLread_lp_state_bad_keyword (state); + } + else + { + if (strcasecmp (state->field, "SUBJECT") == 0) + { + p = state->p; + while (ILL_ISBLANK (p)) + { + p++; + } + if (!strncasecmp (p, "TO", (size_t) 2)) + { + rval = ILLread_lp_state_bad_keyword (state); + if (rval == 0) + { + state->p = p + 2; + } + } + } + else + { + rval = 1; + } + } + if (rval != 0) + { + ILLread_lp_state_prev_field (state); + } + else + { + ILLread_lp_state_skip_blanks (state, 1); + } + } + ILL_RESULT (rval, "check_subject_to"); +} diff --git a/src/read_lp.h b/src/read_lp.h new file mode 100644 index 0000000..06f607e --- /dev/null +++ b/src/read_lp.h @@ -0,0 +1,145 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: read_lp_state.h,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:57:39 $"; */ +#ifndef READ_LP_STATE_H +#define READ_LP_STATE_H + +/****************************************************************************/ +/* */ +/* Routines to support Reading LP Files */ +/* */ +/****************************************************************************/ + +/* + * -) anything after '\' is comment + * -) variables consist of a-z A-Z 0-9!"#$%(),;.?@_`'{}|~ + * don't start with a digit or '.' + */ + +#include "iqsutil.h" +#include "readline.h" + +typedef struct ILLread_lp_state +{ + qsline_reader *file; + const char *file_name; + char *p; + EGlpNum_t bound_val; + int interactive; + int line_num; + int column_index; + char realline[ILL_namebufsize]; + char line[ILL_namebufsize]; + char field[ILL_namebufsize + 1]; + char fieldOnFirstCol; + char eof; + char sense_val; +} +ILLread_lp_state; + +extern int ILLread_lp_state_init ( + ILLread_lp_state * state, + qsline_reader * file, + const char *fname, + int interactve); +extern int ILLread_lp_state_next_line ( + ILLread_lp_state * state); +extern int ILLread_lp_state_next_var ( + ILLread_lp_state * state); +extern int ILLread_lp_state_keyword ( + ILLread_lp_state * state, + const char **kwd); +extern int ILLread_lp_state_bad_keyword ( + ILLread_lp_state * state); +extern int ILLtest_lp_state_keyword ( + ILLread_lp_state * state, + const char *kwd[]); +extern int ILLread_lp_state_next_field ( + ILLread_lp_state * state); +extern int ILLread_lp_state_next_field_on_line ( + ILLread_lp_state * state); +extern void ILLread_lp_state_prev_field ( + ILLread_lp_state * state); +extern int ILLread_lp_state_sign ( + ILLread_lp_state * state, + EGlpNum_t * sign); +extern int ILLread_lp_state_possible_coef ( + ILLread_lp_state * state, + EGlpNum_t * coef, + const EGlpNum_t defValue); + + /* returns 1 iff found a number + * otherwise 0 */ +extern int ILLread_lp_state_possible_bound_value ( + ILLread_lp_state * state); + + /* returns 1 iff found a number + * otherwise 0 */ +extern int ILLread_lp_state_colon ( + ILLread_lp_state * state); +extern int ILLread_lp_state_has_colon ( + ILLread_lp_state * state); +extern int ILLread_lp_statxe_has_colon ( + ILLread_lp_state * state); +extern int ILLread_lp_state_next_constraint ( + ILLread_lp_state * state); +extern int ILLread_lp_state_sense ( + ILLread_lp_state * state); +extern int ILLtest_lp_state_sense ( + ILLread_lp_state * state, + int all); +extern void ILLtest_lp_state_bound_sense ( + ILLread_lp_state * state); +extern int ILLread_lp_state_value ( + ILLread_lp_state * state, + EGlpNum_t * d); +extern int ILLtest_lp_state_next_is ( + ILLread_lp_state * state, + const char *str); +extern int ILLread_lp_state_skip_blanks ( + ILLread_lp_state * state, + int wrapLines); + +extern int ILLcheck_subject_to ( + ILLread_lp_state * state); + +/*---------------------------------------------------------------------------*/ +/* errors and warnings + */ +extern int ILLlp_error ( + ILLread_lp_state * state, + const char *format, + ...); +extern void ILLlp_warn ( + ILLread_lp_state * state, + const char *format, + ...); + +/*---------------------------------------------------------------------------*/ +/* shared with read_mps_state.c + */ +extern int ILLget_value ( + char *line, + EGlpNum_t * coef); + +#endif diff --git a/src/read_mps.c b/src/read_mps.c new file mode 100644 index 0000000..0b6799c --- /dev/null +++ b/src/read_mps.c @@ -0,0 +1,516 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: read_mps_state.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +/****************************************************************************/ +/* */ +/* Routines to Support Reading MPS Files */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "iqsutil.h" +#include "rawlp.h" +#include "read_mps.h" +#include "read_lp.h" /* for ILLget_value */ +#include "format.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif +static int TRACE = 0; + +#define END_LINE(p) (((*(p)) == '$' || (*(p)) == '\n' || (*(p)) == '\0') ? 1 : 0) + +static int mps_skip_comment ( + ILLread_mps_state * state); +static char ILLmps_next_field_is_number ( + ILLread_mps_state * state); + +int ILLmps_state_init ( + ILLread_mps_state * state, + qsline_reader * file, + const char *fname) +{ + int i, rval = 0; + + ILL_FAILtrue (file == 0, "need file"); + state->p = 0; + state->file_name = fname; + state->file = file; + + for (i = 0; i < ILL_MPS_N_SECTIONS; i++) + { + state->section[i] = 0; + } + state->active = ILL_MPS_NONE; + state->intvar = 0; + state->sosvar = 0; + state->line_num = 0; + state->p = 0; + + state->obj = 0; + state->line[0] = '\0'; + state->key[0] = '\0'; + state->field[0] = '\0'; + +CLEANUP: + ILL_RESULT (rval, "ILLmps_state_init"); +} + +int ILLmps_next_line ( + ILLread_mps_state * state) +{ + int rval = 0; + + /* if field 3 or 5 start with $ rest of line is interpreted as comment */ + state->line[0] = '\0'; + state->p = 0; + while (ILLline_reader_get (state->line, ILL_namebufsize - 2, state->file) + != 0) + { + state->line_num++; + state->key[0] = '\0'; + state->field[0] = '\0'; + state->field_num = 1; + state->p = state->line; + if (!ILL_ISBLANK ((state->line))) + { + if (state->line[0] == '*' || state->line[0] == '\n') + { + continue; /* comment or blank line */ + } + else + { + if (sscanf (state->p, "%s", state->key) == 1) + { + state->p += strlen (state->key); + while (ILL_ISBLANK (state->p)) + { + state->p++; + } + if (sscanf (state->p, "%s", state->field) == 1) + { + state->p += strlen (state->field); + } + else + { + ILL_FAILfalse (state->field[0] == '\0', "sscanf problem?"); + } + } + else + { + ILL_FAILfalse (0, "should almost never happen"); + } + } + } + else + { + while (ILL_ISBLANK (state->p)) + { + state->p++; + } + if (sscanf (state->p, "%s", state->field) < 1) + { + continue; /* nothing more on line */ + } + else + { + if (state->field[0] == '\0') + { + continue; /* found empty string */ + } + state->p += strlen (state->field); + } + } + return 0; + } +CLEANUP: + return 1; /* end of file */ +} + +/* fields 3,5,7,... may start with '$' signifying comment + * ==> if we find a '$' as next non blank and + * we read 2,4,6,... fields successfully so far + * we have a comment + */ +static int mps_skip_comment ( + ILLread_mps_state * state) +{ + int rval; + + while (ILL_ISBLANK (state->p)) + { + state->p++; + } + rval = ((*state->p == '$') && (state->field_num >= 2) && + (state->field_num % 2 == 0)); + return rval; +} + +int ILLmps_next_field ( + ILLread_mps_state * state) +{ + state->field[0] = '\0'; + if (!mps_skip_comment (state)) + { + if (sscanf (state->p, "%s", state->field) == 1) + { + state->p += strlen (state->field) + 1; + state->field_num++; + return 0; + } + } + return 1; /* no more fields */ +} + +static char get_double ( + ILLread_mps_state * state, + int peek, + EGlpNum_t * coef) +{ + char ok = 0; + int len, rval = 0; + + ILL_FAILfalse (state != 0, "must have state"); + if (mps_skip_comment (state)) + return 0; + len = ILLget_value (state->p, coef); + if (len > 0) + { + if (!peek) + { + state->p += len; + state->field_num++; + } + ok = 1; + } +CLEANUP: + ILL_RESULT (ok, "get_double"); +} + +int ILLmps_next_coef ( + ILLread_mps_state * state, + EGlpNum_t * coef) +{ + int len = 0; + + if (!mps_skip_comment (state)) + { + len = get_double (state, 0, coef); + } + ILL_RESULT (!(len > 0), "ILLmps_next_coef"); +} + +int ILLmps_next_bound ( + ILLread_mps_state * state, + EGlpNum_t * coef) +{ + int len = 0, sign = 1; + char c, *p; + + if (!mps_skip_comment (state)) + { + c = *state->p; + if (c == '-') + { + sign = -1; + len = 1; + } + else + { + if (c == '+') + { + len = 1; + } + } + if (!strncasecmp (state->p + len, "INFINITY", (size_t) 8)) + { + len += 8; + } + else + { + if (!strncasecmp (state->p + len, "INF", (size_t) 3)) + { + len += 3; + } + } + if (len > 1) + { + state->p += len; + p = state->p; + mps_skip_comment (state); + if (!END_LINE (state->p) && p == state->p) + { + /* found no blanks so this INF/INFINITY is the prefix + * of something else */ + state->p -= len; + return 1; /* no coef found */ + } + else + { + if (sign == 1) + EGlpNumCopy (*coef, ILL_MAXDOUBLE); + else + EGlpNumCopy (*coef, ILL_MINDOUBLE); + state->field_num++; + ILL_RESULT (0, "ILLmps_next_bound"); + } + } + if (get_double (state, 0, coef)) + { + ILL_RESULT (0, "ILLmps_next_bound"); + } + else + { + ILL_RESULT (1, "ILLmps_next_bound"); /* no coef found */ + } + } + ILL_RETURN (1, "ILLmps_next_bound"); +} + +static char ILLmps_next_field_is_number ( + ILLread_mps_state * state) +{ + EGlpNum_t d; + int len = 0; + + if (!mps_skip_comment (state)) + { + EGlpNumInitVar (d); + len = get_double (state, 1, &d); + EGlpNumClearVar (d); + } + return (len > 0); +} + +void ILLmps_check_end_of_line ( + ILLread_mps_state * state) +{ + if (!mps_skip_comment (state)) + { + if (!END_LINE (state->p)) + { + ILLmps_warn (state, "Extra fields on line."); + } + } +} + +void ILLmps_set_end_of_line ( + ILLread_mps_state * state) +{ + *state->p = '\n'; +} + +int ILLmps_set_section ( + ILLread_mps_state * state, + const ILLmps_section sec) +{ + int rval = 0; + + ILL_FAILfalse (sec != ILL_MPS_NONE, "must be in a proper section"); + if (state->section[sec]) + { + rval = ILLmps_error (state, "Two %s sections.\n", ILLmps_section_name[sec]); + } + state->section[sec]++; + state->active = sec; +CLEANUP: + ILL_RESULT (rval, "ILLmps_set_section"); +} + +int ILLmps_int_sos_mode ( + ILLread_mps_state * state) +{ + if (!strcmp (state->field, "'INTORG'")) + { + if (state->intvar) + { + return !ILLmps_error (state, "'INTEND' expected.\n"); + } + else + { + state->intvar = 1; + ILL_RESULT (0, "ILLmps_int_sos_mode"); + } + } + if (!strcmp (state->field, "'INTEND'")) + { + if (state->intvar) + { + state->intvar = 0; + ILL_RESULT (0, "ILLmps_int_sos_mode"); + } + else + { + return !ILLmps_error (state, "'INTORG' expected.\n"); + } + } + if (!strcmp (state->field, "'SOSORG'")) + { + if (state->sosvar) + { + return !ILLmps_error (state, "'SOSEND' expected.\n"); + } + else + { + state->sosvar = 1; + ILL_RESULT (0, "ILLmps_int_sos_mode"); + } + } + if (!strcmp (state->field, "'SOSEND'")) + { + if (state->sosvar) + { + state->sosvar = 0; + ILL_RESULT (0, "ILLmps_int_sos_mode"); + } + else + { + return !ILLmps_error (state, "'SOSORG' expected.\n"); + } + } + return ILLmps_error (state, "%s is not a MARKER field.\n", state->field); +} + +const char *ILLmps_possibly_blank_name ( + const char *field, + ILLread_mps_state * state, + ILLsymboltab * tab) +{ + int ind; + + if (ILLsymboltab_lookup (tab, field, &ind) == 0) + { + /* Possibly a blank identifier on the line */ + if (ILLmps_next_field_is_number (state)) + { + /* assume a blank bound ident */ + return " "; + } + else + { + return field; + } + } + else + { + return field; + } +} + +int ILLmps_empty_key ( + ILLread_mps_state * state) +{ + return state->key[0] == '\0'; +} + +int ILLmps_empty_field ( + ILLread_mps_state * state) +{ + return state->field[0] == '\0'; +} + +static void mps_err ( + ILLread_mps_state * state, + int isError, + const char *format, + va_list args) +{ + int rval = 0; + const char *type = (isError) ? "MPS Error" : "MPS Warning"; + int errtype, slen, at; + qsformat_error error; + char error_desc[256]; + + ILL_FAILfalse_no_rval (format != 0, "format != 0"); + ILL_FAILfalse_no_rval (format[0] != '\0', "format[0] != '0'"); + ILL_FAILfalse_no_rval (state != 0, "state != 0"); + ILL_FAILfalse_no_rval (state->file != 0, "state->file != 0"); + + if (state->p == 0) + { + at = -1; + } + else + { + ILL_FAILfalse (state->p >= state->line, "state->p >= state->line"); + at = state->p - state->line; + } + vsprintf (error_desc, format, args); + slen = strlen (error_desc); + if ((slen > 0) && error_desc[slen - 1] != '\n') + { + error_desc[slen] = '\n'; + error_desc[slen + 1] = '\0'; + } + + if (state->file->error_collector != 0) + { + errtype = (isError) ? QS_MPS_FORMAT_ERROR : QS_MPS_FORMAT_WARN; + ILLformat_error_create (&error, errtype, error_desc, + (int) (state->line_num), state->line, at); + ILLformat_error (state->file->error_collector, &error); + ILLformat_error_delete (&error); + } + else + { + fprintf (stderr, "%s %d: %s\t", state->file_name, state->line_num, + state->line); + fprintf (stderr, "%s: ", type); + vfprintf (stderr, format, args); + if (format[strlen (format) - 1] != '\n') + { + fprintf (stderr, "\n"); + } + fflush (stderr); + } +CLEANUP: + ; +} + +int ILLmps_error ( + ILLread_mps_state * state, + const char *format, + ...) +{ + va_list args; + + va_start (args, format); + mps_err (state, TRUE, format, args); + /* ILL_RESULT(1, "ILLmps_error"); */ + return 1; +} + +void ILLmps_warn ( + ILLread_mps_state * state, + const char *format, + ...) +{ + va_list args; + + va_start (args, format); + if (format != 0) + { + mps_err (state, FALSE, format, args); + } +} diff --git a/src/read_mps.h b/src/read_mps.h new file mode 100644 index 0000000..c09e49c --- /dev/null +++ b/src/read_mps.h @@ -0,0 +1,95 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: rd_mps.h,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:57:39 $ */ +#ifndef READ_MPS_STATE_H +#define READ_MPS_STATE_H + +#include "iqsutil.h" + +#include "mps.h" + +typedef struct ILLread_mps_state_struct +{ + int section[ILL_MPS_N_SECTIONS]; + ILLmps_section active; + const char *file_name; + qsline_reader *file; + unsigned int line_num; + unsigned int field_num; /* number of successfully read fields on line */ + int intvar; + int sosvar; + char line[ILL_namebufsize]; + char key[ILL_namebufsize]; + char field[ILL_namebufsize]; + char *obj; + char *p; /* ptr to next 'unread' character */ +} +ILLread_mps_state; + +extern int ILLmps_state_init ( + ILLread_mps_state * state, + qsline_reader * file, + const char *fname); +extern void ILLmps_state_clear ( + ILLread_mps_state * state); +extern int ILLmps_set_section ( + ILLread_mps_state * state, + const ILLmps_section sec); + +extern int ILLmps_next_line ( + ILLread_mps_state * state); +extern int ILLmps_next_field ( + ILLread_mps_state * state); +extern int ILLmps_next_coef ( + ILLread_mps_state * state, + EGlpNum_t * coef); +extern int ILLmps_next_bound ( + ILLread_mps_state * state, + EGlpNum_t * coef); +extern void ILLmps_check_end_of_line ( + ILLread_mps_state * state); +extern void ILLmps_set_end_of_line ( + ILLread_mps_state * state); + +extern int ILLmps_int_sos_mode ( + ILLread_mps_state * state); + +extern const char *ILLmps_possibly_blank_name ( + const char *field, + ILLread_mps_state * state, + ILLsymboltab * tab); +extern int ILLmps_empty_key ( + ILLread_mps_state * state); +extern int ILLmps_empty_field ( + ILLread_mps_state * state); + +extern int ILLmps_error ( + ILLread_mps_state * state, + const char *format, + ...); +extern void ILLmps_warn ( + ILLread_mps_state * state, + const char *format, + ...); + +#endif diff --git a/src/reader.c b/src/reader.c new file mode 100644 index 0000000..9be3eb8 --- /dev/null +++ b/src/reader.c @@ -0,0 +1,284 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: reader.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +#include "reader.h" +#include "qstruct.h" +#include "iqsutil.h" +#include "qsopt.h" + +static int TRACE = 0; +static int TEST_ERROR_COLLECTOR = 0; +static int TEST_ERROR_MEMORY = 0; + +static char *fname = (char *) NULL; +static char *out_lp = (char *) NULL; +static char *out_mps = (char *) NULL; +static int lpfile = 0; +static int stats = 0; + +static void usage ( + char *s); + +static int parseargs ( + int ac, + char **av); + +static int add_error ( + void *dest, + QSformat_error error) +{ + const char *type = "Error"; + const char *line; + int tp, i, at; + FILE *out = (FILE *) dest; + + at = QSerror_get_pos (error); + tp = QSerror_get_type (error); + type = QSformat_error_type_string (tp); + + fprintf (out, "ADD: "); + fprintf (out, "%s line %d pos %d\n", + type, QSerror_get_line_number (error), at); + line = QSerror_get_line (error); + if (line != NULL) + { + fprintf (out, "LINE %s", line); + if (at >= 0) + { + fprintf (out, "....."); + for (i = 0; i <= (at - 1); i++) + { + if (line[i] == '\t') + { + fputc ('\t', out); + } + else + { + fputc ('.', out); + } + } + fprintf (out, "^\n"); + } + } + else + { + fprintf (out, "NO LINE\n"); + } + + fprintf (out, "MSG: %s\n", QSerror_get_desc (error)); + return 0; +} + +QSLIB_INTERFACE int reader_main ( + int ac, + char **av) +{ + int rval = 0; + int rvalmps = 0; + int rvallp = 0; + QSdata *p = NULL; + ILLutil_timer timer_read; + ILLutil_timer timer_write; + FILE *fin = NULL; + QSline_reader reader = NULL; + QSerror_collector collector = NULL; + QSerror_memory error_mem = NULL; + QSformat_error e = NULL; + + if (parseargs (ac, av)) + goto CLEANUP; + + ILLutil_init_timer (&timer_read, "READER_READ"); + ILLutil_start_timer (&timer_read); + if (TEST_ERROR_COLLECTOR || TEST_ERROR_MEMORY) + { + fin = fopen (fname, "r"); + reader = QSline_reader_new ((void *) fgets, fin); + if (TEST_ERROR_COLLECTOR) + { + collector = QSerror_collector_new ((void *) add_error, stderr); + } + if (TEST_ERROR_MEMORY) + { + error_mem = QSerror_memory_create (0); + ILL_CHECKnull (error_mem, "Could not make error memory"); + collector = QSerror_memory_collector_new (error_mem); + } + if (fin == NULL) + { + fprintf (stderr, "Can't open \"%s\" for reading.\n", fname); + } + rval = (fin == NULL) || (reader == NULL) || (collector == NULL); + ILL_CLEANUP_IF (rval); + + QSline_reader_set_error_collector (reader, collector); + p = QSget_prob (reader, fname, (lpfile == 0) ? "MPS" : "LP"); + + if (TEST_ERROR_MEMORY) + { + int n = QSerror_memory_get_nerrors (error_mem); + + fprintf (stderr, "#error %d\n", n); + for (e = QSerror_memory_get_last_error (error_mem); + e != NULL; e = QSerror_memory_get_prev_error (e)) + { + QSerror_print (stderr, e); + } + } + } + else + { + if (lpfile == 0) + { + p = QSread_prob (fname, "MPS"); + } + else + { + p = QSread_prob (fname, "LP"); + } + } + ILL_IFTRACE ("QSread_prob %s\n", fname); + ILLutil_stop_timer (&timer_read, 1); + rval = (p == NULL); + fprintf (stdout, + "read \"%s\" %s.\n", fname, (rval == 0) ? "succeeded" : "failed"); + ILL_CLEANUP_IF (rval); + + if (stats) + { + fprintf (stdout, "\n"); + fprintf (stdout, "The problem \"%s\" has %d rows and %d cols.\n", + QSget_probname (p), QSget_rowcount (p), QSget_colcount (p)); + } + ILLutil_init_timer (&timer_write, "READER_WRITE"); + ILLutil_start_timer (&timer_write); + if (out_mps) + { + fprintf (stdout, "\n"); + rvalmps = QSwrite_prob (p, out_mps, "MPS"); + fprintf (stdout, "write \"%s\" %s.\n", out_mps, + (rvalmps == 0) ? "succeeded" : "failed"); + } + if (out_lp) + { + fprintf (stdout, "\n"); + rvallp = QSwrite_prob (p, out_lp, "LP"); + fprintf (stdout, "write \"%s\" %s.\n", out_lp, + (rvallp == 0) ? "succeeded" : "failed"); + } + ILLutil_stop_timer (&timer_write, 1); + + rval = rvalmps || rvallp; + ILL_CLEANUP_IF (rval); + +CLEANUP: + + if (p != NULL) + QSfree_prob (p); + if (fin != NULL) + fclose (fin); + if (reader != NULL) + QSline_reader_free (reader); + if (collector != NULL) + QSerror_collector_free (collector); + if (error_mem != NULL) + QSerror_memory_free (error_mem); + + return rval; /* main return */ +} + +static void usage ( + char *s) +{ + fprintf (stderr, "Usage: %s [- below -] prob_file\n", s); + fprintf (stderr, " -L input file is in lp format (default: mps)\n"); + fprintf (stderr, " -s print information about problem to stdout\n"); + fprintf (stderr, " -l f write lp in LP format to file f\n"); + fprintf (stderr, " -m f write lp in MPS format to file f\n"); +#if 0 + fprintf (stderr, " -E test error_memory\n"); + fprintf (stderr, " -e test error_collector\n"); +#endif +} + +static int parseargs ( + int ac, + char **av) +{ + int c; + int boptind = 1; + char *boptarg = (char *) NULL; + + while ((c = + ILLutil_bix_getopt (ac, av, "Ll:m:tseE", &boptind, &boptarg)) != EOF) + switch (c) + { + case 'L': + lpfile = 1; + break; + case 'l': + out_lp = boptarg; + break; + case 'm': + out_mps = boptarg; + break; + case 's': + stats = 1; + break; + case 't': + TRACE++; + break; +#if 0 + case 'E': + TEST_ERROR_MEMORY++; + break; + case 'e': + TEST_ERROR_COLLECTOR++; + break; +#endif + case '?': + default: + usage (av[0]); + return 1; + } + + if (boptind != (ac - 1)) + { + usage (av[0]); + return 1; + } + + fname = av[boptind++]; + return 0; +} + + +#ifndef WIN32 +int main ( + int ac, + char **av) +{ + return reader_main (ac, av); +} +#endif diff --git a/src/reader.h b/src/reader.h new file mode 100644 index 0000000..d5c7fe2 --- /dev/null +++ b/src/reader.h @@ -0,0 +1,34 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: reader.h,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:57:39 $"; */ +#ifndef READER_H +#define READER_H + +#include "config.h" +#include "qsopt.h" + +QSLIB_INTERFACE int reader_main ( + int argc, + char **argv); + +#endif diff --git a/src/readline.c b/src/readline.c new file mode 100644 index 0000000..c22c64d --- /dev/null +++ b/src/readline.c @@ -0,0 +1,56 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$Id: line_reader.c,v 1.2 2003/11/05 16:49:52 meven Exp $"; */ + +#include "config.h" +#include +#include "iqsutil.h" +#include "readline.h" + + +/* #ifdef _WINDOWS*/ +qsline_reader *ILLline_reader_new ( + qsread_line_fct fct, + void *data_src) +{ + qsline_reader *reader; + int rval = 0; + + ILL_NEW (reader, qsline_reader); + if (reader != NULL) + { + reader->read_line_fct = fct; + reader->data_src = data_src; + reader->error_collector = NULL; + } +CLEANUP: + return reader; +} + +void ILLline_reader_free ( + qsline_reader * reader) +{ + ILL_IFFREE (reader, qsline_reader); +} + +/* #endif */ diff --git a/src/readline.h b/src/readline.h new file mode 100644 index 0000000..77553e8 --- /dev/null +++ b/src/readline.h @@ -0,0 +1,64 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: rdline.h,v 1.2 2003/11/05 16:57:39 meven Exp $ */ +#ifndef LINE_READER_FILE_H +#define LINE_READER_FILE_H + +#include "qsopt.h" +#include "format.h" + +/* #ifdef _WINDOWS */ +typedef char *( + *qsread_line_fct) ( + char *s, + int size, + void *src); + +typedef struct qsline_reader +{ + qsread_line_fct read_line_fct; + void *data_src; + struct qserror_collector *error_collector; +} +qsline_reader; + +qsline_reader *ILLline_reader_new ( + qsread_line_fct fct, + void *data_src); +void ILLline_reader_free ( + qsline_reader * reader); + +#define ILLline_reader_get(s, size, reader) \ + (reader)->read_line_fct(s, size, (reader)->data_src) + /* used by parsers to retrieve next input line */ +/* #else + * + * typedef FILE qsline_reader; + * + * #define ILLline_reader_new(fct, data) ((FILE*) (data)) + * #define ILLline_reader_free(reader) + * #define ILLline_reader_get(s, size, reader) fgets(s,size,reader) + * #endif + */ + +#endif diff --git a/src/reporter.c b/src/reporter.c new file mode 100644 index 0000000..75e099f --- /dev/null +++ b/src/reporter.c @@ -0,0 +1,89 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$Id: reporter.c,v 1.1 2003/11/05 16:49:52 meven Exp $"; */ + +#include "config.h" +#include +#include "iqsutil.h" +#include "reporter.h" + +int ILL_fprintf ( + void *dest, + const char *s) +{ + if (s != NULL) + return fprintf ((FILE *) dest, s); + return 0; +} + +void ILLstring_reporter_init ( + qsstring_reporter * reporter, + qsreport_string_fct fct, + void *dest) +{ + int rval = 0; + + ILL_FAILfalse (reporter != NULL, "Must get non NULL reporter"); + if (reporter != NULL) + { + reporter->report_fct = fct; + reporter->dest = dest; + } +CLEANUP: + return; +} + +void ILLstring_reporter_copy ( + qsstring_reporter * dest, + qsstring_reporter * src) +{ + *dest = *src; +} + + +#ifdef REPORTER_MAIN +static int string_reporter_main ( + int ac, + char **av) +{ + int i = 0; + qsstring_reporter reporter; + + ILLstring_reporter_init (&reporter, ILL_fprintf, stdout); + for (i = 0; i < ac; i++) + { + (void) ILLstring_report (av[i], &reporter); + (void) ILLstring_report ("\n", &reporter); + } + (void) ILLstring_report (NULL, &reporter); + + return 0; +} + +int main ( + int ac, + char **av) +{ + return string_reporter_main (ac, av); +} +#endif diff --git a/src/reporter.h b/src/reporter.h new file mode 100644 index 0000000..4ea6a24 --- /dev/null +++ b/src/reporter.h @@ -0,0 +1,57 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: reporter.h,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:57:39 $ */ +#ifndef REPORTER_FILE +#define REPORTER_FILE + +typedef int ( + *qsreport_string_fct) ( + void *dest, + const char *s); + +typedef struct qsstring_reporter +{ + qsreport_string_fct report_fct; + void *dest; +} +qsstring_reporter; + +extern int ILL_fprintf ( + void *dest, + const char *s); + +void ILLstring_reporter_init ( + qsstring_reporter * reporter, + qsreport_string_fct fct, + void *dest); + +void ILLstring_reporter_copy ( + qsstring_reporter * dest, + qsstring_reporter * src); + +#define ILLstring_report(s, reporter) \ + ((reporter)->report_fct((reporter)->dest, s) < 0) + /* used from with ILL fct to report progress */ + +/* REPORTER_FILE */ +#endif diff --git a/src/simplex.c b/src/simplex.c new file mode 100644 index 0000000..21ba2a4 --- /dev/null +++ b/src/simplex.c @@ -0,0 +1,3045 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: simplex.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ +static int TRACE = 0; + +#define QSOPT_CURRENT_PRECICION +#include "basicdefs.h" +#include "config.h" +#include "iqsutil.h" +#include "lpdata.h" +#include "lpdefs.h" + +#include "stddefs.h" +#include "fct.h" +#include "ratio.h" +#include "price.h" +#include "basis.h" +#include "simplex.h" +#include "dstruct.h" +#include "qstruct.h" +#include "qsopt.h" +#include "lib.h" /* for ILLlib_writebasis */ +#include "lp.h" /* for ILLwrite_lp */ + +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +static void init_lp_status_info ( + lp_status_info * ls), + init_simplex_tols ( + lpinfo * lp), + monitor_iter ( + lpinfo * lp, + price_info * p, + iter_info * it, + int cphase), + get_current_stat ( + lp_status_info * p, + int algorithm, + int *bstat); + +static int terminate_simplex ( + lpinfo * lp, + int phase, + iter_info * it), + primal_phaseI_step ( + lpinfo * lp, + price_info * pinf, + svector * updz, + svector * wz, + iter_info * it), + primal_phaseII_step ( + lpinfo * lp, + price_info * pinf, + svector * updz, + svector * wz, + iter_info * it), + dual_phaseI_step ( + lpinfo * lp, + price_info * pinf, + svector * updz, + svector * wz, + iter_info * it), + dual_phaseII_step ( + lpinfo * lp, + price_info * pinf, + svector * updz, + svector * wz, + iter_info * it), + report_value ( + lpinfo * lp, + iter_info * it, + const char *value_name, + EGlpNum_t value); + + +void ILLsimplex_init_lpinfo ( + lpinfo * lp) +{ + ILLbasis_init_basisinfo (lp); + init_internal_lpinfo (lp); +} + +void ILLsimplex_free_lpinfo ( + lpinfo * lp) +{ + if (lp) + { + EGlpNumFreeArray (lp->lz); + EGlpNumFreeArray (lp->uz); + EGlpNumFreeArray (lp->cz); + ILLbasis_free_basisinfo (lp); + free_internal_lpinfo (lp); + } +} + +void ILLsimplex_load_lpinfo ( + ILLlpdata * qslp, + lpinfo * lp) +{ + lp->basisid = -1; + lp->maxiter = 500000; + lp->maxtime = 300000; + //lp->iterskip = 10; + lp->iterskip = 100; + EGlpNumCopy (lp->objbound, INFTY); + lp->O = qslp; +} + +void ILLsimplex_set_bound ( + lpinfo * lp, + const EGlpNum_t * objbound, + int sense) +{ + EGlpNumCopy (lp->objbound, *objbound); + if (sense == ILL_MAX) + EGlpNumSign (lp->objbound); +} + +static void init_lp_status_info ( + lp_status_info * ls) +{ + ls->optimal = 0; + ls->primal_feasible = 0; + ls->primal_infeasible = 0; + ls->primal_unbounded = 0; + ls->dual_feasible = 0; + ls->dual_infeasible = 0; + ls->dual_unbounded = 0; +} + +static void init_simplex_tols ( + lpinfo * lp) +{ + EGlpNumCopy (lp->tol->pfeas_tol, PFEAS_TOLER); + EGlpNumCopy (lp->tol->dfeas_tol, DFEAS_TOLER); + EGlpNumCopy (lp->tol->pivot_tol, PIVOT_TOLER); + EGlpNumCopy (lp->tol->szero_tol, SZERO_TOLER); + EGlpNumCopy (lp->tol->ip_tol, lp->tol->pfeas_tol); + EGlpNumCopy (lp->tol->id_tol, lp->tol->dfeas_tol); + if (EGlpNumIsNeqqZero (lp->tol->ip_tol)) + { +#if VERBOSE_LEVEL <= DEBUG + MESSAGE (VERBOSE_LEVEL, "ip_tol %lg", EGlpNumToLf (lp->tol->ip_tol)); + MESSAGE (VERBOSE_LEVEL, "eps %lg", EGlpNumToLf (epsLpNum)); + MESSAGE (VERBOSE_LEVEL, "PFEAS_TOLER %lg", EGlpNumToLf (PFEAS_TOLER)); +#endif + EGlpNumDivUiTo (lp->tol->ip_tol, 2UL); + } + if (EGlpNumIsNeqqZero (lp->tol->id_tol)) + { +#if VERBOSE_LEVEL <= DEBUG + MESSAGE (VERBOSE_LEVEL, "id_tol %lg", EGlpNumToLf (lp->tol->id_tol)); +#endif + EGlpNumDivUiTo (lp->tol->id_tol, 2UL); + } +} + +void init_internal_lpinfo ( + lpinfo * lp) +{ + int rval = 0; + + lp->nrows = 0; + lp->nnbasic = 0; + lp->localrows = 0; + lp->rowcnt = 0; + lp->rowbeg = 0; + lp->rowind = 0; + lp->rowval = 0; + lp->cz = 0; + lp->lz = 0; + lp->uz = 0; + lp->xbz = 0; + lp->piz = 0; + lp->dz = 0; + lp->pIxbz = 0; + lp->pIpiz = 0; + lp->pIdz = 0; + lp->vtype = 0; + lp->vclass = 0; + lp->iwork = 0; + lp->upd.perm = 0; + lp->upd.ix = 0; + lp->upd.t = 0; + lp->bfeas = 0; + lp->dfeas = 0; + lp->tol = 0; + lp->cnts = 0; + lp->bchanges = 0; + lp->cchanges = 0; + ILLsvector_init (&(lp->zz)); + ILLsvector_init (&(lp->yjz)); + ILLsvector_init (&(lp->zA)); + ILLsvector_init (&(lp->work)); + ILLsvector_init (&(lp->srhs)); + ILLsvector_init (&(lp->ssoln)); + ILL_SAFE_MALLOC (lp->tol, 1, tol_struct); + EGlpNumInitVar (lp->tol->pfeas_tol); + EGlpNumInitVar (lp->tol->dfeas_tol); + EGlpNumInitVar (lp->tol->pivot_tol); + EGlpNumInitVar (lp->tol->szero_tol); + EGlpNumInitVar (lp->tol->ip_tol); + EGlpNumInitVar (lp->tol->id_tol); + ILL_SAFE_MALLOC (lp->cnts, 1, count_struct); + EGlpNumInitVar (lp->cnts->y_ravg); + EGlpNumInitVar (lp->cnts->z_ravg); + EGlpNumInitVar (lp->cnts->za_ravg); +CLEANUP: + if (rval) + { + fprintf (stderr, "\nno memory, in %s, exit\n", __func__); + exit (1); + } +} + +void free_internal_lpinfo ( + lpinfo * lp) +{ + bndinfo *binfo = 0; + coefinfo *cinfo = 0; + + if (lp->localrows) + { + ILL_IFFREE (lp->rowcnt, int); + ILL_IFFREE (lp->rowbeg, int); + ILL_IFFREE (lp->rowind, int); + + EGlpNumFreeArray (lp->rowval); + lp->localrows = 0; + } + EGlpNumFreeArray (lp->lz); + EGlpNumFreeArray (lp->uz); + EGlpNumFreeArray (lp->cz); + EGlpNumFreeArray (lp->xbz); + EGlpNumFreeArray (lp->piz); + EGlpNumFreeArray (lp->pIpiz); + EGlpNumFreeArray (lp->dz); + EGlpNumFreeArray (lp->pIdz); + EGlpNumFreeArray (lp->pIxbz); + + ILL_IFFREE (lp->vtype, int); + ILL_IFFREE (lp->vclass, char); + + ILLsvector_free (&(lp->zz)); + ILLsvector_free (&(lp->yjz)); + ILLsvector_free (&(lp->zA)); + ILLsvector_free (&(lp->work)); + ILLsvector_free (&(lp->srhs)); + ILLsvector_free (&(lp->ssoln)); + ILL_IFFREE (lp->iwork, int); + ILL_IFFREE (lp->upd.perm, int); + ILL_IFFREE (lp->upd.ix, int); + + EGlpNumFreeArray (lp->upd.t); + + ILL_IFFREE (lp->bfeas, int); + ILL_IFFREE (lp->dfeas, int); + + if (lp->tol) + { + EGlpNumClearVar (lp->tol->pfeas_tol); + EGlpNumClearVar (lp->tol->dfeas_tol); + EGlpNumClearVar (lp->tol->pivot_tol); + EGlpNumClearVar (lp->tol->szero_tol); + EGlpNumClearVar (lp->tol->ip_tol); + EGlpNumClearVar (lp->tol->id_tol); + ILL_IFFREE (lp->tol, tol_struct); + } + if (lp->cnts) + { + EGlpNumClearVar (lp->cnts->y_ravg); + EGlpNumClearVar (lp->cnts->z_ravg); + EGlpNumClearVar (lp->cnts->za_ravg); + ILL_IFFREE (lp->cnts, count_struct); + } + + while (lp->bchanges) + { + binfo = lp->bchanges; + EGlpNumClearVar (binfo->pbound); + EGlpNumClearVar (binfo->cbound); + lp->bchanges = binfo->next; + ILL_IFFREE (binfo, bndinfo); + } + + while (lp->cchanges) + { + cinfo = lp->cchanges; + EGlpNumClearVar (cinfo->pcoef); + EGlpNumClearVar (cinfo->ccoef); + lp->cchanges = cinfo->next; + ILL_IFFREE (cinfo, coefinfo); + } +} + +int build_internal_lpinfo ( + lpinfo * lp) +{ + int rval = 0; + int i, n; + ILLlpdata *qslp = lp->O; + ILLlp_sinfo *S = lp->O->sinfo; + EGlpNum_t *lower, *upper, *obj; + ILLlp_rows lprows; + ILLmatrix *A; + + init_lp_status_info (&(lp->probstat)); + init_lp_status_info (&(lp->basisstat)); + + if (S != 0) + { + lp->nrows = S->nrows; + lp->ncols = S->ncols; + lp->bz = S->rhs; + lower = S->lower; + upper = S->upper; + obj = S->obj; + A = &(S->A); + } + else + { + lp->nrows = qslp->nrows; + lp->ncols = qslp->ncols; + lp->bz = qslp->rhs; + lower = qslp->lower; + upper = qslp->upper; + obj = qslp->obj; + A = &(qslp->A); + } + + lp->matbeg = A->matbeg; + lp->matcnt = A->matcnt; + lp->matind = A->matind; + lp->matval = A->matval; + + lp->nnbasic = lp->ncols - lp->nrows; + + lp->lz = EGlpNumAllocArray (lp->ncols); + lp->cz = EGlpNumAllocArray (lp->ncols); + lp->uz = EGlpNumAllocArray (lp->ncols); + if (!lp->lz || !lp->uz || !lp->cz) + { + fprintf (stderr, "build_internal_lpinfo\n"); + rval = 1; + goto CLEANUP; + } + for (i = 0; i < lp->ncols; i++) + { + EGlpNumCopy (lp->lz[i], lower[i]); + EGlpNumCopy (lp->uz[i], upper[i]); + EGlpNumCopy (lp->cz[i], obj[i]); + if (qslp->objsense == ILL_MAX) + { + EGlpNumSign (lp->cz[i]); + } + } + + if (!lp->O->rA) + { + rval = ILLlp_rows_init (&lprows, lp->O, 1); + CHECKRVALG (rval, CLEANUP); + lp->rowbeg = lprows.rowbeg; + lp->rowcnt = lprows.rowcnt; + lp->rowind = lprows.rowind; + lp->rowval = lprows.rowval; + lp->localrows = 1; + } + else + { + /* row format exists, just use pointers */ + lp->rowbeg = lp->O->rA->rowbeg; + lp->rowcnt = lp->O->rA->rowcnt; + lp->rowind = lp->O->rA->rowind; + lp->rowval = lp->O->rA->rowval; + lp->localrows = 0; + } + + lp->xbz = EGlpNumAllocArray (lp->nrows); + lp->piz = EGlpNumAllocArray (lp->nrows); + lp->dz = EGlpNumAllocArray (lp->nnbasic); + lp->final_phase = -1; + lp->infub_ix = -1; + + ILL_SAFE_MALLOC (lp->vtype, lp->ncols, int); + ILL_SAFE_MALLOC (lp->vclass, lp->ncols, char); + + rval = ILLsvector_alloc (&(lp->zz), lp->nrows); + CHECKRVALG (rval, CLEANUP); + rval = ILLsvector_alloc (&(lp->yjz), lp->nrows); + CHECKRVALG (rval, CLEANUP); + rval = ILLsvector_alloc (&(lp->zA), lp->nnbasic); + CHECKRVALG (rval, CLEANUP); + rval = ILLsvector_alloc (&(lp->work), lp->ncols); + CHECKRVALG (rval, CLEANUP); + rval = ILLsvector_alloc (&(lp->srhs), lp->nrows); + CHECKRVALG (rval, CLEANUP); + rval = ILLsvector_alloc (&(lp->ssoln), lp->nrows); + CHECKRVALG (rval, CLEANUP); + ILL_SAFE_MALLOC (lp->iwork, lp->ncols, int); + + for (i = 0; i < lp->ncols; i++) + { + lp->work.indx[i] = 0; + EGlpNumZero (lp->work.coef[i]); + lp->iwork[i] = 0; + } + n = lp->nrows > lp->ncols ? 2 * (lp->nrows) + 1 : 2 * (lp->ncols) + 1; + lp->upd.t = EGlpNumAllocArray (n); + ILL_SAFE_MALLOC (lp->upd.perm, n, int); + ILL_SAFE_MALLOC (lp->upd.ix, n, int); + + + ILL_SAFE_MALLOC (lp->bfeas, lp->nrows, int); + ILL_SAFE_MALLOC (lp->dfeas, lp->nnbasic, int); + + init_simplex_tols (lp); + ILLfct_init_counts (lp); + + lp->nbchange = 0; + lp->ncchange = 0; + + lp->pIratio = RATIOTEST_HARRIS; + lp->pIIratio = RATIOTEST_HARRIS; + lp->dIratio = RATIOTEST_HARRIS; + lp->dIIratio = RATIOTEST_HARRIS; + lp->starttime = ILLutil_zeit (); + ILLutil_sprand (1, &(lp->rstate)); + +CLEANUP: + if (rval) + free_internal_lpinfo (lp); + EG_RETURN (rval); +} + +int ILLsimplex_retest_psolution ( + lpinfo * lp, + price_info * p, + int phase, + feas_info * fi) +{ + int rval = 0; + int fbid = lp->fbasisid; + int bid = lp->basisid; + EGlpNum_t *ptol = &(lp->tol->pfeas_tol); + EGlpNum_t *dtol = &(lp->tol->dfeas_tol); + EGlpNum_t *iptol = &(lp->tol->ip_tol); + EGlpNum_t *idtol = &(lp->tol->id_tol); + + fi->pstatus = -1; + fi->dstatus = -1; + if (fbid < bid - PARAM_PRIMAL_REFACTORGAP) + { + rval = ILLbasis_refactor (lp); + CHECKRVALG (rval, CLEANUP); + } + if (fbid < bid - PARAM_PRIMAL_RESOLVEGAP) + ILLfct_compute_xbz (lp); + + if (phase == PRIMAL_PHASEII) + { + if (fbid < bid - PARAM_PRIMAL_RESOLVEGAP) + { + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + if (p != NULL && p->p_strategy == COMPLETE_PRICING) + ILLprice_compute_dual_inf (lp, p, NULL, 0, PRIMAL_PHASEII); + } + ILLfct_compute_pobj (lp); + ILLfct_check_pfeasible (lp, fi, *ptol); + ILLfct_check_dfeasible (lp, fi, *dtol); + } + else if (phase == PRIMAL_PHASEI) + { + ILLfct_check_pfeasible (lp, fi, *iptol); + if (fi->pstatus != PRIMAL_FEASIBLE) + { + if (lp->pIpiz) + { + ILLfct_compute_phaseI_piz (lp); + ILLfct_compute_phaseI_dz (lp); + ILLfct_check_pIdfeasible (lp, fi, *idtol); + if (p != NULL && p->p_strategy == COMPLETE_PRICING) + ILLprice_compute_dual_inf (lp, p, NULL, 0, PRIMAL_PHASEI); + } + } + } +CLEANUP: + if (rval == QS_LP_CHANGE_PREC) + { + MESSAGE (__QS_SB_VERB, "Changing precision"); + return rval; + } + EG_RETURN (rval); +} + +int ILLsimplex_retest_dsolution ( + lpinfo * lp, + price_info * p, + int phase, + feas_info * fi) +{ + int rval = 0; + int fbid = lp->fbasisid; + int bid = lp->basisid; + EGlpNum_t *ptol = &(lp->tol->pfeas_tol); + EGlpNum_t *dtol = &(lp->tol->dfeas_tol); + EGlpNum_t *iptol = &(lp->tol->ip_tol); + EGlpNum_t *idtol = &(lp->tol->id_tol); + + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + + fi->pstatus = -1; + fi->dstatus = -1; + if (fbid < bid - PARAM_DUAL_REFACTORGAP) + { + //ILL_IFTRACE("Refactor: %s:%s:%d\n",__func__,__FILE__,__LINE__); + rval = ILLbasis_refactor (lp); + CHECKRVALG (rval, CLEANUP); + } + if (fbid < bid - PARAM_DUAL_RESOLVEGAP) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + } + + if (phase == DUAL_PHASEII) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + if (fbid < bid - PARAM_DUAL_RESOLVEGAP) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + ILLfct_compute_xbz (lp); + CHECKRVALG (rval, CLEANUP); + if (p != NULL) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + if (p->d_strategy == COMPLETE_PRICING) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + ILLprice_compute_primal_inf (lp, p, NULL, 0, DUAL_PHASEII); + } + else + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + ILLprice_update_mpartial_price (lp, p, DUAL_PHASEII, ROW_PRICING); + } + } + } + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + ILLfct_compute_dobj (lp); + ILLfct_check_dfeasible (lp, fi, *dtol); + ILLfct_check_pfeasible (lp, fi, *ptol); + } + else if (phase == DUAL_PHASEI) + { + ILLfct_check_dfeasible (lp, fi, *idtol); + if (fi->dstatus != DUAL_FEASIBLE) + { + ILLfct_compute_phaseI_xbz (lp); + ILLfct_check_pIpfeasible (lp, fi, *iptol); + if (p != NULL) + { + if (p->d_strategy == COMPLETE_PRICING) + ILLprice_compute_primal_inf (lp, p, NULL, 0, DUAL_PHASEI); + else + ILLprice_update_mpartial_price (lp, p, DUAL_PHASEI, ROW_PRICING); + } + } + } +CLEANUP: + EG_RETURN (rval); +} + +int ILLsimplex_solution ( + lpinfo * lp, + EGlpNum_t * xz, + EGlpNum_t * piz, + EGlpNum_t * dz, + EGlpNum_t * objval) +{ + int i, j; + int col; + + if (xz != NULL) + { + if (lp->basisstat.optimal == 0) + { + EG_RETURN (1); + } + for (i = 0; i < lp->nrows; i++) + EGlpNumCopy (xz[lp->baz[i]], lp->xbz[i]); + for (j = 0; j < lp->nnbasic; j++) + { + col = lp->nbaz[j]; + if (lp->vstat[col] == STAT_UPPER) + EGlpNumCopy (xz[col], lp->uz[col]); + else if (lp->vstat[col] == STAT_LOWER) + EGlpNumCopy (xz[col], lp->lz[col]); + else + EGlpNumZero (xz[col]); + } + } + if (piz != NULL) + { + if (lp->basisstat.optimal == 0) + { + EG_RETURN (1); + } + for (i = 0; i < lp->nrows; i++) + EGlpNumCopy (piz[i], lp->piz[i]); + } + if (dz != NULL) + { + if (lp->basisstat.optimal == 0) + { + EG_RETURN (1); + } + for (i = 0; i < lp->nrows; i++) + EGlpNumZero (dz[lp->baz[i]]); + for (j = 0; j < lp->nnbasic; j++) + EGlpNumCopy (dz[lp->nbaz[j]], lp->dz[j]); + } + if (objval != NULL) + EGlpNumCopy (*objval, lp->objval); + return 0; +} + +int ILLsimplex_infcertificate ( + lpinfo * lp, + EGlpNum_t * pi) +{ + int i, col, nz; + char *sense; + EGlpNum_t *x, *l, *u; + lp_status_info *ls; + + if (pi == NULL) + return 0; + + ls = &(lp->basisstat); + if (ls->primal_infeasible == 0 && ls->dual_unbounded == 0) + { + EG_RETURN (1); + } + + if (lp->final_phase == PRIMAL_PHASEI && lp->pIpiz != NULL) + { + for (i = 0; i < lp->nrows; i++) + EGlpNumCopy (pi[i], lp->pIpiz[i]); + } + else if (lp->final_phase == DUAL_PHASEII && lp->infub_ix != -1) + { + col = lp->baz[lp->infub_ix]; + x = &(lp->xbz[lp->infub_ix]); + l = &(lp->lz[col]); + u = &(lp->uz[col]); + + for (i = 0; i < lp->nrows; i++) + EGlpNumZero (pi[i]); + + if (EGlpNumIsNeqq (*l, NINFTY) && EGlpNumIsLess (*x, *l)) + { + for (i = 0, nz = lp->zz.nzcnt; i < nz; i++) + EGlpNumCopyNeg (pi[lp->zz.indx[i]], lp->zz.coef[i]); + } + else + { + for (i = 0, nz = lp->zz.nzcnt; i < nz; i++) + EGlpNumCopy (pi[lp->zz.indx[i]], lp->zz.coef[i]); + } + } + else + { + fprintf (stderr, "Invalid call to inf. certificate routine\n"); + EG_RETURN (1); + } + + sense = lp->O->sense; + for (i = 0; i < lp->nrows; i++) + { + if (sense[i] == 'G' && EGlpNumIsLessZero (pi[i])) + EGlpNumZero (pi[i]); + if (sense[i] == 'L' && EGlpNumIsGreatZero (pi[i])) + EGlpNumZero (pi[i]); + } + return 0; +} + +#if SIMPLEX_DEBUG > 1 +static void test_cert ( + lpinfo * lp, + EGlpNum_t * pi) +{ + int i, j; + int mcnt, mbeg; + EGlpNum_t fsum, sum; + + EGlpNumInitVar (fsum); + EGlpNumInitVar (sum); + EGlpNumZero (fsum); + + for (i = 0; i < lp->nrows; i++) + { + if (lp->O->sense[i] == 'G' && EGlpNumIsLessZero (pi[i])) + printf ("compl \n"); + if (lp->O->sense[i] == 'L' && EGlpNumIsGreatZero (pi[i])) + printf ("compll \n"); + } + + for (i = 0; i < lp->nrows; i++) + EGlpNumAddInnProdTo (fsum, pi[i], lp->bz[i]); + + for (j = 0; j < lp->nnbasic; j++) + { + EGlpNumZero (sum); + mcnt = lp->matcnt[j]; + mbeg = lp->matbeg[j]; + for (i = 0; i < mcnt; i++) + EGlpNumAddInnProdTo (sum, pi[lp->matind[mbeg + i]], lp->matval[mbeg + i]); + + if (EGlpNumIsLess (PFEAS_TOLER, sum) && + (lp->vtype[j] == VLOWER || lp->vtype[j] == VFREE)) + printf ("compl2\n"); + else + { + EGlpNumSign (sum); + if (EGlpNumIsLess (PFEAS_TOLER, sum) && + (lp->vtype[j] == VUPPER || lp->vtype[j] == VFREE)) + printf ("compl1\n"); + EGlpNumSign (sum); + } + + if (EGlpNumIsLessZero (sum) + && (lp->vtype[j] & (VFREE | VUPPER)) == 0) + EGlpNumSubInnProdTo (fsum, sum, lp->lz[j]); + else if (EGlpNumIsGreatZero (sum) + && (lp->vtype[j] & (VFREE | VLOWER)) == 0) + EGlpNumSubInnProdTo (fsum, sum, lp->uz[j]); + } + printf ("fsum = %.8f\n", EGlpNumToLf (fsum)); + EGlpNumClearVar (fsum); + EGlpNumClearVar (sum); +} +#endif + +static void save_paraminfo ( + price_info * pinf, + iter_info * it) +{ + param_info *pr = &(it->oldinfo); + + pr->origalgo = it->algorithm; + pr->pphaseI = pinf->pI_price; + pr->pphaseII = pinf->pII_price; + pr->dphaseI = pinf->dI_price; + pr->dphaseII = pinf->dII_price; + pr->p_strategy = pinf->p_strategy; + pr->d_strategy = pinf->d_strategy; +} + +static void restore_paraminfo ( + iter_info * it, + price_info * pinf) +{ + param_info *pr = &(it->oldinfo); + + it->algorithm = pr->origalgo; + pinf->pI_price = pr->pphaseI; + pinf->pII_price = pr->pphaseII; + pinf->dI_price = pr->dphaseI; + pinf->dII_price = pr->dphaseII; + pinf->p_strategy = pr->p_strategy; + pinf->d_strategy = pr->d_strategy; +} + +int ILLsimplex ( + lpinfo * lp, + int algorithm, + ILLlp_basis * B, + price_info * pinf, + int *status, + int sdisplay, + itcnt_t*itcnt) +{ + int phase = -1; + int singular = -1; + int rval = 0; + int new_price = -1; + svector wz; + svector updz; + feas_info fi; + iter_info it; + + EGlpNumInitVar (fi.totinfeas); + EGlpNumInitVar (it.prevobj); + EGlpNumInitVar (it.objtol); + + it.newphase = -1; + it.nextphase = -1; + it.nextstep = -1; + it.sdisplay = sdisplay; + it.n_pivot_fail = 0; + it.itercnt = 0; + it.n_restart = 0; + it.solstatus = ILL_LP_UNSOLVED; + it.curtime = 0; + it.rounds = 0; + EGlpNumCopy (it.prevobj, INFTY); + it.nosolve = 0; + it.noprog = 0; + EGlpNumCopy (it.objtol, OBJBND_TOLER); + it.chkobj = PARAM_MAX_NOPROG; + it.inner = 0; + it.algorithm = algorithm; + it.pricetype = -1; + it.resumeid = -1; + save_paraminfo (pinf, &it); + +#if SIMPLEX_DEBUG > 0 + if (lp->O->nrows > 1000) + it.sdisplay = 1; +#endif + if (status) + *status = QS_LP_UNSOLVED; + + free_internal_lpinfo (lp); + init_internal_lpinfo (lp); + rval = build_internal_lpinfo (lp); + CHECKRVALG (rval, CLEANUP); + + ILLsvector_init (&wz); + rval = ILLsvector_alloc (&wz, lp->nrows); + CHECKRVALG (rval, CLEANUP); + ILLsvector_init (&updz); + rval = ILLsvector_alloc (&updz, lp->nrows); + CHECKRVALG (rval, CLEANUP); + + if (it.sdisplay) + { + char buffer[256]; + int nonzero = 0; + register int i = lp->ncols; + + while (i--) + nonzero += lp->matcnt[i]; + sprintf (buffer, "starting ILLsimplex on %s...\n", lp->O->probname); + /* depending on LP's reporter + * string is printed to stdout + * or handed to GUI */ + rval = rval || ILLstring_report (buffer, &lp->O->reporter); + printf ("Problem has %d rows and %d cols and %d nonzeros\n", lp->nrows, + lp->ncols, nonzero); + fflush (stdout); + } + ILLfct_set_variable_type (lp); + + if (B != 0) + { + rval = ILLbasis_load (lp, B); + CHECKRVALG (rval, CLEANUP); + if (it.algorithm == DUAL_SIMPLEX) + { + if (B->rownorms) + { + rval = ILLprice_load_rownorms (lp, B->rownorms, pinf); + CHECKRVALG (rval, CLEANUP); + } + else + EGlpNumFreeArray (pinf->dsinfo.norms); + } + else if (it.algorithm == PRIMAL_SIMPLEX) + { + if (B->colnorms) + { + rval = ILLprice_load_colnorms (lp, B->colnorms, pinf); + CHECKRVALG (rval, CLEANUP); + } + else + EGlpNumFreeArray (pinf->psinfo.norms); + } + else if (it.algorithm != PRIMAL_OR_DUAL) + { + fprintf (stderr, "Unknown algorithm %d in ILLsimplex\n", it.algorithm); + rval = 1; + ILL_CLEANUP; + } + } + else if (lp->basisid == -1) + { + if (lp->nrows < 200 && lp->ncols < 400) + rval = ILLbasis_get_initial (lp, it.algorithm); + else + rval = ILLbasis_get_cinitial (lp, it.algorithm); + CHECKRVALG (rval, CLEANUP); + ILLprice_free_pricing_info (pinf); + } + + if (lp->fbasisid != lp->basisid) + { + rval = ILLbasis_factor (lp, &singular); + CHECKRVALG (rval, CLEANUP); + if (singular) + { + MESSAGE (__QS_SB_VERB, "Singular basis found!"); + ILLprice_free_pricing_info (pinf); + } + } + +START: +#if 0 + if (it.resumeid == SIMPLEX_RESUME_UNSHIFT) + fprintf (stderr, "Resuming Unshift\n"); + else if (it.resumeid == SIMPLEX_RESUME_SING) + fprintf (stderr, "Resuming Singular\n"); + else if (it.resumeid == SIMPLEX_RESUME_NUMER) + fprintf (stderr, "Resuming Numer\n"); + else if (it.resumeid != -1) + fprintf (stderr, "Resuming for other reason... %d\n", it.resumeid); +#endif + it.solstatus = ILL_LP_UNSOLVED; + init_lp_status_info (&(lp->basisstat)); + + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + if (it.algorithm == DUAL_SIMPLEX) + { + if (B != NULL || it.resumeid == SIMPLEX_RESUME_UNSHIFT) + ILLfct_dual_adjust (lp, lp->tol->dfeas_tol); + else + ILLfct_dual_adjust (lp, zeroLpNum); + } + ILLfct_compute_xbz (lp); + + ILLfct_check_pfeasible (lp, &fi, lp->tol->pfeas_tol); + ILLfct_check_dfeasible (lp, &fi, lp->tol->dfeas_tol); + ILLfct_set_status_values (lp, fi.pstatus, fi.dstatus, PHASEII, PHASEII); + + if (fi.dstatus == DUAL_FEASIBLE && EGlpNumIsNeqq (lp->objbound, INFTY)) + { + ILLfct_compute_dobj (lp); + if (EGlpNumIsLess (lp->objbound, lp->dobjval)) + { + it.solstatus = ILL_BND_REACHED; + printf ("solstatus = ILL_BND_REACHED = 5 %lf %lf\n", + EGlpNumToLf (lp->objbound), EGlpNumToLf (lp->dobjval)); + goto TERMINATE; + } + } + if (fi.pstatus == PRIMAL_FEASIBLE && fi.dstatus == DUAL_FEASIBLE) + { + it.solstatus = ILL_LP_SOLVED; + ILLfct_compute_pobj (lp); + goto TERMINATE; + } + + if (it.algorithm == PRIMAL_OR_DUAL) + { + if (fi.pstatus == PRIMAL_FEASIBLE) + it.algorithm = PRIMAL_SIMPLEX; + else if (fi.dstatus == DUAL_FEASIBLE) + it.algorithm = DUAL_SIMPLEX; + else if (EGlpNumToLf (lp->pinfeas) < 10 * EGlpNumToLf (lp->dinfeas)) + it.algorithm = PRIMAL_SIMPLEX; + else + it.algorithm = DUAL_SIMPLEX; + } + + if (it.algorithm == PRIMAL_SIMPLEX) + { + if (fi.pstatus == PRIMAL_FEASIBLE) + phase = PRIMAL_PHASEII; + else + phase = PRIMAL_PHASEI; + } + else if (it.algorithm == DUAL_SIMPLEX) + { + if (fi.dstatus == DUAL_FEASIBLE) + phase = DUAL_PHASEII; + else + phase = DUAL_PHASEI; + } + + rval = ILLprice_build_pricing_info (lp, pinf, phase); + CHECKRVALG (rval, CLEANUP); + + it.newphase = SIMPLEX_PHASE_NEW; + it.nextstep = SIMPLEX_CONTINUE; + + while (it.nextstep == SIMPLEX_CONTINUE) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + + if (phase == PRIMAL_PHASEI) + { + rval = primal_phaseI_step (lp, pinf, &updz, &wz, &it); + CHECKRVALG (rval, CLEANUP); + } + + else if (phase == PRIMAL_PHASEII) + { + rval = primal_phaseII_step (lp, pinf, &updz, &wz, &it); + CHECKRVALG (rval, CLEANUP); + } + + else if (phase == DUAL_PHASEI) + { + rval = dual_phaseI_step (lp, pinf, &updz, &wz, &it); + CHECKRVALG (rval, CLEANUP); + } + + else if (phase == DUAL_PHASEII) + { + rval = dual_phaseII_step (lp, pinf, &updz, &wz, &it); + CHECKRVALG (rval, CLEANUP); + } + if (it.nextstep == SIMPLEX_RESUME) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + ILLprice_free_pricing_info (pinf); + if (it.resumeid == SIMPLEX_RESUME_UNSHIFT) + { + if (it.pricetype == QS_PRICE_PDEVEX) + { + pinf->pI_price = QS_PRICE_PDEVEX; + pinf->pII_price = QS_PRICE_PDEVEX; + } + else if (it.pricetype == QS_PRICE_DDEVEX) + { + pinf->dI_price = QS_PRICE_DDEVEX; + pinf->dII_price = QS_PRICE_DDEVEX; + } + } + else if (it.resumeid == SIMPLEX_RESUME_NUMER) + { + ILLfct_unroll_bound_change (lp); + ILLfct_unroll_coef_change (lp); + /* we are disabling re-do under this circunstances ! */ + rval = ILLbasis_get_initial (lp, it.algorithm); + CHECKRVALG (rval, CLEANUP); + rval = ILLbasis_factor (lp, &singular); + if (singular) + MESSAGE (__QS_SB_VERB, "Singular basis found!"); + CHECKRVALG (rval, CLEANUP); + } + it.pricetype = -1; + if (it.n_restart > SIMPLEX_MAX_RESTART) + { + it.solstatus = ILL_MAX_ITER; + goto LIMIT_TERMINATE; + } + goto START; + } + else if (it.nextstep == SIMPLEX_CONTINUE) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + it.itercnt++; + + if (it.nextphase != phase) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + it.newphase = SIMPLEX_PHASE_NEW; + phase = it.nextphase; + new_price = ILLprice_get_price (pinf, phase); + + if (pinf->cur_price != new_price) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + ILLprice_free_pricing_info (pinf); + rval = ILLprice_build_pricing_info (lp, pinf, phase); + CHECKRVALG (rval, CLEANUP); + } + } + } + } + +#if SIMPLEX_DEBUG > 0 + ILLfct_print_counts (lp); +#endif +LIMIT_TERMINATE: + rval = terminate_simplex (lp, phase, &it); + CHECKRVALG (rval, CLEANUP); + +TERMINATE: + restore_paraminfo (&it, pinf); + + if (it.sdisplay) + { + printf ("completed ILLsimplex\n"); + printf ("%s: ", lp->O->probname); + fflush (stdout); + } + + if (status) + { + if (it.solstatus == ILL_MAX_ITER) + { + *status = QS_LP_ITER_LIMIT; + } + else if (it.solstatus == ILL_MAX_TIME) + { + *status = QS_LP_TIME_LIMIT; + } + else if (it.solstatus == ILL_LP_ABORTED) + { + *status = QS_LP_ABORTED; + } + else if (it.solstatus == ILL_PPHASEI_ERROR || + it.solstatus == ILL_PPHASEII_ERROR || + it.solstatus == ILL_DPHASEI_ERROR || + it.solstatus == ILL_DPHASEII_ERROR) + { + *status = QS_LP_NUMERR; + } + else if(it.solstatus == ILL_LP_UNSOLVED) + { + *status = QS_LP_UNSOLVED; + } + else if (it.solstatus == ILL_BND_REACHED) + { + *status = QS_LP_OBJ_LIMIT; + } + else if (it.solstatus == ILL_LP_SOLVED) + { + if (lp->basisstat.optimal) + { + *status = QS_LP_OPTIMAL; + } + else if (lp->basisstat.primal_infeasible || lp->basisstat.dual_unbounded) + { + *status = QS_LP_INFEASIBLE; + if (it.sdisplay) + { + if (lp->basisstat.primal_infeasible) + fprintf (stdout, "Primal Infeasible\n"); + else + fprintf (stdout, "Dual Unbounded\n"); + } + } + else if (lp->basisstat.primal_unbounded) + { + *status = QS_LP_UNBOUNDED; + } + } + else + { + fprintf (stderr, "unknown solution status in ILLsimplex %d\n", + it.solstatus); + rval = 1; + CHECKRVALG (rval, CLEANUP); + } + } + +#if SIMPLEX_DEBUG > 1 + { + int rva = 0; + EGlpNum_t *pi = NULL; + + pi = EGlpNumAllocArray (lp->nrows); + rva = ILLsimplex_infcertificate (lp, pi); + printf ("rva = %d\n", rva); + if (!rva) + { + test_cert (lp, pi); + } + EGlpNumFreeArray (pi); + } +#endif + /* update counter */ + itcnt->pI_iter += lp->cnts->pI_iter; + itcnt->pII_iter += lp->cnts->pII_iter; + itcnt->dI_iter += lp->cnts->dI_iter; + itcnt->dII_iter += lp->cnts->dII_iter; + itcnt->tot_iter = itcnt->pI_iter + itcnt->pII_iter + itcnt->dI_iter + + itcnt->dII_iter; + /* end update */ + if (it.sdisplay) + { + int bstat = 0; + + printf ("time = %.3f, pI = %d, pII = %d, dI = %d, dII = %d, ", + ILLutil_zeit () - lp->starttime, lp->cnts->pI_iter, + lp->cnts->pII_iter, lp->cnts->dI_iter, lp->cnts->dII_iter); + fflush (stdout); + get_current_stat (&(lp->basisstat), it.algorithm, &bstat); + switch (bstat) + { + case OPTIMAL: + printf ("opt = %f\n", EGlpNumToLf (lp->objval)); + break; + case PRIMAL_INFEASIBLE: + printf ("no primal soln\n"); + break; + case PRIMAL_UNBOUNDED: + printf ("primal unbounded\n"); + break; + case PRIMAL_FEASIBLE: + printf ("primal obj = %f\n", EGlpNumToLf (lp->pobjval)); + break; + case DUAL_INFEASIBLE: + printf ("no dual soln\n"); + break; + case DUAL_UNBOUNDED: + printf ("dual unbounded\n"); + break; + case DUAL_FEASIBLE: + printf ("dual obj = %f\n", EGlpNumToLf (lp->dobjval)); + break; + } + fflush (stdout); + + if (it.sdisplay > 1) + { + if (it.algorithm == PRIMAL_SIMPLEX && pinf->pI_price == QS_PRICE_PDEVEX) + printf ("Devex norms initialised %d times\n", pinf->pdinfo.ninit); + fflush (stdout); + } + } + +CLEANUP: + ILLsvector_free (&wz); + ILLsvector_free (&updz); + EGlpNumClearVar (it.prevobj); + EGlpNumClearVar (it.objtol); + EGlpNumClearVar (fi.totinfeas); + if (rval == QS_LP_CHANGE_PREC) + { + MESSAGE (__QS_SB_VERB, "Changing precision"); + return rval; + } + else + { + MESSAGE (rval ? 0 : 1000, "Error code %d", rval); + EG_RETURN (rval); + } +} + +static int terminate_simplex ( + lpinfo * lp, + int phase, + iter_info * it) +{ + int rval = 0; + int sphase; + feas_info fi; + + EGlpNumInitVar (fi.totinfeas); + + if (it->solstatus != ILL_MAX_TIME && it->solstatus != ILL_MAX_ITER) + ILL_CLEANUP; + + if (it->algorithm == PRIMAL_SIMPLEX) + { + if (lp->nbchange != 0) + { + if (it->sdisplay > 1) + { + printf ("unrolling %d bound shifts\n", lp->nbchange); + fflush (stdout); + } + ILLfct_unroll_bound_change (lp); + } + rval = ILLsimplex_retest_psolution (lp, NULL, phase, &fi); + CHECKRVALG (rval, CLEANUP); + + sphase = (phase == PRIMAL_PHASEI) ? PHASEI : PHASEII; + ILLfct_set_status_values (lp, fi.pstatus, fi.dstatus, PHASEII, sphase); + } + else if (it->algorithm == DUAL_SIMPLEX) + { + if (lp->ncchange != 0) + { + if (it->sdisplay > 1) + { + printf ("unrolling %d coef shifts\n", lp->ncchange); + fflush (stdout); + } + ILLfct_unroll_coef_change (lp); + } + rval = ILLsimplex_retest_dsolution (lp, NULL, phase, &fi); + CHECKRVALG (rval, CLEANUP); + + sphase = (phase == DUAL_PHASEI) ? PHASEI : PHASEII; + ILLfct_set_status_values (lp, fi.pstatus, fi.dstatus, sphase, PHASEII); + } + +CLEANUP: + EGlpNumClearVar (fi.totinfeas); + EG_RETURN (rval); +} + +static int test_progress ( + EGlpNum_t objval, + EGlpNum_t prevobj) +{ + EGlpNum_t denom; + + EGlpNumInitVar (denom); + EGlpNumCopyDiff (denom, objval, prevobj); + if (EGlpNumIsNeqZero (objval, PROGRESS_ZERO)) + EGlpNumDivTo (denom, objval); + if (!EGlpNumIsNeqZero (denom, PROGRESS_THRESH)) + { + EGlpNumClearVar (denom); + return 0; + } + else + { + EGlpNumClearVar (denom); + return 1; + } +} + +static void monitor_iter ( + lpinfo * lp, + price_info * p, + iter_info * it, + int phase) +{ + EGlpNum_t print_val; + double tottime = ILLutil_zeit () - lp->starttime; + int curtime = ILLutil_our_floor (tottime); /* MONIKA */ + char print_str[20]; + feas_info fi; + int aborted = 0; + + EGlpNumInitVar (print_val); + EGlpNumInitVar (fi.totinfeas); + EGlpNumZero (fi.totinfeas); + EGlpNumZero (print_val); + + /* one of the following two time display mechanisms */ + switch (phase) + { + case PRIMAL_PHASEI: + EGlpNumCopy (print_val, lp->pinfeas); + EGlpNumAddTo (fi.totinfeas, lp->pinfeas); + strcpy (print_str, "primal infeas"); + if (EGlpNumIsLessZero (lp->pinfeas) && + (EGlpNumIsNeqZero (lp->pinfeas, oneLpNum))) + { + /*printf ("Negative Infeasibility! Imposible %lg %la, iter %d\n", + * EGlpNumToLf (print_val), EGlpNumToLf (print_val), it->itercnt); + */ + //exit(1); + } + break; + case PRIMAL_PHASEII: + EGlpNumCopy (print_val, lp->pobjval); + strcpy (print_str, "primal objval"); + break; + case DUAL_PHASEI: + EGlpNumCopy (print_val, lp->dinfeas); + EGlpNumAddTo (fi.totinfeas, lp->dinfeas); + strcpy (print_str, "dual infeas"); + break; + case DUAL_PHASEII: + EGlpNumCopy (print_val, lp->dobjval); + strcpy (print_str, "dual objval"); + break; + } + + aborted = report_value (lp, it, print_str, print_val); + /*if (it->sdisplay && it->itercnt % lp->iterskip == 0) { + * // printf ("(%d): %s = %f\n", it->itercnt, print_str, print_val); + * // fflush (stdout); + * } */ + if (curtime != it->curtime) + { + it->curtime = curtime; + /* + * if (it->sdisplay){ + * printf ("time = %d.0, ", curtime); + * printf ("(%d): %s = %f\n", it->itercnt, print_str, print_val); + * fflush (stdout); + * } + */ + } + + EGlpNumAddUiTo (fi.totinfeas, 1000); + if (EGlpNumIsLessZero (fi.totinfeas)) + { + it->nextstep = SIMPLEX_TERMINATE; + it->solstatus = ILL_MAX_ITER; + MESSAGE (it->sdisplay ? 0 : __QS_SB_VERB, + "early finish by excess infeasibility"); + ILL_CLEANUP; + } + + if (phase == DUAL_PHASEII && EGlpNumIsNeqq (lp->objbound, INFTY)) + { + /*if (lp->dobjval > lp->objbound + it->objtol) */ + EGlpNumCopyDiff (print_val, lp->dobjval, lp->objbound); + if (EGlpNumIsLess (it->objtol, print_val)) + { + ILLfct_unroll_coef_change (lp); + ILLfct_check_dfeasible (lp, &fi, lp->tol->dfeas_tol); + ILLfct_set_status_values (lp, -1, fi.dstatus, -1, PHASEII); + + if (fi.dstatus == DUAL_FEASIBLE) + { + ILLfct_compute_dobj (lp); + if (EGlpNumIsLess (lp->objbound, lp->dobjval)) + { + it->solstatus = ILL_BND_REACHED; + it->nextstep = SIMPLEX_TERMINATE; + /*if (it->sdisplay) */ + { + printf ("bound reached %lf %lf\n", EGlpNumToLf (lp->objbound), + EGlpNumToLf (lp->dobjval)); + fflush (stdout); + } + } + else + EGlpNumMultUiTo (it->objtol, 10); + } + else + { + it->nextphase = DUAL_PHASEI; + it->newphase = SIMPLEX_PHASE_NEW; + EGlpNumMultUiTo (it->objtol, 5); + } + } + } + if (it->itercnt >= lp->maxiter) + { + it->solstatus = ILL_MAX_ITER; + it->nextstep = SIMPLEX_TERMINATE; + if (it->sdisplay) + { + printf ("iter limit reached\n"); + fflush (stdout); + } + ILL_CLEANUP; + } + else if (tottime >= lp->maxtime) + { + it->solstatus = ILL_MAX_TIME; + it->nextstep = SIMPLEX_TERMINATE; + if (it->sdisplay) + { + printf ("time limit reached\n"); + fflush (stdout); + } + ILL_CLEANUP; + } + else if (aborted) + { + it->solstatus = ILL_LP_ABORTED; + it->nextstep = SIMPLEX_TERMINATE; + if (it->sdisplay) + { + printf ("aborted\n"); + fflush (stdout); + } + ILL_CLEANUP; + } + /* why is this commented out? */ + if(0){ + if (it->rounds && it->inner){ + it->inner --; + if (it->inner == 0){ + printf ("restoring ..\n"); + restore_paraminfo (it, p); + it->newphase = SIMPLEX_PHASE_NEW; + it->nextstep = SIMPLEX_RESUME; + /*it->resumeid = SIMPLEX_RESUME_OUTER;*/ + ILL_CLEANUP; + } + } + } + if (phase == DUAL_PHASEII) + { + if (it->noprog > it->chkobj) + { + ILLfct_perturb_coefs (lp); + it->noprog = 0; + EGlpNumCopy (it->prevobj, lp->dobjval); + } + } + else if (phase == PRIMAL_PHASEII) + { + if (it->noprog > it->chkobj) + { + ILLfct_perturb_bounds (lp); + it->noprog = 0; + EGlpNumCopy (it->prevobj, lp->pobjval); + } + } + else if (phase == PRIMAL_PHASEI) + { + if (it->noprog > it->chkobj) + { + it->algorithm = DUAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_NUMER; + /* this is to force to exit in the case of bad basis */ + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + it->n_restart++; + //fprintf(stderr,"Resume Numerical %s:%s:%d\n",__func__,__FILE__,__LINE__); + } + } + else if (phase == DUAL_PHASEI) + { + if (it->noprog > it->chkobj) + { + it->algorithm = PRIMAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_NUMER; + /* this is to force to exit in the case of bad basis */ + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + it->n_restart++; + //fprintf(stderr,"Resume Numerical %s:%s:%d\n",__func__,__FILE__,__LINE__); + } + } +CLEANUP: + EGlpNumClearVar (fi.totinfeas); + EGlpNumClearVar (print_val); + return; +} + +static int primal_phaseI_step ( + lpinfo * lp, + price_info * pinf, + svector * updz, + svector * wz, + iter_info * it) +{ + int rval = 0; + int singular = 0; + int refactor = 0; + int cphase = PRIMAL_PHASEI; + EGlpNum_t alpha; + feas_info fi; + ratio_res rs; + price_res pr; + + EGlpNumInitVar (alpha); + EGlpNumInitVar (fi.totinfeas); + EGlpNumInitVar (pr.dinfeas); + EGlpNumInitVar (pr.pinfeas); + EGlpNumInitVar (rs.tz); + EGlpNumInitVar (rs.lbound); + EGlpNumInitVar (rs.ecoeff); + EGlpNumInitVar (rs.pivotval); + EGlpNumZero (alpha); + + ILLfct_update_counts (lp, CNT_PPHASE1ITER, 0, zeroLpNum); + it->nextstep = SIMPLEX_CONTINUE; + it->nextphase = PRIMAL_PHASEI; + lp->final_phase = PRIMAL_PHASEI; + it->nosolve++; + + if (it->newphase != 0) + { + ILLfct_check_pfeasible (lp, &fi, lp->tol->ip_tol); + if (it->newphase == SIMPLEX_PHASE_NEW) + { + it->noprog = 0; + if (it->sdisplay) + { + printf ("starting primal phase I, nosolve %d\n", it->nosolve); + fflush (stdout); + } + } + it->newphase = 0; + it->nosolve = 0; + EGlpNumCopy (it->prevobj, lp->pinfeas); + lp->pIpiz = EGlpNumAllocArray (lp->nrows); + lp->pIdz = EGlpNumAllocArray (lp->nnbasic); + + ILLfct_compute_phaseI_piz (lp); + if (pinf->p_strategy == COMPLETE_PRICING) + { + ILLfct_compute_phaseI_dz (lp); +#if USEHEAP > 0 + ILLprice_free_heap (pinf); +#endif + ILLprice_compute_dual_inf (lp, pinf, NULL, 0, PRIMAL_PHASEI); +#if USEHEAP > 0 + rval = ILLprice_test_for_heap (lp, pinf, lp->nnbasic, pinf->d_scaleinf, + PRIMAL_SIMPLEX, 0); + CHECKRVALG (rval, CLEANUP); +#endif + } + else if (pinf->p_strategy == MULTI_PART_PRICING) + ILLprice_init_mpartial_price (lp, pinf, cphase, COL_PRICING); + } + + monitor_iter (lp, pinf, it, cphase); + if (it->nextstep == SIMPLEX_TERMINATE || it->nextstep == SIMPLEX_RESUME || + it->newphase != 0) + ILL_CLEANUP; + + ILLprice_primal (lp, pinf, &pr, cphase); + ILL_IFTRACE2 ("%s:after_price\n", __func__); + + if (pr.price_stat == PRICE_OPTIMAL) + { + if (it->sdisplay > 1) + { + printf ("primal phase I seemingly done\n"); + printf ("retesting soln\n"); + fflush (stdout); + } + rval = ILLsimplex_retest_psolution (lp, pinf, cphase, &fi); + + CHECKRVALG (rval, CLEANUP); + ILLfct_set_status_values (lp, fi.pstatus, fi.dstatus, PHASEII, PHASEI); + + if (fi.pstatus == PRIMAL_FEASIBLE) + { + it->nextphase = PRIMAL_PHASEII; + } + else if (fi.dstatus == DUAL_FEASIBLE) + { + it->solstatus = ILL_LP_SOLVED; + it->nextstep = SIMPLEX_TERMINATE; + } + ILL_CLEANUP; + } + + ILLfct_compute_yz (lp, &(lp->yjz), updz, lp->nbaz[pr.eindex]); + ILLfct_update_counts (lp, CNT_YNZ, lp->yjz.nzcnt, zeroLpNum); + ILLfct_update_counts (lp, CNT_UPNZ, updz->nzcnt, zeroLpNum); + + ILLratio_pI_test (lp, pr.eindex, pr.dir, &rs); + //ILL_IFTRACE(":%d",rs.lindex); + + if (rs.ratio_stat == RATIO_FAILED) + { + /* + * rval = E_SIMPLEX_ERROR; + * it->solstatus = ILL_PPHASEI_ERROR; + */ + //ILL_IFTRACE("ratio_failed\n"); + it->algorithm = DUAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_NUMER; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Numerical %s:%s:%d\n",__func__,__FILE__,__LINE__); + ILL_CLEANUP; + } + else if (rs.ratio_stat == RATIO_NEGATIVE) + { + EGlpNum_t itol; + + EGlpNumInitVar (itol); + //ILL_IFTRACE("ratio_negative\n"); + EGlpNumCopy (itol, lp->tol->ip_tol); + EGlpNumZero (lp->tol->ip_tol); + EGlpNumAddTo (lp->pinfeas, lp->upd.c_obj); + if (!test_progress (lp->pinfeas, it->prevobj)) + it->noprog++; + else + { + EGlpNumCopy (it->prevobj, lp->pinfeas); + it->noprog = 0; + } + ILLfct_update_pfeas (lp, rs.lindex, &(lp->srhs)); + EGlpNumCopy (lp->tol->ip_tol, itol); + ILLfct_compute_ppIzz (lp, &(lp->srhs), &(lp->ssoln)); + ILLfct_update_ppI_prices (lp, pinf, &(lp->srhs), &(lp->ssoln), pr.eindex, + rs.lindex, zeroLpNum); + EGlpNumClearVar (itol); + } + else if (rs.ratio_stat == RATIO_NOBCHANGE) + { + //ILL_IFTRACE("ratio_nobchange\n"); + EGlpNumAddTo (lp->pinfeas, lp->upd.c_obj); + if (!test_progress (lp->pinfeas, it->prevobj)) + it->noprog++; + else + { + EGlpNumCopy (it->prevobj, lp->pinfeas); + it->noprog = 0; + } + + //ILL_IFTRACE("%s:a\n",__func__); + ILLfct_update_xz (lp, rs.tz, pr.eindex, rs.lindex); + ILLfct_update_pfeas (lp, rs.lindex, &(lp->srhs)); + ILLfct_compute_ppIzz (lp, &(lp->srhs), &(lp->ssoln)); + ILLfct_update_basis_info (lp, pr.eindex, rs.lindex, rs.lvstat); +#if DENSE_PI > 0 + fct_test_workvector (lp); + fct_test_pfeasible (lp); +#endif + ILLfct_update_ppI_prices (lp, pinf, &(lp->srhs), &(lp->ssoln), pr.eindex, + rs.lindex, zeroLpNum); + } + else if (rs.ratio_stat == RATIO_BCHANGE) + { + //ILL_IFTRACE("ratio_bchange\n"); + EGlpNumCopyFrac (alpha, lp->pIdz[pr.eindex], rs.pivotval); + EGlpNumAddTo (lp->pinfeas, lp->upd.c_obj); + + if (!test_progress (lp->pinfeas, it->prevobj)) + { + if (lp->vtype[lp->nbaz[pr.eindex]] == VFREE || + lp->vtype[lp->baz[rs.lindex]] == VARTIFICIAL) + { + if (it->noprog > 0) + it->noprog--; + } + else + it->noprog++; + } + else + { + EGlpNumCopy (it->prevobj, lp->pinfeas); + it->noprog = 0; + } + + ILLfct_compute_zz (lp, &(lp->zz), rs.lindex); + ILLfct_update_counts (lp, CNT_ZNZ, lp->zz.nzcnt, zeroLpNum); + if (pinf->p_strategy == COMPLETE_PRICING) + { + //ILL_IFTRACE("%s:a\n",__func__); + ILLfct_compute_zA (lp, &(lp->zz), &(lp->zA)); + ILLfct_update_counts (lp, CNT_ZANZ, lp->zA.nzcnt, zeroLpNum); + + if (pinf->pI_price == QS_PRICE_PSTEEP) + { + ILLfct_compute_psteep_upv (lp, wz); + } + } + + rval = + ILLprice_update_pricing_info (lp, pinf, cphase, wz, pr.eindex, rs.lindex, + rs.pivotval); + CHECKRVALG (rval, CLEANUP); + + //ILL_IFTRACE("%s:b:%d\n",__func__,rs.lindex); + ILLfct_update_xz (lp, rs.tz, pr.eindex, rs.lindex); + ILLfct_update_pfeas (lp, rs.lindex, &(lp->srhs)); + //ILL_IFTRACE("%s:%d:%d\n",__func__,rs.lindex,lp->srhs.nzcnt); + ILLfct_compute_ppIzz (lp, &(lp->srhs), &(lp->ssoln)); + ILLfct_update_basis_info (lp, pr.eindex, rs.lindex, rs.lvstat); +#if DENSE_PI > 0 + fct_test_workvector (lp); + fct_test_pfeasible (lp); +#endif + rval = ILLbasis_update (lp, updz, rs.lindex, &refactor, &singular); + CHECKRVALG (rval, CLEANUP); + + if (singular) + { + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_SING; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Singular %s:%s:%d\n",__func__,__FILE__,__LINE__); + ILL_CLEANUP; + } + if (!refactor) + { + ILLfct_update_ppI_prices (lp, pinf, &(lp->srhs), &(lp->ssoln), pr.eindex, + rs.lindex, alpha); + } + if (refactor != 0 || it->nosolve > PARAM_MAX_NOSOLVE) + { + ILLfct_compute_xbz (lp); + ILLfct_check_pfeasible (lp, &fi, lp->tol->ip_tol); + ILLfct_set_status_values (lp, fi.pstatus, -1, PHASEII, -1); + if (fi.pstatus == PRIMAL_FEASIBLE) + it->nextphase = PRIMAL_PHASEII; + + it->newphase = SIMPLEX_PHASE_RECOMP; + ILL_CLEANUP; + } + } + +#if DENSE_PI > 1 + fct_test_workvector (lp); + fct_test_pi_dz (lp, pinf); +#endif + +CLEANUP: + if (it->nextphase != PRIMAL_PHASEI || it->nextstep == SIMPLEX_RESUME || + it->newphase != 0 || rval != 0) + { + EGlpNumFreeArray (lp->pIpiz); + EGlpNumFreeArray (lp->pIdz); + } + EGlpNumClearVar (alpha); + EGlpNumClearVar (fi.totinfeas); + EGlpNumClearVar (pr.dinfeas); + EGlpNumClearVar (pr.pinfeas); + EGlpNumClearVar (rs.tz); + EGlpNumClearVar (rs.lbound); + EGlpNumClearVar (rs.ecoeff); + EGlpNumClearVar (rs.pivotval); + //EG_RETURN(rval); + return rval; +} + +static int primal_phaseII_step ( + lpinfo * lp, + price_info * pinf, + svector * updz, + svector * wz, + iter_info * it) +{ + int boundch; + int rval = 0; + int bndtype = 0; + int singular = 0; + int refactor = 0; + int ratio_iter = 0; + int cphase = PRIMAL_PHASEII; + EGlpNum_t lbound; + EGlpNum_t alpha; + feas_info fi; + ratio_res rs; + price_res pr; + + EGlpNumInitVar (alpha); + EGlpNumInitVar (lbound); + EGlpNumInitVar (fi.totinfeas); + EGlpNumInitVar (pr.dinfeas); + EGlpNumInitVar (pr.pinfeas); + EGlpNumInitVar (rs.tz); + EGlpNumInitVar (rs.lbound); + EGlpNumInitVar (rs.ecoeff); + EGlpNumInitVar (rs.pivotval); + + ILLfct_update_counts (lp, CNT_PPHASE2ITER, 0, zeroLpNum); + it->nextstep = SIMPLEX_CONTINUE; + it->nextphase = PRIMAL_PHASEII; + lp->final_phase = PRIMAL_PHASEII; + it->nosolve++; + + if (it->newphase != 0) + { + ILLfct_compute_pobj (lp); + if (it->newphase == SIMPLEX_PHASE_NEW) + { + it->noprog = 0; + if (it->sdisplay) + { + printf ("starting primal phase II, nosolve %d\n", it->nosolve); + fflush (stdout); + } + } + it->newphase = 0; + it->nosolve = 0; + EGlpNumCopy (it->prevobj, lp->pobjval); + ILLfct_compute_piz (lp); + if (pinf->p_strategy == COMPLETE_PRICING) + { + ILLfct_compute_dz (lp); +#if USEHEAP > 0 + ILLprice_free_heap (pinf); +#endif + ILLprice_compute_dual_inf (lp, pinf, NULL, 0, PRIMAL_PHASEII); +#if USEHEAP > 0 + rval = ILLprice_test_for_heap (lp, pinf, lp->nnbasic, pinf->d_scaleinf, + PRIMAL_SIMPLEX, 0); + CHECKRVALG (rval, CLEANUP); +#endif + } + else if (pinf->p_strategy == MULTI_PART_PRICING) + { + ILLprice_init_mpartial_price (lp, pinf, cphase, COL_PRICING); + } + } + + monitor_iter (lp, pinf, it, cphase); + if (it->nextstep == SIMPLEX_TERMINATE || it->nextstep == SIMPLEX_RESUME || + it->newphase != 0) + ILL_CLEANUP; + + ILLprice_primal (lp, pinf, &pr, cphase); + + if (pr.price_stat == PRICE_OPTIMAL) + { + //ILL_IFTRACE("%s:PRICE_OPTIMAL\n",__func__); + if (lp->nbchange != 0) + { + if (it->sdisplay > 1) + { + printf ("unrolling %d bound shifts\n", lp->nbchange); + fflush (stdout); + } + ILLfct_unroll_bound_change (lp); + ILLfct_check_pfeasible (lp, &fi, lp->tol->pfeas_tol); + ILLfct_set_status_values (lp, fi.pstatus, -1, PHASEII, -1); + + /*HHH*/ ILLfct_check_dfeasible (lp, &fi, lp->tol->dfeas_tol); + /*HHH* printf ("primal (opt) infeas %.6f\n", lp->pinfeas); fflush (stdout); + *HHH* printf ("dual (opt) infeas %.6f\n", lp->dinfeas); fflush (stdout);*/ + + if (fi.pstatus != PRIMAL_FEASIBLE) + { + it->algorithm = DUAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_UNSHIFT; + it->pricetype = QS_PRICE_DDEVEX; + /* this is to force to exit in the case of bad basis */ + //fprintf(stderr,"Resume Unshift %s:%s:%d\n",__func__,__FILE__,__LINE__); + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + it->n_restart++; + ILL_CLEANUP; + /* + * it->nextphase = PRIMAL_PHASEI; + * lp->tol->ip_tol /= 5.0; + * lp->tol->id_tol /= 5.0; + * ILL_CLEANUP; + */ + } + } + + if (it->sdisplay > 1) + { + printf ("problem seemingly solved\n"); + printf ("seemingly opt = %f\nretesting soln\n", + EGlpNumToLf (lp->pobjval)); + fflush (stdout); + } + rval = ILLsimplex_retest_psolution (lp, pinf, cphase, &fi); + CHECKRVALG (rval, CLEANUP); + ILLfct_set_status_values (lp, fi.pstatus, fi.dstatus, PHASEII, PHASEII); + + if (fi.pstatus == PRIMAL_INFEASIBLE) + { + it->nextphase = PRIMAL_PHASEI; + EGlpNumDivUiTo (lp->tol->ip_tol, 5); + EGlpNumDivUiTo (lp->tol->id_tol, 5); + ILL_IFTRACE ("%s:PINF:%lg\n", __func__, EGlpNumToLf (lp->tol->ip_tol)); + } + else if (fi.dstatus == DUAL_FEASIBLE) + { + //ILL_IFTRACE("%s:PFEAS_DFEAS\n",__func__); + it->solstatus = ILL_LP_SOLVED; + EGlpNumCopy (lp->objval, lp->pobjval); + it->nextstep = SIMPLEX_TERMINATE; + } + else + ILL_IFTRACE ("%s:DINF:%la:%lf\n", __func__, EGlpNumToLf (lp->dinfeas), + EGlpNumToLf (lp->dinfeas)); + ILL_CLEANUP; + } + + ILLfct_compute_yz (lp, &(lp->yjz), updz, lp->nbaz[pr.eindex]); + ILLfct_update_counts (lp, CNT_YNZ, lp->yjz.nzcnt, zeroLpNum); + ILLfct_update_counts (lp, CNT_UPNZ, updz->nzcnt, zeroLpNum); + ratio_iter = 0; + do + { + ILLratio_pII_test (lp, pr.eindex, pr.dir, &rs); + //ILL_IFTRACE("all:%d",rs.lindex); + EGlpNumCopy (lbound, rs.lbound); + boundch = rs.boundch; + ratio_iter++; + + if (boundch) + { + /* + * if (ratio_iter > PARAM_PRATIOTESTS){ + * lbound = lp->xbz[rs.lindex]; + * boundch = 0; + * } + */ + boundch = 0; + bndtype = (rs.lvstat == STAT_UPPER) ? BOUND_UPPER : BOUND_LOWER; + rval = ILLfct_bound_shift (lp, lp->baz[rs.lindex], bndtype, lbound); + CHECKRVALG (rval, CLEANUP); + } + } while (boundch); + + if (rs.ratio_stat == RATIO_FAILED) + { + //ILL_IFTRACE(":%d",rs.lindex); + /* + * rval = E_SIMPLEX_ERROR; + * it->solstatus = ILL_PPHASEII_ERROR; + */ + it->algorithm = DUAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_NUMER; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Numerical %s:%s:%d\n",__func__,__FILE__,__LINE__); + ILL_CLEANUP; + } + else if (rs.ratio_stat == RATIO_UNBOUNDED) + { + //ILL_IFTRACE(":%d",rs.lindex); + if (lp->nbchange != 0) + { + if (it->sdisplay > 1) + { + printf ("unrolling %d bound shifts\n", lp->nbchange); + fflush (stdout); + } + ILLfct_unroll_bound_change (lp); + } + ILLfct_set_status_values (lp, PRIMAL_UNBOUNDED, -1, PHASEII, -1); + it->solstatus = ILL_LP_SOLVED; + it->nextstep = SIMPLEX_TERMINATE; + ILL_CLEANUP; + } + else if (rs.ratio_stat == RATIO_NOBCHANGE) + { + //ILL_IFTRACE(":%d",rs.lindex); + EGlpNumAddInnProdTo (lp->pobjval, rs.tz, lp->dz[pr.eindex]); + EGlpNumCopy (lp->objval, lp->pobjval); + if (!test_progress (lp->pobjval, it->prevobj)) + it->noprog++; + else + { + EGlpNumCopy (it->prevobj, lp->pobjval); + it->noprog = 0; + } + + //ILL_IFTRACE("%s:c:%d\n",__func__,rs.lindex); + ILLfct_update_xz (lp, rs.tz, pr.eindex, rs.lindex); + ILLfct_update_basis_info (lp, pr.eindex, rs.lindex, rs.lvstat); + if (pinf->p_strategy == COMPLETE_PRICING) + ILLprice_compute_dual_inf (lp, pinf, &pr.eindex, 1, PRIMAL_PHASEII); + else if (pinf->p_strategy == MULTI_PART_PRICING) + ILLprice_update_mpartial_price (lp, pinf, cphase, COL_PRICING); + } + else if (rs.ratio_stat == RATIO_BCHANGE) + { + EGlpNumCopyFrac (alpha, lp->dz[pr.eindex], rs.pivotval); + EGlpNumAddInnProdTo (lp->pobjval, rs.tz, lp->dz[pr.eindex]); + EGlpNumCopy (lp->objval, lp->pobjval); + + if (!test_progress (lp->pobjval, it->prevobj)) + { + //ILL_IFTRACE(":%d",rs.lindex); + if (lp->vtype[lp->nbaz[pr.eindex]] == VFREE || + lp->vtype[lp->baz[rs.lindex]] == VARTIFICIAL) + { + if (it->noprog > 0) + it->noprog--; + } + else + it->noprog++; + } + else + { + EGlpNumCopy (it->prevobj, lp->pobjval); + it->noprog = 0; + } + + //ILL_IFTRACE(":%d",rs.lindex); + ILLfct_compute_zz (lp, &(lp->zz), rs.lindex); + ILLfct_update_counts (lp, CNT_ZNZ, lp->zz.nzcnt, zeroLpNum); + if (pinf->p_strategy == COMPLETE_PRICING) + { + //ILL_IFTRACE("%s:b\n",__func__); + ILLfct_compute_zA (lp, &(lp->zz), &(lp->zA)); + ILLfct_update_counts (lp, CNT_ZANZ, lp->zA.nzcnt, zeroLpNum); + if (pinf->pII_price == QS_PRICE_PSTEEP) + ILLfct_compute_psteep_upv (lp, wz); + } + rval = + ILLprice_update_pricing_info (lp, pinf, cphase, wz, pr.eindex, rs.lindex, + rs.pivotval); + CHECKRVALG (rval, CLEANUP); + + //ILL_IFTRACE("%s:d:%d\n",__func__,rs.lindex); + ILLfct_update_xz (lp, rs.tz, pr.eindex, rs.lindex); + ILLfct_update_basis_info (lp, pr.eindex, rs.lindex, rs.lvstat); + rval = ILLbasis_update (lp, updz, rs.lindex, &refactor, &singular); + CHECKRVALG (rval, CLEANUP); + + if (singular) + { + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_SING; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + //fprintf(stderr,"Resume Singular %s:%s:%d\n",__func__,__FILE__,__LINE__); + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + ILL_CLEANUP; + } + if (!refactor) + { + ILLfct_update_piz (lp, alpha); + + if (pinf->p_strategy == COMPLETE_PRICING) + { + ILLfct_update_dz (lp, pr.eindex, alpha); + ILLprice_compute_dual_inf (lp, pinf, lp->zA.indx, lp->zA.nzcnt, + PRIMAL_PHASEII); + ILLfct_update_counts (lp, CNT_ZARAVG, lp->zA.nzcnt, zeroLpNum); + } + else if (pinf->p_strategy == MULTI_PART_PRICING) + { + ILLprice_update_mpartial_price (lp, pinf, cphase, COL_PRICING); + } + } + if (refactor != 0 || it->nosolve > PARAM_MAX_NOSOLVE) + { + ILLfct_compute_xbz (lp); + it->newphase = SIMPLEX_PHASE_RECOMP; + } + } + +CLEANUP: + EGlpNumClearVar (alpha); + EGlpNumClearVar (lbound); + EGlpNumClearVar (fi.totinfeas); + EGlpNumClearVar (pr.dinfeas); + EGlpNumClearVar (pr.pinfeas); + EGlpNumClearVar (rs.tz); + EGlpNumClearVar (rs.lbound); + EGlpNumClearVar (rs.ecoeff); + EGlpNumClearVar (rs.pivotval); + //EG_RETURN(rval); + return rval; +} + +static int dual_phaseI_step ( + lpinfo * lp, + price_info * pinf, + svector * updz, + svector * wz, + iter_info * it) +{ + int rval = 0; + int singular = 0; + int refactor = 0; + int cphase = DUAL_PHASEI; + EGlpNum_t alpha; + EGlpNum_t alpha1; + feas_info fi; + ratio_res rs; + price_res pr; + + EGlpNumInitVar (alpha); + EGlpNumInitVar (alpha1); + EGlpNumInitVar (fi.totinfeas); + EGlpNumInitVar (pr.dinfeas); + EGlpNumInitVar (pr.pinfeas); + EGlpNumInitVar (rs.tz); + EGlpNumInitVar (rs.lbound); + EGlpNumInitVar (rs.ecoeff); + EGlpNumInitVar (rs.pivotval); + EGlpNumZero (alpha1); + + ILLfct_update_counts (lp, CNT_DPHASE1ITER, 0, zeroLpNum); + it->nextstep = SIMPLEX_CONTINUE; + it->nextphase = DUAL_PHASEI; + lp->final_phase = DUAL_PHASEI; + it->nosolve++; + + if (it->newphase != 0) + { + ILLfct_check_dfeasible (lp, &fi, lp->tol->id_tol); + if (it->newphase == SIMPLEX_PHASE_NEW) + { + it->noprog = 0; + if (it->sdisplay) + { + printf ("starting dual phase I, nosolve %d\n", it->nosolve); + fflush (stdout); + } + } + it->newphase = 0; + it->nosolve = 0; + EGlpNumCopy (it->prevobj, lp->dinfeas); + + ILLfct_compute_phaseI_xbz (lp); + if (pinf->d_strategy == COMPLETE_PRICING) + { +#if USEHEAP > 0 + ILLprice_free_heap (pinf); +#endif + ILLprice_compute_primal_inf (lp, pinf, NULL, 0, DUAL_PHASEI); +#if USEHEAP > 0 + rval = ILLprice_test_for_heap (lp, pinf, lp->nrows, pinf->p_scaleinf, + DUAL_SIMPLEX, 0); + CHECKRVALG (rval, CLEANUP); +#endif + } + else if (pinf->d_strategy == MULTI_PART_PRICING) + { + ILLprice_init_mpartial_price (lp, pinf, cphase, ROW_PRICING); + } + } + + monitor_iter (lp, pinf, it, cphase); + if (it->nextstep == SIMPLEX_TERMINATE || it->nextstep == SIMPLEX_RESUME || + it->newphase != 0) + ILL_CLEANUP; + + ILLprice_dual (lp, pinf, cphase, &pr); + + if (pr.price_stat == PRICE_OPTIMAL) + { + if (it->sdisplay > 1) + { + printf ("dual phase I seemingly done\n"); + printf ("retesting soln\n"); + fflush (stdout); + } + + rval = ILLsimplex_retest_dsolution (lp, pinf, cphase, &fi); + CHECKRVALG (rval, CLEANUP); + ILLfct_set_status_values (lp, fi.pstatus, fi.dstatus, PHASEI, PHASEII); + + if (fi.dstatus == DUAL_FEASIBLE) + { + it->nextphase = DUAL_PHASEII; + } + else if (fi.pstatus == PRIMAL_FEASIBLE) + { + it->solstatus = ILL_LP_SOLVED; + it->nextstep = SIMPLEX_TERMINATE; + } + it->newphase = SIMPLEX_PHASE_NEW; + ILL_CLEANUP; + } + + ILLfct_compute_zz (lp, &(lp->zz), pr.lindex); + //ILL_IFTRACE("%s:c\n",__func__); + ILLfct_compute_zA (lp, &(lp->zz), &(lp->zA)); + ILLfct_update_counts (lp, CNT_ZNZ, lp->zz.nzcnt, zeroLpNum); + ILLfct_update_counts (lp, CNT_ZANZ, lp->zA.nzcnt, zeroLpNum); + + ILLratio_dI_test (lp, pr.lindex, pr.lvstat, &rs); + + if (rs.ratio_stat == RATIO_FAILED) + { + /* + * rval = E_SIMPLEX_ERROR; + * it->solstatus = ILL_DPHASEI_ERROR; + */ + it->algorithm = PRIMAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_NUMER; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Numerical %s:%s:%d\n",__func__,__FILE__,__LINE__); + ILL_CLEANUP; + } + else if (rs.ratio_stat == RATIO_BCHANGE) + { + ILLfct_compute_yz (lp, &(lp->yjz), updz, lp->nbaz[rs.eindex]); + rval = ILLfct_test_pivot (lp, pr.lindex, ROW_PIVOT, rs.pivotval); + if (rval) + { + it->n_pivot_fail++; + if (it->n_pivot_fail > SIMPLEX_MAX_PIVOT_FAIL) + { + it->n_pivot_fail = 0; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + it->algorithm = PRIMAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_NUMER; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Pivot %s:%s:%d\n",__func__,__FILE__,__LINE__); + rval = 0; + ILL_CLEANUP; + } + rval = ILLbasis_factor (lp, &singular); + if (singular) + MESSAGE (__QS_SB_VERB, "Singular basis found!"); + CHECKRVALG (rval, CLEANUP); + if (singular == 0) + refactor = 1; + goto END; + } + ILLfct_update_counts (lp, CNT_YNZ, lp->yjz.nzcnt, zeroLpNum); + ILLfct_update_counts (lp, CNT_UPNZ, updz->nzcnt, zeroLpNum); + + if (pinf->dI_price == QS_PRICE_DSTEEP) + ILLfct_compute_dsteep_upv (lp, wz); + rval = + ILLprice_update_pricing_info (lp, pinf, cphase, wz, rs.eindex, pr.lindex, + rs.pivotval); + CHECKRVALG (rval, CLEANUP); + + EGlpNumSubTo (lp->dinfeas, lp->upd.c_obj); + + if (!test_progress (lp->dinfeas, it->prevobj)) + { + if (lp->vtype[lp->baz[pr.lindex]] == VARTIFICIAL || + lp->vtype[lp->nbaz[rs.eindex]] == VFREE) + { + if (it->noprog > 0) + it->noprog--; + } + else + it->noprog++; + } + else + { + EGlpNumCopy (it->prevobj, lp->dinfeas); + it->noprog = 0; + } + + EGlpNumCopyFrac (alpha, lp->dz[rs.eindex], rs.pivotval); + EGlpNumCopyFrac (alpha1, lp->xbz[pr.lindex], rs.pivotval); + + ILLfct_update_piz (lp, alpha); + ILLfct_update_dz (lp, rs.eindex, alpha); + ILLfct_update_dfeas (lp, rs.eindex, &(lp->srhs)); + ILLfct_compute_dpIy (lp, &(lp->srhs), &(lp->ssoln)); + ILLfct_update_basis_info (lp, rs.eindex, pr.lindex, pr.lvstat); + +#if DENSE_PI > 0 + fct_test_workvector (lp); + fct_test_dfeasible (lp); +#endif + rval = ILLbasis_update (lp, updz, pr.lindex, &refactor, &singular); + CHECKRVALG (rval, CLEANUP); + +#if DENSE_NORM > 0 + test_dsteep_norms (lp, pinf); +#endif + + ILLfct_update_dpI_prices (lp, pinf, &(lp->srhs), &(lp->ssoln), pr.lindex, + alpha1); + + END: + if (singular) + { + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_SING; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + //fprintf(stderr,"Resume Singular %s:%s:%d\n",__func__,__FILE__,__LINE__); + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + ILL_CLEANUP; + } + if (refactor != 0 || it->nosolve > PARAM_MAX_NOSOLVE) + { + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + ILLfct_dual_adjust (lp, zeroLpNum); + ILLfct_check_dfeasible (lp, &fi, lp->tol->id_tol); + ILLfct_set_status_values (lp, -1, fi.dstatus, -1, PHASEII); + if (fi.dstatus == DUAL_FEASIBLE) + it->nextphase = DUAL_PHASEII; + + it->newphase = SIMPLEX_PHASE_RECOMP; + ILL_CLEANUP; + } + } + +#if DENSE_PI > 1 + fct_test_workvector (lp); + fct_test_pI_x (lp, pinf); +#endif + +CLEANUP: + EGlpNumClearVar (alpha); + EGlpNumClearVar (alpha1); + EGlpNumClearVar (fi.totinfeas); + EGlpNumClearVar (pr.dinfeas); + EGlpNumClearVar (pr.pinfeas); + EGlpNumClearVar (rs.tz); + EGlpNumClearVar (rs.lbound); + EGlpNumClearVar (rs.ecoeff); + EGlpNumClearVar (rs.pivotval); + //EG_RETURN(rval); + return rval; +} + +static int dual_phaseII_step ( + lpinfo * lp, + price_info * pinf, + svector * updz, + svector * wz, + iter_info * it) +{ + int coeffch; + int rval = 0; + int singular = 0; + int refactor = 0; + int ratio_iter = 0; + int cphase = DUAL_PHASEII; + int lcol, ecol; + int estat, newphase; + EGlpNum_t x_bi, v_l, eval; + EGlpNum_t ecoeff; + EGlpNum_t alpha; + EGlpNum_t alpha1; + feas_info fi; + ratio_res rs; + price_res pr; + + EGlpNumInitVar (x_bi); + EGlpNumInitVar (v_l); + EGlpNumInitVar (eval); + EGlpNumInitVar (ecoeff); + EGlpNumInitVar (alpha); + EGlpNumInitVar (alpha1); + EGlpNumInitVar (fi.totinfeas); + EGlpNumInitVar (pr.dinfeas); + EGlpNumInitVar (pr.pinfeas); + EGlpNumInitVar (rs.tz); + EGlpNumInitVar (rs.lbound); + EGlpNumInitVar (rs.ecoeff); + EGlpNumInitVar (rs.pivotval); + EGlpNumZero (rs.ecoeff); + EGlpNumZero (alpha1); + + ILLfct_update_counts (lp, CNT_DPHASE2ITER, 0, zeroLpNum); + it->nextstep = SIMPLEX_CONTINUE; + it->nextphase = DUAL_PHASEII; + lp->final_phase = DUAL_PHASEII; + newphase = it->newphase; + it->nosolve++; + + if (it->newphase != 0) + { + ILLfct_compute_dobj (lp); + if (it->newphase == SIMPLEX_PHASE_NEW) + { + it->noprog = 0; + if (it->sdisplay) + { + printf ("starting dual phase II, nosolve %d\n", it->nosolve); + fflush (stdout); + } + } + it->newphase = 0; + it->nosolve = 0; + EGlpNumCopy (it->prevobj, lp->dobjval); + ILLfct_compute_xbz (lp); + + if (pinf->d_strategy == COMPLETE_PRICING) + { +#if USEHEAP > 0 + ILLprice_free_heap (pinf); +#endif + ILLprice_compute_primal_inf (lp, pinf, NULL, 0, DUAL_PHASEII); +#if USEHEAP > 0 + rval = ILLprice_test_for_heap (lp, pinf, lp->nrows, pinf->p_scaleinf, + DUAL_SIMPLEX, 0); + CHECKRVALG (rval, CLEANUP); +#endif + } + else if (pinf->d_strategy == MULTI_PART_PRICING) + { + ILLprice_init_mpartial_price (lp, pinf, cphase, ROW_PRICING); + } + } + + monitor_iter (lp, pinf, it, cphase); + if (it->nextstep == SIMPLEX_TERMINATE || it->nextstep == SIMPLEX_RESUME || + it->newphase != 0) + ILL_CLEANUP; + + ILLprice_dual (lp, pinf, cphase, &pr); + + if (pr.price_stat == PRICE_OPTIMAL) + { + if (lp->ncchange != 0) + { + if (it->sdisplay > 1) + { + printf ("unrolling %d coef shifts\n", lp->ncchange); + fflush (stdout); + } + ILLfct_unroll_coef_change (lp); + ILLfct_check_dfeasible (lp, &fi, lp->tol->dfeas_tol); + ILLfct_set_status_values (lp, -1, fi.dstatus, -1, PHASEII); + + /*HHH*/ ILLfct_check_pfeasible (lp, &fi, lp->tol->pfeas_tol); + /*HHH* printf ("dual (opt) infeas %.6f\n", lp->dinfeas); fflush (stdout); + *HHH* printf ("primal (opt) infeas %.6f\n", lp->pinfeas); fflush (stdout);*/ + + if (fi.dstatus != DUAL_FEASIBLE) + { + it->algorithm = PRIMAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_UNSHIFT; + it->pricetype = QS_PRICE_PDEVEX; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Unshift %s:%s:%d\n",__func__,__FILE__,__LINE__); + ILL_CLEANUP; + /* + * it->nextphase = DUAL_PHASEI; + * lp->tol->ip_tol /= 5.0; + * lp->tol->id_tol /= 5.0; + * ILL_CLEANUP; + */ + } + } + if (it->sdisplay > 1) + { + //ILL_IFTRACE("\t%s:%s:%d\n",__func__,__FILE__,__LINE__); + printf ("problem seemingly solved\n"); + printf ("seemingly dual opt = %f\n", EGlpNumToLf (lp->dobjval)); + printf ("retesting soln\n"); + fflush (stdout); + } + + rval = ILLsimplex_retest_dsolution (lp, pinf, cphase, &fi); + CHECKRVALG (rval, CLEANUP); + ILLfct_set_status_values (lp, fi.pstatus, fi.dstatus, PHASEII, PHASEII); + + if (fi.dstatus == DUAL_INFEASIBLE) + { + ILL_IFTRACE ("DUAL_INFEAS: %s\n", __func__); + it->nextphase = DUAL_PHASEI; + EGlpNumDivUiTo (lp->tol->ip_tol, 5); + EGlpNumDivUiTo (lp->tol->id_tol, 5); + } + else if (fi.pstatus == PRIMAL_FEASIBLE) + { + ILL_IFTRACE ("PRIM_FEAS: %s\n", __func__); + EGlpNumCopy (lp->objval, lp->dobjval); + it->solstatus = ILL_LP_SOLVED; + it->nextstep = SIMPLEX_TERMINATE; + } + else + ILL_IFTRACE ("PRIM_INFEAS: %s\n", __func__); + ILL_CLEANUP; + } + + ILLfct_compute_zz (lp, &(lp->zz), pr.lindex); + //ILL_IFTRACE("%s:d\n",__func__); + ILLfct_compute_zA (lp, &(lp->zz), &(lp->zA)); + ILLfct_update_counts (lp, CNT_ZNZ, lp->zz.nzcnt, zeroLpNum); + ILLfct_update_counts (lp, CNT_ZANZ, lp->zA.nzcnt, zeroLpNum); + + ratio_iter = 0; + do + { + ILLratio_longdII_test (lp, pr.lindex, pr.lvstat, &rs); + if (rs.ratio_stat == RATIO_NEGATIVE) + { + if (it->sdisplay > 1) + { + printf ("adjust coefs to remove negative ratio tests\n"); + fflush (stdout); + } + ILLfct_adjust_viol_coefs (lp); + ILLratio_longdII_test (lp, pr.lindex, pr.lvstat, &rs); + if (rs.ratio_stat == RATIO_NEGATIVE) + { + MESSAGE (__QS_SB_VERB, "internal error: bad ratio test"); + fflush (stdout); + rs.ratio_stat = RATIO_FAILED; + break; + } + } + + coeffch = rs.coeffch; + EGlpNumCopy (ecoeff, rs.ecoeff); + ratio_iter++; + + if (coeffch) + { + /* + * if (ratio_iter > PARAM_DRATIOTESTS){ + * ecoeff = lp->cz[lp->nbaz[rs.eindex]] - lp->dz[rs.eindex]; + * coeffch = 0; + * } + */ + coeffch = 0; + rval = ILLfct_coef_shift (lp, lp->nbaz[rs.eindex], ecoeff); + CHECKRVALG (rval, CLEANUP); + } + if (rs.ratio_stat == RATIO_BCHANGE) + if (lp->vstat[lp->nbaz[rs.eindex]] == STAT_ZERO) + break; + + } while (coeffch); + + if (rs.ratio_stat == RATIO_FAILED) + { + /* + * rval = E_SIMPLEX_ERROR; + * it->solstatus = ILL_DPHASEII_ERROR; + */ + it->algorithm = PRIMAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_NUMER; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Numerical %s:%s:%d\n",__func__,__FILE__,__LINE__); + ILL_CLEANUP; + } + else if (rs.ratio_stat == RATIO_UNBOUNDED) + { + lp->infub_ix = pr.lindex; + if (lp->ncchange != 0) + { + if (it->sdisplay > 1) + { + printf ("unrolling %d coef shifts\n", lp->ncchange); + fflush (stdout); + } + ILLfct_unroll_coef_change (lp); + } + ILLfct_set_status_values (lp, -1, DUAL_UNBOUNDED, -1, PHASEII); + it->solstatus = ILL_LP_SOLVED; + it->nextstep = SIMPLEX_TERMINATE; + } + else if (rs.ratio_stat == RATIO_BCHANGE) + { + lcol = lp->baz[pr.lindex]; + ecol = lp->nbaz[rs.eindex]; + + ILLfct_compute_yz (lp, &(lp->yjz), updz, ecol); + ILLfct_update_counts (lp, CNT_YNZ, lp->yjz.nzcnt, zeroLpNum); + ILLfct_update_counts (lp, CNT_UPNZ, updz->nzcnt, zeroLpNum); + rval = ILLfct_test_pivot (lp, pr.lindex, ROW_PIVOT, rs.pivotval); + if (rval != 0) + { + it->n_pivot_fail++; + if (it->n_pivot_fail > SIMPLEX_MAX_PIVOT_FAIL) + { + it->n_pivot_fail = 0; + /* this is to force to exit in the case of bad basis */ + it->algorithm = PRIMAL_SIMPLEX; + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_NUMER; + it->n_restart++; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Pivot %s:%s:%d\n",__func__,__FILE__,__LINE__); + rval = 0; + ILL_CLEANUP; + } + if (newphase == 0) + { + rval = ILLbasis_factor (lp, &singular); + CHECKRVALG (rval, CLEANUP); + if (singular) + MESSAGE (__QS_SB_VERB, "Singular basis found!"); +#ifdef dbl_QSOPT_CURRENT_PRECICION + if (singular) + { + MESSAGE (__QS_SB_VERB, "Forcing fail!"); + rval = QS_LP_CHANGE_PREC; + } +#endif + if (singular == 0) + refactor = 1; + goto END; + } + else + { + if (it->sdisplay > 1) + { + printf ("warning: bad step\n"); + fflush (stdout); + } + } + } + + EGlpNumAddTo (lp->dobjval, lp->upd.c_obj); + EGlpNumCopy (lp->objval, lp->dobjval); + + if (!test_progress (lp->dobjval, it->prevobj)) + { + if (lp->vtype[lcol] == VARTIFICIAL || lp->vtype[ecol] == VFREE) + { + if (it->noprog > 0) + it->noprog--; + } + else + it->noprog++; + } + else + { + EGlpNumCopy (it->prevobj, lp->dobjval); + it->noprog = 0; + } + + if (pinf->dII_price == QS_PRICE_DSTEEP) + ILLfct_compute_dsteep_upv (lp, wz); + rval = + ILLprice_update_pricing_info (lp, pinf, cphase, wz, rs.eindex, pr.lindex, + rs.pivotval); + CHECKRVALG (rval, CLEANUP); + + EGlpNumCopy (x_bi, lp->xbz[pr.lindex]); + if (pr.lvstat == STAT_LOWER) + EGlpNumCopy (v_l, lp->lz[lcol]); + else + EGlpNumCopy (v_l, lp->uz[lcol]); + EGlpNumCopy (alpha, rs.tz); + if (pr.lvstat == STAT_LOWER) + EGlpNumSign (alpha); + estat = lp->vstat[ecol]; + if (estat == STAT_LOWER) + EGlpNumCopy (eval, lp->lz[ecol]); + else if (estat == STAT_ZERO) + EGlpNumZero (eval); + else + EGlpNumCopy (eval, lp->uz[ecol]); + + ILLfct_update_piz (lp, alpha); + ILLfct_update_dz (lp, rs.eindex, alpha); + ILLfct_update_dIIfeas (lp, rs.eindex, &(lp->srhs)); + ILLfct_compute_dpIIy (lp, &(lp->srhs), &(lp->ssoln)); + EGlpNumCopyDiff (alpha1, x_bi, v_l); + EGlpNumSubTo (alpha1, lp->upd.dty); + EGlpNumDivTo (alpha1, rs.pivotval); + ILLfct_update_basis_info (lp, rs.eindex, pr.lindex, pr.lvstat); + rval = ILLbasis_update (lp, updz, pr.lindex, &refactor, &singular); + CHECKRVALG (rval, CLEANUP); + + ILLfct_update_dpII_prices (lp, pinf, &(lp->srhs), &(lp->ssoln), /*rs.eindex,*/ + pr.lindex, eval, alpha1); + +#if DENSE_NORM > 0 + test_dsteep_norms (lp, pinf); +#endif + + END: + if (singular) + { + it->nextstep = SIMPLEX_RESUME; + it->resumeid = SIMPLEX_RESUME_SING; + /* this is to force to exit in the case of bad basis */ + it->n_restart++; + EGlpNumMultUiTo (lp->tol->pfeas_tol, SIMPLEX_FACTOR); + EGlpNumMultUiTo (lp->tol->dfeas_tol, SIMPLEX_FACTOR); + //fprintf(stderr,"Resume Singular %s:%s:%d\n",__func__,__FILE__,__LINE__); + ILL_CLEANUP; + } + if (refactor != 0 || it->nosolve > PARAM_MAX_NOSOLVE) + { + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + ILLfct_dual_adjust (lp, zeroLpNum); + it->newphase = SIMPLEX_PHASE_RECOMP; + } + } + +#if DENSE_PIIPI > 0 + fct_test_workvector (lp); + if (!refactor) + { + fct_test_pII_x (lp, pinf); + fct_test_pII_pi_dz (lp, pinf); + } +#endif + +CLEANUP: + EGlpNumClearVar (x_bi); + EGlpNumClearVar (v_l); + EGlpNumClearVar (eval); + EGlpNumClearVar (ecoeff); + EGlpNumClearVar (alpha); + EGlpNumClearVar (alpha1); + EGlpNumClearVar (fi.totinfeas); + EGlpNumClearVar (pr.dinfeas); + EGlpNumClearVar (pr.pinfeas); + EGlpNumClearVar (rs.tz); + EGlpNumClearVar (rs.lbound); + EGlpNumClearVar (rs.ecoeff); + EGlpNumClearVar (rs.pivotval); + //EG_RETURN(rval); + return rval; +} + +static void get_current_stat ( + lp_status_info * p, + int algorithm, + int *bstat) +{ + if (p->optimal) + *bstat = OPTIMAL; + else if (algorithm == PRIMAL_SIMPLEX) + { + if (p->primal_feasible) + *bstat = PRIMAL_FEASIBLE; + else if (p->primal_infeasible) + *bstat = PRIMAL_INFEASIBLE; + else if (p->primal_unbounded) + *bstat = PRIMAL_UNBOUNDED; + else + *bstat = NONOPTIMAL; + } + else if (algorithm == DUAL_SIMPLEX) + { + if (p->dual_feasible) + *bstat = DUAL_FEASIBLE; + else if (p->dual_infeasible) + *bstat = DUAL_INFEASIBLE; + else if (p->dual_unbounded) + *bstat = DUAL_UNBOUNDED; + else + *bstat = NONOPTIMAL; + } +} + +int ILLsimplex_pivotin ( + lpinfo * lp, + price_info * pinf, + int rcnt, + int *rlist, + int pivot_opt, + int *basis_mod) +{ + int i, npiv = 0; + int eindex; + int rval = 0; + int singular = 0; + int refactor = 0; + int *rowmap = lp->O->rowmap; + int *clist = NULL; + svector wz; + svector updz; + EGlpNum_t alpha; + ratio_res rs; + feas_info fi; + + EGlpNumInitVar (alpha); + EGlpNumInitVar (fi.totinfeas); + EGlpNumInitVar (rs.tz); + EGlpNumInitVar (rs.lbound); + EGlpNumInitVar (rs.ecoeff); + EGlpNumInitVar (rs.pivotval); + EGlpNumZero (alpha); + + *basis_mod = 0; + if (rcnt <= 0) + { + EG_RETURN (rval); + } + + if (pivot_opt == SIMPLEX_PIVOTINROW) + { + ILL_SAFE_MALLOC (clist, rcnt, int); + + for (i = 0; i < rcnt; i++) + clist[i] = rowmap[rlist[i]]; + } + else + clist = rlist; + + for (i = 0; i < rcnt; i++) + { + if (lp->vstat[clist[i]] != STAT_BASIC) + { + *basis_mod = 1; + break; + } + } + if (*basis_mod == 0) + { + if (pivot_opt == SIMPLEX_PIVOTINROW) + { + ILL_IFFREE (clist, int); + } + EG_RETURN (rval); + } + + /* printf ("Forcing vars into basis in ILLsimplex_pivotin \n"); */ + ILLsvector_init (&wz); + rval = ILLsvector_alloc (&wz, lp->nrows); + CHECKRVALG (rval, CLEANUP); + ILLsvector_init (&updz); + rval = ILLsvector_alloc (&updz, lp->nrows); + CHECKRVALG (rval, CLEANUP); + + EGlpNumCopy (lp->pobjval, lp->dobjval); + for (i = 0; i < rcnt; i++) + { + if (lp->vstat[clist[i]] == STAT_BASIC) + continue; + npiv++; + + eindex = lp->vindex[clist[i]]; + ILLfct_compute_yz (lp, &(lp->yjz), &updz, lp->nbaz[eindex]); + ILLfct_update_counts (lp, CNT_YNZ, lp->yjz.nzcnt, zeroLpNum); + ILLfct_update_counts (lp, CNT_UPNZ, updz.nzcnt, zeroLpNum); + + ILLratio_pivotin_test (lp, clist, rcnt, &rs); + + if (rs.ratio_stat == RATIO_UNBOUNDED || rs.ratio_stat == RATIO_FAILED) + { + fprintf (stderr, "Pivot_in failed\n"); + rval = E_SIMPLEX_ERROR; + ILL_CLEANUP; + } + else if (rs.ratio_stat == RATIO_BCHANGE) + { + if (rs.lvstat == STAT_LOWER) + { + EGlpNumCopyDiff (alpha, lp->lz[lp->baz[rs.lindex]], lp->xbz[rs.lindex]); + EGlpNumAddInnProdTo (lp->dobjval, rs.tz, alpha); + } + else + { + EGlpNumCopyDiff (alpha, lp->xbz[rs.lindex], lp->uz[lp->baz[rs.lindex]]); + EGlpNumAddInnProdTo (lp->dobjval, rs.tz, alpha); + } + EGlpNumCopyFrac (alpha, lp->dz[eindex], rs.pivotval); + EGlpNumCopy (lp->objval, lp->dobjval); + + ILLfct_compute_zz (lp, &(lp->zz), rs.lindex); + //ILL_IFTRACE("%s:e\n",__func__); + ILLfct_compute_zA (lp, &(lp->zz), &(lp->zA)); + ILLfct_update_counts (lp, CNT_ZNZ, lp->zz.nzcnt, zeroLpNum); + ILLfct_update_counts (lp, CNT_ZANZ, lp->zA.nzcnt, zeroLpNum); + + if (pinf->dsinfo.norms && pinf->dII_price == QS_PRICE_DSTEEP) + { + ILLfct_compute_dsteep_upv (lp, &wz); + rval = ILLprice_update_pricing_info (lp, pinf, DUAL_PHASEII, &wz, + eindex, rs.lindex, rs.pivotval); + CHECKRVALG (rval, CLEANUP); + } + else if (pinf->psinfo.norms && pinf->pII_price == QS_PRICE_PSTEEP) + { + ILLfct_compute_psteep_upv (lp, &wz); + rval = ILLprice_update_pricing_info (lp, pinf, PRIMAL_PHASEII, &wz, + eindex, rs.lindex, rs.pivotval); + CHECKRVALG (rval, CLEANUP); + } + + //ILL_IFTRACE("%s:e\n",__func__); + ILLfct_update_xz (lp, rs.tz, eindex, rs.lindex); + ILLfct_update_basis_info (lp, eindex, rs.lindex, rs.lvstat); + rval = ILLbasis_update (lp, &updz, rs.lindex, &refactor, &singular); + CHECKRVALG (rval, CLEANUP); + + if (singular) + { + fprintf (stderr, "singular matrix in pivot_in\n"); + rval = E_SIMPLEX_ERROR; + ILL_CLEANUP; + } + if (!refactor) + { + ILLfct_update_piz (lp, alpha); + ILLfct_update_dz (lp, eindex, alpha); + } + else + { + ILLfct_compute_xbz (lp); + ILLfct_compute_piz (lp); + ILLfct_compute_dz (lp); + ILLfct_compute_dobj (lp); + } + } + } + /* + * ILLfct_dphaseI_simple_update (lp, lp->tol->dfeas_tol); + * ILLfct_compute_xbz (lp); + * ILLfct_compute_dobj (lp); + */ + + ILLfct_check_pfeasible (lp, &fi, lp->tol->pfeas_tol); + ILLfct_check_dfeasible (lp, &fi, lp->tol->dfeas_tol); + ILLfct_set_status_values (lp, fi.pstatus, fi.dstatus, PHASEII, PHASEII); + +CLEANUP: + if (pivot_opt == SIMPLEX_PIVOTINROW) + ILL_IFFREE (clist, int); + + ILLsvector_free (&wz); + ILLsvector_free (&updz); + EGlpNumClearVar (alpha); + EGlpNumClearVar (fi.totinfeas); + EGlpNumClearVar (rs.tz); + EGlpNumClearVar (rs.lbound); + EGlpNumClearVar (rs.ecoeff); + EGlpNumClearVar (rs.pivotval); + EG_RETURN (rval); +} + +static int report_value ( + lpinfo * lp, + iter_info * it, + const char *value_name, + EGlpNum_t value) +{ + int rval = 0; + + if (it->sdisplay && it->itercnt % lp->iterskip == 0) + { + char buffer[1024]; + + snprintf (buffer, (size_t) 1023, "(%d): %s = %10.7lf\n", it->itercnt, + value_name, EGlpNumToLf (value)); + buffer[1022] = '\n'; + buffer[1023] = '\0'; + rval = ILLstring_report (buffer, &lp->O->reporter); + fflush (stdout); + } + else + { + /* make sure ILLstring_report is called at least every 10 iterations */ + if (it->itercnt % (lp->iterskip / 10)) + { + rval = ILLstring_report (NULL, &lp->O->reporter); + } + } + if (rval != 0) + { /* ILLstring_report was called and failed, which means we should abort */ + it->solstatus = QS_LP_ABORTED; + } + return rval; +} + +#undef QSOPT_CURRENT_PRECICION diff --git a/src/simplex.h b/src/simplex.h new file mode 100644 index 0000000..c7aa2c1 --- /dev/null +++ b/src/simplex.h @@ -0,0 +1,88 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: simplex.h,v $ $Revision: 1.3 $ $Date: 2003/11/05 16:57:39 $ */ + +#ifndef __SIMPLEX_H +#define __SIMPLEX_H + +struct itcnt_t; +#include "config.h" +#include "lpdata.h" +#include "basicdefs.h" +typedef struct param_info +{ + int origalgo; + int pphaseI; + int pphaseII; + int dphaseI; + int dphaseII; + int p_strategy; + int d_strategy; +} +param_info; + +typedef struct iter_info +{ + int newphase; + int nextphase; + int nextstep; + int sdisplay; + int itercnt; + int solstatus; + int curtime; + int rounds; + int chkobj; + int nosolve; + int noprog; + int inner; + int algorithm; + int resumeid; + int pricetype; + int n_restart; + int n_pivot_fail; + EGlpNum_t prevobj; + EGlpNum_t objtol; + param_info oldinfo; +} +iter_info; + +void ILLsimplex_init_lpinfo ( lpinfo * lp), + ILLsimplex_free_lpinfo ( lpinfo * lp), + ILLsimplex_load_lpinfo ( ILLlpdata * qslp, lpinfo * lp), + ILLsimplex_set_bound ( lpinfo * lp, const EGlpNum_t * objbound, int sense); +void free_internal_lpinfo ( lpinfo * lp); +void init_internal_lpinfo ( lpinfo * lp); +int build_internal_lpinfo ( lpinfo * lp); +int ILLsimplex_retest_psolution ( lpinfo * lp, price_info * p, int phase, + feas_info * fs), + ILLsimplex_retest_dsolution ( lpinfo * lp, price_info * p, int phase, + feas_info * fs), + ILLsimplex_solution ( lpinfo * lp, EGlpNum_t * xz, EGlpNum_t * piz, + EGlpNum_t * dz, EGlpNum_t * objval), + ILLsimplex_infcertificate ( lpinfo * lp, EGlpNum_t * pi), + ILLsimplex ( lpinfo * lp, int algorithm, ILLlp_basis * B, + price_info * pinf, int *sol_status, int sdisplay, itcnt_t* itcnt), + ILLsimplex_pivotin ( lpinfo * lp, price_info * pinf, int rcnt, + int *rlist, int pivot_opt, int *basis_mod); + +#endif /* __SIMPLEX_H */ diff --git a/src/solver.c b/src/solver.c new file mode 100644 index 0000000..ff6a804 --- /dev/null +++ b/src/solver.c @@ -0,0 +1,361 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: solver.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +#include "qs_config.h" +#include "exact.h" +#include "solver.h" +#include "iqsutil.h" +#include "util.h" +#include "lpdefs.h" /* for PRIMAL_SIMPLEX */ +#include "qstruct.h" +#include "qsopt.h" +#include "binary.h" +#include "editor.h" +#include "price.h" +#include "lib.h" /* for ILLmip_binary_dfs */ +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +static char *fname = 0; +static int lpfile = 0; +static int solvemip = 0; +static int interactive = 0; +static int usescaling = 1; +static int showversion = 0; +static int simplexalgo = PRIMAL_SIMPLEX; +static int pstrategy = QS_PRICE_PSTEEP; +static int dstrategy = QS_PRICE_DSTEEP; +static unsigned precision = 128; +static int printsol = 0; +static char *readbasis = 0; +static char *writebasis = 0; + +static void usage ( + char *s), + get_ftype ( + char *name, + int *ftype); + +#ifdef TEST_FEEDBACK +static int feedback ( + FILE * dest, + const char *str); +#endif +static int parseargs ( + int ac, + char **av); + +#ifndef WIN32 +QSLIB_INTERFACE int main ( int ac, char **av); +int main ( int ac, char **av) +{ + int rval; + EGlib_info(); + EGlib_version(); + QSopt_ex_version(); + QSexactStart(); + rval = solver_main (ac, av); + QSexactClear(); + return rval; +} +#endif + +QSLIB_INTERFACE int solver_main ( + int ac, + char **av) +{ + int rval = 0; + QSdata *p = 0; + ILLutil_timer timer_solve; + ILLutil_timer timer_read; + int ftype = 0; /* 0 mps, 1 lp */ + EGlpNum_t *x = 0; + EGlpNum_t val; + double szeit; + + rval = parseargs (ac, av); + if (rval) + ILL_CLEANUP; + + QSset_precision (precision); + EGlpNumInitVar (val); + if (showversion) + { + char *buf = 0; + + buf = QSversion (); + if (buf == 0) + { + ILL_CLEANUP; + } + else + { + printf ("%s\n", buf); + QSfree ((void *) buf); + } + } + + if (lpfile) + { + ftype = 1; + } + else + { + get_ftype (fname, &ftype); + } + + ILLutil_init_timer (&timer_read, "SOLVER_READ"); + ILLutil_start_timer (&timer_read); + if (ftype == 1) + { + p = QSread_prob ((const char *) fname, "LP"); + if (p == 0) + { + fprintf (stderr, "Could not read lp file.\n"); + rval = 1; + ILL_CLEANUP_IF (rval); + } + } + else + { + p = QSread_prob ((const char *) fname, "MPS"); + if (p == 0) + { + fprintf (stderr, "Could not read mps file.\n"); + rval = 1; + ILL_CLEANUP_IF (rval); + } + } + + if (readbasis) + { + rval = QSread_and_load_basis (p, (const char *) readbasis); + ILL_CLEANUP_IF (rval); + } + ILLutil_stop_timer (&timer_read, 1); + rval = QSset_param (p, QS_PARAM_SIMPLEX_DISPLAY, 1) + || QSset_param (p, QS_PARAM_PRIMAL_PRICING, pstrategy) + || QSset_param (p, QS_PARAM_DUAL_PRICING, dstrategy) + || QSset_param (p, QS_PARAM_SIMPLEX_SCALING, usescaling); + ILL_CLEANUP_IF (rval); + + if (interactive) + { + ILLeditor_init (); + ILLeditor (p); + goto CLEANUP; + } + + szeit = ILLutil_zeit(); + ILLutil_init_timer (&timer_solve, "SOLVER"); + ILLutil_start_timer (&timer_solve); + +#ifdef TEST_FEEDBACK + QSset_reporter (p, (void *) feedback, stdout); +#endif + rval = ILLeditor_solve (p, simplexalgo); + ILLutil_stop_timer (&timer_solve, 1); + ILL_CLEANUP_IF (rval); + + printf ("ZZ %s %.2f\n", p->lp->O->probname, ILLutil_zeit () - szeit); + fflush (stdout); + + if (printsol) + x = EGlpNumAllocArray (p->lp->O->nstruct); + + if (solvemip) + { + rval = ILLmip_bfs (p->lp, &val, x, &(p->itcnt)); + ILL_CLEANUP_IF (rval); + printf ("MIP Objective Value: %.6f\n", EGlpNumToLf (val)); + fflush (stdout); + if (printsol && EGlpNumIsNeqq (val, ILL_MAXDOUBLE) && + EGlpNumIsNeqq (val, ILL_MINDOUBLE)) + { + EGioFile_t*out = EGioOpenFILE(stdout); + rval = ILLlib_print_x (out, p->lp, 0, x, 1); + EGioClose(out); + ILL_CLEANUP_IF (rval); + } + } + else + { + if (writebasis) + { + rval = QSwrite_basis (p, 0, writebasis); + ILL_CLEANUP_IF (rval); + } + if (printsol) + { + EGioFile_t*out = EGioOpenFILE(stdout); + rval = ILLlib_print_x (out, p->lp, 0, 0, 1); + EGioClose(out); + ILL_CLEANUP_IF (rval); + } + } + +CLEANUP: + EGlpNumFreeArray (x); + QSfree_prob (p); + EGlpNumClearVar (val); + return rval; /* main return */ +} + +static void usage ( + char *s) +{ + char *buf = 0; + + buf = QSversion (); + if (buf) + { + fprintf (stderr, "%s\n", buf); + QSfree ((void *) buf); + } + + fprintf (stderr, "Usage: %s [- below -] prob_file\n", s); + fprintf (stderr, " -b f write basis to file f\n"); + fprintf (stderr, " -B f read initial basis from file f\n"); +#if 0 + fprintf (stderr, " -I solve the MIP using BestBound\n"); + fprintf (stderr, " -E edit problem after solving initial version\n"); +#endif + fprintf (stderr, " -L input file is in lp format (default: mps)\n"); + fprintf (stderr, " -O print the final solution\n"); + fprintf (stderr, " -p # run primal simplex with pricing rule #\n"); + fprintf (stderr, + " (%d-Dantzig, %d-Devex, %d-Steep (default), %d-Partial\n", + QS_PRICE_PDANTZIG, QS_PRICE_PDEVEX, QS_PRICE_PSTEEP, + QS_PRICE_PMULTPARTIAL); + fprintf (stderr, " -d # run dual simplex with pricing rule #\n"); + fprintf (stderr, " (%d-Dantzig, %d-Steep, %d-Partial, %d-Devex)\n", + QS_PRICE_DDANTZIG, QS_PRICE_DSTEEP, QS_PRICE_DMULTPARTIAL, + QS_PRICE_DDEVEX); + fprintf (stderr, " -S do NOT scale the initial LP\n"); + fprintf (stderr, " -v print QSopt version number\n"); +} + +static int parseargs ( + int ac, + char **av) +{ + int c; + int boptind = 1; + char *boptarg = 0; + + while ((c = + ILLutil_bix_getopt (ac, av, "b:B:d:p:P:IELOSv", &boptind, + &boptarg)) != EOF) + switch (c) + { + case 'b': + writebasis = boptarg; + break; + case 'B': + readbasis = boptarg; + break; + case 'P': + precision = atoi (boptarg); + break; + case 'd': + simplexalgo = DUAL_SIMPLEX; + dstrategy = atoi (boptarg); + break; +#if 0 + case 'E': + interactive = 1; + break; + case 'I': + solvemip = 1; + break; +#endif + case 'L': + lpfile = 1; + break; + case 'O': + printsol = 1; + break; + case 'p': + simplexalgo = PRIMAL_SIMPLEX; + pstrategy = atoi (boptarg); + break; + case 'S': + usescaling = 0; + break; + case 'v': + showversion = 1; + break; + case '?': + default: + usage (av[0]); + return 1; + } + if (boptind != (ac - 1)) + { + usage (av[0]); + return 1; + } + + fname = av[boptind++]; + fprintf (stderr, "Reading problem from %s\n", fname); + return 0; +} + +static void get_ftype ( + char *name, + int *ftype) +{ + char *q; + + q = strrchr (name, '.'); + if (q) + { + q++; + if (!strcmp (q, "lp") || !strcmp (q, "LP")) + { + *ftype = 1; + } + else + { + *ftype = 0; + } + } +} + +#ifdef TEST_FEEDBACK +static int feedback ( + FILE * dest, + const char *str) +{ + if (str != NULL) + { + int rc = fprintf ((FILE *) dest, "FEEDBACK: %s", str); + + fflush (dest); + return rc; + } + return 0; +} +#endif diff --git a/src/solver.h b/src/solver.h new file mode 100644 index 0000000..46586e6 --- /dev/null +++ b/src/solver.h @@ -0,0 +1,33 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: solver.h,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:57:39 $ */ +#ifndef SOLVER_H +#define SOLVER_H + +#include "qsopt.h" + +QSLIB_INTERFACE int solver_main ( + int argc, + char **argv); + +#endif diff --git a/src/sortrus.c b/src/sortrus.c new file mode 100644 index 0000000..e8de11d --- /dev/null +++ b/src/sortrus.c @@ -0,0 +1,285 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: sortrus.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* SORTING ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* DATE: February 24, 1994 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* char *ILLutil_linked_radixsort (char *data, char *datanext, */ +/* char *dataval, int valsize) */ +/* USAGE: */ +/* head = (bar *) ILLutil_linked_radixsort ((char *) head, */ +/* (char *) &(head->next), (char *) &(head->val), sizeof (int)); */ +/* Then head is the start of the linked list in increasing order of */ +/* val, with next as the field that links the bars. */ +/* WARNING: DOES NOT HANDLE NEGATIVE NUMBERS PROPERLY. */ +/* */ +/* void ILLutil_int_array_quicksort (int *len, int n) */ +/* len - the array to be sorted */ +/* n - the number of elements in len */ +/* Uses quicksort to put len in increasing order. */ +/* */ +/* void ILLutil_int_perm_quicksort (int *perm, int *len, int n) */ +/* perm - must be allocated and initialized by the calling routine, */ +/* it will be arranged in increasing order of len. */ +/* n - the number of elements in perm and len. */ +/* */ +/* void ILLutil_double_perm_quicksort (int *perm, double *len, int n) */ +/* perm - must be allocated and initialized by the calling routine, */ +/* it will be arranged in increasing order of len. */ +/* n - the number of elements in perm and len. */ +/* */ +/* void ILLutil_rselect (int *arr, int l, int r, int m, */ +/* double *coord, ILLrandstate *rstate) */ +/* arr - permutation that will be rearranged */ +/* l,r - specify the range of arr that we are interested in */ +/* m - is the index into l,r that is the break point for the perm */ +/* coord - gives the keys that determine the ordering */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "machdefs.h" +#include "util.h" +#include "except.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +#define BITS_PER_PASS (8) + +#define NBINS (1< SORTSIZE) + { + for (i = 0; i < NSAMPLES; i++) + { + EGlpNumCopy (samplevals[i], coord[arr[ILLutil_lprand (rstate) % n]]); + } + select_EGlpNum_sort_dsample (samplevals, NSAMPLES); + select_EGlpNum_split (arr, n, &(samplevals[(NSAMPLES - 1) / 2]), + &st, &en, coord); + if (st > m) + { + n = st; + } + else if (en <= m) + { + arr += en; + n -= en; + m -= en; + } + else + { + return; + } + } + + select_EGlpNum_sort (arr, n, coord); + EGlpNumFreeArray (samplevals); + return; +} + +static void select_EGlpNum_split ( + int *arr, + int n, + EGlpNum_t * v, + int *start, + int *end, + EGlpNum_t * coord) +{ + int i, j, k; + int t; + + i = 0; + j = k = n; + + while (i < j) + { + if (EGlpNumIsLess (coord[arr[i]], *v)) + { + i++; + } + else if (EGlpNumIsEqqual (coord[arr[i]], *v)) + { + j--; + ILL_SWAP (arr[i], arr[j], t); + } + else + { + j--; + k--; + t = arr[i]; + arr[i] = arr[j]; + arr[j] = arr[k]; + arr[k] = t; + } + } + *start = j; + *end = k; + return; +} + +static void select_EGlpNum_sort ( + int *arr, + int n, + EGlpNum_t * coord) +{ + int i, j; + int t; + + for (i = 1; i < n; i++) + { + t = arr[i]; + for (j = i; j > 0 && EGlpNumIsLess (coord[t], coord[arr[j - 1]]); j--) + { + arr[j] = arr[j - 1]; + } + arr[j] = t; + } +} + +static void select_EGlpNum_sort_dsample ( + EGlpNum_t * samp, + int n) +{ + int i, j; + EGlpNum_t t; + + EGlpNumInitVar (t); + + for (i = 1; i < n; i++) + { + EGlpNumCopy (t, samp[i]); + for (j = i; j > 0 && EGlpNumIsLess (t, samp[j - 1]); j--) + { + EGlpNumCopy (samp[j], samp[j - 1]); + } + EGlpNumCopy (samp[j], t); + } + EGlpNumClearVar (t); +} + + + + diff --git a/src/sortrus.h b/src/sortrus.h new file mode 100644 index 0000000..49d8d61 --- /dev/null +++ b/src/sortrus.h @@ -0,0 +1,43 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __SORTRUS_H__ +#define __SORTRUS_H__ +/****************************************************************************/ +/* */ +/* sortrus.c */ +/* */ +/****************************************************************************/ +#include "qs_config.h" +#include "urandom.h" +void ILLutil_EGlpNum_perm_quicksort ( + int *perm, + EGlpNum_t * len, + int n), + ILLutil_EGlpNum_rselect ( + int *arr, + int l, + int r, + int m, + EGlpNum_t * coord, + ILLrandstate * rstate); +#endif diff --git a/src/sortrus_common.c b/src/sortrus_common.c new file mode 100644 index 0000000..57e7c53 --- /dev/null +++ b/src/sortrus_common.c @@ -0,0 +1,423 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: sortrus.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* SORTING ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* DATE: February 24, 1994 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* char *ILLutil_linked_radixsort (char *data, char *datanext, */ +/* char *dataval, int valsize) */ +/* USAGE: */ +/* head = (bar *) ILLutil_linked_radixsort ((char *) head, */ +/* (char *) &(head->next), (char *) &(head->val), sizeof (int)); */ +/* Then head is the start of the linked list in increasing order of */ +/* val, with next as the field that links the bars. */ +/* WARNING: DOES NOT HANDLE NEGATIVE NUMBERS PROPERLY. */ +/* */ +/* void ILLutil_int_array_quicksort (int *len, int n) */ +/* len - the array to be sorted */ +/* n - the number of elements in len */ +/* Uses quicksort to put len in increasing order. */ +/* */ +/* void ILLutil_int_perm_quicksort (int *perm, int *len, int n) */ +/* perm - must be allocated and initialized by the calling routine, */ +/* it will be arranged in increasing order of len. */ +/* n - the number of elements in perm and len. */ +/* */ +/* void ILLutil_double_perm_quicksort (int *perm, double *len, int n) */ +/* perm - must be allocated and initialized by the calling routine, */ +/* it will be arranged in increasing order of len. */ +/* n - the number of elements in perm and len. */ +/* */ +/* void ILLutil_rselect (int *arr, int l, int r, int m, */ +/* double *coord, ILLrandstate *rstate) */ +/* arr - permutation that will be rearranged */ +/* l,r - specify the range of arr that we are interested in */ +/* m - is the index into l,r that is the break point for the perm */ +/* coord - gives the keys that determine the ordering */ +/* */ +/****************************************************************************/ + +#include "qs_config.h" +#include "machdefs.h" +#include "util.h" +#include "except.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +#define BITS_PER_PASS (8) + +#define NBINS (1<= 0; j--) + { + for (i = 0; i < NBINS; i++) + { + head[i] = (char *) NULL; + tail[i] = &head[i]; + } + for (p = data; p; p = *(char **) (p + nextoff)) + { + v = (unsigned char) p[valoff + j]; + *tail[v] = p; + tail[v] = (char **) (p + nextoff); + } + last = &data; + for (i = 0; i < NBINS; i++) + { + if (head[i]) + { + *last = head[i]; + last = tail[i]; + } + } + *last = (char *) NULL; + } + return data; +} + +void ILLutil_int_array_quicksort ( + int *len, + int n) +{ + int i, j, temp, t; + + if (n <= 1) + return; + + ILL_SWAP (len[0], len[(n - 1) / 2], temp); + + i = 0; + j = n; + t = len[0]; + + for (;;) + { + do + i++; + while (i < n && len[i] < t); + do + j--; + while (len[j] > t); + if (j < i) + break; + ILL_SWAP (len[i], len[j], temp); + } + ILL_SWAP (len[0], len[j], temp); + + ILLutil_int_array_quicksort (len, j); + ILLutil_int_array_quicksort (len + i, n - i); +} + +void ILLutil_int_perm_quicksort ( + int *perm, + int *len, + int n) +{ + int i, j, temp, t; + + if (n <= 1) + return; + + ILL_SWAP (perm[0], perm[(n - 1) / 2], temp); + + i = 0; + j = n; + t = len[perm[0]]; + + for (;;) + { + do + i++; + while (i < n && len[perm[i]] < t); + do + j--; + while (len[perm[j]] > t); + if (j < i) + break; + ILL_SWAP (perm[i], perm[j], temp); + } + ILL_SWAP (perm[0], perm[j], temp); + + ILLutil_int_perm_quicksort (perm, len, j); + ILLutil_int_perm_quicksort (perm + i, len, n - i); +} + + +void ILLutil_double_perm_quicksort ( + int *perm, + double *len, + int n) +{ + int i, j, temp; + double t; + + if (n <= 1) + return; + + ILL_SWAP (perm[0], perm[(n - 1) / 2], temp); + + i = 0; + j = n; + t = len[perm[0]]; + + for (;;) + { + do + i++; + while (i < n && len[perm[i]] < t); + do + j--; + while (t < len[perm[j]]); + if (j < i) + break; + ILL_SWAP (perm[i], perm[j], temp); + } + ILL_SWAP (perm[0], perm[j], temp); + + ILLutil_double_perm_quicksort (perm, len, j); + ILLutil_double_perm_quicksort (perm + i, len, n - i); +} + +void ILLutil_str_perm_quicksort ( + int *perm, + char **len, + int n) +{ + int i, j, temp; + char *t; + + if (n <= 1) + return; + + ILL_SWAP (perm[0], perm[(n - 1) / 2], temp); + + i = 0; + j = n; + t = len[perm[0]]; + + for (;;) + { + do + i++; + while (i < n && (strcmp (len[perm[i]], t) < 0)); + do + j--; + while (strcmp (len[perm[j]], t) > 0); + if (j < i) + break; + ILL_SWAP (perm[i], perm[j], temp); + } + ILL_SWAP (perm[0], perm[j], temp); + + ILLutil_str_perm_quicksort (perm, len, j); + ILLutil_str_perm_quicksort (perm + i, len, n - i); +} + + +/********** Median - Select Routines **********/ + +/* NSAMPLES should be odd */ +#define NSAMPLES 3 +#define SORTSIZE 20 + +void ILLutil_rselect ( + int *arr, + int l, + int r, + int m, + double *coord, + ILLrandstate * rstate) +{ + double samplevals[NSAMPLES]; + int i; + int st, en; + int n; + + arr += l; + n = r - l + 1; + m -= l; + + while (n > SORTSIZE) + { + for (i = 0; i < NSAMPLES; i++) + { + samplevals[i] = coord[arr[ILLutil_lprand (rstate) % n]]; + } + select_sort_dsample (samplevals, NSAMPLES); + select_split (arr, n, samplevals[(NSAMPLES - 1) / 2], &st, &en, coord); + if (st > m) + { + n = st; + } + else if (en <= m) + { + arr += en; + n -= en; + m -= en; + } + else + { + return; + } + } + + select_sort (arr, n, coord); + return; +} + +static void select_split ( + int *arr, + int n, + double v, + int *start, + int *end, + double *coord) +{ + int i, j, k; + int t; + + i = 0; + j = k = n; + + while (i < j) + { + if (coord[arr[i]] < v) + { + i++; + } + else if (coord[arr[i]] == v) + { + j--; + ILL_SWAP (arr[i], arr[j], t); + } + else + { + j--; + k--; + t = arr[i]; + arr[i] = arr[j]; + arr[j] = arr[k]; + arr[k] = t; + } + } + *start = j; + *end = k; + return; +} + +static void select_sort ( + int *arr, + int n, + double *coord) +{ + int i, j; + int t; + + for (i = 1; i < n; i++) + { + t = arr[i]; + for (j = i; j > 0 && coord[arr[j - 1]] > coord[t]; j--) + { + arr[j] = arr[j - 1]; + } + arr[j] = t; + } +} + +static void select_sort_dsample ( + double *samp, + int n) +{ + int i, j; + double t; + + for (i = 1; i < n; i++) + { + t = samp[i]; + for (j = i; j > 0 && samp[j - 1] > t; j--) + { + samp[j] = samp[j - 1]; + } + samp[j] = t; + } +} diff --git a/src/sortrus_common.h b/src/sortrus_common.h new file mode 100644 index 0000000..ad2a340 --- /dev/null +++ b/src/sortrus_common.h @@ -0,0 +1,62 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __SORTRUS_H__ +#define __SORTRUS_H__ +/****************************************************************************/ +/* */ +/* sortrus.c */ +/* */ +/****************************************************************************/ +#include "qs_config.h" +#include "urandom.h" +void ILLutil_int_array_quicksort ( + int *len, + int n), + ILLutil_int_perm_quicksort ( + int *perm, + int *len, + int n), + ILLutil_double_perm_quicksort ( + int *perm, + double *len, + int n), + ILLutil_str_perm_quicksort ( + int *perm, + char **len, + int n), + ILLutil_rselect ( + int *arr, + int l, + int r, + int m, + double *coord, + ILLrandstate * rstate); + +char *ILLutil_linked_radixsort ( + char *data, + char *datanext, + char *dataval, + int valsize); + + +#endif diff --git a/src/stddefs.h b/src/stddefs.h new file mode 100644 index 0000000..0200c55 --- /dev/null +++ b/src/stddefs.h @@ -0,0 +1,34 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* $RCSfile: stddefs.h,v $ $Revision: 1.3 $ $Date: 2003/11/05 16:57:39 $ */ +#ifndef ILL_STDDEFS_H +#define ILL_STDDEFS_H + +#define SWAP(x,y,temp) {temp = x; x = y; y = temp;} + +#define QSMIN(x,y) ((x) < (y) ? (x) : (y)) +#define QSMAX(x,y) ((x) > (y) ? (x) : (y)) + +#define ABS(x) ((x) >= 0 ? (x) : -(x)) + +#endif /* ILL_STDDEFS_H */ diff --git a/src/symtab.c b/src/symtab.c new file mode 100644 index 0000000..419dc6f --- /dev/null +++ b/src/symtab.c @@ -0,0 +1,965 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: symboltab.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +#include "util.h" +#include "trace.h" +#include "except.h" +#include "symtab.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +static int TRACE = 0; + +static unsigned int stringhash ( + const char *key, + int tsize); +static int look_it_up ( + ILLsymboltab * h, + const char *s); +static int grow_symboltab ( + ILLsymboltab * h); +static int grow_namelist ( + ILLsymboltab * h); +static int add_string ( + ILLsymboltab * h, + const char *s, + int *symbol); +static void delete_from_list ( + ILLsymboltab * h, + int del_ind, + int prev_ind, + int x); + +#ifdef TRY_CODE +/* debug support */ +static const char *get_str ( + const ILLsymboltab * h, + int indx); +static void prt_xchain ( + const ILLsymboltab * h, + int x); +static void prt_chain ( + const ILLsymboltab * h, + char *s); +#endif + + +void ILLsymboltab_init ( + ILLsymboltab * h) +{ + h->tablesize = 0; + h->strsize = 0; + h->freedchars = 0; + h->hashspace = 0; + h->name_space = 0; + h->strspace = 0; + h->hashtable = (int *) NULL; + h->nametable = (ILLsymbolent *) NULL; + h->namelist = (char *) NULL; +} + +void ILLsymboltab_free ( + ILLsymboltab * h) +{ + ILL_IFFREE (h->hashtable, int); + + ILL_IFFREE (h->nametable, ILLsymbolent); + ILL_IFFREE (h->namelist, char); + + ILLsymboltab_init (h); +} + +int ILLsymboltab_create ( + ILLsymboltab * h, + int init_size) +{ + int rval = 0; + int i; + + if (init_size <= 0) + init_size = 1000; + + ILLsymboltab_free (h); + + h->tablesize = 0; + h->strsize = 0; + h->freedchars = 0; + h->name_space = init_size; + h->hashspace = ILLutil_nextprime (((unsigned) h->name_space)); +#ifdef TRY_CODE + h->strspace = init_size; +#else + h->strspace = init_size * 5; +#endif + h->index_ok = 0; + + ILL_SAFE_MALLOC (h->hashtable, h->hashspace, int); + + ILL_SAFE_MALLOC (h->nametable, h->name_space, ILLsymbolent); + ILL_SAFE_MALLOC (h->namelist, h->strspace, char); + + for (i = 0; i < h->hashspace; i++) + { + h->hashtable[i] = ILL_SYM_NOINDEX; + } + +CLEANUP: + if (rval) + { + ILLsymboltab_free (h); + } + ILL_RETURN (rval, "ILLsymboltab_create"); +} + +int ILLsymboltab_copy ( + ILLsymboltab * src, + ILLsymboltab * dst) +{ + int rval = 0; + int i; + + ILLsymboltab_free (dst); + + *dst = *src; + ILL_SAFE_MALLOC (dst->hashtable, dst->hashspace, int); + + ILL_SAFE_MALLOC (dst->nametable, dst->name_space, ILLsymbolent); + ILL_SAFE_MALLOC (dst->namelist, dst->strspace, char); + + for (i = 0; i < src->hashspace; i++) + { + dst->hashtable[i] = src->hashtable[i]; + } + for (i = 0; i < src->tablesize; i++) + { + dst->nametable[i] = src->nametable[i]; + } + for (i = 0; i < src->strsize; i++) + { + dst->namelist[i] = src->namelist[i]; + } + +CLEANUP: + if (rval) + { + ILLsymboltab_free (dst); + } + ILL_RETURN (rval, "ILLsymboltab_copy"); +} + + +const char *ILLsymboltab_get ( + const ILLsymboltab * h, + int i) +{ + char *name = NULL; + + ILL_FAILfalse_no_rval ((i >= 0) && (i <= h->tablesize), "Index out of range"); + if (h->nametable[i].symbol != -1) + name = h->namelist + h->nametable[i].symbol; +CLEANUP: + return name; +} + +int ILLsymboltab_index_ok ( + ILLsymboltab * h) +{ + return (h && (h->index_ok == 1)); +} + +int ILLsymboltab_index_reset ( + ILLsymboltab * h, + int icount, + char **names) +{ + int rval = 0; + int i, k; + + /* Note may have tablesize 1 larger than icount, due to objname */ + + if ((h->tablesize != icount) && (h->tablesize != icount + 1)) + { + fprintf (stderr, "symbol table (%d) does not match reset list (%d)\n", + h->tablesize, icount); + rval = 1; + ILL_CLEANUP; + } + + for (i = 0; i < icount; i++) + { + k = look_it_up (h, (const char *) names[i]); + if (k) + { + fprintf (stderr, "Symbol %s is not in table\n", names[i]); + rval = 1; + ILL_CLEANUP; + } + k = h->the_index; + h->nametable[k].index = i; + } + + h->index_ok = 1; + +CLEANUP: + return rval; +} + +int ILLsymboltab_getindex ( + ILLsymboltab * h, + const char *name, + int *hindex) +{ + int rval = 0; + int k; + + *hindex = -1; + + if (!h || !h->index_ok) + { + fprintf (stderr, "symbol table index out of date\n"); + rval = 1; + ILL_CLEANUP; + } + + k = look_it_up (h, name); + if (k) + { + printf ("Symbol %s is not in table\n", name); + fflush (stdout); + ILL_CLEANUP; + } + k = h->the_index; + + *hindex = h->nametable[k].index; + +CLEANUP: + + ILL_RETURN (rval, "ILLsymboltab_getindex"); +} + +int ILLsymboltab_rename ( + ILLsymboltab * h, + int i, + const char *new_name) +{ + int rval = 0; + int symbol = 0; + + ILL_FAILfalse ((i >= 0) && (i <= h->tablesize), "Index out of range"); + if ((new_name != NULL) && (look_it_up (h, new_name) == 0)) + { + rval = (i != h->the_index); + ILL_RETURN (rval, "ILLsymboltab_rename"); + } + if (h->nametable[i].symbol != -1) + { + (void) look_it_up (h, h->namelist + h->nametable[i].symbol); + ILL_FAILfalse (i == h->the_index, "must find it at i"); + delete_from_list (h, i, h->the_prev_index, h->the_hash); + } + if (new_name != NULL) + { + rval = add_string (h, new_name, &symbol); + ILL_CLEANUP_IF (rval); + h->the_hash = stringhash (new_name, h->hashspace); + h->nametable[i].symbol = symbol; + h->nametable[i].next = h->hashtable[h->the_hash]; + h->hashtable[h->the_hash] = i; + } + else + { + h->nametable[i].symbol = -1; + h->nametable[i].next = ILL_SYM_NOINDEX; + } +CLEANUP: + ILL_RETURN (rval, "ILLsymboltab_rename"); +} + +int ILLsymboltab_lookup ( + ILLsymboltab * h, + const char *s, + int *ind) +{ + int rval = look_it_up (h, s); + + *ind = h->the_index; + return rval; +} + +int ILLsymboltab_contains ( + ILLsymboltab * tab, + const char *name) +{ + return !look_it_up (tab, name); +} + +void ILLsymboltab_size ( + const ILLsymboltab * h, + int *p_size) +{ + *p_size = h->tablesize; +} + +int ILLsymboltab_register ( + ILLsymboltab * h, + const char *s, + int itemindex, + int *the_prev_index, + int *existed) +{ + ILLsymbolent *nametable = h->nametable; + int e, symbol = 0; + int rval = 0; + + if (itemindex < 0) + { + h->index_ok = 0; + } + + h->the_prev_index = ILL_SYM_NOINDEX; + h->the_index = ILL_SYM_NOINDEX; + if (s == NULL) + { + e = h->tablesize; + h->the_index = e; + *existed = 0; + while (h->tablesize >= h->name_space) + { + rval = grow_symboltab (h); + ILL_CLEANUP_IF (rval); + } + h->tablesize++; + h->nametable[e].symbol = -1; + h->nametable[e].index = itemindex; + h->nametable[e].next = ILL_SYM_NOINDEX; + ILL_IFTRACE ("register: %s NULL entry#=%d\n", (*existed) ? "OLD" : "NEW", + e); + } + else + { + *existed = !look_it_up (h, s); + if (*existed) + { + ILL_IFTRACE ("register: OLD %s entry#=%d hash=%d\n", + s, h->the_index, h->the_hash); + return 0; + } + + rval = add_string (h, s, &symbol); + ILL_CLEANUP_IF (rval); + + while (h->tablesize >= h->name_space) + { + rval = grow_symboltab (h); + ILL_CLEANUP_IF (rval); + h->the_hash = stringhash (s, h->hashspace); /*hash changes with bigger table */ + } + + nametable = h->nametable; + + e = h->tablesize; + h->tablesize++; + h->the_prev_index = e; + + nametable[e].symbol = symbol; + nametable[e].index = itemindex; + nametable[e].next = h->hashtable[h->the_hash]; + h->hashtable[h->the_hash] = e; + + ILL_IFTRACE ("register: %s NULL entry#=%d\n", (*existed) ? "OLD" : "NEW", + e); + } + +CLEANUP: + *the_prev_index = h->the_prev_index; + ILL_RETURN (rval, "ILLsymboltab_register"); +} + +int ILLsymboltab_delete ( + ILLsymboltab * h, + const char *s) +{ + int del_ind, rval = 0; + char *last; + + ILL_FAILtrue (s == NULL, "must give non NULL str"); + + rval = look_it_up (h, s); + del_ind = h->the_index; + ILL_CLEANUP_IF (rval); /* was not in table */ + ILL_FAILfalse ((del_ind != ILL_SYM_NOINDEX) && + (h->nametable[del_ind].symbol != -1), + "we should have found this non NULL str"); + h->index_ok = 0; + delete_from_list (h, del_ind, h->the_prev_index, h->the_hash); + + h->tablesize--; + if (del_ind != h->tablesize) + { + if (h->nametable[h->tablesize].symbol != -1) + { + last = h->namelist + h->nametable[h->tablesize].symbol; + rval = look_it_up (h, last); + ILL_FAILfalse ((rval == 0) && (h->the_index == h->tablesize), + "Should find last entry"); + if (h->the_prev_index != ILL_SYM_NOINDEX) + { + h->nametable[h->the_prev_index].next = del_ind; + } + else + { + h->hashtable[h->the_hash] = del_ind; + } + } + h->nametable[del_ind] = h->nametable[h->tablesize]; + } +CLEANUP: + ILL_RETURN (rval, "ILLsymboltab_delete"); +} + +void ILLsymboltab_prt ( + FILE * fd, + ILLsymboltab * h) +{ + char *str; + int i; + + for (i = 0; i < h->tablesize; i++) + { + if (h->nametable[i].symbol == -1) + { + fprintf (fd, "%d: NULL nohash\n", i); + } + else + { + str = h->namelist + h->nametable[i].symbol; + fprintf (fd, "%d: %s hash=%d\n", i, str, stringhash (str, h->hashspace)); + } + } +} + +static int look_it_up ( + ILLsymboltab * h, + const char *s) +{ + ILLsymbolent *nametable = h->nametable; + char *namelist = h->namelist; + int e; + + if(!h->hashspace) goto CLEANUP; + ILL_FAILfalse_no_rval (s, "Should never call with NULL string"); + h->the_prev_index = ILL_SYM_NOINDEX; + h->the_hash = stringhash (s, h->hashspace); + for (e = h->hashtable[h->the_hash]; e != ILL_SYM_NOINDEX; + e = nametable[e].next) + { + if (strcmp (namelist + nametable[e].symbol, s) == 0) + { + h->the_index = e; + ILL_IFTRACE ("look_it_up: OLD %s entry#=%d hash=%d\n", s, e, h->the_hash); + return 0; + } + h->the_prev_index = e; + } +CLEANUP: + h->the_index = ILL_SYM_NOINDEX; + ILL_IFTRACE ("look_it_up: NEW %s \n", s); + return 1; +} + + +static void delete_from_list ( + ILLsymboltab * h, + int del_ind, + int prev_ind, + int x) +{ + if (prev_ind != ILL_SYM_NOINDEX) + { + ILL_FAILtrue_no_rval (h->nametable[prev_ind].symbol == -1, + "A NULL str with same hash ?"); + h->nametable[prev_ind].next = h->nametable[del_ind].next; + } + else + { + h->hashtable[x] = h->nametable[del_ind].next; + } + h->freedchars += strlen (h->namelist + h->nametable[del_ind].symbol) + 1; +CLEANUP: + ; +} + + +static int grow_symboltab ( + ILLsymboltab * h) +{ + int newnamespace, newhashspace, *newhash, tablesize; + ILLsymbolent *newname; + char *namelist = h->namelist; + int i; + unsigned int x; + int rval = 0; + + newnamespace = h->name_space * 2; + newhashspace = ILLutil_nextprime (((unsigned) newnamespace)); + // rval = ILLutil_reallocrus_count ((void **) (&h->nametable), newnamespace, + // sizeof (ILLsymbolent)); + //ILL_CLEANUP_IF (rval); + h->nametable = EGrealloc (h->nametable, sizeof (ILLsymbolent) * newnamespace); + newname = h->nametable; + + ILL_SAFE_MALLOC (newhash, newhashspace, int); + ILL_IFFREE (h->hashtable, int); + + h->hashtable = newhash; + + h->name_space = newnamespace; + h->hashspace = newhashspace; + + newhash = h->hashtable; + tablesize = h->tablesize; + + for (i = 0; i < newhashspace; i++) + { + newhash[i] = ILL_SYM_NOINDEX; + } + for (i = 0; i < tablesize; i++) + { + if (newname[i].symbol != -1) + { + x = stringhash (namelist + newname[i].symbol, newhashspace); + newname[i].next = newhash[x]; + newhash[x] = i; + } + } +CLEANUP: + ILL_RETURN (rval, "grow_symboltab"); +} + +static int grow_namelist ( + ILLsymboltab * h) +{ + int newstrspace, i, j, newsymbol, rval = 0; + char *newnamelist, *newc; + + if (2 * h->freedchars >= h->strspace) + { + /* compact string array */ + ILL_SAFE_MALLOC (newnamelist, h->strspace, char); + + newc = newnamelist; + for (i = 0; i < h->tablesize; i++) + { + if (h->nametable[i].symbol != -1) + { + newsymbol = newc - newnamelist; + for (j = h->nametable[i].symbol; h->namelist[j] != '\0'; j++) + { + *newc = h->namelist[j]; + newc++; + } + *newc = '\0'; + newc++; + h->nametable[i].symbol = newsymbol; + } + } + ILL_IFFREE (h->namelist, char); + + h->namelist = newnamelist; + h->strsize = newc - newnamelist; + h->freedchars = 0; + } + else + { + newstrspace = h->strspace * 2; + h->namelist = EGrealloc (h->namelist, sizeof (char) * newstrspace); + //rval = ILLutil_reallocrus_count ((void **) &h->namelist, newstrspace, + // sizeof (char)); + //ILL_CLEANUP_IF (rval); + h->strspace = newstrspace; + } +CLEANUP: + ILL_RETURN (rval, "grow_namelist"); +} + +static int add_string ( + ILLsymboltab * h, + const char *s, + int *symbol) +{ + int l, rval = 0; + + l = strlen (s) + 1; + while (h->strsize + l > h->strspace) + { + rval = grow_namelist (h); + ILL_CLEANUP_IF (rval); + } + strcpy (h->namelist + h->strsize, s); + *symbol = h->strsize; + h->strsize += l; +CLEANUP: + ILL_RETURN (rval, "add_string"); +} + +static unsigned int stringhash ( + const char *key, + int tsize) +{ + unsigned int x = 0; + +#ifdef TRY_CODE + while (*key) + { + x += *key; + key++; + } +#else + while (*key) + { + x = 37 * x + *key; + key++; + } +#endif + return x % tsize; +} + +/**************************************************************************/ +/* ILLsymboltab_unique_name and its support */ +/**************************************************************************/ +static void make_var ( + char *new_var, + const char *prefix, + char *name) +{ + size_t plen = strlen (prefix); + size_t nlen = strlen (name); + char *p; + + if (nlen + plen >= ILL_namebufsize) + { + nlen = ILL_namebufsize - plen - 1; + } + strcpy (new_var, prefix); + p = new_var + plen; + strncpy (p, name, nlen + 1); +} + +int ILLsymboltab_uname ( + ILLsymboltab * symtab, + char *name, + const char *try_prefix1, + const char *try_prefix2) +{ + int nvars = symtab->tablesize; + int rval = 0; + int i, found, numlen; + const char *try_prefix[3]; + char prefix[ILL_namebufsize]; + char new_pre[ILL_namebufsize]; + char new[ILL_namebufsize]; + + ILL_FAILtrue (try_prefix1 == NULL, "try_prefix must not be NULL"); + try_prefix[0] = try_prefix1; + try_prefix[1] = try_prefix2; + try_prefix[2] = NULL; + new[0] = '\0'; + found = 0; + for (i = 0; (!found) && try_prefix[i]; i++) + { + make_var (new, try_prefix[i], name); + found = !ILLsymboltab_contains (symtab, new); + } + if (!found) + { + i = 0; + sprintf (prefix, "%s", try_prefix[0]); + numlen = (log10 ((double) (symtab->tablesize - 1) * 10)) + 1; + while (!found) + { + ILL_FAILfalse (i <= nvars, "something wrong in find_unique_name"); + make_var (new_pre, prefix, name); + new_pre[ILL_namebufsize - numlen - 1] = '\0'; + sprintf (new, "%s_%d", new_pre, i); + found = !ILLsymboltab_contains (symtab, new); + i++; + } + } + +CLEANUP: + strcpy (name, new); + return rval; +} + +void ILLsymboltab_unique_name ( + ILLsymboltab * tab, + int i, + const char *pref, + char uname2[ILL_namebufsize]) +{ + int notUnique; + + sprintf (uname2, "%d", i); + notUnique = ILLsymboltab_uname (tab, uname2, pref, NULL); + ILL_FAILtrue_no_rval (notUnique, "Programming error"); +CLEANUP: + return; +} + +#ifdef TRY_CODE +/* debugging */ +static const char *get_str ( + const ILLsymboltab * h, + int indx) +{ + if (indx < 0 || indx >= h->tablesize) + { + return "INDEX OUT OF RANGE"; + } + if (h->nametable[indx].symbol == -1) + { + return "NULL"; + } + else + { + return h->namelist + h->nametable[indx].symbol; + } +} + +static void prt_xchain ( + const ILLsymboltab * h, + int x) +{ + int e; + char *str; + + x = x % h->hashspace; + printf ("chain hash %d:", x); + for (e = h->hashtable[x]; e != ILL_SYM_NOINDEX; e = h->nametable[e].next) + { + if (h->nametable[e].symbol >= 0) + { + str = h->namelist + h->nametable[e].symbol; + x = stringhash (str, h->hashspace); + printf (" %s(h=%d, e=%d)", str, x, e); + } + else + { + printf (" NULL"); + } + } + printf ("\n"); +} + +static void prt_chain ( + const ILLsymboltab * h, + char *s) +{ + int e; + + if (s != NULL) + { + prt_xchain (h, stringhash (s, h->hashspace)); + } + else + { + for (e = 0; e < h->hashspace; e++) + { + if (h->hashtable[e] != ILL_SYM_NOINDEX) + prt_xchain (h, e); + } + } +} +#endif + +#ifdef TRY_CODE +int main ( + int ac, + char **av) +{ + + int i, rval, index, pre_exist, nwords; + const char *prefix[3]; + ILLsymboltab t, *tab = &t; + char cmd[100], symbol[100], line[256], str[100]; + const char *s; + int ok; + + TRACE = 1; + prefix[0] = "C"; + prefix[1] = "c"; + prefix[2] = NULL; + ILLsymboltab_init (tab); + ILLsymboltab_create (tab, 1); + + fprintf (stdout, "> "); + fflush (stdout); + while (fgets (line, 100, stdin)) + { + ok = 0; + symbol[0] = '\0'; + nwords = sscanf (line, "%s%s%s", cmd, symbol, str); + if (nwords >= 1) + { + fprintf (stdout, ":: %s", line); + if ((nwords >= 2) && strcmp (cmd, "REG") == 0) + { + ok = 1; + if (strcmp (symbol, "NULL") == 0) + { + rval = ILLsymboltab_register (tab, NULL, &index, &pre_exist); + } + else + { + rval = ILLsymboltab_register (tab, symbol, &index, &pre_exist); + } + } + if ((nwords >= 2) && strcmp (cmd, "LOOK") == 0) + { + ok = 1; + rval = ILLsymboltab_register (tab, symbol, &index, &pre_exist); + } + if ((nwords >= 2) && strcmp (cmd, "DEL") == 0) + { + ok = 1; + rval = ILLsymboltab_delete (tab, symbol); + } + if ((nwords >= 2) && strcmp (cmd, "UNIQUE") == 0) + { + ok = 1; + rval = ILLsymboltab_uname (tab, symbol, "c", "C"); + } + if ((nwords >= 1) && strcmp (cmd, "PRT") == 0) + { + ok = 1; + ILLsymboltab_prt (stdout, tab); + } + if ((nwords >= 2) && strcmp (cmd, "GET") == 0) + { + ok = 1; + i = atoi (symbol); + s = ILLsymboltab_get (tab, i); + fprintf (stdout, "%d: %s\n", i, (s != NULL) ? s : "NULL"); + } + if ((nwords >= 3) && strcmp (cmd, "RENAME") == 0) + { + ok = 1; + i = atoi (symbol); + if (strcmp (str, "NULL") == 0) + { + ILLsymboltab_rename (tab, i, NULL); + } + else + { + ILLsymboltab_rename (tab, i, str); + } + } + if (strcmp (cmd, "CHAIN") == 0) + { + ok = 1; + if ((nwords == 1) || strcmp (symbol, "NULL") == 0) + { + prt_chain (tab, NULL); + fprintf (stdout, + "last %s(%d) strsize/space: %d/%d freedchars: %d\n", + get_str (tab, tab->tablesize - 1), tab->tablesize - 1, + tab->strsize, tab->strspace, tab->freedchars); + } + else + { + prt_chain (tab, symbol); + } + } + if ((nwords >= 1) && strcmp (cmd, "INFO") == 0) + { + ok = 1; + fprintf (stdout, + "last %s(%d) strsize/space: %d/%d freedchars: %d\n", + get_str (tab, tab->tablesize - 1), tab->tablesize - 1, + tab->strsize, tab->strspace, tab->freedchars); + } + if ((nwords >= 1) && strcmp (cmd, "STR") == 0) + { + ok = 1; + for (i = 0; i < tab->strsize; i++) + { + if (tab->namelist[i] == '\0') + fprintf (stdout, "\\0"); + else + fprintf (stdout, "%c", tab->namelist[i]); + } + fprintf (stdout, "\n"); + } + } + if (ok == 0) + { + fprintf (stdout, "commands: REG, LOOK, DEL, RENAME, GET, %s\n", + "RENAME, UNIQUE, CHAIN, STR, INFO, PRT"); + } + fprintf (stdout, "> "); + fflush (stdout); + } + + return 0; +} + +/* sample input for testing symboltab */ +#ifdef NEVER +REG aabb REG aabb // its already there + REG abab REG abab // its already there + REG baba REG baba // its already there + REG bbaa REG bbaa // its already there + CHAIN aabb STR // all with same hash + DEL abab // remove from middle + CHAIN baba DEL aabb // remove last + CHAIN baba DEL bbaa // remove first + CHAIN baba DEL baba // remove the only element + CHAIN PRT STR REG 123456789012 // compact name list no entries in table + STR REG longnametoo INFO REG a REG b DEL 123456789012 DEL longnametoo INFO STR REG more // compact name list with entries in table + STR INFO PRT REG NULL // add NULL str + PRT DEL b // remove with NULL being last entry + PRT CHAIN DEL a // remove with NULL somewhere in table + PRT DEL more CHAIN // nothing left in table + REG NULL // add NULL str + REG NULL // add NULL str + REG NULL // add NULL str + REG more PRT CHAIN // only chain is for more + RENAME 0 more // should fail + RENAME 0 another // own hash + RENAME 0 another // must fail + CHAIN RENAME 1 orem // existing hash + CHAIN RENAME 2 makestrarraygrowevenlongerwiththisid CHAIN PRT INFO STR DEL makestrarraygrowevenlongerwiththisid STR RENAME 3 somemore // should trigger grownamelist + + PRT + REG omemore + STR + CHAIN + INFO + UNIQUE a + UNIQUE a + REG Ca + UNIQUE a REG ca UNIQUE a REG Ca_0 REG Ca_1 REG Ca_2 REG Ca_3 REG Ca_4 UNIQUE a +#endif +#endif diff --git a/src/symtab.h b/src/symtab.h new file mode 100644 index 0000000..fcd9983 --- /dev/null +++ b/src/symtab.h @@ -0,0 +1,138 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: symtab.h,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +#ifndef ILL_SYMTAB_H +#define ILL_SYMTAB_H + +/* we allow 256KB of buffer space i.e. 2^17*/ +#define ILL_namebufsize 0x20000U + +typedef struct ILLsymbolent +{ + int symbol; + int index; + int next; +} +ILLsymbolent; + +typedef struct ILLsymboltab +{ + int *hashtable; + ILLsymbolent *nametable; + char *namelist; + int tablesize; + int strsize; + int hashspace; + int name_space; + int strspace; + int freedchars; + int the_hash; + int the_index; + int the_prev_index; + int index_ok; +} +ILLsymboltab; + +/* + * hashtable[stringhash(entry) % hashspace] either NO_INDEX or some hash number + * nametable[hash number] = { next: another index for nametable + * symbol: index into namelist where string resides + * } + * tablesize: number of entries (tablesize <= name_space) + * name_space: length of nametable and indexlist + * hashspace: length of hashtable nextprime(name_space) + * strsize: number of chars used in namelist + * strspace: length of namelist + * indexlist: LP col/row indices for the table entries + * indexlist_ok: 1 if column indices in indexlist are up-to-date, 0 otherwise + * + * Deletion of entries affects their ordering in symboltab->nametable. + * Strings may move around within symboltab->namelist. + */ + + +#define ILL_SYM_NOINDEX (-1) +extern void ILLsymboltab_init ( + ILLsymboltab * h), + ILLsymboltab_free ( + ILLsymboltab * h), + ILLsymboltab_size ( + const ILLsymboltab * h, + int *p_size), + ILLsymboltab_prt ( + FILE * fd, + ILLsymboltab * h); + +extern int ILLsymboltab_create ( + ILLsymboltab * h, + int init_size), + ILLsymboltab_copy ( + ILLsymboltab * src, + ILLsymboltab * dst), + ILLsymboltab_register ( + ILLsymboltab * h, + const char *s, + int itemindex, + int *p_index, + int *p_existed), + ILLsymboltab_lookup ( + ILLsymboltab * h, + const char *s, + int *p_index), + ILLsymboltab_index_ok ( + ILLsymboltab * h), + ILLsymboltab_index_reset ( + ILLsymboltab * h, + int icount, + char **names), + ILLsymboltab_getindex ( + ILLsymboltab * h, + const char *name, + int *hindex), + ILLsymboltab_contains ( + ILLsymboltab * h, + const char *s), + ILLsymboltab_delete ( + ILLsymboltab * h, + const char *s), + ILLsymboltab_uname ( + ILLsymboltab * h, + char name[ILL_namebufsize], + const char *try_prefix1, + const char *try_prefix2); + +extern void ILLsymboltab_unique_name ( + ILLsymboltab * tab, + int i, + const char *pref, + char uname[ILL_namebufsize]); + +extern const char *ILLsymboltab_get ( + const ILLsymboltab * tab, + int i); +extern int ILLsymboltab_rename ( + ILLsymboltab * h, + int i, + const char *new_name); + +#endif /* __SYMTAB_H */ diff --git a/src/trace.h b/src/trace.h new file mode 100644 index 0000000..290df0b --- /dev/null +++ b/src/trace.h @@ -0,0 +1,41 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: trace.h,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +#ifndef ILL_trace_h +#define ILL_trace_h + +#include + +/* users of these macros must declare a static int TRACE variable */ +#ifndef NDEBUG +#define ILL_IFTRACE if (TRACE) printf +#define ILL_IFTRACE2 if (TRACE > 1) printf +#define ILL_IFDOTRACE if (TRACE) +#else +/* the optimizer will take care of this */ +#define ILL_IFTRACE if (0) printf +#define ILL_IFTRACE if (0) printf +#define ILL_IFDOTRACE if (0) +#endif + +#endif diff --git a/src/urandom.c b/src/urandom.c new file mode 100644 index 0000000..1ba6538 --- /dev/null +++ b/src/urandom.c @@ -0,0 +1,174 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: urandom.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* MACHINE INDEPENDENT RANDOM NUMBER GENERATOR */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: DIMACS (modified for TSP) */ +/* Date: February 7, 1995 (cofeb16) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void ILLutil_sprand (int seed, ILLrandstate *r) */ +/* - Call once to initialize the generator. */ +/* */ +/* int ILLutil_lprand (QSrandstate *r) */ +/* - Returns an integer in the range 0 to ILL_PRANDMAX - 1. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* NOTES (from DIMACS): */ +/* This file contains a set of c-language functions for generating */ +/* uniform integers. This is a COMPLETELY PORTABLE generator. It will */ +/* give IDENTICAL sequences of random numbers for any architecture with */ +/* at least 30-bit integers, regardless of the integer representation, */ +/* INT_MAX value, or roundoff/truncation method, etc. */ +/* This Truly Remarkable RNG is described more fully in */ +/* J. Bentley's column, ``The Software Exploratorium ''. It is based on */ +/* one in Knuth, Vol 2, Section 3.2.2 (Algorithm A). */ +/* */ +/****************************************************************************/ + + +#include "machdefs.h" +#include "util.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + + +void ILLutil_sprand ( + int seed, + ILLrandstate * r) +{ + int i, ii; + int last, next; + int *arr = r->arr; + + arr[0] = last = seed; + next = 1; + for (i = 1; i < 55; i++) + { + ii = (21 * i) % 55; + arr[ii] = next; + next = last - next; + if (next < 0) + next += ILL_PRANDMAX; + last = arr[ii]; + } + r->a = 0; + r->b = 24; + for (i = 0; i < 165; i++) + last = ILLutil_lprand (r); +} + + +int ILLutil_lprand ( + ILLrandstate * r) +{ + int t; + + if (r->a-- == 0) + r->a = 54; + if (r->b-- == 0) + r->b = 54; + + t = r->arr[r->a] - r->arr[r->b]; + + if (t < 0) + t += ILL_PRANDMAX; + + r->arr[r->a] = t; + + return t; +} + + +#ifdef TRY_CODE + +/*-----------------------------------------------*/ +/* This is a little driver program so you can */ +/* test the code. */ +/* Typing: a.out 0 3 1 */ +/* should produce */ +/* 921674862 */ +/* 250065336 */ +/* 377506581 */ +/* Typing: a.out 1000000 1 2 */ +/* should produce */ +/* 57265995 */ +/*-----------------------------------------------*/ + +int main ( + int ac, + char **av) +{ + int i; + int j; + int n; + int m; + int seed; + ILLrandstate rstate; + + if (ac < 4) + { + fprintf (stderr, "Usage: #discard #print #seed\n"); + return 0; + } + m = atoi (av[1]); /* Number to discard initially */ + n = atoi (av[2]); /* Number to print */ + seed = atoi (av[3]); /* Seed */ + + ILLutil_sprand (seed, &rstate); + + for (i = 0; i < m; i++) + j = ILLutil_lprand (&rstate); + for (i = 0; i < n; i++) + printf ("%ld\n", ILLutil_lprand (&rstate)); + return 0; +} + +#endif /* TRY_CODE */ diff --git a/src/urandom.h b/src/urandom.h new file mode 100644 index 0000000..dc298ac --- /dev/null +++ b/src/urandom.h @@ -0,0 +1,59 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __URANDOM_H__ +#define __URANDOM_H__ +/****************************************************************************/ +/* */ +/* urandom.c */ +/* */ +/****************************************************************************/ + +/* since urandom's generator does everything modulo ILL_PRANDMAX, if two + * seeds are congruent mod x and x|ILL_PRANDMAX, then the resulting numbers + * will be congruent mod x. One example was if ILL_PRANDMAX = 1000000000 and + * urandom is used to generate a point set from a 1000x1000 grid, seeds + * congruent mod 1000 generate the same point set. + * + * For this reason, we use 1000000007 (a prime) + */ +#define ILL_PRANDMAX 1000000007 + +typedef struct ILLrandstate +{ + int a; + int b; + int arr[55]; +} +ILLrandstate; + + +void ILLutil_sprand ( + int seed, + ILLrandstate * r); + +int ILLutil_lprand ( + ILLrandstate * r); + + + +#endif diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..2bd6c30 --- /dev/null +++ b/src/util.c @@ -0,0 +1,284 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: util.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* MISCELLANEOUS UTILITY ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: October 12, 1995 */ +/* Date: September 28, 1997 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* unsigned int ILLutil_nextprime (unsigned int x) */ +/* FINDS the smallest positive prime >= x */ +/* */ +/* int ILLutil_our_gcd (int a, int b) */ +/* COMPUTES gcd(a,b) */ +/* -gcd(a,b) is always >= 0 */ +/* -a and b can be negative, positive, or zero */ +/* */ +/* int ILLutil_our_lcm (int a, int b) */ +/* COMPUTES lcm(a,b) */ +/* -lcm(a,b) is always >= 0 */ +/* -a and b can be negative, positive, or zero */ +/* */ +/* double ILLutil_our_floor (double x) */ +/* REURNS the greatest integer no larger than x. */ +/* */ +/* double ILLutil_our_ceil (double x) */ +/* REURNS the least integer no smaller than x. */ +/* */ +/* double ILLutil_our_frac (double x) */ +/* REURNS the fractional part of x. */ +/* */ +/* char *ILLutil_strchr (const char *s, int c) */ +/* RETURNS a pointer to the first occurrence of c in s, or NULL if c */ +/* does not occur in s */ +/* */ +/* int ILLutil_strcasecmp(const char *s1, const char *s2) */ +/* RETURNS the string comparison, iqnoring the case of the letters. */ +/* */ +/* int ILLutil_strncasecmp(const char *s1, const char *s2, size_t n) */ +/* RETURNS the string comparision, iqnoring case, looks at max n bytes. */ +/* */ +/* char *ILLutil_str(const char *s) */ +/* allocates and returns a copy of s */ +/* */ +/****************************************************************************/ + +#include "machdefs.h" +#include "except.h" +#include "util.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + + +static int isprime ( + unsigned int x); + + +unsigned int ILLutil_nextprime ( + unsigned int x) +{ + if (x < 3) + return 3; + x |= 1; + while (!isprime (x)) + x += 2; + return x; +} + +static int isprime ( + unsigned int p) +{ + unsigned int i; + + if ((p & 1) == 0) + return 0; + for (i = 3; i * i <= p; i += 2) + { + if (p % i == 0) + return 0; + } + return 1; +} + +int ILLutil_our_gcd ( + int a, + int b) +{ + int c; + + if (a < 0) + a = -a; + if (b < 0) + b = -b; + if (a > b) + ILL_SWAP (a, b, c); + + while (a) + { + c = b % a; + b = a; + a = c; + } + return b; +} + +int ILLutil_our_lcm ( + int a, + int b) +{ + int c; + + if (a < 0) + a = -a; + if (b < 0) + b = -b; + + c = ILLutil_our_gcd (a, b); + + return (a / c) * b; +} + +double ILLutil_our_floor ( + double x) +{ + return floor (x); +} + +double ILLutil_our_ceil ( + double x) +{ + return ceil (x); +} + +double ILLutil_our_frac ( + double x) +{ + return x - floor (x); +} + +double ILLutil_norm_sqr ( + double *v, + int len) +{ + int i; + double sum = 0.0; + + for (i = 0; i < len; i++) + sum += v[i] * v[i]; + return sum; +} + +int ILLutil_our_log2 ( + int a) +{ + int i = 0, j = 1; + + while (j < a) + { + j = j << 1; + i++; + } + return i ? i : 1; +} + +const char *ILLutil_strchr ( + const char *s, + int c) +{ + while (*s) + { + if (*s == c) + return s; + s++; + } + return (char *) NULL; +} + +int ILLutil_strcasecmp ( + const char *s1, + const char *s2) +{ + return strcasecmp (s1, s2); +} + +int ILLutil_strncasecmp ( + const char *s1, + const char *s2, + size_t n) +{ + return strncasecmp (s1, s2, n); +} + +int ILLutil_index ( + const char *list[], + const char *name) +{ + int i; + + for (i = 0; list[i] != NULL; i++) + { + if (!strcmp (name, list[i])) + { + return i; + } + } + return -1; +} + +int ILLutil_array_index ( + char *list[], + int n, + const char *name) +{ + int i; + + for (i = 0; i < n; i++) + { + if ((list[i] != NULL) && !strcmp (name, list[i])) + { + return i; + } + } + return -1; +} + +char *ILLutil_str ( + const char *str) +{ + int len; + char *cpy = NULL; + + if (str != NULL) + { + len = strlen (str) + 1; + ILL_SAFE_MALLOC_no_rval (cpy, len, char); + + strcpy (cpy, str); + } +CLEANUP: + return cpy; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..7d3b906 --- /dev/null +++ b/src/util.h @@ -0,0 +1,156 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: util.h,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +#ifndef ILL_UTIL_H +#define ILL_UTIL_H + +#include "machdefs.h" +#include "config.h" + +#ifdef _USRDLL + +#ifdef QSLIB_EXPORTS +#define QSLIB_INTERFACE __declspec(dllexport) +#else +#define QSLIB_INTERFACE __declspec(dllimport) +#endif + +#else + +#define QSLIB_INTERFACE extern + +#endif + +#ifdef WIN32 +#define strcasecmp(s1, s2) stricmp(s1, s2) +#define strncasecmp(s1, s2, n) strnicmp(s1, s2, n) +#endif + +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* EGLPNUMPT_SWAP */ +/* ILL_SWAP(a,b,t) */ +/* swaps a and b, using t as temporary space. a, b, and t should all */ +/* be the same type. */ +/* */ +/* ILL_OURABS(a) */ +/* returns the absolute value of a. */ +/* */ +/****************************************************************************/ +typedef char ILLbool; + +#define FALSE 0 +#define TRUE 1 + +#define ILL_SWAP(a,b,t) (((t)=(a)),((a)=(b)),((b)=(t))) +#define EGLPNUM_SWAP(a,b,t) ((EGlpNumCopy(t,a)),(EGlpNumCopy(a,b)),(EGlpNumCopy(b,t))) + +#define ILL_OURABS(a) (((a) >= 0) ? (a) : -(a)) + +#include "sortrus_common.h" +#include "allocrus.h" +#include "urandom.h" +#include "zeit.h" +/****************************************************************************/ +/* */ +/* util.c */ +/* */ +/****************************************************************************/ +#define ILL_UTIL_STR(new, str) \ + { new = ILLutil_str(str); \ + if (str != NULL) { ILL_CHECKnull(new, "out of memeory"); } } + +extern char *ILLutil_str ( + const char *str); + + /* allocates and returns a copy of s */ + +extern int ILLutil_array_index ( + char *list[], + int n, + const char *name); + + /* returns index of name in list or -1 */ + +extern int ILLutil_index ( + const char *list[], + const char *name); + + /* returns index of name in list or -1 */ + +extern unsigned int ILLutil_nextprime ( + unsigned int x); + +extern const char *ILLutil_strchr ( + const char *s, + int c); + +extern int ILLutil_strcasecmp ( + const char *s1, + const char *s2); +extern int ILLutil_strncasecmp ( + const char *s1, + const char *s2, + size_t n); + + +extern int ILLutil_our_gcd ( + int a, + int b), + ILLutil_our_lcm ( + int a, + int b), + ILLutil_our_log2 ( + int a); + +double ILLutil_our_floor ( + double x), + ILLutil_our_ceil ( + double x), + ILLutil_our_frac ( + double x), + ILLutil_norm_sqr ( + double *v, + int len); + +#include "bgetopt.h" +/*#include "dheaps_i.h"*/ +/*#include "priority.h"*/ +#endif /* ILL_UTIL_H */ diff --git a/src/write_lp.c b/src/write_lp.c new file mode 100644 index 0000000..e186afe --- /dev/null +++ b/src/write_lp.c @@ -0,0 +1,253 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: wr_lp.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */ + +/****************************************************************************/ +/* */ +/* Routines to support writing of LP files */ +/* */ +/****************************************************************************/ + +/* + * -) anything after '\' is comment + * -) variables consist of a-z A-Z 0-9!"#$%(),;.?@_`'{}|~ + * don't start with a digit or '.' + */ + +#include "config.h" +#include "iqsutil.h" +#include "lpdefs.h" +#include "write_lp.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + +void ILLwrite_lp_state_init ( + ILLwrite_lp_state * line, + const char *str) +{ + line->total = 0; + line->p = line->buf; + *line->p = '\0'; + if (str != NULL) + { + ILLwrite_lp_state_append (line, str); + } +} + +void ILLwrite_lp_state_append ( + ILLwrite_lp_state * line, + const char *str) +{ + int len, rval = 0; + + ILL_FAILfalse (str, "Must have non NULL string"); + sprintf (line->p, str); + len = strlen (line->p); + line->total += len; + line->p += len; +CLEANUP: + return; +} + +void ILLwrite_lp_state_append_coef ( + ILLwrite_lp_state * line, + EGlpNum_t v, + int cnt) +{ + EGlpNum_t ntmp; + int len = 0; + + EGlpNumInitVar (ntmp); + EGlpNumCopy (ntmp, v); + if (EGlpNumIsLessZero (ntmp)) + { + sprintf (line->p, " - "); + len = 3; + EGlpNumSign (ntmp); + } + else + { + if (cnt > 0) + { + sprintf (line->p, " + "); + len = 3; + } + else + { + sprintf (line->p, " "); + len = 1; + } + } + line->p += len; + line->total += len; + if (EGlpNumIsNeqq (ntmp, oneLpNum)) + { + ILLwrite_lp_state_append_number (line, ntmp); + } + EGlpNumClearVar (ntmp); +} + +/* so that diff will not stumble over too many number format differences + * between c and java generated lp files we make here sure that doubles + * which are printed without a ".xxx" part get ".0" from us + */ +static void append_number ( + ILLwrite_lp_state * line, + EGlpNum_t v); +void ILLwrite_lp_state_append_number ( + ILLwrite_lp_state * line, + EGlpNum_t v) +{ + /* write a blank after 'inf' in case it is used as a coefficient and + * a variable follows */ + if (EGlpNumIsEqqual (v, ILL_MAXDOUBLE)) + { + ILLwrite_lp_state_append (line, "inf "); + } + else + { + if (EGlpNumIsEqqual (v, ILL_MINDOUBLE)) + { + ILLwrite_lp_state_append (line, "-inf "); + } + else + append_number (line, v); + } +} + +static void append_number ( + ILLwrite_lp_state * line, + EGlpNum_t v) +{ + int len = 0; + char *numstr = EGlpNumGetStr (v); + + sprintf (line->p, "%s%n", numstr, &len); + EGfree (numstr); + line->p += len; + line->total += len; +} + +#if 0 +#define D_SCALE (1e9) +static void append_number ( + ILLwrite_lp_state * line, + double x) +{ + /* Better code for writing rational problems */ + int i, k; + int got = 0; + double w, t; + int nnum = 0; + int nden = 0; + + if (x != 0.0) + { + if (x < 0.0) + w = -x; + else + w = x; + + for (i = -9, t = 0.000000001; i <= 7; i++, t *= 10.0) + { + if (w >= t && w <= t * 10) + { + got = 1; + break; + } + } + if (got == 0) + { + fprintf (stderr, "Out-of-range number: %f\n", x); + exit (1); + } + } + + if (x < 0.0) + { + sprintf (line->p, "-"); + line->p++; + line->total++; + x = -x; + } + + while (x >= 10.0 * D_SCALE) + { + x /= 10.0; + nnum++; + } + + /* (x != (double) (int) x) is a hack to let small integers print nicely */ + + while (x < D_SCALE && x != (double) (int) x) + { + x *= 10.0; + nden++; + } + + sprintf (line->p, "%.0f%n", x, &k); + line->p += k; + line->total += k; + + for (i = 0; i < nnum; i++) + { + sprintf (line->p, "0"); + line->p++; + line->total++; + } + + if (nden) + { + sprintf (line->p, "/1%n", &k); + line->p += k; + line->total += k; + for (i = 0; i < nden; i++) + { + sprintf (line->p, "0"); + line->p++; + line->total++; + } + } +} +#endif + +void ILLwrite_lp_state_save_start ( + ILLwrite_lp_state * line) +{ + line->startlen = line->total; +} + +void ILLwrite_lp_state_start ( + ILLwrite_lp_state * line) +{ + int j; + + for (j = 0; j < line->startlen; j++) + { + line->buf[j] = ' '; + } + line->buf[j] = '\0'; + line->p = line->buf + j; + line->total = j; +} diff --git a/src/write_lp.h b/src/write_lp.h new file mode 100644 index 0000000..f4ece97 --- /dev/null +++ b/src/write_lp.h @@ -0,0 +1,71 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCS_INFO = "$RCSfile: wr_lp.h,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:57:39 $"; */ +#ifndef WRITE_LP_STATE_H +#define WRITE_LP_STATE_H + +/****************************************************************************/ +/* */ +/* Routines to support writing of LP files */ +/* */ +/****************************************************************************/ + +/* + * -) anything after '\' is comment + * -) variables consist of a-z A-Z 0-9!"#$%(),;.?@_`'{}|~ + * don't start with a digit or '.' + */ +#include "iqsutil.h" + +typedef struct ILLwrite_lp_state +{ + char buf[ILL_namebufsize]; + char *p; + int startlen; + int total; +} +ILLwrite_lp_state; + +extern void ILLwrite_lp_state_init ( + ILLwrite_lp_state * line, + const char *str); +extern void ILLwrite_lp_state_append ( + ILLwrite_lp_state * line, + const char *str); +extern void ILLwrite_lp_state_append_coef ( + ILLwrite_lp_state * line, + EGlpNum_t v, + int cnt); + + /* append number sign ('+', '-') iff cnt > 0 or v < 0.0 + * append number iff v != 1.0, v != -1.0 + */ +extern void ILLwrite_lp_state_append_number ( + ILLwrite_lp_state * line, + EGlpNum_t v); +extern void ILLwrite_lp_state_save_start ( + ILLwrite_lp_state * line); +extern void ILLwrite_lp_state_start ( + ILLwrite_lp_state * line); + +#endif diff --git a/src/zeit.c b/src/zeit.c new file mode 100644 index 0000000..9fc0b35 --- /dev/null +++ b/src/zeit.c @@ -0,0 +1,292 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/* RCSINFO $Id: zeit.c,v 1.2 2003/11/05 16:47:22 meven Exp $ */ +/****************************************************************************/ +/* */ +/* This file is part of CONCORDE */ +/* */ +/* (c) Copyright 1995--1999 by David Applegate, Robert Bixby, */ +/* Vasek Chvatal, and William Cook */ +/* */ +/* Permission is granted for academic research use. For other uses, */ +/* contact the authors for licensing options. */ +/* */ +/* Use at your own risk. We make no guarantees about the */ +/* correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* TIMING FUNCTIONS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: Summer 1994 (cofeb16) */ +/* December 1997 (dla) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* double ILLutil_zeit (void) */ +/* - To measure cpu time. */ +/* To use this, set double t = ILLutil_zeit (), run the function you */ +/* want to time, then compute ILLutil_zeit () - t. */ +/* */ +/* double ILLutil_real_zeit (void) */ +/* - To measure wall clock time. */ +/* */ +/* To use this, set double t = ILLutil_real_zeit (), run the function */ +/* you want to time, then compute ILLutil_real_zeit () - t. */ +/* */ +/* void ILLutil_init_timer (ILLutil_timer *t, const char *name) */ +/* - Initializes a ILLutil_timer, and gives it a name. */ +/* - The name is silently truncated if it is too long. */ +/* */ +/* void ILLutil_start_timer (ILLutil_timer *t) */ +/* - Starts the timer. */ +/* */ +/* void ILLutil_suspend_timer (ILLutil_timer *t) */ +/* - Suspends the timer. Similar to ILLutil_stop_timer, but doesn't */ +/* count a call, and doesn't output. */ +/* */ +/* void ILLutil_resume_timer (QSutil_timer *t) */ +/* - Resumes the timer after a suspend. */ +/* */ +/* double ILLutil_stop_timer (ILLutil_timer *t, int printit) */ +/* - Stops the timer, and returns the time since the last start. */ +/* - if printit == 1, outputs the time spent. */ +/* - if printit == 2, outputs the time spent only if nonzero */ +/* - if printit == 3,4, like 1,2, except brief, table-form output */ +/* */ +/* double ILLutil_total_timer (ILLutil_timer *t, int printit) */ +/* - Returns the cumulative time for this timer. */ +/* - if printit == 1, outputs the cumulative time. */ +/* - if printit == 2, outputs the cumulative time only if nonzero */ +/* - if printit == 3,4, like 1,2, except brief, table-form output */ +/* */ +/****************************************************************************/ + + +#include "machdefs.h" +#include "util.h" +#ifdef USEDMALLOC +#include "dmalloc.h" +#endif + + +#ifdef HAVE_GETRUSAGE + +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif + +#define ZEIT_FCT "getrusage" + +double ILLutil_zeit ( + void) +{ + struct rusage ru; + double t; + + getrusage (RUSAGE_SELF, &ru); + + t = ((double) ru.ru_utime.tv_sec) + + ((double) ru.ru_utime.tv_usec) / 1000000.0; + return t; +} +#else /* HAVE_GETRUSAGE */ + +#ifdef HAVE_TIMES + +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYS_TIMES_H +# include +#endif + +#ifdef CLK_TCK +#define MACHINE_FREQ CLK_TCK +#else +#define MACHINE_FREQ HZ +#endif + +#define ZEIT_FCT "times" + +double ILLutil_zeit ( + void) +{ + struct tms now; + + times (&now); + return ((double) now.tms_utime) / ((double) MACHINE_FREQ); +} +#else /* HAVE_TIMES */ + +#ifdef HAVE_CLOCK + +#ifndef CLOCKS_PER_SEC +#ifdef CLK_TCK +#define CLOCKS_PER_SEC CLK_TCK +#else +#define CLOCKS_PER_SEC 60 +#endif +#endif + +#define ZEIT_FCT "clock" + +double ILLutil_zeit ( + void) +{ + return ((double) clock ()) / ((double) CLOCKS_PER_SEC); +} + +#else /* HAVE_CLOCK */ + +#define ZEIT_FCT "???" + +double ILLutil_zeit ( + void) +{ + return 0.0; +} +#endif /* HAVE_CLOCK */ +#endif /* HAVE_TIMES */ +#endif /* HAVE_GETRUSAGE */ + +double ILLutil_real_zeit ( + void) +{ + return time (0); +} + +void ILLutil_init_timer ( + ILLutil_timer * t, + const char *name) +{ + t->szeit = -1.0; + t->cum_zeit = 0.0; + t->count = 0; + if (name == (char *) NULL || name[0] == '\0') + { + strncpy (t->name, "ANONYMOUS", sizeof (t->name) - 1); + } + else + { + strncpy (t->name, name, sizeof (t->name) - 1); + } + t->name[sizeof (t->name) - 1] = '\0'; +} + +void ILLutil_start_timer ( + ILLutil_timer * t) +{ + if (t->szeit != -1.0) + { + fprintf (stderr, "Warning: restarting running timer %s\n", t->name); + } + t->szeit = ILLutil_zeit (); +} + +void ILLutil_suspend_timer ( + ILLutil_timer * t) +{ + if (t->szeit == -1.0) + { + fprintf (stderr, "Warning: suspended non-running timer %s\n", t->name); + return; + } + + t->cum_zeit += ILLutil_zeit () - t->szeit; + t->szeit = -1.0; +} + +void ILLutil_resume_timer ( + ILLutil_timer * t) +{ + if (t->szeit != -1.0) + { + fprintf (stderr, "Warning: resuming running timer %s\n", t->name); + return; + } + t->szeit = ILLutil_zeit (); +} + +static void ILL_print ( + ILLutil_timer * t, + double z, + int printit) +{ + if (printit == 1 || (printit == 2 && z > 0.0)) + { + if (t->count > 1) + { + printf ("Time for %s: %.2f seconds (%.2f total in %d calls).\n", + t->name, z, t->cum_zeit, t->count); + } + else + { + printf ("Time for %s: %.2f seconds.\n", t->name, z); + } + } + else if (printit == 3 || (printit == 4 && z > 0.0)) + { + printf ("T %-34.34s %9.2f %9.2f %d (%s)\n", + t->name, z, t->cum_zeit, t->count, ZEIT_FCT); + } + fflush (stdout); +} + +double ILLutil_stop_timer ( + ILLutil_timer * t, + int printit) +{ + double z; + + if (t->szeit == -1.0) + { + fprintf (stderr, "Warning: stopping non-running timer %s\n", t->name); + return 0.0; + } + z = ILLutil_zeit () - t->szeit; + t->szeit = -1.0; + t->cum_zeit += z; + t->count++; + ILL_print (t, z, printit); + return z; +} + +double ILLutil_total_timer ( + ILLutil_timer * t, + int printit) +{ + double z = t->cum_zeit; + + if (t->szeit != -1.0) + z += ILLutil_zeit () - t->szeit; + ILL_print (t, z, printit); + return z; +} diff --git a/src/zeit.h b/src/zeit.h new file mode 100644 index 0000000..9793a1d --- /dev/null +++ b/src/zeit.h @@ -0,0 +1,65 @@ +/****************************************************************************/ +/* */ +/* This file is part of QSopt_ex. */ +/* */ +/* (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash, */ +/* and Daniel Espinoza */ +/* */ +/* Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his */ +/* copyright in QSopt. */ +/* */ +/* This code may be used under the terms of the GNU General Public License */ +/* (Version 2.1 or later) as published by the Free Software Foundation. */ +/* */ +/* Alternatively, use is granted for research purposes only. */ +/* */ +/* It is your choice of which of these two licenses you are operating */ +/* under. */ +/* */ +/* We make no guarantees about the correctness or usefulness of this code. */ +/* */ +/****************************************************************************/ + +#ifndef __ZEIT_H__ +#define __ZEIT_H__ +/****************************************************************************/ +/* */ +/* zeit.c */ +/* */ +/****************************************************************************/ + +typedef struct ILLutil_timer +{ + double szeit; + double cum_zeit; + char name[40]; + int count; +} +ILLutil_timer; + + +double ILLutil_zeit ( + void), + ILLutil_real_zeit ( + void), + ILLutil_stop_timer ( + ILLutil_timer * t, + int printit), + ILLutil_total_timer ( + ILLutil_timer * t, + int printit); + + +void ILLutil_init_timer ( + ILLutil_timer * t, + const char *name), + ILLutil_start_timer ( + ILLutil_timer * t), + ILLutil_suspend_timer ( + ILLutil_timer * t), + ILLutil_resume_timer ( + ILLutil_timer * t); + + + +#endif