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