Added cddlib-094h from http://www.inf.ethz.ch/personal/fukudak/cdd_home/
Change-Id: I64519509269e434b1b9ea87c3fe0805e711c0ac9
diff --git a/third_party/cddlib/lib-src/Makefile.am b/third_party/cddlib/lib-src/Makefile.am
new file mode 100644
index 0000000..fe08dc3
--- /dev/null
+++ b/third_party/cddlib/lib-src/Makefile.am
@@ -0,0 +1,19 @@
+lib_LTLIBRARIES = libcdd.la
+
+libcdd_la_SOURCES = \
+cddcore.c \
+cddlp.c \
+cddmp.c \
+cddio.c \
+cddlib.c \
+cddproj.c \
+setoper.c
+
+include_HEADERS = \
+cdd.h \
+cddmp.h \
+cddtypes.h \
+setoper.h
+
+AM_CPPFLAGS = -UGMPRATIONAL
+AM_LDFLAGS = -version-info 0:0:0
diff --git a/third_party/cddlib/lib-src/Makefile.in b/third_party/cddlib/lib-src/Makefile.in
new file mode 100644
index 0000000..bd3c2b5
--- /dev/null
+++ b/third_party/cddlib/lib-src/Makefile.in
@@ -0,0 +1,508 @@
+# Makefile.in generated by automake 1.10.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lib-src
+DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libcdd_la_LIBADD =
+am_libcdd_la_OBJECTS = cddcore.lo cddlp.lo cddmp.lo cddio.lo cddlib.lo \
+ cddproj.lo setoper.lo
+libcdd_la_OBJECTS = $(am_libcdd_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libcdd_la_SOURCES)
+DIST_SOURCES = $(libcdd_la_SOURCES)
+includeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(include_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+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@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+lib_LTLIBRARIES = libcdd.la
+libcdd_la_SOURCES = \
+cddcore.c \
+cddlp.c \
+cddmp.c \
+cddio.c \
+cddlib.c \
+cddproj.c \
+setoper.c
+
+include_HEADERS = \
+cdd.h \
+cddmp.h \
+cddtypes.h \
+setoper.h
+
+AM_CPPFLAGS = -UGMPRATIONAL
+AM_LDFLAGS = -version-info 0:0:0
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib-src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lib-src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libcdd.la: $(libcdd_la_OBJECTS) $(libcdd_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libcdd_la_OBJECTS) $(libcdd_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cddcore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cddio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cddlib.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cddlp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cddmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cddproj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setoper.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
+ $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-includeHEADERS install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-includeHEADERS \
+ uninstall-libLTLIBRARIES
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/cddlib/lib-src/cdd.h b/third_party/cddlib/lib-src/cdd.h
new file mode 100644
index 0000000..6925745
--- /dev/null
+++ b/third_party/cddlib/lib-src/cdd.h
@@ -0,0 +1,290 @@
+/* cdd.h: Header file for cddlib.c
+ written by Komei Fukuda, fukuda@math.ethz.ch
+ Version 0.94h, April 30, 2015
+*/
+
+/* cddlib.c : C-Implementation of the double description method for
+ computing all vertices and extreme rays of the polyhedron
+ P= {x : b - A x >= 0}.
+ Please read COPYING (GNU General Public Licence) and
+ the manual cddlibman.tex for detail.
+*/
+
+#ifndef __CDD_H
+#define __CDD_H
+#endif /* __CDD_H */
+
+#ifndef __CDDMP_H
+#include "cddmp.h"
+#endif /* __CDDMP_H */
+
+#ifndef __CDDTYPES_H
+#include "cddtypes.h"
+#endif /* __CDDTYPES_H */
+
+#ifdef GMPRATIONAL
+#ifndef __CDD_HF
+#include "cdd_f.h"
+#endif
+#endif
+
+/* GLOBAL CONSTANTS and STATISTICS VARIABLES (to be set by dd_set_global_constants() */
+extern mytype dd_zero;
+extern mytype dd_one;
+extern mytype dd_purezero;
+extern mytype dd_minuszero;
+extern mytype dd_minusone;
+
+extern time_t dd_statStartTime; /* cddlib starting time */
+extern long dd_statBApivots; /* basis finding pivots */
+extern long dd_statCCpivots; /* criss-cross pivots */
+extern long dd_statDS1pivots; /* phase 1 pivots */
+extern long dd_statDS2pivots; /* phase 2 pivots */
+extern long dd_statACpivots; /* anticycling (cc) pivots */
+#ifdef GMPRATIONAL
+extern long dd_statBSpivots; /* basis status checking pivots */
+#endif
+extern dd_LPSolverType dd_choiceLPSolverDefault; /* Default LP solver Algorithm */
+extern dd_LPSolverType dd_choiceRedcheckAlgorithm; /* Redundancy Checking Algorithm */
+extern dd_boolean dd_choiceLexicoPivotQ; /* whether to use the lexicographic pivot */
+
+ /* to be used to avoid creating temporary spaces for mytype */
+#define dd_almostzero 1.0E-7
+
+/* ---------- FUNCTIONS MEANT TO BE PUBLIC ---------- */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* basic matrix manipulations */
+void dd_InitializeArow(dd_colrange,dd_Arow *);
+void dd_InitializeAmatrix(dd_rowrange,dd_colrange,dd_Amatrix *);
+void dd_InitializeBmatrix(dd_colrange, dd_Bmatrix *);
+dd_SetFamilyPtr dd_CreateSetFamily(dd_bigrange,dd_bigrange);
+void dd_FreeSetFamily(dd_SetFamilyPtr);
+dd_MatrixPtr dd_CreateMatrix(dd_rowrange,dd_colrange);
+void dd_FreeAmatrix(dd_rowrange,dd_colrange,dd_Amatrix);
+void dd_FreeArow(dd_colrange, dd_Arow);
+void dd_FreeBmatrix(dd_colrange,dd_Bmatrix);
+void dd_FreeDDMemory(dd_PolyhedraPtr);
+void dd_FreePolyhedra(dd_PolyhedraPtr);
+void dd_FreeMatrix(dd_MatrixPtr);
+void dd_SetToIdentity(dd_colrange, dd_Bmatrix);
+
+/* sign recognitions */
+dd_boolean dd_Nonnegative(mytype);
+dd_boolean dd_Nonpositive(mytype);
+dd_boolean dd_Positive(mytype);
+dd_boolean dd_Negative(mytype);
+dd_boolean dd_EqualToZero(mytype);
+dd_boolean dd_Nonzero(mytype);
+dd_boolean dd_Equal(mytype,mytype);
+dd_boolean dd_Larger(mytype,mytype);
+dd_boolean dd_Smaller(mytype,mytype);
+void dd_abs(mytype, mytype);
+void dd_LinearComb(mytype, mytype, mytype, mytype, mytype);
+void dd_InnerProduct(mytype, dd_colrange, dd_Arow, dd_Arow);
+
+/* major cddlib operations */
+dd_MatrixPtr dd_CopyInput(dd_PolyhedraPtr);
+dd_MatrixPtr dd_CopyOutput(dd_PolyhedraPtr);
+dd_MatrixPtr dd_CopyInequalities(dd_PolyhedraPtr);
+dd_MatrixPtr dd_CopyGenerators(dd_PolyhedraPtr);
+dd_SetFamilyPtr dd_CopyIncidence(dd_PolyhedraPtr);
+dd_SetFamilyPtr dd_CopyAdjacency(dd_PolyhedraPtr);
+dd_SetFamilyPtr dd_CopyInputIncidence(dd_PolyhedraPtr);
+dd_SetFamilyPtr dd_CopyInputAdjacency(dd_PolyhedraPtr);
+dd_boolean dd_DDFile2File(char *ifile, char *ofile, dd_ErrorType *err);
+dd_boolean dd_DDInputAppend(dd_PolyhedraPtr*, dd_MatrixPtr, dd_ErrorType*);
+dd_MatrixPtr dd_PolyFile2Matrix(FILE *f, dd_ErrorType *);
+
+dd_PolyhedraPtr dd_DDMatrix2Poly(dd_MatrixPtr, dd_ErrorType *);
+dd_PolyhedraPtr dd_DDMatrix2Poly2(dd_MatrixPtr, dd_RowOrderType, dd_ErrorType *);
+dd_boolean dd_Redundant(dd_MatrixPtr, dd_rowrange, dd_Arow, dd_ErrorType *); /* 092 */
+dd_rowset dd_RedundantRows(dd_MatrixPtr, dd_ErrorType *); /* 092 */
+dd_boolean dd_SRedundant(dd_MatrixPtr, dd_rowrange, dd_Arow, dd_ErrorType *); /* 093a */
+dd_rowset dd_SRedundantRows(dd_MatrixPtr, dd_ErrorType *); /* 093a */
+dd_rowset dd_RedundantRowsViaShooting(dd_MatrixPtr, dd_ErrorType *); /* 092 */
+dd_rowrange dd_RayShooting(dd_MatrixPtr, dd_Arow intpt, dd_Arow direction); /* 092 */
+ /* 092, find the first inequality "hit" by a ray from an intpt. */
+dd_boolean dd_ImplicitLinearity(dd_MatrixPtr, dd_rowrange, dd_Arow, dd_ErrorType *); /* 092 */
+dd_rowset dd_ImplicitLinearityRows(dd_MatrixPtr, dd_ErrorType *); /* 092 */
+int dd_FreeOfImplicitLinearity(dd_MatrixPtr, dd_Arow, dd_rowset *, dd_ErrorType *) ; /* 094 */
+dd_boolean dd_MatrixCanonicalizeLinearity(dd_MatrixPtr *, dd_rowset *,dd_rowindex *, dd_ErrorType *); /* 094 */
+dd_boolean dd_MatrixCanonicalize(dd_MatrixPtr *, dd_rowset *, dd_rowset *, dd_rowindex *, dd_ErrorType *); /* 094 */
+dd_boolean dd_MatrixRedundancyRemove(dd_MatrixPtr *M, dd_rowset *redset,dd_rowindex *newpos, dd_ErrorType *); /* 094 */
+dd_boolean dd_FindRelativeInterior(dd_MatrixPtr, dd_rowset *, dd_rowset *, dd_LPSolutionPtr *, dd_ErrorType *); /* 094 */
+dd_boolean dd_ExistsRestrictedFace(dd_MatrixPtr, dd_rowset, dd_rowset, dd_ErrorType *); /* 0.94 */
+dd_boolean dd_ExistsRestrictedFace2(dd_MatrixPtr, dd_rowset, dd_rowset, dd_LPSolutionPtr *, dd_ErrorType *); /* 0.94 */
+
+dd_SetFamilyPtr dd_Matrix2Adjacency(dd_MatrixPtr, dd_ErrorType *); /* 093 */
+dd_SetFamilyPtr dd_Matrix2WeakAdjacency(dd_MatrixPtr, dd_ErrorType *); /* 093a */
+long dd_MatrixRank(dd_MatrixPtr, dd_rowset, dd_colset, dd_rowset *, dd_colset *);
+
+/* Matrix Basic Operations */
+dd_MatrixPtr dd_MatrixCopy(dd_MatrixPtr); /* a new name for dd_CopyMatrix */
+dd_MatrixPtr dd_CopyMatrix(dd_MatrixPtr); /* 090c, kept for compatibility */
+dd_MatrixPtr dd_MatrixNormalizedCopy(dd_MatrixPtr); /* 094 */
+dd_MatrixPtr dd_MatrixNormalizedSortedCopy(dd_MatrixPtr,dd_rowindex*); /* 094 */
+dd_MatrixPtr dd_MatrixUniqueCopy(dd_MatrixPtr,dd_rowindex*); /* 094 */
+dd_MatrixPtr dd_MatrixNormalizedSortedUniqueCopy(dd_MatrixPtr,dd_rowindex*); /* 094 */
+dd_MatrixPtr dd_MatrixSortedUniqueCopy(dd_MatrixPtr,dd_rowindex*); /* 094 */
+
+dd_MatrixPtr dd_MatrixAppend(dd_MatrixPtr, dd_MatrixPtr); /* a name for dd_AppendMatrix */
+dd_MatrixPtr dd_AppendMatrix(dd_MatrixPtr, dd_MatrixPtr); /* 090c, kept for compatibility */
+
+int dd_MatrixAppendTo(dd_MatrixPtr*, dd_MatrixPtr); /* 092 */
+int dd_Remove(dd_MatrixPtr*, dd_rowrange); /* 092 */
+dd_MatrixPtr dd_MatrixSubmatrix(dd_MatrixPtr, dd_rowset delset); /* 092 */
+dd_MatrixPtr dd_MatrixSubmatrix2(dd_MatrixPtr, dd_rowset delset,dd_rowindex*); /* 094. It returns new row positions. */
+dd_MatrixPtr dd_MatrixSubmatrix2L(dd_MatrixPtr, dd_rowset delset,dd_rowindex*); /* 094. Linearity shifted up. */
+int dd_MatrixShiftupLinearity(dd_MatrixPtr *,dd_rowindex *); /* 094 */
+int dd_MatrixRowRemove(dd_MatrixPtr *M, dd_rowrange r); /* 092 */
+int dd_MatrixRowRemove2(dd_MatrixPtr *M, dd_rowrange r,dd_rowindex*); /* 094*/
+int dd_MatrixRowsRemove(dd_MatrixPtr *M, dd_rowset delset); /* 094 */
+int dd_MatrixRowsRemove2(dd_MatrixPtr *M, dd_rowset delset,dd_rowindex*); /* 094 */
+
+/* input/output */
+void dd_SetInputFile(FILE **f,dd_DataFileType inputfile, dd_ErrorType *);
+void dd_SetWriteFileName(dd_DataFileType, dd_DataFileType, char, dd_RepresentationType);
+
+void dd_WriteAmatrix(FILE *, dd_Amatrix, dd_rowrange, dd_colrange);
+void dd_WriteArow(FILE *f, dd_Arow a, dd_colrange);
+void dd_WriteBmatrix(FILE *, dd_colrange, dd_Bmatrix T);
+void dd_WriteMatrix(FILE *, dd_MatrixPtr);
+void dd_MatrixIntegerFilter(dd_MatrixPtr);
+void dd_WriteReal(FILE *, mytype);
+void dd_WriteNumber(FILE *f, mytype x);
+ /* write a number depending on the arithmetic used. */
+void dd_WritePolyFile(FILE *, dd_PolyhedraPtr);
+void dd_WriteRunningMode(FILE *, dd_PolyhedraPtr);
+void dd_WriteErrorMessages(FILE *, dd_ErrorType);
+void dd_WriteSetFamily(FILE *, dd_SetFamilyPtr);
+void dd_WriteSetFamilyCompressed(FILE *, dd_SetFamilyPtr);
+void dd_WriteProgramDescription(FILE *);
+void dd_WriteDDTimes(FILE *, dd_PolyhedraPtr);
+void dd_WriteTimes(FILE *, time_t, time_t);
+void dd_WriteIncidence(FILE *, dd_PolyhedraPtr);
+void dd_WriteAdjacency(FILE *, dd_PolyhedraPtr);
+void dd_WriteInputAdjacency(FILE *, dd_PolyhedraPtr);
+void dd_WriteInputIncidence(FILE *, dd_PolyhedraPtr);
+
+/* functions and types for LP solving */
+
+dd_LPPtr dd_Matrix2LP(dd_MatrixPtr, dd_ErrorType *);
+ /* Load a matrix to create an LP object. */
+
+dd_LPPtr dd_Matrix2Feasibility(dd_MatrixPtr, dd_ErrorType *);
+ /* Load a matrix to create an LP object for feasibility (obj == 0) .*/ /* 094 */
+
+dd_LPPtr dd_Matrix2Feasibility2(dd_MatrixPtr, dd_rowset, dd_rowset, dd_ErrorType *);
+ /* Load a matrix to create an LP object for feasibility with additional equality and
+ strict inequality constraints. */ /* 094 */
+
+dd_boolean dd_LPSolve(dd_LPPtr,dd_LPSolverType,dd_ErrorType *);
+dd_boolean dd_LPSolve0(dd_LPPtr,dd_LPSolverType,dd_ErrorType *);
+void dd_CrissCrossSolve(dd_LPPtr lp,dd_ErrorType *);
+void dd_DualSimplexSolve(dd_LPPtr lp,dd_ErrorType *);
+
+dd_LPPtr dd_MakeLPforInteriorFinding(dd_LPPtr);
+dd_LPSolutionPtr dd_CopyLPSolution(dd_LPPtr); /* 0.90c */
+void dd_WriteLP(FILE *, dd_LPPtr); /* 092 */
+
+dd_LPPtr dd_CreateLPData(dd_LPObjectiveType,dd_NumberType,dd_rowrange,dd_colrange);
+int dd_LPReverseRow(dd_LPPtr, dd_rowrange);
+ /* reverse the i-th row (1 <= i <= no. of rows) */
+int dd_LPReplaceRow(dd_LPPtr, dd_rowrange, dd_Arow);
+ /* replace the i-th row (1 <= i <= no. of rows) */
+dd_Arow dd_LPCopyRow(dd_LPPtr, dd_rowrange);
+ /* copy the i-th row (1 <= i <= no. of rows) */
+
+void dd_FreeLPData(dd_LPPtr);
+void dd_FreeLPSolution(dd_LPSolutionPtr);
+
+void dd_WriteLPResult(FILE *, dd_LPPtr, dd_ErrorType);
+void dd_WriteLPErrorMessages(FILE *, dd_ErrorType);
+void dd_WriteLPTimes(FILE *, dd_LPPtr);
+void dd_WriteLPStats(FILE *f);
+void dd_WriteLPMode(FILE *f);
+
+dd_MatrixPtr dd_FourierElimination(dd_MatrixPtr,dd_ErrorType *);
+dd_MatrixPtr dd_BlockElimination(dd_MatrixPtr, dd_colset, dd_ErrorType *);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* ---------- FUNCTIONS MEANT TO BE NON-PUBLIC ---------- */
+void dd_QuickSort(dd_rowindex, long, long, dd_Amatrix, long);
+void dd_RandomPermutation(dd_rowindex, long, unsigned int seed);
+void dd_UniqueRows(dd_rowindex, long, long, dd_Amatrix, long, dd_rowset, long *);
+
+dd_boolean dd_DoubleDescription(dd_PolyhedraPtr, dd_ErrorType*);
+dd_boolean dd_DoubleDescription2(dd_PolyhedraPtr, dd_RowOrderType, dd_ErrorType *);
+
+void dd_FreeDDMemory0(dd_ConePtr);
+void dd_fread_rational_value (FILE *f, mytype value);
+void dd_sread_rational_value (const char *s, mytype value);
+void dd_AddNewHalfspace1(dd_ConePtr, dd_rowrange);
+void dd_AddNewHalfspace2(dd_ConePtr, dd_rowrange);
+void dd_AddRay(dd_ConePtr, mytype *);
+void dd_AddArtificialRay(dd_ConePtr);
+void dd_AValue(mytype*,dd_colrange, dd_Amatrix, mytype *, dd_rowrange);
+void dd_CheckAdjacency(dd_ConePtr, dd_RayPtr*, dd_RayPtr*, dd_boolean *);
+void dd_CheckEquality(dd_colrange, dd_RayPtr *, dd_RayPtr *, dd_boolean *);
+void dd_ComputeRowOrderVector(dd_ConePtr);
+void dd_ConditionalAddEdge(dd_ConePtr,dd_RayPtr, dd_RayPtr, dd_RayPtr);
+void dd_CopyArow(mytype *, mytype *, dd_colrange);
+void dd_CopyNormalizedAmatrix(mytype **, mytype **, dd_rowrange, dd_colrange);
+void dd_CopyNormalizedArow(mytype *, mytype *, dd_colrange);
+void dd_CopyAmatrix(mytype **, mytype **, dd_rowrange, dd_colrange);
+void dd_PermuteCopyAmatrix(mytype **, mytype **, dd_rowrange, dd_colrange, dd_rowindex);
+void dd_PermutePartialCopyAmatrix(mytype **, mytype **, dd_rowrange, dd_colrange, dd_rowindex,dd_rowrange, dd_rowrange);
+void dd_CopyBmatrix(dd_colrange, dd_Bmatrix T, dd_Bmatrix TCOPY);
+void dd_CopyRay(mytype *, dd_colrange, dd_RayPtr,
+ dd_RepresentationType, dd_colindex);
+void dd_CreateInitialEdges(dd_ConePtr);
+void dd_CreateNewRay(dd_ConePtr, dd_RayPtr, dd_RayPtr, dd_rowrange);
+void dd_Eliminate(dd_ConePtr, dd_RayPtr*);
+void dd_EvaluateARay1(dd_rowrange, dd_ConePtr);
+void dd_EvaluateARay2(dd_rowrange, dd_ConePtr);
+void dd_FeasibilityIndices(long *, long *, dd_rowrange, dd_ConePtr);
+void dd_FindBasis(dd_ConePtr, long *rank);
+void dd_FindInitialRays(dd_ConePtr, dd_boolean *);
+void dd_ColumnReduce(dd_ConePtr);
+void dd_GaussianColumnPivot(dd_rowrange, dd_colrange, dd_Amatrix, dd_Bmatrix, dd_rowrange, dd_colrange);
+dd_boolean dd_LexSmaller(mytype *, mytype *, long);
+dd_boolean dd_LexLarger(mytype *, mytype *, long);
+dd_boolean dd_LexEqual(mytype *, mytype *, long);
+void dd_Normalize(dd_colrange, mytype *);
+void dd_MatrixIntegerFilter(dd_MatrixPtr);
+void dd_ProcessCommandLine(FILE*,dd_MatrixPtr, const char *);
+void dd_SelectNextHalfspace(dd_ConePtr, dd_rowset, dd_rowrange *);
+void dd_SelectPivot2(dd_rowrange,dd_colrange,dd_Amatrix,
+dd_Bmatrix,dd_RowOrderType,dd_rowindex, dd_rowset,dd_rowrange,dd_rowset,
+dd_colset,dd_rowrange *,dd_colrange *,dd_boolean *);
+void dd_SelectPreorderedNext(dd_ConePtr, dd_rowset, dd_rowrange *);
+void dd_SetInequalitySets(dd_ConePtr);
+void dd_SnapToInteger(mytype, mytype);
+void dd_StoreRay1(dd_ConePtr, mytype *, dd_boolean *);
+void dd_StoreRay2(dd_ConePtr, mytype *, dd_boolean *, dd_boolean *);
+void dd_TableauEntry(mytype *, dd_rowrange, dd_colrange, dd_Amatrix, dd_Bmatrix T, dd_rowrange, dd_colrange);
+void dd_UpdateEdges(dd_ConePtr, dd_RayPtr, dd_RayPtr);
+void dd_UpdateRowOrderVector(dd_ConePtr, dd_rowset PriorityRows);
+void dd_WriteRay(FILE *, dd_colrange, dd_RayPtr,
+ dd_RepresentationType, dd_colindex);
+void dd_ZeroIndexSet(dd_rowrange, dd_colrange, dd_Amatrix, mytype *, dd_rowset);
+
+/* New functions to handle data loading, NON-PUBLIC */
+dd_NumberType dd_GetNumberType(const char *);
+dd_ConePtr dd_ConeDataLoad(dd_PolyhedraPtr);
+dd_PolyhedraPtr dd_CreatePolyhedraData(dd_rowrange, dd_colrange);
+dd_boolean dd_InitializeConeData(dd_rowrange, dd_colrange, dd_ConePtr*);
+dd_boolean dd_AppendMatrix2Poly(dd_PolyhedraPtr*, dd_MatrixPtr);
+
+
+
+
+
+/* end of cddlib.h */
diff --git a/third_party/cddlib/lib-src/cddcore.c b/third_party/cddlib/lib-src/cddcore.c
new file mode 100644
index 0000000..de6f21f
--- /dev/null
+++ b/third_party/cddlib/lib-src/cddcore.c
@@ -0,0 +1,2110 @@
+/* cddcore.c: Core Procedures for cddlib
+ written by Komei Fukuda, fukuda@math.ethz.ch
+ Version 0.94h, April 30, 2015
+*/
+
+/* cddlib : C-library of the double description method for
+ computing all vertices and extreme rays of the polyhedron
+ P= {x : b - A x >= 0}.
+ Please read COPYING (GNU General Public Licence) and
+ the manual cddlibman.tex for detail.
+*/
+
+#include "setoper.h" /* set operation library header (Ver. June 1, 2000 or later) */
+#include "cdd.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+
+void dd_CheckAdjacency(dd_ConePtr cone,
+ dd_RayPtr *RP1, dd_RayPtr *RP2, dd_boolean *adjacent)
+{
+ dd_RayPtr TempRay;
+ dd_boolean localdebug=dd_FALSE;
+ static dd_rowset Face, Face1;
+ static dd_rowrange last_m=0;
+
+ if (last_m!=cone->m) {
+ if (last_m>0){
+ set_free(Face); set_free(Face1);
+ }
+ set_initialize(&Face, cone->m);
+ set_initialize(&Face1, cone->m);
+ last_m=cone->m;
+ }
+
+ if (dd_debug) localdebug=dd_TRUE;
+ *adjacent = dd_TRUE;
+ set_int(Face1, (*RP1)->ZeroSet, (*RP2)->ZeroSet);
+ set_int(Face, Face1, cone->AddedHalfspaces);
+ if (set_card(Face)< cone->d - 2) {
+ *adjacent = dd_FALSE;
+ if (localdebug) {
+ fprintf(stderr,"non adjacent: set_card(face) %ld < %ld = cone->d.\n",
+ set_card(Face),cone->d);
+ }
+ return;
+ }
+ else if (cone->parent->NondegAssumed) {
+ *adjacent = dd_TRUE;
+ return;
+ }
+ TempRay = cone->FirstRay;
+ while (TempRay != NULL && *adjacent) {
+ if (TempRay != *RP1 && TempRay != *RP2) {
+ set_int(Face1, TempRay->ZeroSet, cone->AddedHalfspaces);
+ if (set_subset(Face, Face1)) *adjacent = dd_FALSE;
+ }
+ TempRay = TempRay->Next;
+ }
+}
+
+void dd_Eliminate(dd_ConePtr cone, dd_RayPtr*Ptr)
+{
+ /*eliminate the record pointed by Ptr^.Next*/
+ dd_RayPtr TempPtr;
+ dd_colrange j;
+
+ TempPtr = (*Ptr)->Next;
+ (*Ptr)->Next = (*Ptr)->Next->Next;
+ if (TempPtr == cone->FirstRay) /*Update the first pointer*/
+ cone->FirstRay = (*Ptr)->Next;
+ if (TempPtr == cone->LastRay) /*Update the last pointer*/
+ cone->LastRay = *Ptr;
+
+ /* Added, Marc Pfetsch 010219 */
+ for (j=0;j < cone->d;j++)
+dd_clear(TempPtr->Ray[j]);
+ dd_clear(TempPtr->ARay);
+
+ free(TempPtr->Ray); /* free the ray vector memory */
+ set_free(TempPtr->ZeroSet); /* free the ZeroSet memory */
+ free(TempPtr); /* free the dd_Ray structure memory */
+ cone->RayCount--;
+}
+
+void dd_SetInequalitySets(dd_ConePtr cone)
+{
+ dd_rowrange i;
+
+ set_emptyset(cone->GroundSet);
+ set_emptyset(cone->EqualitySet);
+ set_emptyset(cone->NonequalitySet);
+ for (i = 1; i <= (cone->parent->m); i++){
+ set_addelem(cone->GroundSet, i);
+ if (cone->parent->EqualityIndex[i]==1) set_addelem(cone->EqualitySet,i);
+ if (cone->parent->EqualityIndex[i]==-1) set_addelem(cone->NonequalitySet,i);
+ }
+}
+
+
+void dd_AValue(mytype *val, dd_colrange d_size, dd_Amatrix A, mytype *p, dd_rowrange i)
+{
+ /*return the ith component of the vector A x p */
+ dd_colrange j;
+ mytype x;
+
+ dd_init(x);
+ dd_set(*val,dd_purezero);
+ /* Changed by Marc Pfetsch 010219 */
+
+ for (j = 0; j < d_size; j++){
+ dd_mul(x,A[i - 1][j], p[j]);
+ dd_add(*val, *val, x);
+ }
+ dd_clear(x);
+}
+
+void dd_StoreRay1(dd_ConePtr cone, mytype *p, dd_boolean *feasible)
+{ /* Original ray storing routine when RelaxedEnumeration is dd_FALSE */
+ dd_rowrange i,k,fii=cone->m+1;
+ dd_colrange j;
+ mytype temp;
+ dd_RayPtr RR;
+ dd_boolean localdebug=dd_debug;
+
+ dd_init(temp);
+ RR=cone->LastRay;
+ *feasible = dd_TRUE;
+ set_initialize(&(RR->ZeroSet),cone->m);
+ for (j = 0; j < cone->d; j++){
+ dd_set(RR->Ray[j],p[j]);
+ }
+ for (i = 1; i <= cone->m; i++) {
+ k=cone->OrderVector[i];
+ dd_AValue(&temp, cone->d, cone->A, p, k);
+ if (localdebug) {
+ fprintf(stderr,"dd_StoreRay1: dd_AValue at row %ld =",k);
+ dd_WriteNumber(stderr, temp);
+ fprintf(stderr,"\n");
+ }
+ if (dd_EqualToZero(temp)) {
+ set_addelem(RR->ZeroSet, k);
+ if (localdebug) {
+ fprintf(stderr,"recognized zero!\n");
+ }
+ }
+ if (dd_Negative(temp)){
+ if (localdebug) {
+ fprintf(stderr,"recognized negative!\n");
+ }
+ *feasible = dd_FALSE;
+ if (fii>cone->m) fii=i; /* the first violating inequality index */
+ if (localdebug) {
+ fprintf(stderr,"this ray is not feasible, neg comp = %ld\n", fii);
+ dd_WriteNumber(stderr, temp); fprintf(stderr,"\n");
+ }
+ }
+ }
+ RR->FirstInfeasIndex=fii;
+ RR->feasible = *feasible;
+ dd_clear(temp);
+}
+
+void dd_StoreRay2(dd_ConePtr cone, mytype *p,
+ dd_boolean *feasible, dd_boolean *weaklyfeasible)
+ /* Ray storing routine when RelaxedEnumeration is dd_TRUE.
+ weaklyfeasible is true iff it is feasible with
+ the strict_inequality conditions deleted. */
+{
+ dd_RayPtr RR;
+ dd_rowrange i,k,fii=cone->m+1;
+ dd_colrange j;
+ mytype temp;
+ dd_boolean localdebug=dd_debug;
+
+ dd_init(temp);
+ RR=cone->LastRay;
+ if (dd_debug) localdebug=dd_TRUE;
+ *feasible = dd_TRUE;
+ *weaklyfeasible = dd_TRUE;
+ set_initialize(&(RR->ZeroSet),cone->m);
+ for (j = 0; j < cone->d; j++){
+ dd_set(RR->Ray[j],p[j]);
+ }
+ for (i = 1; i <= cone->m; i++) {
+ k=cone->OrderVector[i];
+ dd_AValue(&temp, cone->d, cone->A, p, k);
+ if (dd_EqualToZero(temp)){
+ set_addelem(RR->ZeroSet, k);
+ if (cone->parent->EqualityIndex[k]==-1)
+ *feasible=dd_FALSE; /* strict inequality required */
+ }
+/* if (temp < -zero){ */
+ if (dd_Negative(temp)){
+ *feasible = dd_FALSE;
+ if (fii>cone->m && cone->parent->EqualityIndex[k]>=0) {
+ fii=i; /* the first violating inequality index */
+ *weaklyfeasible=dd_FALSE;
+ }
+ }
+ }
+ RR->FirstInfeasIndex=fii;
+ RR->feasible = *feasible;
+ dd_clear(temp);
+}
+
+
+void dd_AddRay(dd_ConePtr cone, mytype *p)
+{
+ dd_boolean feasible, weaklyfeasible;
+ dd_colrange j;
+
+ if (cone->FirstRay == NULL) {
+ cone->FirstRay = (dd_RayPtr) malloc(sizeof(dd_RayType));
+ cone->FirstRay->Ray = (mytype *) calloc(cone->d, sizeof(mytype));
+ for (j=0; j<cone->d; j++) dd_init(cone->FirstRay->Ray[j]);
+ dd_init(cone->FirstRay->ARay);
+ if (dd_debug)
+ fprintf(stderr,"Create the first ray pointer\n");
+ cone->LastRay = cone->FirstRay;
+ cone->ArtificialRay->Next = cone->FirstRay;
+ } else {
+ cone->LastRay->Next = (dd_RayPtr) malloc(sizeof(dd_RayType));
+ cone->LastRay->Next->Ray = (mytype *) calloc(cone->d, sizeof(mytype));
+ for (j=0; j<cone->d; j++) dd_init(cone->LastRay->Next->Ray[j]);
+ dd_init(cone->LastRay->Next->ARay);
+ if (dd_debug) fprintf(stderr,"Create a new ray pointer\n");
+ cone->LastRay = cone->LastRay->Next;
+ }
+ cone->LastRay->Next = NULL;
+ cone->RayCount++;
+ cone->TotalRayCount++;
+ if (dd_debug) {
+ if (cone->TotalRayCount % 100 == 0) {
+ fprintf(stderr,"*Rays (Total, Currently Active, Feasible) =%8ld%8ld%8ld\n",
+ cone->TotalRayCount, cone->RayCount, cone->FeasibleRayCount);
+ }
+ }
+ if (cone->parent->RelaxedEnumeration){
+ dd_StoreRay2(cone, p, &feasible, &weaklyfeasible);
+ if (weaklyfeasible) (cone->WeaklyFeasibleRayCount)++;
+ } else {
+ dd_StoreRay1(cone, p, &feasible);
+ if (feasible) (cone->WeaklyFeasibleRayCount)++;
+ /* weaklyfeasible is equiv. to feasible in this case. */
+ }
+ if (!feasible) return;
+ else {
+ (cone->FeasibleRayCount)++;
+ }
+}
+
+void dd_AddArtificialRay(dd_ConePtr cone)
+{
+ dd_Arow zerovector;
+ dd_colrange j,d1;
+ dd_boolean feasible;
+
+ if (cone->d<=0) d1=1; else d1=cone->d;
+ dd_InitializeArow(d1, &zerovector);
+ if (cone->ArtificialRay != NULL) {
+ fprintf(stderr,"Warning !!! FirstRay in not nil. Illegal Call\n");
+ free(zerovector); /* 086 */
+ return;
+ }
+ cone->ArtificialRay = (dd_RayPtr) malloc(sizeof(dd_RayType));
+ cone->ArtificialRay->Ray = (mytype *) calloc(d1, sizeof(mytype));
+ for (j=0; j<d1; j++) dd_init(cone->ArtificialRay->Ray[j]);
+ dd_init(cone->ArtificialRay->ARay);
+
+ if (dd_debug) fprintf(stderr,"Create the artificial ray pointer\n");
+
+ cone->LastRay=cone->ArtificialRay;
+ dd_StoreRay1(cone, zerovector, &feasible);
+ /* This stores a vector to the record pointed by cone->LastRay */
+ cone->ArtificialRay->Next = NULL;
+ for (j = 0; j < d1; j++){
+ dd_clear(zerovector[j]);
+ }
+ free(zerovector); /* 086 */
+}
+
+void dd_ConditionalAddEdge(dd_ConePtr cone,
+ dd_RayPtr Ray1, dd_RayPtr Ray2, dd_RayPtr ValidFirstRay)
+{
+ long it,it_row,fii1,fii2,fmin,fmax;
+ dd_boolean adjacent,lastchance;
+ dd_RayPtr TempRay,Rmin,Rmax;
+ dd_AdjacencyType *NewEdge;
+ dd_boolean localdebug=dd_FALSE;
+ dd_rowset ZSmin, ZSmax;
+ static dd_rowset Face, Face1;
+ static dd_rowrange last_m=0;
+
+ if (last_m!=cone->m) {
+ if (last_m>0){
+ set_free(Face); set_free(Face1);
+ }
+ set_initialize(&Face, cone->m);
+ set_initialize(&Face1, cone->m);
+ last_m=cone->m;
+ }
+
+ fii1=Ray1->FirstInfeasIndex;
+ fii2=Ray2->FirstInfeasIndex;
+ if (fii1<fii2){
+ fmin=fii1; fmax=fii2;
+ Rmin=Ray1;
+ Rmax=Ray2;
+ }
+ else{
+ fmin=fii2; fmax=fii1;
+ Rmin=Ray2;
+ Rmax=Ray1;
+ }
+ ZSmin = Rmin->ZeroSet;
+ ZSmax = Rmax->ZeroSet;
+ if (localdebug) {
+ fprintf(stderr,"dd_ConditionalAddEdge: FMIN = %ld (row%ld) FMAX=%ld\n",
+ fmin, cone->OrderVector[fmin], fmax);
+ }
+ if (fmin==fmax){
+ if (localdebug) fprintf(stderr,"dd_ConditionalAddEdge: equal FII value-> No edge added\n");
+ }
+ else if (set_member(cone->OrderVector[fmin],ZSmax)){
+ if (localdebug) fprintf(stderr,"dd_ConditionalAddEdge: No strong separation -> No edge added\n");
+ }
+ else { /* the pair will be separated at the iteration fmin */
+ lastchance=dd_TRUE;
+ /* flag to check it will be the last chance to store the edge candidate */
+ set_int(Face1, ZSmax, ZSmin);
+ (cone->count_int)++;
+ if (localdebug){
+ fprintf(stderr,"Face: ");
+ for (it=1; it<=cone->m; it++) {
+ it_row=cone->OrderVector[it];
+ if (set_member(it_row, Face1)) fprintf(stderr,"%ld ",it_row);
+ }
+ fprintf(stderr,"\n");
+ }
+ for (it=cone->Iteration+1; it < fmin && lastchance; it++){
+ it_row=cone->OrderVector[it];
+ if (cone->parent->EqualityIndex[it_row]>=0 && set_member(it_row, Face1)){
+ lastchance=dd_FALSE;
+ (cone->count_int_bad)++;
+ if (localdebug){
+ fprintf(stderr,"There will be another chance iteration %ld (row %ld) to store the pair\n", it, it_row);
+ }
+ }
+ }
+ if (lastchance){
+ adjacent = dd_TRUE;
+ (cone->count_int_good)++;
+ /* adjacent checking */
+ set_int(Face, Face1, cone->AddedHalfspaces);
+ if (localdebug){
+ fprintf(stderr,"Check adjacency\n");
+ fprintf(stderr,"AddedHalfspaces: "); set_fwrite(stderr,cone->AddedHalfspaces);
+ fprintf(stderr,"Face: ");
+ for (it=1; it<=cone->m; it++) {
+ it_row=cone->OrderVector[it];
+ if (set_member(it_row, Face)) fprintf(stderr,"%ld ",it_row);
+ }
+ fprintf(stderr,"\n");
+ }
+ if (set_card(Face)< cone->d - 2) {
+ adjacent = dd_FALSE;
+ }
+ else if (cone->parent->NondegAssumed) {
+ adjacent = dd_TRUE;
+ }
+ else{
+ TempRay = ValidFirstRay; /* the first ray for adjacency checking */
+ while (TempRay != NULL && adjacent) {
+ if (TempRay != Ray1 && TempRay != Ray2) {
+ set_int(Face1, TempRay->ZeroSet, cone->AddedHalfspaces);
+ if (set_subset(Face, Face1)) {
+ if (localdebug) set_fwrite(stderr,Face1);
+ adjacent = dd_FALSE;
+ }
+ }
+ TempRay = TempRay->Next;
+ }
+ }
+ if (adjacent){
+ if (localdebug) fprintf(stderr,"The pair is adjacent and the pair must be stored for iteration %ld (row%ld)\n",
+ fmin, cone->OrderVector[fmin]);
+ NewEdge=(dd_AdjacencyPtr) malloc(sizeof *NewEdge);
+ NewEdge->Ray1=Rmax; /* save the one remains in iteration fmin in the first */
+ NewEdge->Ray2=Rmin; /* save the one deleted in iteration fmin in the second */
+ NewEdge->Next=NULL;
+ (cone->EdgeCount)++;
+ (cone->TotalEdgeCount)++;
+ if (cone->Edges[fmin]==NULL){
+ cone->Edges[fmin]=NewEdge;
+ if (localdebug) fprintf(stderr,"Create a new edge list of %ld\n", fmin);
+ }else{
+ NewEdge->Next=cone->Edges[fmin];
+ cone->Edges[fmin]=NewEdge;
+ }
+ }
+ }
+ }
+}
+
+void dd_CreateInitialEdges(dd_ConePtr cone)
+{
+ dd_RayPtr Ptr1, Ptr2;
+ dd_rowrange fii1,fii2;
+ long count=0;
+ dd_boolean adj,localdebug=dd_FALSE;
+
+ cone->Iteration=cone->d; /* CHECK */
+ if (cone->FirstRay ==NULL || cone->LastRay==NULL){
+ /* fprintf(stderr,"Warning: dd_ CreateInitialEdges called with NULL pointer(s)\n"); */
+ goto _L99;
+ }
+ Ptr1=cone->FirstRay;
+ while(Ptr1!=cone->LastRay && Ptr1!=NULL){
+ fii1=Ptr1->FirstInfeasIndex;
+ Ptr2=Ptr1->Next;
+ while(Ptr2!=NULL){
+ fii2=Ptr2->FirstInfeasIndex;
+ count++;
+ if (localdebug) fprintf(stderr,"dd_ CreateInitialEdges: edge %ld \n",count);
+ dd_CheckAdjacency(cone, &Ptr1, &Ptr2, &adj);
+ if (fii1!=fii2 && adj)
+ dd_ConditionalAddEdge(cone, Ptr1, Ptr2, cone->FirstRay);
+ Ptr2=Ptr2->Next;
+ }
+ Ptr1=Ptr1->Next;
+ }
+_L99:;
+}
+
+
+void dd_UpdateEdges(dd_ConePtr cone, dd_RayPtr RRbegin, dd_RayPtr RRend)
+/* This procedure must be called after the ray list is sorted
+ by dd_EvaluateARay2 so that FirstInfeasIndex's are monotonically
+ increasing.
+*/
+{
+ dd_RayPtr Ptr1, Ptr2begin, Ptr2;
+ dd_rowrange fii1;
+ dd_boolean ptr2found,quit,localdebug=dd_FALSE;
+ long count=0,pos1, pos2;
+ float workleft,prevworkleft=110.0,totalpairs;
+
+ totalpairs=(cone->ZeroRayCount-1.0)*(cone->ZeroRayCount-2.0)+1.0;
+ Ptr2begin = NULL;
+ if (RRbegin ==NULL || RRend==NULL){
+ if (1) fprintf(stderr,"Warning: dd_UpdateEdges called with NULL pointer(s)\n");
+ goto _L99;
+ }
+ Ptr1=RRbegin;
+ pos1=1;
+ do{
+ ptr2found=dd_FALSE;
+ quit=dd_FALSE;
+ fii1=Ptr1->FirstInfeasIndex;
+ pos2=2;
+ for (Ptr2=Ptr1->Next; !ptr2found && !quit; Ptr2=Ptr2->Next,pos2++){
+ if (Ptr2->FirstInfeasIndex > fii1){
+ Ptr2begin=Ptr2;
+ ptr2found=dd_TRUE;
+ }
+ else if (Ptr2==RRend) quit=dd_TRUE;
+ }
+ if (ptr2found){
+ quit=dd_FALSE;
+ for (Ptr2=Ptr2begin; !quit ; Ptr2=Ptr2->Next){
+ count++;
+ if (localdebug) fprintf(stderr,"dd_UpdateEdges: edge %ld \n",count);
+ dd_ConditionalAddEdge(cone, Ptr1,Ptr2,RRbegin);
+ if (Ptr2==RRend || Ptr2->Next==NULL) quit=dd_TRUE;
+ }
+ }
+ Ptr1=Ptr1->Next;
+ pos1++;
+ workleft = 100.0 * (cone->ZeroRayCount-pos1) * (cone->ZeroRayCount - pos1-1.0) / totalpairs;
+ if (cone->ZeroRayCount>=500 && dd_debug && pos1%10 ==0 && prevworkleft-workleft>=10 ) {
+ fprintf(stderr,"*Work of iteration %5ld(/%ld): %4ld/%4ld => %4.1f%% left\n",
+ cone->Iteration, cone->m, pos1, cone->ZeroRayCount, workleft);
+ prevworkleft=workleft;
+ }
+ }while(Ptr1!=RRend && Ptr1!=NULL);
+_L99:;
+}
+
+void dd_FreeDDMemory0(dd_ConePtr cone)
+{
+ dd_RayPtr Ptr, PrevPtr;
+ long count;
+ dd_colrange j;
+ dd_boolean localdebug=dd_FALSE;
+
+ /* THIS SHOULD BE REWRITTEN carefully */
+ PrevPtr=cone->ArtificialRay;
+ if (PrevPtr!=NULL){
+ count=0;
+ for (Ptr=cone->ArtificialRay->Next; Ptr!=NULL; Ptr=Ptr->Next){
+ /* Added Marc Pfetsch 2/19/01 */
+ for (j=0;j < cone->d;j++)
+dd_clear(PrevPtr->Ray[j]);
+ dd_clear(PrevPtr->ARay);
+
+ free(PrevPtr->Ray);
+ free(PrevPtr->ZeroSet);
+ free(PrevPtr);
+ count++;
+ PrevPtr=Ptr;
+ };
+ cone->FirstRay=NULL;
+ /* Added Marc Pfetsch 010219 */
+ for (j=0;j < cone->d;j++)
+dd_clear(cone->LastRay->Ray[j]);
+ dd_clear(cone->LastRay->ARay);
+
+ free(cone->LastRay->Ray);
+ cone->LastRay->Ray = NULL;
+ set_free(cone->LastRay->ZeroSet);
+ cone->LastRay->ZeroSet = NULL;
+ free(cone->LastRay);
+ cone->LastRay = NULL;
+ cone->ArtificialRay=NULL;
+ if (localdebug) fprintf(stderr,"%ld ray storage spaces freed\n",count);
+ }
+/* must add (by Sato) */
+ free(cone->Edges);
+
+ set_free(cone->GroundSet);
+ set_free(cone->EqualitySet);
+ set_free(cone->NonequalitySet);
+ set_free(cone->AddedHalfspaces);
+ set_free(cone->WeaklyAddedHalfspaces);
+ set_free(cone->InitialHalfspaces);
+ free(cone->InitialRayIndex);
+ free(cone->OrderVector);
+ free(cone->newcol);
+
+/* Fixed by Shawn Rusaw. Originally it was cone->d instead of cone->d_alloc */
+ dd_FreeBmatrix(cone->d_alloc,cone->B);
+ dd_FreeBmatrix(cone->d_alloc,cone->Bsave);
+
+/* Fixed by Marc Pfetsch 010219*/
+ dd_FreeAmatrix(cone->m_alloc,cone->d_alloc,cone->A);
+ cone->A = NULL;
+
+ free(cone);
+}
+
+void dd_FreeDDMemory(dd_PolyhedraPtr poly)
+{
+ dd_FreeDDMemory0(poly->child);
+ poly->child=NULL;
+}
+
+void dd_FreePolyhedra(dd_PolyhedraPtr poly)
+{
+ dd_bigrange i;
+
+ if ((poly)->child != NULL) dd_FreeDDMemory(poly);
+ dd_FreeAmatrix((poly)->m_alloc,poly->d_alloc, poly->A);
+ dd_FreeArow((poly)->d_alloc,(poly)->c);
+ free((poly)->EqualityIndex);
+ if (poly->AincGenerated){
+ for (i=1; i<=poly->m1; i++){
+ set_free(poly->Ainc[i-1]);
+ }
+ free(poly->Ainc);
+ set_free(poly->Ared);
+ set_free(poly->Adom);
+ poly->Ainc=NULL;
+ }
+
+ free(poly);
+}
+
+void dd_Normalize(dd_colrange d_size, mytype *V)
+{
+ long j,jmin=0;
+ mytype temp,min;
+ dd_boolean nonzerofound=dd_FALSE;
+
+ if (d_size>0){
+ dd_init(min); dd_init(temp);
+ dd_abs(min,V[0]); jmin=0; /* set the minmizer to 0 */
+ if (dd_Positive(min)) nonzerofound=dd_TRUE;
+ for (j = 1; j < d_size; j++) {
+ dd_abs(temp,V[j]);
+ if (dd_Positive(temp)){
+ if (!nonzerofound || dd_Smaller(temp,min)){
+ nonzerofound=dd_TRUE;
+ dd_set(min, temp); jmin=j;
+ }
+ }
+ }
+ if (dd_Positive(min)){
+ for (j = 0; j < d_size; j++) dd_div(V[j], V[j], min);
+ }
+ dd_clear(min); dd_clear(temp);
+ }
+}
+
+
+void dd_ZeroIndexSet(dd_rowrange m_size, dd_colrange d_size, dd_Amatrix A, mytype *x, dd_rowset ZS)
+{
+ dd_rowrange i;
+ mytype temp;
+
+ /* Changed by Marc Pfetsch 010219 */
+ dd_init(temp);
+ set_emptyset(ZS);
+ for (i = 1; i <= m_size; i++) {
+ dd_AValue(&temp, d_size, A, x, i);
+ if (dd_EqualToZero(temp)) set_addelem(ZS, i);
+ }
+
+ /* Changed by Marc Pfetsch 010219 */
+ dd_clear(temp);
+}
+
+void dd_CopyBmatrix(dd_colrange d_size, dd_Bmatrix T, dd_Bmatrix TCOPY)
+{
+ dd_rowrange i;
+ dd_colrange j;
+
+ for (i=0; i < d_size; i++) {
+ for (j=0; j < d_size; j++) {
+ dd_set(TCOPY[i][j],T[i][j]);
+ }
+ }
+}
+
+
+void dd_CopyArow(mytype *acopy, mytype *a, dd_colrange d)
+{
+ dd_colrange j;
+
+ for (j = 0; j < d; j++) {
+ dd_set(acopy[j],a[j]);
+ }
+}
+
+void dd_CopyNormalizedArow(mytype *acopy, mytype *a, dd_colrange d)
+{
+ dd_CopyArow(acopy, a, d);
+ dd_Normalize(d,acopy);
+}
+
+void dd_CopyAmatrix(mytype **Acopy, mytype **A, dd_rowrange m, dd_colrange d)
+{
+ dd_rowrange i;
+
+ for (i = 0; i< m; i++) {
+ dd_CopyArow(Acopy[i],A[i],d);
+ }
+}
+
+void dd_CopyNormalizedAmatrix(mytype **Acopy, mytype **A, dd_rowrange m, dd_colrange d)
+{
+ dd_rowrange i;
+
+ for (i = 0; i< m; i++) {
+ dd_CopyNormalizedArow(Acopy[i],A[i],d);
+ }
+}
+
+void dd_PermuteCopyAmatrix(mytype **Acopy, mytype **A, dd_rowrange m, dd_colrange d, dd_rowindex roworder)
+{
+ dd_rowrange i;
+
+ for (i = 1; i<= m; i++) {
+ dd_CopyArow(Acopy[i-1],A[roworder[i]-1],d);
+ }
+}
+
+void dd_PermutePartialCopyAmatrix(mytype **Acopy, mytype **A, dd_rowrange m, dd_colrange d, dd_rowindex roworder,dd_rowrange p, dd_rowrange q)
+{
+ /* copy the rows of A whose roworder is positive. roworder[i] is the row index of the copied row. */
+ dd_rowrange i,k;
+
+ k=0;
+ for (i = 1; i<= m; i++) {
+ if (roworder[i]>0) dd_CopyArow(Acopy[roworder[i]-1],A[i-1],d);
+ }
+}
+
+void dd_InitializeArow(dd_colrange d,dd_Arow *a)
+{
+ dd_colrange j;
+
+ if (d>0) *a=(mytype*) calloc(d,sizeof(mytype));
+ for (j = 0; j < d; j++) {
+ dd_init((*a)[j]);
+ }
+}
+
+void dd_InitializeAmatrix(dd_rowrange m,dd_colrange d,dd_Amatrix *A)
+{
+ dd_rowrange i;
+
+ if (m>0) (*A)=(mytype**) calloc(m,sizeof(mytype*));
+ for (i = 0; i < m; i++) {
+ dd_InitializeArow(d,&((*A)[i]));
+ }
+}
+
+void dd_FreeAmatrix(dd_rowrange m,dd_colrange d,dd_Amatrix A)
+{
+ dd_rowrange i;
+ dd_colrange j;
+
+ for (i = 0; i < m; i++) {
+ for (j = 0; j < d; j++) {
+ dd_clear(A[i][j]);
+ }
+ }
+ if (A!=NULL) {
+ for (i = 0; i < m; i++) {
+ free(A[i]);
+ }
+ free(A);
+ }
+}
+
+void dd_FreeArow(dd_colrange d, dd_Arow a)
+{
+ dd_colrange j;
+
+ for (j = 0; j < d; j++) {
+ dd_clear(a[j]);
+ }
+ free(a);
+}
+
+
+void dd_InitializeBmatrix(dd_colrange d,dd_Bmatrix *B)
+{
+ dd_colrange i,j;
+
+ (*B)=(mytype**) calloc(d,sizeof(mytype*));
+ for (j = 0; j < d; j++) {
+ (*B)[j]=(mytype*) calloc(d,sizeof(mytype));
+ }
+ for (i = 0; i < d; i++) {
+ for (j = 0; j < d; j++) {
+ dd_init((*B)[i][j]);
+ }
+ }
+}
+
+void dd_FreeBmatrix(dd_colrange d,dd_Bmatrix B)
+{
+ dd_colrange i,j;
+
+ for (i = 0; i < d; i++) {
+ for (j = 0; j < d; j++) {
+ dd_clear(B[i][j]);
+ }
+ }
+ if (B!=NULL) {
+ for (j = 0; j < d; j++) {
+ free(B[j]);
+ }
+ free(B);
+ }
+}
+
+dd_SetFamilyPtr dd_CreateSetFamily(dd_bigrange fsize, dd_bigrange ssize)
+{
+ dd_SetFamilyPtr F;
+ dd_bigrange i,f0,f1,s0,s1;
+
+ if (fsize<=0) {
+ f0=0; f1=1;
+ /* if fsize<=0, the fsize is set to zero and the created size is one */
+ } else {
+ f0=fsize; f1=fsize;
+ }
+ if (ssize<=0) {
+ s0=0; s1=1;
+ /* if ssize<=0, the ssize is set to zero and the created size is one */
+ } else {
+ s0=ssize; s1=ssize;
+ }
+
+ F=(dd_SetFamilyPtr) malloc (sizeof(dd_SetFamilyType));
+ F->set=(set_type*) calloc(f1,sizeof(set_type));
+ for (i=0; i<f1; i++) {
+ set_initialize(&(F->set[i]), s1);
+ }
+ F->famsize=f0;
+ F->setsize=s0;
+ return F;
+}
+
+
+void dd_FreeSetFamily(dd_SetFamilyPtr F)
+{
+ dd_bigrange i,f1;
+
+ if (F!=NULL){
+ if (F->famsize<=0) f1=1; else f1=F->famsize;
+ /* the smallest created size is one */
+ for (i=0; i<f1; i++) {
+ set_free(F->set[i]);
+ }
+ free(F->set);
+ free(F);
+ }
+}
+
+dd_MatrixPtr dd_CreateMatrix(dd_rowrange m_size,dd_colrange d_size)
+{
+ dd_MatrixPtr M;
+ dd_rowrange m0,m1;
+ dd_colrange d0,d1;
+
+ if (m_size<=0){
+ m0=0; m1=1;
+ /* if m_size <=0, the number of rows is set to zero, the actual size is 1 */
+ } else {
+ m0=m_size; m1=m_size;
+ }
+ if (d_size<=0){
+ d0=0; d1=1;
+ /* if d_size <=0, the number of cols is set to zero, the actual size is 1 */
+ } else {
+ d0=d_size; d1=d_size;
+ }
+ M=(dd_MatrixPtr) malloc (sizeof(dd_MatrixType));
+ dd_InitializeAmatrix(m1,d1,&(M->matrix));
+ dd_InitializeArow(d1,&(M->rowvec));
+ M->rowsize=m0;
+ set_initialize(&(M->linset), m1);
+ M->colsize=d0;
+ M->objective=dd_LPnone;
+ M->numbtype=dd_Unknown;
+ M->representation=dd_Unspecified;
+ return M;
+}
+
+void dd_FreeMatrix(dd_MatrixPtr M)
+{
+ dd_rowrange m1;
+ dd_colrange d1;
+
+ if (M!=NULL) {
+ if (M->rowsize<=0) m1=1; else m1=M->rowsize;
+ if (M->colsize<=0) d1=1; else d1=M->colsize;
+ if (M!=NULL) {
+ dd_FreeAmatrix(m1,d1,M->matrix);
+ dd_FreeArow(d1,M->rowvec);
+ set_free(M->linset);
+ free(M);
+ }
+ }
+}
+
+void dd_SetToIdentity(dd_colrange d_size, dd_Bmatrix T)
+{
+ dd_colrange j1, j2;
+
+ for (j1 = 1; j1 <= d_size; j1++) {
+ for (j2 = 1; j2 <= d_size; j2++) {
+ if (j1 == j2)
+ dd_set(T[j1 - 1][j2 - 1],dd_one);
+ else
+ dd_set(T[j1 - 1][j2 - 1],dd_purezero);
+ }
+ }
+}
+
+void dd_ColumnReduce(dd_ConePtr cone)
+{
+ dd_colrange j,j1=0;
+ dd_rowrange i;
+ dd_boolean localdebug=dd_FALSE;
+
+ for (j=1;j<=cone->d;j++) {
+ if (cone->InitialRayIndex[j]>0){
+ j1=j1+1;
+ if (j1<j) {
+ for (i=1; i<=cone->m; i++) dd_set(cone->A[i-1][j1-1],cone->A[i-1][j-1]);
+ cone->newcol[j]=j1;
+ if (localdebug){
+ fprintf(stderr,"shifting the column %ld to column %ld\n", j, j1);
+ }
+ /* shifting forward */
+ }
+ } else {
+ cone->newcol[j]=0;
+ if (localdebug) {
+ fprintf(stderr,"a generator (or an equation) of the linearity space: ");
+ for (i=1; i<=cone->d; i++) dd_WriteNumber(stderr, cone->B[i-1][j-1]);
+ fprintf(stderr,"\n");
+ }
+ }
+ }
+ cone->d=j1; /* update the dimension. cone->d_orig remembers the old. */
+ dd_CopyBmatrix(cone->d_orig, cone->B, cone->Bsave);
+ /* save the dual basis inverse as Bsave. This matrix contains the linearity space generators. */
+ cone->ColReduced=dd_TRUE;
+}
+
+long dd_MatrixRank(dd_MatrixPtr M, dd_rowset ignoredrows, dd_colset ignoredcols, dd_rowset *rowbasis, dd_colset *colbasis)
+{
+ dd_boolean stop, chosen, localdebug=dd_debug;
+ dd_rowset NopivotRow,PriorityRow;
+ dd_colset ColSelected;
+ dd_Bmatrix B;
+ dd_rowindex roworder;
+ dd_rowrange r;
+ dd_colrange s;
+ long rank;
+
+ rank = 0;
+ stop = dd_FALSE;
+ set_initialize(&ColSelected, M->colsize);
+ set_initialize(&NopivotRow, M->rowsize);
+ set_initialize(rowbasis, M->rowsize);
+ set_initialize(colbasis, M->colsize);
+ set_initialize(&PriorityRow, M->rowsize);
+ set_copy(NopivotRow,ignoredrows);
+ set_copy(ColSelected,ignoredcols);
+ dd_InitializeBmatrix(M->colsize, &B);
+ dd_SetToIdentity(M->colsize, B);
+ roworder=(long *)calloc(M->rowsize+1,sizeof(long));
+ for (r=0; r<M->rowsize; r++){roworder[r+1]=r+1;
+ }
+
+ do { /* Find a set of rows for a basis */
+ dd_SelectPivot2(M->rowsize, M->colsize,M->matrix,B,dd_MinIndex,roworder,
+ PriorityRow,M->rowsize, NopivotRow, ColSelected, &r, &s, &chosen);
+ if (dd_debug && chosen)
+ fprintf(stderr,"Procedure dd_MatrixRank: pivot on (r,s) =(%ld, %ld).\n", r, s);
+ if (chosen) {
+ set_addelem(NopivotRow, r);
+ set_addelem(*rowbasis, r);
+ set_addelem(ColSelected, s);
+ set_addelem(*colbasis, s);
+ rank++;
+ dd_GaussianColumnPivot(M->rowsize, M->colsize, M->matrix, B, r, s);
+ if (localdebug) dd_WriteBmatrix(stderr,M->colsize,B);
+ } else {
+ stop=dd_TRUE;
+ }
+ if (rank==M->colsize) stop = dd_TRUE;
+ } while (!stop);
+ dd_FreeBmatrix(M->colsize,B);
+ free(roworder);
+ set_free(ColSelected);
+ set_free(NopivotRow);
+ set_free(PriorityRow);
+ return rank;
+}
+
+
+void dd_FindBasis(dd_ConePtr cone, long *rank)
+{
+ dd_boolean stop, chosen, localdebug=dd_debug;
+ dd_rowset NopivotRow;
+ dd_colset ColSelected;
+ dd_rowrange r;
+ dd_colrange j,s;
+
+ *rank = 0;
+ stop = dd_FALSE;
+ for (j=0;j<=cone->d;j++) cone->InitialRayIndex[j]=0;
+ set_emptyset(cone->InitialHalfspaces);
+ set_initialize(&ColSelected, cone->d);
+ set_initialize(&NopivotRow, cone->m);
+ set_copy(NopivotRow,cone->NonequalitySet);
+ dd_SetToIdentity(cone->d, cone->B);
+ do { /* Find a set of rows for a basis */
+ dd_SelectPivot2(cone->m, cone->d,cone->A,cone->B,cone->HalfspaceOrder,cone->OrderVector,
+ cone->EqualitySet,cone->m, NopivotRow, ColSelected, &r, &s, &chosen);
+ if (dd_debug && chosen)
+ fprintf(stderr,"Procedure dd_FindBasis: pivot on (r,s) =(%ld, %ld).\n", r, s);
+ if (chosen) {
+ set_addelem(cone->InitialHalfspaces, r);
+ set_addelem(NopivotRow, r);
+ set_addelem(ColSelected, s);
+ cone->InitialRayIndex[s]=r; /* cone->InitialRayIndex[s] stores the corr. row index */
+ (*rank)++;
+ dd_GaussianColumnPivot(cone->m, cone->d, cone->A, cone->B, r, s);
+ if (localdebug) dd_WriteBmatrix(stderr,cone->d,cone->B);
+ } else {
+ stop=dd_TRUE;
+ }
+ if (*rank==cone->d) stop = dd_TRUE;
+ } while (!stop);
+ set_free(ColSelected);
+ set_free(NopivotRow);
+}
+
+
+void dd_FindInitialRays(dd_ConePtr cone, dd_boolean *found)
+{
+ dd_rowset CandidateRows;
+ dd_rowrange i;
+ long rank;
+ dd_RowOrderType roworder_save=dd_LexMin;
+
+ *found = dd_FALSE;
+ set_initialize(&CandidateRows, cone->m);
+ if (cone->parent->InitBasisAtBottom==dd_TRUE) {
+ roworder_save=cone->HalfspaceOrder;
+ cone->HalfspaceOrder=dd_MaxIndex;
+ cone->PreOrderedRun=dd_FALSE;
+ }
+ else cone->PreOrderedRun=dd_TRUE;
+ if (dd_debug) dd_WriteBmatrix(stderr, cone->d, cone->B);
+ for (i = 1; i <= cone->m; i++)
+ if (!set_member(i,cone->NonequalitySet)) set_addelem(CandidateRows, i);
+ /*all rows not in NonequalitySet are candidates for initial cone*/
+ dd_FindBasis(cone, &rank);
+ if (dd_debug) dd_WriteBmatrix(stderr, cone->d, cone->B);
+ if (dd_debug) fprintf(stderr,"dd_FindInitialRays: rank of Amatrix = %ld\n", rank);
+ cone->LinearityDim=cone->d - rank;
+ if (dd_debug) fprintf(stderr,"Linearity Dimension = %ld\n", cone->LinearityDim);
+ if (cone->LinearityDim > 0) {
+ dd_ColumnReduce(cone);
+ dd_FindBasis(cone, &rank);
+ }
+ if (!set_subset(cone->EqualitySet,cone->InitialHalfspaces)) {
+ if (dd_debug) {
+ fprintf(stderr,"Equality set is dependent. Equality Set and an initial basis:\n");
+ set_fwrite(stderr,cone->EqualitySet);
+ set_fwrite(stderr,cone->InitialHalfspaces);
+ };
+ }
+ *found = dd_TRUE;
+ set_free(CandidateRows);
+ if (cone->parent->InitBasisAtBottom==dd_TRUE) {
+ cone->HalfspaceOrder=roworder_save;
+ }
+ if (cone->HalfspaceOrder==dd_MaxCutoff||
+ cone->HalfspaceOrder==dd_MinCutoff||
+ cone->HalfspaceOrder==dd_MixCutoff){
+ cone->PreOrderedRun=dd_FALSE;
+ } else cone->PreOrderedRun=dd_TRUE;
+}
+
+void dd_CheckEquality(dd_colrange d_size, dd_RayPtr*RP1, dd_RayPtr*RP2, dd_boolean *equal)
+{
+ long j;
+
+ if (dd_debug)
+ fprintf(stderr,"Check equality of two rays\n");
+ *equal = dd_TRUE;
+ j = 1;
+ while (j <= d_size && *equal) {
+ if (!dd_Equal((*RP1)->Ray[j - 1],(*RP2)->Ray[j - 1]))
+ *equal = dd_FALSE;
+ j++;
+ }
+ if (*equal)
+ fprintf(stderr,"Equal records found !!!!\n");
+}
+
+void dd_CreateNewRay(dd_ConePtr cone,
+ dd_RayPtr Ptr1, dd_RayPtr Ptr2, dd_rowrange ii)
+{
+ /*Create a new ray by taking a linear combination of two rays*/
+ dd_colrange j;
+ mytype a1, a2, v1, v2;
+ static dd_Arow NewRay;
+ static dd_colrange last_d=0;
+ dd_boolean localdebug=dd_debug;
+
+ dd_init(a1); dd_init(a2); dd_init(v1); dd_init(v2);
+ if (last_d!=cone->d){
+ if (last_d>0) {
+ for (j=0; j<last_d; j++) dd_clear(NewRay[j]);
+ free(NewRay);
+ }
+ NewRay=(mytype*)calloc(cone->d,sizeof(mytype));
+ for (j=0; j<cone->d; j++) dd_init(NewRay[j]);
+ last_d=cone->d;
+ }
+
+ dd_AValue(&a1, cone->d, cone->A, Ptr1->Ray, ii);
+ dd_AValue(&a2, cone->d, cone->A, Ptr2->Ray, ii);
+ if (localdebug) {
+ fprintf(stderr,"CreatNewRay: Ray1 ="); dd_WriteArow(stderr, Ptr1->Ray, cone->d);
+ fprintf(stderr,"CreatNewRay: Ray2 ="); dd_WriteArow(stderr, Ptr2->Ray, cone->d);
+ }
+ dd_abs(v1,a1);
+ dd_abs(v2,a2);
+ if (localdebug){
+ fprintf(stderr,"dd_AValue1 and ABS"); dd_WriteNumber(stderr,a1); dd_WriteNumber(stderr,v1); fprintf(stderr,"\n");
+ fprintf(stderr,"dd_AValue2 and ABS"); dd_WriteNumber(stderr,a2); dd_WriteNumber(stderr,v2); fprintf(stderr,"\n");
+ }
+ for (j = 0; j < cone->d; j++){
+ dd_LinearComb(NewRay[j], Ptr1->Ray[j],v2,Ptr2->Ray[j],v1);
+ }
+ if (localdebug) {
+ fprintf(stderr,"CreatNewRay: New ray ="); dd_WriteArow(stderr, NewRay, cone->d);
+ }
+ dd_Normalize(cone->d, NewRay);
+ if (localdebug) {
+ fprintf(stderr,"CreatNewRay: dd_Normalized ray ="); dd_WriteArow(stderr, NewRay, cone->d);
+ }
+ dd_AddRay(cone, NewRay);
+ dd_clear(a1); dd_clear(a2); dd_clear(v1); dd_clear(v2);
+}
+
+void dd_EvaluateARay1(dd_rowrange i, dd_ConePtr cone)
+/* Evaluate the ith component of the vector A x RD.Ray
+ and rearrange the linked list so that
+ the infeasible rays with respect to i will be
+ placed consecutively from First
+ */
+{
+ dd_colrange j;
+ mytype temp,tnext;
+ dd_RayPtr Ptr, PrevPtr, TempPtr;
+
+ dd_init(temp); dd_init(tnext);
+ Ptr = cone->FirstRay;
+ PrevPtr = cone->ArtificialRay;
+ if (PrevPtr->Next != Ptr) {
+ fprintf(stderr,"Error. Artificial Ray does not point to FirstRay!!!\n");
+ }
+ while (Ptr != NULL) {
+ dd_set(temp,dd_purezero);
+ for (j = 0; j < cone->d; j++){
+ dd_mul(tnext,cone->A[i - 1][j],Ptr->Ray[j]);
+ dd_add(temp,temp,tnext);
+ }
+ dd_set(Ptr->ARay,temp);
+/* if ( temp <= -zero && Ptr != cone->FirstRay) {*/
+ if ( dd_Negative(temp) && Ptr != cone->FirstRay) {
+ /* fprintf(stderr,"Moving an infeasible record w.r.t. %ld to FirstRay\n",i); */
+ if (Ptr==cone->LastRay) cone->LastRay=PrevPtr;
+ TempPtr=Ptr;
+ Ptr = Ptr->Next;
+ PrevPtr->Next = Ptr;
+ cone->ArtificialRay->Next = TempPtr;
+ TempPtr->Next = cone->FirstRay;
+ cone->FirstRay = TempPtr;
+ }
+ else {
+ PrevPtr = Ptr;
+ Ptr = Ptr->Next;
+ }
+ }
+ dd_clear(temp); dd_clear(tnext);
+}
+
+void dd_EvaluateARay2(dd_rowrange i, dd_ConePtr cone)
+/* Evaluate the ith component of the vector A x RD.Ray
+ and rearrange the linked list so that
+ the infeasible rays with respect to i will be
+ placed consecutively from First. Also for all feasible rays,
+ "positive" rays and "zero" rays will be placed consecutively.
+ */
+{
+ dd_colrange j;
+ mytype temp,tnext;
+ dd_RayPtr Ptr, NextPtr;
+ dd_boolean zerofound=dd_FALSE,negfound=dd_FALSE,posfound=dd_FALSE;
+
+ if (cone==NULL || cone->TotalRayCount<=0) goto _L99;
+ dd_init(temp); dd_init(tnext);
+ cone->PosHead=NULL;cone->ZeroHead=NULL;cone->NegHead=NULL;
+ cone->PosLast=NULL;cone->ZeroLast=NULL;cone->NegLast=NULL;
+ Ptr = cone->FirstRay;
+ while (Ptr != NULL) {
+ NextPtr=Ptr->Next; /* remember the Next record */
+ Ptr->Next=NULL; /* then clear the Next pointer */
+ dd_set(temp,dd_purezero);
+ for (j = 0; j < cone->d; j++){
+ dd_mul(tnext,cone->A[i - 1][j],Ptr->Ray[j]);
+ dd_add(temp,temp,tnext);
+ }
+ dd_set(Ptr->ARay,temp);
+/* if ( temp < -zero) {*/
+ if ( dd_Negative(temp)) {
+ if (!negfound){
+ negfound=dd_TRUE;
+ cone->NegHead=Ptr;
+ cone->NegLast=Ptr;
+ }
+ else{
+ Ptr->Next=cone->NegHead;
+ cone->NegHead=Ptr;
+ }
+ }
+/* else if (temp > zero){*/
+ else if (dd_Positive(temp)){
+ if (!posfound){
+ posfound=dd_TRUE;
+ cone->PosHead=Ptr;
+ cone->PosLast=Ptr;
+ }
+ else{
+ Ptr->Next=cone->PosHead;
+ cone->PosHead=Ptr;
+ }
+ }
+ else {
+ if (!zerofound){
+ zerofound=dd_TRUE;
+ cone->ZeroHead=Ptr;
+ cone->ZeroLast=Ptr;
+ }
+ else{
+ Ptr->Next=cone->ZeroHead;
+ cone->ZeroHead=Ptr;
+ }
+ }
+ Ptr=NextPtr;
+ }
+ /* joining three neg, pos and zero lists */
+ if (negfound){ /* -list nonempty */
+ cone->FirstRay=cone->NegHead;
+ if (posfound){ /* -list & +list nonempty */
+ cone->NegLast->Next=cone->PosHead;
+ if (zerofound){ /* -list, +list, 0list all nonempty */
+ cone->PosLast->Next=cone->ZeroHead;
+ cone->LastRay=cone->ZeroLast;
+ }
+ else{ /* -list, +list nonempty but 0list empty */
+ cone->LastRay=cone->PosLast;
+ }
+ }
+ else{ /* -list nonempty & +list empty */
+ if (zerofound){ /* -list,0list nonempty & +list empty */
+ cone->NegLast->Next=cone->ZeroHead;
+ cone->LastRay=cone->ZeroLast;
+ }
+ else { /* -list nonempty & +list,0list empty */
+ cone->LastRay=cone->NegLast;
+ }
+ }
+ }
+ else if (posfound){ /* -list empty & +list nonempty */
+ cone->FirstRay=cone->PosHead;
+ if (zerofound){ /* -list empty & +list,0list nonempty */
+ cone->PosLast->Next=cone->ZeroHead;
+ cone->LastRay=cone->ZeroLast;
+ }
+ else{ /* -list,0list empty & +list nonempty */
+ cone->LastRay=cone->PosLast;
+ }
+ }
+ else{ /* -list,+list empty & 0list nonempty */
+ cone->FirstRay=cone->ZeroHead;
+ cone->LastRay=cone->ZeroLast;
+ }
+ cone->ArtificialRay->Next=cone->FirstRay;
+ cone->LastRay->Next=NULL;
+ dd_clear(temp); dd_clear(tnext);
+ _L99:;
+}
+
+void dd_DeleteNegativeRays(dd_ConePtr cone)
+/* Eliminate the infeasible rays with respect to i which
+ are supposed to be consecutive from the head of the dd_Ray list,
+ and sort the zero list assumed to be consecutive at the
+ end of the list.
+ */
+{
+ dd_rowrange fii,fiitest;
+ mytype temp;
+ dd_RayPtr Ptr, PrevPtr,NextPtr,ZeroPtr1,ZeroPtr0;
+ dd_boolean found, completed, zerofound=dd_FALSE,negfound=dd_FALSE,posfound=dd_FALSE;
+ dd_boolean localdebug=dd_FALSE;
+
+ dd_init(temp);
+ cone->PosHead=NULL;cone->ZeroHead=NULL;cone->NegHead=NULL;
+ cone->PosLast=NULL;cone->ZeroLast=NULL;cone->NegLast=NULL;
+
+ /* Delete the infeasible rays */
+ PrevPtr= cone->ArtificialRay;
+ Ptr = cone->FirstRay;
+ if (PrevPtr->Next != Ptr)
+ fprintf(stderr,"Error at dd_DeleteNegativeRays: ArtificialRay does not point the FirstRay.\n");
+ completed=dd_FALSE;
+ while (Ptr != NULL && !completed){
+/* if ( (Ptr->ARay) < -zero ){ */
+ if ( dd_Negative(Ptr->ARay)){
+ dd_Eliminate(cone, &PrevPtr);
+ Ptr=PrevPtr->Next;
+ }
+ else{
+ completed=dd_TRUE;
+ }
+ }
+
+ /* Sort the zero rays */
+ Ptr = cone->FirstRay;
+ cone->ZeroRayCount=0;
+ while (Ptr != NULL) {
+ NextPtr=Ptr->Next; /* remember the Next record */
+ dd_set(temp,Ptr->ARay);
+ if (localdebug) {fprintf(stderr,"Ptr->ARay :"); dd_WriteNumber(stderr, temp);}
+/* if ( temp < -zero) {*/
+ if ( dd_Negative(temp)) {
+ if (!negfound){
+ fprintf(stderr,"Error: An infeasible ray found after their removal\n");
+ negfound=dd_TRUE;
+ }
+ }
+/* else if (temp > zero){*/
+ else if (dd_Positive(temp)){
+ if (!posfound){
+ posfound=dd_TRUE;
+ cone->PosHead=Ptr;
+ cone->PosLast=Ptr;
+ }
+ else{
+ cone->PosLast=Ptr;
+ }
+ }
+ else {
+ (cone->ZeroRayCount)++;
+ if (!zerofound){
+ zerofound=dd_TRUE;
+ cone->ZeroHead=Ptr;
+ cone->ZeroLast=Ptr;
+ cone->ZeroLast->Next=NULL;
+ }
+ else{/* Find a right position to store the record sorted w.r.t. FirstInfeasIndex */
+ fii=Ptr->FirstInfeasIndex;
+ found=dd_FALSE;
+ ZeroPtr1=NULL;
+ for (ZeroPtr0=cone->ZeroHead; !found && ZeroPtr0!=NULL ; ZeroPtr0=ZeroPtr0->Next){
+ fiitest=ZeroPtr0->FirstInfeasIndex;
+ if (fiitest >= fii){
+ found=dd_TRUE;
+ }
+ else ZeroPtr1=ZeroPtr0;
+ }
+ /* fprintf(stderr,"insert position found \n %d index %ld\n",found, fiitest); */
+ if (!found){ /* the new record must be stored at the end of list */
+ cone->ZeroLast->Next=Ptr;
+ cone->ZeroLast=Ptr;
+ cone->ZeroLast->Next=NULL;
+ }
+ else{
+ if (ZeroPtr1==NULL){ /* store the new one at the head, and update the head ptr */
+ /* fprintf(stderr,"Insert at the head\n"); */
+ Ptr->Next=cone->ZeroHead;
+ cone->ZeroHead=Ptr;
+ }
+ else{ /* store the new one inbetween ZeroPtr1 and 0 */
+ /* fprintf(stderr,"Insert inbetween\n"); */
+ Ptr->Next=ZeroPtr1->Next;
+ ZeroPtr1->Next=Ptr;
+ }
+ }
+ /*
+ Ptr->Next=cone->ZeroHead;
+ cone->ZeroHead=Ptr;
+ */
+ }
+ }
+ Ptr=NextPtr;
+ }
+ /* joining the pos and zero lists */
+ if (posfound){ /* -list empty & +list nonempty */
+ cone->FirstRay=cone->PosHead;
+ if (zerofound){ /* +list,0list nonempty */
+ cone->PosLast->Next=cone->ZeroHead;
+ cone->LastRay=cone->ZeroLast;
+ }
+ else{ /* 0list empty & +list nonempty */
+ cone->LastRay=cone->PosLast;
+ }
+ }
+ else{ /* +list empty & 0list nonempty */
+ cone->FirstRay=cone->ZeroHead;
+ cone->LastRay=cone->ZeroLast;
+ }
+ cone->ArtificialRay->Next=cone->FirstRay;
+ cone->LastRay->Next=NULL;
+ dd_clear(temp);
+}
+
+void dd_FeasibilityIndices(long *fnum, long *infnum, dd_rowrange i, dd_ConePtr cone)
+{
+ /*Evaluate the number of feasible rays and infeasible rays*/
+ /* w.r.t the hyperplane i*/
+ dd_colrange j;
+ mytype temp, tnext;
+ dd_RayPtr Ptr;
+
+ dd_init(temp); dd_init(tnext);
+ *fnum = 0;
+ *infnum = 0;
+ Ptr = cone->FirstRay;
+ while (Ptr != NULL) {
+ dd_set(temp,dd_purezero);
+ for (j = 0; j < cone->d; j++){
+ dd_mul(tnext, cone->A[i - 1][j],Ptr->Ray[j]);
+ dd_add(temp, temp, tnext);
+ }
+ if (dd_Nonnegative(temp))
+ (*fnum)++;
+ else
+ (*infnum)++;
+ Ptr = Ptr->Next;
+ }
+ dd_clear(temp); dd_clear(tnext);
+}
+
+dd_boolean dd_LexSmaller(mytype *v1, mytype *v2, long dmax)
+{ /* dmax is the size of vectors v1,v2 */
+ dd_boolean determined, smaller;
+ dd_colrange j;
+
+ smaller = dd_FALSE;
+ determined = dd_FALSE;
+ j = 1;
+ do {
+ if (!dd_Equal(v1[j - 1],v2[j - 1])) { /* 086 */
+ if (dd_Smaller(v1[j - 1],v2[j - 1])) { /*086 */
+ smaller = dd_TRUE;
+ }
+ determined = dd_TRUE;
+ } else
+ j++;
+ } while (!(determined) && (j <= dmax));
+ return smaller;
+}
+
+
+dd_boolean dd_LexLarger(mytype *v1, mytype *v2, long dmax)
+{
+ return dd_LexSmaller(v2, v1, dmax);
+}
+
+dd_boolean dd_LexEqual(mytype *v1, mytype *v2, long dmax)
+{ /* dmax is the size of vectors v1,v2 */
+ dd_boolean determined, equal;
+ dd_colrange j;
+
+ equal = dd_TRUE;
+ determined = dd_FALSE;
+ j = 1;
+ do {
+ if (!dd_Equal(v1[j - 1],v2[j - 1])) { /* 093c */
+ equal = dd_FALSE;
+ determined = dd_TRUE;
+ } else {
+ j++;
+ }
+ } while (!(determined) && (j <= dmax));
+ return equal;
+}
+
+void dd_AddNewHalfspace1(dd_ConePtr cone, dd_rowrange hnew)
+/* This procedure 1 must be used with PreorderedRun=dd_FALSE
+ This procedure is the most elementary implementation of
+ DD and can be used with any type of ordering, including
+ dynamic ordering of rows, e.g. MaxCutoff, MinCutoff.
+ The memory requirement is minimum because it does not
+ store any adjacency among the rays.
+*/
+{
+ dd_RayPtr RayPtr0,RayPtr1,RayPtr2,RayPtr2s,RayPtr3;
+ long pos1, pos2;
+ double prevprogress, progress;
+ mytype value1, value2;
+ dd_boolean adj, equal, completed;
+
+ dd_init(value1); dd_init(value2);
+ dd_EvaluateARay1(hnew, cone);
+ /*Check feasibility of rays w.r.t. hnew
+ and put all infeasible ones consecutively */
+
+ RayPtr0 = cone->ArtificialRay; /*Pointer pointing RayPrt1*/
+ RayPtr1 = cone->FirstRay; /*1st hnew-infeasible ray to scan and compare with feasible rays*/
+ dd_set(value1,cone->FirstRay->ARay);
+ if (dd_Nonnegative(value1)) {
+ if (cone->RayCount==cone->WeaklyFeasibleRayCount) cone->CompStatus=dd_AllFound;
+ goto _L99; /* Sicne there is no hnew-infeasible ray and nothing to do */
+ }
+ else {
+ RayPtr2s = RayPtr1->Next;/* RayPtr2s must point the first feasible ray */
+ pos2=1;
+ while (RayPtr2s!=NULL && dd_Negative(RayPtr2s->ARay)) {
+ RayPtr2s = RayPtr2s->Next;
+ pos2++;
+ }
+ }
+ if (RayPtr2s==NULL) {
+ cone->FirstRay=NULL;
+ cone->ArtificialRay->Next=cone->FirstRay;
+ cone->RayCount=0;
+ cone->CompStatus=dd_AllFound;
+ goto _L99; /* All rays are infeasible, and the computation must stop */
+ }
+ RayPtr2 = RayPtr2s; /*2nd feasible ray to scan and compare with 1st*/
+ RayPtr3 = cone->LastRay; /*Last feasible for scanning*/
+ prevprogress=-10.0;
+ pos1 = 1;
+ completed=dd_FALSE;
+ while ((RayPtr1 != RayPtr2s) && !completed) {
+ dd_set(value1,RayPtr1->ARay);
+ dd_set(value2,RayPtr2->ARay);
+ dd_CheckEquality(cone->d, &RayPtr1, &RayPtr2, &equal);
+ if ((dd_Positive(value1) && dd_Negative(value2)) || (dd_Negative(value1) && dd_Positive(value2))){
+ dd_CheckAdjacency(cone, &RayPtr1, &RayPtr2, &adj);
+ if (adj) dd_CreateNewRay(cone, RayPtr1, RayPtr2, hnew);
+ }
+ if (RayPtr2 != RayPtr3) {
+ RayPtr2 = RayPtr2->Next;
+ continue;
+ }
+ if (dd_Negative(value1) || equal) {
+ dd_Eliminate(cone, &RayPtr0);
+ RayPtr1 = RayPtr0->Next;
+ RayPtr2 = RayPtr2s;
+ } else {
+ completed=dd_TRUE;
+ }
+ pos1++;
+ progress = 100.0 * ((double)pos1 / pos2) * (2.0 * pos2 - pos1) / pos2;
+ if (progress-prevprogress>=10 && pos1%10==0 && dd_debug) {
+ fprintf(stderr,"*Progress of iteration %5ld(/%ld): %4ld/%4ld => %4.1f%% done\n",
+ cone->Iteration, cone->m, pos1, pos2, progress);
+ prevprogress=progress;
+ }
+ }
+ if (cone->RayCount==cone->WeaklyFeasibleRayCount) cone->CompStatus=dd_AllFound;
+ _L99:;
+ dd_clear(value1); dd_clear(value2);
+}
+
+void dd_AddNewHalfspace2(dd_ConePtr cone, dd_rowrange hnew)
+/* This procedure must be used under PreOrderedRun mode */
+{
+ dd_RayPtr RayPtr0,RayPtr1,RayPtr2;
+ dd_AdjacencyType *EdgePtr, *EdgePtr0;
+ long pos1;
+ dd_rowrange fii1, fii2;
+ dd_boolean localdebug=dd_FALSE;
+
+ dd_EvaluateARay2(hnew, cone);
+ /* Check feasibility of rays w.r.t. hnew
+ and sort them. ( -rays, +rays, 0rays)*/
+
+ if (cone->PosHead==NULL && cone->ZeroHead==NULL) {
+ cone->FirstRay=NULL;
+ cone->ArtificialRay->Next=cone->FirstRay;
+ cone->RayCount=0;
+ cone->CompStatus=dd_AllFound;
+ goto _L99; /* All rays are infeasible, and the computation must stop */
+ }
+
+ if (localdebug){
+ pos1=0;
+ fprintf(stderr,"(pos, FirstInfeasIndex, A Ray)=\n");
+ for (RayPtr0=cone->FirstRay; RayPtr0!=NULL; RayPtr0=RayPtr0->Next){
+ pos1++;
+ fprintf(stderr,"(%ld,%ld,",pos1,RayPtr0->FirstInfeasIndex);
+ dd_WriteNumber(stderr,RayPtr0->ARay);
+ fprintf(stderr,") ");
+ }
+ fprintf(stderr,"\n");
+ }
+
+ if (cone->ZeroHead==NULL) cone->ZeroHead=cone->LastRay;
+
+ EdgePtr=cone->Edges[cone->Iteration];
+ while (EdgePtr!=NULL){
+ RayPtr1=EdgePtr->Ray1;
+ RayPtr2=EdgePtr->Ray2;
+ fii1=RayPtr1->FirstInfeasIndex;
+ dd_CreateNewRay(cone, RayPtr1, RayPtr2, hnew);
+ fii2=cone->LastRay->FirstInfeasIndex;
+ if (fii1 != fii2)
+ dd_ConditionalAddEdge(cone,RayPtr1,cone->LastRay,cone->PosHead);
+ EdgePtr0=EdgePtr;
+ EdgePtr=EdgePtr->Next;
+ free(EdgePtr0);
+ (cone->EdgeCount)--;
+ }
+ cone->Edges[cone->Iteration]=NULL;
+
+ dd_DeleteNegativeRays(cone);
+
+ set_addelem(cone->AddedHalfspaces, hnew);
+
+ if (cone->Iteration<cone->m){
+ if (cone->ZeroHead!=NULL && cone->ZeroHead!=cone->LastRay){
+ if (cone->ZeroRayCount>200 && dd_debug) fprintf(stderr,"*New edges being scanned...\n");
+ dd_UpdateEdges(cone, cone->ZeroHead, cone->LastRay);
+ }
+ }
+
+ if (cone->RayCount==cone->WeaklyFeasibleRayCount) cone->CompStatus=dd_AllFound;
+_L99:;
+}
+
+
+void dd_SelectNextHalfspace0(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hnext)
+{
+ /*A natural way to choose the next hyperplane. Simply the largest index*/
+ long i;
+ dd_boolean determined;
+
+ i = cone->m;
+ determined = dd_FALSE;
+ do {
+ if (set_member(i, excluded))
+ i--;
+ else
+ determined = dd_TRUE;
+ } while (!determined && i>=1);
+ if (determined)
+ *hnext = i;
+ else
+ *hnext = 0;
+}
+
+void dd_SelectNextHalfspace1(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hnext)
+{
+ /*Natural way to choose the next hyperplane. Simply the least index*/
+ long i;
+ dd_boolean determined;
+
+ i = 1;
+ determined = dd_FALSE;
+ do {
+ if (set_member(i, excluded))
+ i++;
+ else
+ determined = dd_TRUE;
+ } while (!determined && i<=cone->m);
+ if (determined)
+ *hnext = i;
+ else
+ *hnext=0;
+}
+
+void dd_SelectNextHalfspace2(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hnext)
+{
+ /*Choose the next hyperplane with maximum infeasibility*/
+ long i, fea, inf, infmin, fi=0; /*feasibility and infeasibility numbers*/
+
+ infmin = cone->RayCount + 1;
+ for (i = 1; i <= cone->m; i++) {
+ if (!set_member(i, excluded)) {
+ dd_FeasibilityIndices(&fea, &inf, i, cone);
+ if (inf < infmin) {
+ infmin = inf;
+ fi = fea;
+ *hnext = i;
+ }
+ }
+ }
+ if (dd_debug) {
+ fprintf(stderr,"*infeasible rays (min) =%5ld, #feas rays =%5ld\n", infmin, fi);
+ }
+}
+
+void dd_SelectNextHalfspace3(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hnext)
+{
+ /*Choose the next hyperplane with maximum infeasibility*/
+ long i, fea, inf, infmax, fi=0; /*feasibility and infeasibility numbers*/
+ dd_boolean localdebug=dd_debug;
+
+ infmax = -1;
+ for (i = 1; i <= cone->m; i++) {
+ if (!set_member(i, excluded)) {
+ dd_FeasibilityIndices(&fea, &inf, i, cone);
+ if (inf > infmax) {
+ infmax = inf;
+ fi = fea;
+ *hnext = i;
+ }
+ }
+ }
+ if (localdebug) {
+ fprintf(stderr,"*infeasible rays (max) =%5ld, #feas rays =%5ld\n", infmax, fi);
+ }
+}
+
+void dd_SelectNextHalfspace4(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hnext)
+{
+ /*Choose the next hyperplane with the most unbalanced cut*/
+ long i, fea, inf, max, tmax, fi=0, infi=0;
+ /*feasibility and infeasibility numbers*/
+
+ max = -1;
+ for (i = 1; i <= cone->m; i++) {
+ if (!set_member(i, excluded)) {
+ dd_FeasibilityIndices(&fea, &inf, i, cone);
+ if (fea <= inf)
+ tmax = inf;
+ else
+ tmax = fea;
+ if (tmax > max) {
+ max = tmax;
+ fi = fea;
+ infi = inf;
+ *hnext = i;
+ }
+ }
+ }
+ if (!dd_debug)
+ return;
+ if (max == fi) {
+ fprintf(stderr,"*infeasible rays (min) =%5ld, #feas rays =%5ld\n", infi, fi);
+ } else {
+ fprintf(stderr,"*infeasible rays (max) =%5ld, #feas rays =%5ld\n", infi, fi);
+ }
+}
+
+void dd_SelectNextHalfspace5(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hnext)
+{
+ /*Choose the next hyperplane which is lexico-min*/
+ long i, minindex;
+ mytype *v1, *v2;
+
+ minindex = 0;
+ v1 = NULL;
+ for (i = 1; i <= cone->m; i++) {
+ if (!set_member(i, excluded)) {
+ v2 = cone->A[i - 1];
+ if (minindex == 0) {
+ minindex = i;
+ v1=v2;
+ } else if (dd_LexSmaller(v2,v1,cone->d)) {
+ minindex = i;
+ v1=v2;
+ }
+ }
+ }
+ *hnext = minindex;
+}
+
+
+void dd_SelectNextHalfspace6(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hnext)
+{
+ /*Choose the next hyperplane which is lexico-max*/
+ long i, maxindex;
+ mytype *v1, *v2;
+
+ maxindex = 0;
+ v1 = NULL;
+ for (i = 1; i <= cone->m; i++) {
+ if (!set_member(i, excluded)) {
+ v2= cone->A[i - 1];
+ if (maxindex == 0) {
+ maxindex = i;
+ v1=v2;
+ } else if (dd_LexLarger(v2, v1, cone->d)) {
+ maxindex = i;
+ v1=v2;
+ }
+ }
+ }
+ *hnext = maxindex;
+}
+
+void dd_UniqueRows(dd_rowindex OV, long p, long r, dd_Amatrix A, long dmax, dd_rowset preferred, long *uniqrows)
+{
+ /* Select a subset of rows of A (with range [p, q] up to dimension dmax) by removing duplicates.
+ When a row subset preferred is nonempty, those row indices in the set have priority. If
+ two priority rows define the same row vector, one is chosen.
+ For a selected unique row i, OV[i] returns a new position of the unique row i.
+ For other nonuniqu row i, OV[i] returns a negative of the original row j dominating i.
+ Thus the original contents of OV[p..r] will be rewritten. Other components remain the same.
+ *uniqrows returns the number of unique rows.
+*/
+ long i,iuniq,j;
+ mytype *x;
+ dd_boolean localdebug=dd_FALSE;
+
+ if (p<=0 || p > r) goto _L99;
+ iuniq=p; j=1; /* the first unique row candidate */
+ x=A[p-1];
+ OV[p]=j; /* tentative row index of the candidate */
+ for (i=p+1;i<=r; i++){
+ if (!dd_LexEqual(x,A[i-1],dmax)) {
+ /* a new row vector found. */
+ iuniq=i;
+ j=j+1;
+ OV[i]=j; /* Tentatively register the row i. */
+ x=A[i-1];
+ } else {
+ /* rows are equal */
+ if (set_member(i, preferred) && !set_member(iuniq, preferred)){
+ OV[iuniq]=-i; /* the row iuniq is dominated by the row i */
+ iuniq=i; /* the row i is preferred. Change the candidate. */
+ OV[i]=j; /* the row i is tentatively registered. */
+ x=A[i-1];
+ } else {
+ OV[i]=-iuniq; /* the row iuniq is dominated by the row i */
+ }
+ }
+ }
+ *uniqrows=j;
+ if (localdebug){
+ printf("The number of unique rows are %ld\n with order vector",*uniqrows);
+ for (i=p;i<=r; i++){
+ printf(" %ld:%ld ",i,OV[i]);
+ }
+ printf("\n");
+ }
+ _L99:;
+}
+
+long dd_Partition(dd_rowindex OV, long p, long r, dd_Amatrix A, long dmax)
+{
+ mytype *x;
+ long i,j,ovi;
+
+ x=A[OV[p]-1];
+
+ i=p-1;
+ j=r+1;
+ while (dd_TRUE){
+ do{
+ j--;
+ } while (dd_LexLarger(A[OV[j]-1],x,dmax));
+ do{
+ i++;
+ } while (dd_LexSmaller(A[OV[i]-1],x,dmax));
+ if (i<j){
+ ovi=OV[i];
+ OV[i]=OV[j];
+ OV[j]=ovi;
+ }
+ else{
+ return j;
+ }
+ }
+}
+
+void dd_QuickSort(dd_rowindex OV, long p, long r, dd_Amatrix A, long dmax)
+{
+ long q;
+
+ if (p < r){
+ q = dd_Partition(OV, p, r, A, dmax);
+ dd_QuickSort(OV, p, q, A, dmax);
+ dd_QuickSort(OV, q+1, r, A, dmax);
+ }
+}
+
+
+#ifndef RAND_MAX
+#define RAND_MAX 32767
+#endif
+
+void dd_RandomPermutation(dd_rowindex OV, long t, unsigned int seed)
+{
+ long k,j,ovj;
+ double u,xk,r,rand_max=(double) RAND_MAX;
+ dd_boolean localdebug=dd_FALSE;
+
+ srand(seed);
+ for (j=t; j>1 ; j--) {
+ r=rand();
+ u=r/rand_max;
+ xk=(double)(j*u +1);
+ k=(long)xk;
+ if (localdebug) fprintf(stderr,"u=%g, k=%ld, r=%g, randmax= %g\n",u,k,r,rand_max);
+ ovj=OV[j];
+ OV[j]=OV[k];
+ OV[k]=ovj;
+ if (localdebug) fprintf(stderr,"row %ld is exchanged with %ld\n",j,k);
+ }
+}
+
+void dd_ComputeRowOrderVector(dd_ConePtr cone)
+{
+ long i,itemp;
+
+ cone->OrderVector[0]=0;
+ switch (cone->HalfspaceOrder){
+ case dd_MaxIndex:
+ for(i=1; i<=cone->m; i++) cone->OrderVector[i]=cone->m-i+1;
+ break;
+
+ case dd_MinIndex:
+ for(i=1; i<=cone->m; i++) cone->OrderVector[i]=i;
+ break;
+
+ case dd_LexMin: case dd_MinCutoff: case dd_MixCutoff: case dd_MaxCutoff:
+ for(i=1; i<=cone->m; i++) cone->OrderVector[i]=i;
+ dd_RandomPermutation(cone->OrderVector, cone->m, cone->rseed);
+ dd_QuickSort(cone->OrderVector, 1, cone->m, cone->A, cone->d);
+ break;
+
+ case dd_LexMax:
+ for(i=1; i<=cone->m; i++) cone->OrderVector[i]=i;
+ dd_RandomPermutation(cone->OrderVector, cone->m, cone->rseed);
+ dd_QuickSort(cone->OrderVector, 1, cone->m, cone->A, cone->d);
+ for(i=1; i<=cone->m/2;i++){ /* just reverse the order */
+ itemp=cone->OrderVector[i];
+ cone->OrderVector[i]=cone->OrderVector[cone->m-i+1];
+ cone->OrderVector[cone->m-i+1]=itemp;
+ }
+ break;
+
+ case dd_RandomRow:
+ for(i=1; i<=cone->m; i++) cone->OrderVector[i]=i;
+ dd_RandomPermutation(cone->OrderVector, cone->m, cone->rseed);
+ break;
+
+ }
+}
+
+void dd_UpdateRowOrderVector(dd_ConePtr cone, dd_rowset PriorityRows)
+/* Update the RowOrder vector to shift selected rows
+in highest order.
+*/
+{
+ dd_rowrange i,j,k,j1=0,oj=0;
+ long rr;
+ dd_boolean found, localdebug=dd_FALSE;
+
+ if (dd_debug) localdebug=dd_TRUE;
+ found=dd_TRUE;
+ rr=set_card(PriorityRows);
+ if (localdebug) set_fwrite(stderr,PriorityRows);
+ for (i=1; i<=rr; i++){
+ found=dd_FALSE;
+ for (j=i; j<=cone->m && !found; j++){
+ oj=cone->OrderVector[j];
+ if (set_member(oj, PriorityRows)){
+ found=dd_TRUE;
+ if (localdebug) fprintf(stderr,"%ldth in sorted list (row %ld) is in PriorityRows\n", j, oj);
+ j1=j;
+ }
+ }
+ if (found){
+ if (j1>i) {
+ /* shift everything lower: ov[i]->cone->ov[i+1]..ov[j1-1]->cone->ov[j1] */
+ for (k=j1; k>=i; k--) cone->OrderVector[k]=cone->OrderVector[k-1];
+ cone->OrderVector[i]=oj;
+ if (localdebug){
+ fprintf(stderr,"OrderVector updated to:\n");
+ for (j = 1; j <= cone->m; j++) fprintf(stderr," %2ld", cone->OrderVector[j]);
+ fprintf(stderr,"\n");
+ }
+ }
+ } else {
+ fprintf(stderr,"UpdateRowOrder: Error.\n");
+ goto _L99;
+ }
+ }
+_L99:;
+}
+
+void dd_SelectPreorderedNext(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hh)
+{
+ dd_rowrange i,k;
+
+ *hh=0;
+ for (i=1; i<=cone->m && *hh==0; i++){
+ k=cone->OrderVector[i];
+ if (!set_member(k, excluded)) *hh=k ;
+ }
+}
+
+void dd_SelectNextHalfspace(dd_ConePtr cone, dd_rowset excluded, dd_rowrange *hh)
+{
+ if (cone->PreOrderedRun){
+ if (dd_debug) {
+ fprintf(stderr,"debug dd_SelectNextHalfspace: Use PreorderNext\n");
+ }
+ dd_SelectPreorderedNext(cone, excluded, hh);
+ }
+ else {
+ if (dd_debug) {
+ fprintf(stderr,"debug dd_SelectNextHalfspace: Use DynamicOrderedNext\n");
+ }
+
+ switch (cone->HalfspaceOrder) {
+
+ case dd_MaxIndex:
+ dd_SelectNextHalfspace0(cone, excluded, hh);
+ break;
+
+ case dd_MinIndex:
+ dd_SelectNextHalfspace1(cone, excluded, hh);
+ break;
+
+ case dd_MinCutoff:
+ dd_SelectNextHalfspace2(cone, excluded, hh);
+ break;
+
+ case dd_MaxCutoff:
+ dd_SelectNextHalfspace3(cone, excluded, hh);
+ break;
+
+ case dd_MixCutoff:
+ dd_SelectNextHalfspace4(cone, excluded, hh);
+ break;
+
+ default:
+ dd_SelectNextHalfspace0(cone, excluded, hh);
+ break;
+ }
+ }
+}
+
+dd_boolean dd_Nonnegative(mytype val)
+{
+/* if (val>=-dd_zero) return dd_TRUE; */
+ if (dd_cmp(val,dd_minuszero)>=0) return dd_TRUE;
+ else return dd_FALSE;
+}
+
+dd_boolean dd_Nonpositive(mytype val)
+{
+/* if (val<=dd_zero) return dd_TRUE; */
+ if (dd_cmp(val,dd_zero)<=0) return dd_TRUE;
+ else return dd_FALSE;
+}
+
+dd_boolean dd_Positive(mytype val)
+{
+ return !dd_Nonpositive(val);
+}
+
+dd_boolean dd_Negative(mytype val)
+{
+ return !dd_Nonnegative(val);
+}
+
+dd_boolean dd_EqualToZero(mytype val)
+{
+ return (dd_Nonnegative(val) && dd_Nonpositive(val));
+}
+
+dd_boolean dd_Nonzero(mytype val)
+{
+ return (dd_Positive(val) || dd_Negative(val));
+}
+
+dd_boolean dd_Equal(mytype val1,mytype val2)
+{
+ return (!dd_Larger(val1,val2) && !dd_Smaller(val1,val2));
+}
+
+dd_boolean dd_Larger(mytype val1,mytype val2)
+{
+ mytype temp;
+ dd_boolean answer;
+
+ dd_init(temp);
+ dd_sub(temp,val1, val2);
+ answer=dd_Positive(temp);
+ dd_clear(temp);
+ return answer;
+}
+
+dd_boolean dd_Smaller(mytype val1,mytype val2)
+{
+ return dd_Larger(val2,val1);
+}
+
+void dd_abs(mytype absval, mytype val)
+{
+ if (dd_Negative(val)) dd_neg(absval,val);
+ else dd_set(absval,val);
+}
+
+void dd_LinearComb(mytype lc, mytype v1, mytype c1, mytype v2, mytype c2)
+/* lc := v1 * c1 + v2 * c2 */
+{
+ mytype temp;
+
+ dd_init(temp);
+ dd_mul(lc,v1,c1);
+ dd_mul(temp,v2,c2);
+ dd_add(lc,lc,temp);
+ dd_clear(temp);
+}
+
+void dd_InnerProduct(mytype prod, dd_colrange d, dd_Arow v1, dd_Arow v2)
+{
+ mytype temp;
+ dd_colrange j;
+ dd_boolean localdebug=dd_FALSE;
+
+ dd_init(temp);
+ dd_set_si(prod, 0);
+ for (j = 0; j < d; j++){
+ dd_mul(temp,v1[j],v2[j]);
+ dd_add(prod,prod,temp);
+ }
+ if (localdebug) {
+ fprintf(stderr,"InnerProduct:\n");
+ dd_WriteArow(stderr, v1, d);
+ dd_WriteArow(stderr, v2, d);
+ fprintf(stderr,"prod =");
+ dd_WriteNumber(stderr, prod);
+ fprintf(stderr,"\n");
+ }
+
+ dd_clear(temp);
+}
+
+/* end of cddcore.c */
+
+
diff --git a/third_party/cddlib/lib-src/cddio.c b/third_party/cddlib/lib-src/cddio.c
new file mode 100644
index 0000000..58545d5
--- /dev/null
+++ b/third_party/cddlib/lib-src/cddio.c
@@ -0,0 +1,2021 @@
+/* cddio.c: Basic Input and Output Procedures for cddlib
+ written by Komei Fukuda, fukuda@math.ethz.ch
+ Version 0.94h, April 30, 2015
+*/
+
+/* cddlib : C-library of the double description method for
+ computing all vertices and extreme rays of the polyhedron
+ P= {x : b - A x >= 0}.
+ Please read COPYING (GNU General Public Licence) and
+ the manual cddlibman.tex for detail.
+*/
+
+#include "setoper.h" /* set operation library header (Ver. June 1, 2000 or later) */
+#include "cdd.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+
+/* void dd_fread_rational_value (FILE *, mytype *); */
+void dd_SetLinearity(dd_MatrixPtr, char *);
+
+void dd_SetInputFile(FILE **f,dd_DataFileType inputfile,dd_ErrorType *Error)
+{
+ int opened=0,stop,quit=0;
+ int i,dotpos=0,trial=0;
+ char ch;
+ char *tempname;
+
+
+ *Error=dd_NoError;
+ while (!opened && !quit) {
+ fprintf(stderr,"\n>> Input file: ");
+ scanf("%s",inputfile);
+ ch=getchar();
+ stop=dd_FALSE;
+ for (i=0; i<dd_filenamelen && !stop; i++){
+ ch=inputfile[i];
+ switch (ch) {
+ case '.':
+ dotpos=i+1;
+ break;
+ case ';': case ' ': case '\0': case '\n': case '\t':
+ stop=dd_TRUE;
+ tempname=(char*)calloc(dd_filenamelen,sizeof(ch));
+ strncpy(tempname,inputfile,i);
+ strcpy(inputfile,tempname);
+ free(tempname);
+ break;
+ }
+ }
+ if ( ( *f = fopen(inputfile,"r") )!= NULL) {
+ fprintf(stderr,"input file %s is open\n",inputfile);
+ opened=1;
+ *Error=dd_NoError;
+ }
+ else{
+ fprintf(stderr,"The file %s not found\n",inputfile);
+ trial++;
+ if (trial>5) {
+ *Error=dd_IFileNotFound;
+ quit=1;
+ }
+ }
+ }
+}
+
+void dd_SetWriteFileName(dd_DataFileType inputfile, dd_DataFileType outfile, char cflag, dd_RepresentationType rep)
+{
+ char *extension;
+ dd_DataFileType ifilehead="";
+ int i,dotpos;
+
+ switch (cflag) {
+ case 'o':
+ switch (rep) {
+ case dd_Generator:
+ extension=".ine"; break; /* output file for ine data */
+ case dd_Inequality:
+ extension=".ext"; break; /* output file for ext data */
+ default:
+ extension=".xxx";break;
+ }
+ break;
+
+ case 'a': /* decide for output adjacence */
+ if (rep==dd_Inequality)
+ extension=".ead"; /* adjacency file for ext data */
+ else
+ extension=".iad"; /* adjacency file for ine data */
+ break;
+ case 'i': /* decide for output incidence */
+ if (rep==dd_Inequality)
+ extension=".ecd"; /* ext incidence file */
+ else
+ extension=".icd"; /* ine incidence file */
+ break;
+ case 'n': /* decide for input incidence */
+ if (rep==dd_Inequality)
+ extension=".icd"; /* ine incidence file */
+ else
+ extension=".ecd"; /* ext incidence file */
+ break;
+ case 'j': /* decide for input adjacency */
+ if (rep==dd_Inequality)
+ extension=".iad"; /* ine adjacency file */
+ else
+ extension=".ead"; /* ext adjacency file */
+ break;
+ case 'l':
+ extension=".ddl";break; /* log file */
+ case 'd':
+ extension=".dex";break; /* decomposition output */
+ case 'p':
+ extension="sub.ine";break; /* preprojection sub inequality file */
+ case 'v':
+ extension=".solved";break; /* verify_input file */
+ case 's':
+ extension=".lps";break; /* LP solution file */
+ default:
+ extension=".xxx";break;
+ }
+ dotpos=-1;
+ for (i=0; i< strlen(inputfile); i++){
+ if (inputfile[i]=='.') dotpos=i;
+ }
+ if (dotpos>1) strncpy(ifilehead, inputfile, dotpos);
+ else strcpy(ifilehead,inputfile);
+ if (strlen(inputfile)<=0) strcpy(ifilehead,"tempcdd");
+ strcpy(outfile,ifilehead);
+ strcat(outfile,extension);
+ if (strcmp(inputfile, outfile)==0) {
+ strcpy(outfile,inputfile);
+ strcat(outfile,extension);
+ }
+/* fprintf(stderr,"outfile name = %s\n",outfile); */
+}
+
+
+dd_NumberType dd_GetNumberType(const char *line)
+{
+ dd_NumberType nt;
+
+ if (strncmp(line, "integer", 7)==0) {
+ nt = dd_Integer;
+ }
+ else if (strncmp(line, "rational", 8)==0) {
+ nt = dd_Rational;
+ }
+ else if (strncmp(line, "real", 4)==0) {
+ nt = dd_Real;
+ }
+ else {
+ nt=dd_Unknown;
+ }
+ return nt;
+}
+
+void dd_ProcessCommandLine(FILE *f, dd_MatrixPtr M, const char *line)
+{
+ char newline[dd_linelenmax];
+ dd_colrange j;
+ mytype value;
+
+ dd_init(value);
+ if (strncmp(line, "hull", 4)==0) {
+ M->representation = dd_Generator;
+ }
+ if (strncmp(line, "debug", 5)==0) {
+ dd_debug = dd_TRUE;
+#ifdef GMPRATIONAL
+ ddf_debug = ddf_TRUE;
+#endif
+ }
+ if (strncmp(line, "partial_enum", 12)==0 ||
+ strncmp(line, "equality", 8)==0 ||
+ strncmp(line, "linearity", 9)==0 ) {
+ fgets(newline,dd_linelenmax,f);
+ dd_SetLinearity(M,newline);
+ }
+ if (strncmp(line, "maximize", 8)==0 ||
+ strncmp(line, "minimize", 8)==0) {
+ if (strncmp(line, "maximize", 8)==0) M->objective=dd_LPmax;
+ else M->objective=dd_LPmin;
+ for (j = 1; j <= M->colsize; j++) {
+ if (M->numbtype==dd_Real) {
+#if !defined(GMPRATIONAL)
+ double rvalue;
+ fscanf(f, "%lf", &rvalue);
+ dd_set_d(value, rvalue);
+#endif
+ } else {
+ dd_fread_rational_value (f, value);
+ }
+ dd_set(M->rowvec[j - 1],value);
+ if (dd_debug) {fprintf(stderr,"cost(%5ld) =",j); dd_WriteNumber(stderr,value);}
+ } /*of j*/
+ }
+ dd_clear(value);
+}
+
+dd_boolean dd_AppendMatrix2Poly(dd_PolyhedraPtr *poly, dd_MatrixPtr M)
+{
+ dd_boolean success=dd_FALSE;
+ dd_MatrixPtr Mpoly,Mnew=NULL;
+ dd_ErrorType err;
+
+ if ((*poly)!=NULL && (*poly)->m >=0 && (*poly)->d>=0 &&
+ (*poly)->d==M->colsize && M->rowsize>0){
+ Mpoly=dd_CopyInput(*poly);
+ Mnew=dd_AppendMatrix(Mpoly, M);
+ dd_FreePolyhedra(*poly);
+ *poly=dd_DDMatrix2Poly(Mnew,&err);
+ dd_FreeMatrix(Mpoly);
+ dd_FreeMatrix(Mnew);
+ if (err==dd_NoError) success=dd_TRUE;
+ }
+ return success;
+}
+
+dd_MatrixPtr dd_MatrixCopy(dd_MatrixPtr M)
+{
+ dd_MatrixPtr Mcopy=NULL;
+ dd_rowrange m;
+ dd_colrange d;
+
+ m= M->rowsize;
+ d= M->colsize;
+ if (m >=0 && d >=0){
+ Mcopy=dd_CreateMatrix(m, d);
+ dd_CopyAmatrix(Mcopy->matrix, M->matrix, m, d);
+ dd_CopyArow(Mcopy->rowvec, M->rowvec, d);
+ set_copy(Mcopy->linset,M->linset);
+ Mcopy->numbtype=M->numbtype;
+ Mcopy->representation=M->representation;
+ Mcopy->objective=M->objective;
+ }
+ return Mcopy;
+}
+
+dd_MatrixPtr dd_CopyMatrix(dd_MatrixPtr M)
+{
+ return dd_MatrixCopy(M);
+}
+
+dd_MatrixPtr dd_MatrixNormalizedCopy(dd_MatrixPtr M)
+{
+ dd_MatrixPtr Mcopy=NULL;
+ dd_rowrange m;
+ dd_colrange d;
+
+ m= M->rowsize;
+ d= M->colsize;
+ if (m >=0 && d >=0){
+ Mcopy=dd_CreateMatrix(m, d);
+ dd_CopyNormalizedAmatrix(Mcopy->matrix, M->matrix, m, d);
+ dd_CopyArow(Mcopy->rowvec, M->rowvec, d);
+ set_copy(Mcopy->linset,M->linset);
+ Mcopy->numbtype=M->numbtype;
+ Mcopy->representation=M->representation;
+ Mcopy->objective=M->objective;
+ }
+ return Mcopy;
+}
+
+
+dd_MatrixPtr dd_MatrixAppend(dd_MatrixPtr M1, dd_MatrixPtr M2)
+{
+ dd_MatrixPtr M=NULL;
+ dd_rowrange i, m,m1,m2;
+ dd_colrange j, d,d1,d2;
+
+ m1=M1->rowsize;
+ d1=M1->colsize;
+ m2=M2->rowsize;
+ d2=M2->colsize;
+
+ m=m1+m2;
+ d=d1;
+
+ if (d1>=0 && d1==d2 && m1>=0 && m2>=0){
+ M=dd_CreateMatrix(m, d);
+ dd_CopyAmatrix(M->matrix, M1->matrix, m1, d);
+ dd_CopyArow(M->rowvec, M1->rowvec, d);
+ for (i=0; i<m1; i++){
+ if (set_member(i+1,M1->linset)) set_addelem(M->linset,i+1);
+ }
+ for (i=0; i<m2; i++){
+ for (j=0; j<d; j++)
+ dd_set(M->matrix[m1+i][j],M2->matrix[i][j]);
+ /* append the second matrix */
+ if (set_member(i+1,M2->linset)) set_addelem(M->linset,m1+i+1);
+ }
+ M->numbtype=M1->numbtype;
+ }
+ return M;
+}
+
+dd_MatrixPtr dd_MatrixNormalizedSortedCopy(dd_MatrixPtr M,dd_rowindex *newpos) /* 094 */
+{
+ /* Sort the rows of Amatrix lexicographically, and return a link to this sorted copy.
+ The vector newpos is allocated, where newpos[i] returns the new row index
+ of the original row i (i=1,...,M->rowsize). */
+ dd_MatrixPtr Mcopy=NULL,Mnorm=NULL;
+ dd_rowrange m,i;
+ dd_colrange d;
+ dd_rowindex roworder;
+
+ /* if (newpos!=NULL) free(newpos); */
+ m= M->rowsize;
+ d= M->colsize;
+ roworder=(long *)calloc(m+1,sizeof(long));
+ *newpos=(long *)calloc(m+1,sizeof(long));
+ if (m >=0 && d >=0){
+ Mnorm=dd_MatrixNormalizedCopy(M);
+ Mcopy=dd_CreateMatrix(m, d);
+ for(i=1; i<=m; i++) roworder[i]=i;
+
+ dd_RandomPermutation(roworder, m, 123);
+ dd_QuickSort(roworder,1,m,Mnorm->matrix,d);
+
+ dd_PermuteCopyAmatrix(Mcopy->matrix, Mnorm->matrix, m, d, roworder);
+ dd_CopyArow(Mcopy->rowvec, M->rowvec, d);
+ for(i=1; i<=m; i++) {
+ if (set_member(roworder[i],M->linset)) set_addelem(Mcopy->linset, i);
+ (*newpos)[roworder[i]]=i;
+ }
+ Mcopy->numbtype=M->numbtype;
+ Mcopy->representation=M->representation;
+ Mcopy->objective=M->objective;
+ dd_FreeMatrix(Mnorm);
+ }
+ free(roworder);
+ return Mcopy;
+}
+
+dd_MatrixPtr dd_MatrixUniqueCopy(dd_MatrixPtr M,dd_rowindex *newpos)
+{
+ /* Remove row duplicates, and return a link to this sorted copy.
+ Linearity rows have priority over the other rows.
+ It is better to call this after sorting with dd_MatrixNormalizedSortedCopy.
+ The vector newpos is allocated, where *newpos[i] returns the new row index
+ of the original row i (i=1,...,M->rowsize). *newpos[i] is negative if the original
+ row is dominated by -*newpos[i] and eliminated in the new copy.
+ */
+ dd_MatrixPtr Mcopy=NULL;
+ dd_rowrange m,i,uniqrows;
+ dd_rowset preferredrows;
+ dd_colrange d;
+ dd_rowindex roworder;
+
+ /* if (newpos!=NULL) free(newpos); */
+ m= M->rowsize;
+ d= M->colsize;
+ preferredrows=M->linset;
+ roworder=(long *)calloc(m+1,sizeof(long));
+ if (m >=0 && d >=0){
+ for(i=1; i<=m; i++) roworder[i]=i;
+ dd_UniqueRows(roworder, 1, m, M->matrix, d,preferredrows, &uniqrows);
+
+ Mcopy=dd_CreateMatrix(uniqrows, d);
+ dd_PermutePartialCopyAmatrix(Mcopy->matrix, M->matrix, m, d, roworder,1,m);
+ dd_CopyArow(Mcopy->rowvec, M->rowvec, d);
+ for(i=1; i<=m; i++) {
+ if (roworder[i]>0 && set_member(i,M->linset)) set_addelem(Mcopy->linset, roworder[i]);
+ }
+ Mcopy->numbtype=M->numbtype;
+ Mcopy->representation=M->representation;
+ Mcopy->objective=M->objective;
+ }
+ *newpos=roworder;
+ return Mcopy;
+}
+
+
+dd_MatrixPtr dd_MatrixNormalizedSortedUniqueCopy(dd_MatrixPtr M,dd_rowindex *newpos) /* 094 */
+{
+ /* Sort and remove row duplicates, and return a link to this sorted copy.
+ Linearity rows have priority over the other rows.
+ It is better to call this after sorting with dd_MatrixNormalizedSortedCopy.
+ The vector newpos is allocated, where *newpos[i] returns the new row index
+ of the original row i (i=1,...,M->rowsize). *newpos[i] is negative if the original
+ row is dominated by -*newpos[i] and eliminated in the new copy.
+ */
+ dd_MatrixPtr M1=NULL,M2=NULL;
+ dd_rowrange m,i;
+ dd_colrange d;
+ dd_rowindex newpos1=NULL,newpos1r=NULL,newpos2=NULL;
+
+ /* if (newpos!=NULL) free(newpos); */
+ m= M->rowsize;
+ d= M->colsize;
+ *newpos=(long *)calloc(m+1,sizeof(long));
+ newpos1r=(long *)calloc(m+1,sizeof(long));
+ if (m>=0 && d>=0){
+ M1=dd_MatrixNormalizedSortedCopy(M,&newpos1);
+ for (i=1; i<=m;i++) newpos1r[newpos1[i]]=i; /* reverse of newpos1 */
+ M2=dd_MatrixUniqueCopy(M1,&newpos2);
+ set_emptyset(M2->linset);
+ for(i=1; i<=m; i++) {
+ if (newpos2[newpos1[i]]>0){
+ printf("newpos1[%ld]=%ld, newpos2[newpos1[%ld]]=%ld\n",i,newpos1[i], i,newpos2[newpos1[i]]);
+ if (set_member(i,M->linset)) set_addelem(M2->linset, newpos2[newpos1[i]]);
+ (*newpos)[i]=newpos2[newpos1[i]];
+ } else {
+ (*newpos)[i]=-newpos1r[-newpos2[newpos1[i]]];
+ }
+ }
+ dd_FreeMatrix(M1);free(newpos1);free(newpos2);free(newpos1r);
+ }
+
+ return M2;
+}
+
+dd_MatrixPtr dd_MatrixSortedUniqueCopy(dd_MatrixPtr M,dd_rowindex *newpos) /* 094 */
+{
+ /* Same as dd_MatrixNormalizedSortedUniqueCopy except that it returns a unnormalized origial data
+ with original ordering.
+ */
+ dd_MatrixPtr M1=NULL,M2=NULL;
+ dd_rowrange m,i,k,ii;
+ dd_colrange d;
+ dd_rowindex newpos1=NULL,newpos1r=NULL,newpos2=NULL;
+
+ /* if (newpos!=NULL) free(newpos); */
+ m= M->rowsize;
+ d= M->colsize;
+ *newpos=(long *)calloc(m+1,sizeof(long));
+ newpos1r=(long *)calloc(m+1,sizeof(long));
+ if (m>=0 && d>=0){
+ M1=dd_MatrixNormalizedSortedCopy(M,&newpos1);
+ for (i=1; i<=m;i++) newpos1r[newpos1[i]]=i; /* reverse of newpos1 */
+ M2=dd_MatrixUniqueCopy(M1,&newpos2);
+ dd_FreeMatrix(M1);
+ set_emptyset(M2->linset);
+ for(i=1; i<=m; i++) {
+ if (newpos2[newpos1[i]]>0){
+ if (set_member(i,M->linset)) set_addelem(M2->linset, newpos2[newpos1[i]]);
+ (*newpos)[i]=newpos2[newpos1[i]];
+ } else {
+ (*newpos)[i]=-newpos1r[-newpos2[newpos1[i]]];
+ }
+ }
+
+ ii=0;
+ set_emptyset(M2->linset);
+ for (i = 1; i<=m ; i++) {
+ k=(*newpos)[i];
+ if (k>0) {
+ ii+=1;
+ (*newpos)[i]=ii;
+ dd_CopyArow(M2->matrix[ii-1],M->matrix[i-1],d);
+ if (set_member(i,M->linset)) set_addelem(M2->linset, ii);
+ }
+ }
+
+ free(newpos1);free(newpos2);free(newpos1r);
+ }
+
+ return M2;
+}
+
+dd_MatrixPtr dd_AppendMatrix(dd_MatrixPtr M1, dd_MatrixPtr M2)
+{
+ return dd_MatrixAppend(M1,M2);
+}
+
+int dd_MatrixAppendTo(dd_MatrixPtr *M1, dd_MatrixPtr M2)
+{
+ dd_MatrixPtr M=NULL;
+ dd_rowrange i, m,m1,m2;
+ dd_colrange j, d,d1,d2;
+ dd_boolean success=0;
+
+ m1=(*M1)->rowsize;
+ d1=(*M1)->colsize;
+ m2=M2->rowsize;
+ d2=M2->colsize;
+
+ m=m1+m2;
+ d=d1;
+
+ if (d1>=0 && d1==d2 && m1>=0 && m2>=0){
+ M=dd_CreateMatrix(m, d);
+ dd_CopyAmatrix(M->matrix, (*M1)->matrix, m1, d);
+ dd_CopyArow(M->rowvec, (*M1)->rowvec, d);
+ for (i=0; i<m1; i++){
+ if (set_member(i+1,(*M1)->linset)) set_addelem(M->linset,i+1);
+ }
+ for (i=0; i<m2; i++){
+ for (j=0; j<d; j++)
+ dd_set(M->matrix[m1+i][j],M2->matrix[i][j]);
+ /* append the second matrix */
+ if (set_member(i+1,M2->linset)) set_addelem(M->linset,m1+i+1);
+ }
+ M->numbtype=(*M1)->numbtype;
+ dd_FreeMatrix(*M1);
+ *M1=M;
+ success=1;
+ }
+ return success;
+}
+
+int dd_MatrixRowRemove(dd_MatrixPtr *M, dd_rowrange r) /* 092 */
+{
+ dd_rowrange i,m;
+ dd_colrange d;
+ dd_boolean success=0;
+
+ m=(*M)->rowsize;
+ d=(*M)->colsize;
+
+ if (r >= 1 && r <=m){
+ (*M)->rowsize=m-1;
+ dd_FreeArow(d, (*M)->matrix[r-1]);
+ set_delelem((*M)->linset,r);
+ /* slide the row headers */
+ for (i=r; i<m; i++){
+ (*M)->matrix[i-1]=(*M)->matrix[i];
+ if (set_member(i+1, (*M)->linset)){
+ set_delelem((*M)->linset,i+1);
+ set_addelem((*M)->linset,i);
+ }
+ }
+ success=1;
+ }
+ return success;
+}
+
+int dd_MatrixRowRemove2(dd_MatrixPtr *M, dd_rowrange r, dd_rowindex *newpos) /* 094 */
+{
+ dd_rowrange i,m;
+ dd_colrange d;
+ dd_boolean success=0;
+ dd_rowindex roworder;
+
+ m=(*M)->rowsize;
+ d=(*M)->colsize;
+
+ if (r >= 1 && r <=m){
+ roworder=(long *)calloc(m+1,sizeof(long));
+ (*M)->rowsize=m-1;
+ dd_FreeArow(d, (*M)->matrix[r-1]);
+ set_delelem((*M)->linset,r);
+ /* slide the row headers */
+ for (i=1; i<r; i++) roworder[i]=i;
+ roworder[r]=0; /* meaning it is removed */
+ for (i=r; i<m; i++){
+ (*M)->matrix[i-1]=(*M)->matrix[i];
+ roworder[i+1]=i;
+ if (set_member(i+1, (*M)->linset)){
+ set_delelem((*M)->linset,i+1);
+ set_addelem((*M)->linset,i);
+ }
+ }
+ success=1;
+ }
+ return success;
+}
+
+dd_MatrixPtr dd_MatrixSubmatrix(dd_MatrixPtr M, dd_rowset delset) /* 092 */
+{
+ dd_MatrixPtr Msub=NULL;
+ dd_rowrange i,isub=1, m,msub;
+ dd_colrange d;
+
+ m= M->rowsize;
+ d= M->colsize;
+ msub=m;
+ if (m >=0 && d >=0){
+ for (i=1; i<=m; i++) {
+ if (set_member(i,delset)) msub-=1;
+ }
+ Msub=dd_CreateMatrix(msub, d);
+ for (i=1; i<=m; i++){
+ if (!set_member(i,delset)){
+ dd_CopyArow(Msub->matrix[isub-1], M->matrix[i-1], d);
+ if (set_member(i, M->linset)){
+ set_addelem(Msub->linset,isub);
+ }
+ isub++;
+ }
+ }
+ dd_CopyArow(Msub->rowvec, M->rowvec, d);
+ Msub->numbtype=M->numbtype;
+ Msub->representation=M->representation;
+ Msub->objective=M->objective;
+ }
+ return Msub;
+}
+
+dd_MatrixPtr dd_MatrixSubmatrix2(dd_MatrixPtr M, dd_rowset delset,dd_rowindex *newpos) /* 092 */
+{ /* returns a pointer to a new matrix which is a submatrix of M with rows in delset
+ removed. *newpos[i] returns the position of the original row i in the new matrix.
+ It is -1 if and only if it is deleted.
+ */
+
+ dd_MatrixPtr Msub=NULL;
+ dd_rowrange i,isub=1, m,msub;
+ dd_colrange d;
+ dd_rowindex roworder;
+
+ m= M->rowsize;
+ d= M->colsize;
+ msub=m;
+ if (m >=0 && d >=0){
+ roworder=(long *)calloc(m+1,sizeof(long));
+ for (i=1; i<=m; i++) {
+ if (set_member(i,delset)) msub-=1;
+ }
+ Msub=dd_CreateMatrix(msub, d);
+ for (i=1; i<=m; i++){
+ if (set_member(i,delset)){
+ roworder[i]=0; /* zero means the row i is removed */
+ } else {
+ dd_CopyArow(Msub->matrix[isub-1], M->matrix[i-1], d);
+ if (set_member(i, M->linset)){
+ set_addelem(Msub->linset,isub);
+ }
+ roworder[i]=isub;
+ isub++;
+ }
+ }
+ *newpos=roworder;
+ dd_CopyArow(Msub->rowvec, M->rowvec, d);
+ Msub->numbtype=M->numbtype;
+ Msub->representation=M->representation;
+ Msub->objective=M->objective;
+ }
+ return Msub;
+}
+
+
+dd_MatrixPtr dd_MatrixSubmatrix2L(dd_MatrixPtr M, dd_rowset delset,dd_rowindex *newpos) /* 094 */
+{ /* This is same as dd_MatrixSubmatrix2 except that the linearity rows will be shifted up
+ so that they are at the top of the matrix.
+ */
+ dd_MatrixPtr Msub=NULL;
+ dd_rowrange i,iL, iI, m,msub;
+ dd_colrange d;
+ dd_rowindex roworder;
+
+ m= M->rowsize;
+ d= M->colsize;
+ msub=m;
+ if (m >=0 && d >=0){
+ roworder=(long *)calloc(m+1,sizeof(long));
+ for (i=1; i<=m; i++) {
+ if (set_member(i,delset)) msub-=1;
+ }
+ Msub=dd_CreateMatrix(msub, d);
+ iL=1; iI=set_card(M->linset)+1; /* starting positions */
+ for (i=1; i<=m; i++){
+ if (set_member(i,delset)){
+ roworder[i]=0; /* zero means the row i is removed */
+ } else {
+ if (set_member(i,M->linset)){
+ dd_CopyArow(Msub->matrix[iL-1], M->matrix[i-1], d);
+ set_delelem(Msub->linset,i);
+ set_addelem(Msub->linset,iL);
+ roworder[i]=iL;
+ iL+=1;
+ } else {
+ dd_CopyArow(Msub->matrix[iI-1], M->matrix[i-1], d);
+ roworder[i]=iI;
+ iI+=1;
+ }
+ }
+ }
+ *newpos=roworder;
+ dd_CopyArow(Msub->rowvec, M->rowvec, d);
+ Msub->numbtype=M->numbtype;
+ Msub->representation=M->representation;
+ Msub->objective=M->objective;
+ }
+ return Msub;
+}
+
+int dd_MatrixRowsRemove(dd_MatrixPtr *M, dd_rowset delset) /* 094 */
+{
+ dd_MatrixPtr Msub=NULL;
+ int success;
+
+ Msub=dd_MatrixSubmatrix(*M, delset);
+ dd_FreeMatrix(*M);
+ *M=Msub;
+ success=1;
+ return success;
+}
+
+int dd_MatrixRowsRemove2(dd_MatrixPtr *M, dd_rowset delset,dd_rowindex *newpos) /* 094 */
+{
+ dd_MatrixPtr Msub=NULL;
+ int success;
+
+ Msub=dd_MatrixSubmatrix2(*M, delset,newpos);
+ dd_FreeMatrix(*M);
+ *M=Msub;
+ success=1;
+ return success;
+}
+
+int dd_MatrixShiftupLinearity(dd_MatrixPtr *M,dd_rowindex *newpos) /* 094 */
+{
+ dd_MatrixPtr Msub=NULL;
+ int success;
+ dd_rowset delset;
+
+ set_initialize(&delset,(*M)->rowsize); /* emptyset */
+ Msub=dd_MatrixSubmatrix2L(*M, delset,newpos);
+ dd_FreeMatrix(*M);
+ *M=Msub;
+
+ set_free(delset);
+ success=1;
+ return success;
+}
+
+dd_PolyhedraPtr dd_CreatePolyhedraData(dd_rowrange m, dd_colrange d)
+{
+ dd_rowrange i;
+ dd_PolyhedraPtr poly=NULL;
+
+ poly=(dd_PolyhedraPtr) malloc (sizeof(dd_PolyhedraType));
+ poly->child =NULL; /* this links the homogenized cone data */
+ poly->m =m;
+ poly->d =d;
+ poly->n =-1; /* the size of output is not known */
+ poly->m_alloc =m+2; /* the allocated row size of matrix A */
+ poly->d_alloc =d; /* the allocated col size of matrix A */
+ poly->ldim =0; /* initialize the linearity dimension */
+ poly->numbtype=dd_Real;
+ dd_InitializeAmatrix(poly->m_alloc,poly->d_alloc,&(poly->A));
+ dd_InitializeArow(d,&(poly->c)); /* cost vector */
+ poly->representation =dd_Inequality;
+ poly->homogeneous =dd_FALSE;
+
+ poly->EqualityIndex=(int *)calloc(m+2, sizeof(int));
+ /* size increased to m+2 in 092b because it is used by the child cone,
+ This is a bug fix suggested by Thao Dang. */
+ /* ith component is 1 if it is equality, -1 if it is strict inequality, 0 otherwise. */
+ for (i = 0; i <= m+1; i++) poly->EqualityIndex[i]=0;
+
+ poly->IsEmpty = -1; /* initially set to -1, neither TRUE nor FALSE, meaning unknown */
+
+ poly->NondegAssumed = dd_FALSE;
+ poly->InitBasisAtBottom = dd_FALSE;
+ poly->RestrictedEnumeration = dd_FALSE;
+ poly->RelaxedEnumeration = dd_FALSE;
+
+ poly->AincGenerated=dd_FALSE; /* Ainc is a set array to store the input incidence. */
+
+ return poly;
+}
+
+dd_boolean dd_InitializeConeData(dd_rowrange m, dd_colrange d, dd_ConePtr *cone)
+{
+ dd_boolean success=dd_TRUE;
+ dd_colrange j;
+
+ (*cone)=(dd_ConePtr)calloc(1, sizeof(dd_ConeType));
+
+/* INPUT: A given representation of a cone: inequality */
+ (*cone)->m=m;
+ (*cone)->d=d;
+ (*cone)->m_alloc=m+2; /* allocated row size of matrix A */
+ (*cone)->d_alloc=d; /* allocated col size of matrix A, B and Bsave */
+ (*cone)->numbtype=dd_Real;
+ (*cone)->parent=NULL;
+
+/* CONTROL: variables to control computation */
+ (*cone)->Iteration=0;
+
+ (*cone)->HalfspaceOrder=dd_LexMin;
+
+ (*cone)->ArtificialRay=NULL;
+ (*cone)->FirstRay=NULL;
+ (*cone)->LastRay=NULL; /* The second description: Generator */
+ (*cone)->PosHead=NULL;
+ (*cone)->ZeroHead=NULL;
+ (*cone)->NegHead=NULL;
+ (*cone)->PosLast=NULL;
+ (*cone)->ZeroLast=NULL;
+ (*cone)->NegLast=NULL;
+ (*cone)->RecomputeRowOrder = dd_TRUE;
+ (*cone)->PreOrderedRun = dd_FALSE;
+ set_initialize(&((*cone)->GroundSet),(*cone)->m_alloc);
+ set_initialize(&((*cone)->EqualitySet),(*cone)->m_alloc);
+ set_initialize(&((*cone)->NonequalitySet),(*cone)->m_alloc);
+ set_initialize(&((*cone)->AddedHalfspaces),(*cone)->m_alloc);
+ set_initialize(&((*cone)->WeaklyAddedHalfspaces),(*cone)->m_alloc);
+ set_initialize(&((*cone)->InitialHalfspaces),(*cone)->m_alloc);
+ (*cone)->RayCount=0;
+ (*cone)->FeasibleRayCount=0;
+ (*cone)->WeaklyFeasibleRayCount=0;
+ (*cone)->TotalRayCount=0;
+ (*cone)->ZeroRayCount=0;
+ (*cone)->EdgeCount=0;
+ (*cone)->TotalEdgeCount=0;
+ (*cone)->count_int=0;
+ (*cone)->count_int_good=0;
+ (*cone)->count_int_bad=0;
+ (*cone)->rseed=1; /* random seed for random row permutation */
+
+ dd_InitializeBmatrix((*cone)->d_alloc, &((*cone)->B));
+ dd_InitializeBmatrix((*cone)->d_alloc, &((*cone)->Bsave));
+ dd_InitializeAmatrix((*cone)->m_alloc,(*cone)->d_alloc,&((*cone)->A));
+
+ (*cone)->Edges
+ =(dd_AdjacencyType**) calloc((*cone)->m_alloc,sizeof(dd_AdjacencyType*));
+ for (j=0; j<(*cone)->m_alloc; j++) (*cone)->Edges[j]=NULL; /* 094h */
+ (*cone)->InitialRayIndex=(long*)calloc(d+1,sizeof(long));
+ (*cone)->OrderVector=(long*)calloc((*cone)->m_alloc+1,sizeof(long));
+
+ (*cone)->newcol=(long*)calloc(((*cone)->d)+1,sizeof(long));
+ for (j=0; j<=(*cone)->d; j++) (*cone)->newcol[j]=j; /* identity map, initially */
+ (*cone)->LinearityDim = -2; /* -2 if it is not computed */
+ (*cone)->ColReduced = dd_FALSE;
+ (*cone)->d_orig = d;
+
+/* STATES: variables to represent current state. */
+/*(*cone)->Error;
+ (*cone)->CompStatus;
+ (*cone)->starttime;
+ (*cone)->endtime;
+*/
+
+ return success;
+}
+
+dd_ConePtr dd_ConeDataLoad(dd_PolyhedraPtr poly)
+{
+ dd_ConePtr cone=NULL;
+ dd_colrange d,j;
+ dd_rowrange m,i;
+
+ m=poly->m;
+ d=poly->d;
+ if (!(poly->homogeneous) && poly->representation==dd_Inequality){
+ m=poly->m+1;
+ }
+ poly->m1=m;
+
+ dd_InitializeConeData(m, d, &cone);
+ cone->representation=poly->representation;
+
+/* Points to the original polyhedra data, and reversely */
+ cone->parent=poly;
+ poly->child=cone;
+
+ for (i=1; i<=poly->m; i++)
+ for (j=1; j<=cone->d; j++)
+ dd_set(cone->A[i-1][j-1],poly->A[i-1][j-1]);
+
+ if (poly->representation==dd_Inequality && !(poly->homogeneous)){
+ dd_set(cone->A[m-1][0],dd_one);
+ for (j=2; j<=d; j++) dd_set(cone->A[m-1][j-1],dd_purezero);
+ }
+
+ return cone;
+}
+
+void dd_SetLinearity(dd_MatrixPtr M, char *line)
+{
+ int i=0;
+ dd_rowrange eqsize,var;
+ char *next;
+ const char ct[]=", "; /* allows separators "," and " ". */
+
+ next=strtok(line,ct);
+ eqsize=atol(next);
+ while (i < eqsize && (next=strtok(NULL,ct))!=NULL) {
+ var=atol(next);
+ set_addelem(M->linset,var); i++;
+ }
+ if (i!=eqsize) {
+ fprintf(stderr,"* Warning: there are inconsistencies in linearity setting.\n");
+ }
+ return;
+}
+
+dd_MatrixPtr dd_PolyFile2Matrix (FILE *f, dd_ErrorType *Error)
+{
+ dd_MatrixPtr M=NULL;
+ dd_rowrange m_input,i;
+ dd_colrange d_input,j;
+ dd_RepresentationType rep=dd_Inequality;
+ mytype value;
+ dd_boolean found=dd_FALSE, newformat=dd_FALSE, successful=dd_FALSE, linearity=dd_FALSE;
+ char command[dd_linelenmax], comsave[dd_linelenmax], numbtype[dd_wordlenmax];
+ dd_NumberType NT;
+#if !defined(GMPRATIONAL)
+ double rvalue;
+#endif
+
+ dd_init(value);
+ (*Error)=dd_NoError;
+ while (!found)
+ {
+ if (fscanf(f,"%s",command)==EOF) {
+ (*Error)=dd_ImproperInputFormat;
+ goto _L99;
+ }
+ else {
+ if (strncmp(command, "V-representation", 16)==0) {
+ rep=dd_Generator; newformat=dd_TRUE;
+ }
+ if (strncmp(command, "H-representation", 16)==0){
+ rep=dd_Inequality; newformat=dd_TRUE;
+ }
+ if (strncmp(command, "partial_enum", 12)==0 ||
+ strncmp(command, "equality", 8)==0 ||
+ strncmp(command, "linearity", 9)==0 ) {
+ linearity=dd_TRUE;
+ fgets(comsave,dd_linelenmax,f);
+ }
+ if (strncmp(command, "begin", 5)==0) found=dd_TRUE;
+ }
+ }
+ fscanf(f, "%ld %ld %s", &m_input, &d_input, numbtype);
+ fprintf(stderr,"size = %ld x %ld\nNumber Type = %s\n", m_input, d_input, numbtype);
+ NT=dd_GetNumberType(numbtype);
+ if (NT==dd_Unknown) {
+ (*Error)=dd_ImproperInputFormat;
+ goto _L99;
+ }
+ M=dd_CreateMatrix(m_input, d_input);
+ M->representation=rep;
+ M->numbtype=NT;
+
+ for (i = 1; i <= m_input; i++) {
+ for (j = 1; j <= d_input; j++) {
+ if (NT==dd_Real) {
+#if defined GMPRATIONAL
+ *Error=dd_NoRealNumberSupport;
+ goto _L99;
+#else
+ fscanf(f, "%lf", &rvalue);
+ dd_set_d(value, rvalue);
+#endif
+ } else {
+ dd_fread_rational_value (f, value);
+ }
+ dd_set(M->matrix[i-1][j - 1],value);
+ if (dd_debug) {fprintf(stderr,"a(%3ld,%5ld) = ",i,j); dd_WriteNumber(stderr,value);}
+ } /*of j*/
+ } /*of i*/
+ if (fscanf(f,"%s",command)==EOF) {
+ (*Error)=dd_ImproperInputFormat;
+ goto _L99;
+ }
+ else if (strncmp(command, "end", 3)!=0) {
+ if (dd_debug) fprintf(stderr,"'end' missing or illegal extra data: %s\n",command);
+ (*Error)=dd_ImproperInputFormat;
+ goto _L99;
+ }
+
+ successful=dd_TRUE;
+ if (linearity) {
+ dd_SetLinearity(M,comsave);
+ }
+ while (!feof(f)) {
+ fscanf(f,"%s", command);
+ dd_ProcessCommandLine(f, M, command);
+ fgets(command,dd_linelenmax,f); /* skip the CR/LF */
+ }
+
+_L99: ;
+ dd_clear(value);
+ /* if (f!=NULL) fclose(f); */
+ return M;
+}
+
+
+dd_PolyhedraPtr dd_DDMatrix2Poly(dd_MatrixPtr M, dd_ErrorType *err)
+{
+ dd_rowrange i;
+ dd_colrange j;
+ dd_PolyhedraPtr poly=NULL;
+
+ *err=dd_NoError;
+ if (M->rowsize<0 || M->colsize<0){
+ *err=dd_NegativeMatrixSize;
+ goto _L99;
+ }
+ poly=dd_CreatePolyhedraData(M->rowsize, M->colsize);
+ poly->representation=M->representation;
+ poly->homogeneous=dd_TRUE;
+
+ for (i = 1; i <= M->rowsize; i++) {
+ if (set_member(i, M->linset)) {
+ poly->EqualityIndex[i]=1;
+ }
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(poly->A[i-1][j-1], M->matrix[i-1][j-1]);
+ if (j==1 && dd_Nonzero(M->matrix[i-1][j-1])) poly->homogeneous = dd_FALSE;
+ } /*of j*/
+ } /*of i*/
+ dd_DoubleDescription(poly,err);
+_L99:
+ return poly;
+}
+
+dd_PolyhedraPtr dd_DDMatrix2Poly2(dd_MatrixPtr M, dd_RowOrderType horder, dd_ErrorType *err)
+{
+ dd_rowrange i;
+ dd_colrange j;
+ dd_PolyhedraPtr poly=NULL;
+
+ *err=dd_NoError;
+ if (M->rowsize<0 || M->colsize<0){
+ *err=dd_NegativeMatrixSize;
+ goto _L99;
+ }
+ poly=dd_CreatePolyhedraData(M->rowsize, M->colsize);
+ poly->representation=M->representation;
+ poly->homogeneous=dd_TRUE;
+
+ for (i = 1; i <= M->rowsize; i++) {
+ if (set_member(i, M->linset)) {
+ poly->EqualityIndex[i]=1;
+ }
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(poly->A[i-1][j-1], M->matrix[i-1][j-1]);
+ if (j==1 && dd_Nonzero(M->matrix[i-1][j-1])) poly->homogeneous = dd_FALSE;
+ } /*of j*/
+ } /*of i*/
+ dd_DoubleDescription2(poly, horder, err);
+_L99:
+ return poly;
+}
+
+void dd_MatrixIntegerFilter(dd_MatrixPtr M)
+{ /* setting an almost integer to the integer. */
+ dd_rowrange i;
+ dd_colrange j;
+ mytype x;
+
+ dd_init(x);
+ for (i=0; i< M->rowsize; i++)
+ for (j=0; j< M->colsize; j++){
+ dd_SnapToInteger(x, M->matrix[i][j]);
+ dd_set(M->matrix[i][j],x);
+ }
+ dd_clear(x);
+}
+
+void dd_CopyRay(mytype *a, dd_colrange d_origsize, dd_RayPtr RR,
+ dd_RepresentationType rep, dd_colindex reducedcol)
+{
+ long j,j1;
+ mytype b;
+
+ dd_init(b);
+ for (j = 1; j <= d_origsize; j++){
+ j1=reducedcol[j];
+ if (j1>0){
+ dd_set(a[j-1],RR->Ray[j1-1]);
+ /* the original column j is mapped to j1, and thus
+ copy the corresponding component */
+ } else {
+ dd_set(a[j-1],dd_purezero);
+ /* original column is redundant and removed for computation */
+ }
+ }
+
+ dd_set(b,a[0]);
+ if (rep==dd_Generator && dd_Nonzero(b)){
+ dd_set(a[0],dd_one);
+ for (j = 2; j <= d_origsize; j++)
+ dd_div(a[j-1],a[j-1],b); /* normalization for generators */
+ }
+ dd_clear(b);
+}
+
+void dd_WriteRay(FILE *f, dd_colrange d_origsize, dd_RayPtr RR, dd_RepresentationType rep, dd_colindex reducedcol)
+{
+ dd_colrange j;
+ static dd_colrange d_last=0;
+ static dd_Arow a;
+
+ if (d_last< d_origsize){
+ if (d_last>0) free(a);
+ dd_InitializeArow(d_origsize+1, &a);
+ d_last=d_origsize+1;
+ }
+
+ dd_CopyRay(a, d_origsize, RR, rep, reducedcol);
+ for (j = 0; j < d_origsize; j++) dd_WriteNumber(f, a[j]);
+ fprintf(f, "\n");
+}
+
+void dd_WriteArow(FILE *f, dd_Arow a, dd_colrange d)
+{
+ dd_colrange j;
+
+ for (j = 0; j < d; j++) dd_WriteNumber(f, a[j]);
+ fprintf(f, "\n");
+}
+
+void dd_WriteAmatrix(FILE *f, dd_Amatrix A, long rowmax, long colmax)
+{
+ long i,j;
+
+ if (A==NULL){
+ fprintf(f, "WriteAmatrix: The requested matrix is empty\n");
+ goto _L99;
+ }
+ fprintf(f, "begin\n");
+#if defined GMPRATIONAL
+ fprintf(f, " %ld %ld rational\n",rowmax, colmax);
+#else
+ fprintf(f, " %ld %ld real\n",rowmax, colmax);
+#endif
+ for (i=1; i <= rowmax; i++) {
+ for (j=1; j <= colmax; j++) {
+ dd_WriteNumber(f, A[i-1][j-1]);
+ }
+ fprintf(f,"\n");
+ }
+ fprintf(f, "end\n");
+_L99:;
+}
+
+void dd_WriteBmatrix(FILE *f, dd_colrange d_size, dd_Bmatrix B)
+{
+ dd_colrange j1, j2;
+
+ if (B==NULL){
+ fprintf(f, "WriteBmatrix: The requested matrix is empty\n");
+ goto _L99;
+ }
+ for (j1 = 0; j1 < d_size; j1++) {
+ for (j2 = 0; j2 < d_size; j2++) {
+ dd_WriteNumber(f, B[j1][j2]);
+ } /*of j2*/
+ putc('\n', f);
+ } /*of j1*/
+ putc('\n', f);
+_L99:;
+}
+
+void dd_WriteSetFamily(FILE *f, dd_SetFamilyPtr F)
+{
+ dd_bigrange i;
+
+ if (F==NULL){
+ fprintf(f, "WriteSetFamily: The requested family is empty\n");
+ goto _L99;
+ }
+ fprintf(f,"begin\n");
+ fprintf(f," %ld %ld\n", F->famsize, F->setsize);
+ for (i=0; i<F->famsize; i++) {
+ fprintf(f, " %ld %ld : ", i+1, set_card(F->set[i]));
+ set_fwrite(f, F->set[i]);
+ }
+ fprintf(f,"end\n");
+_L99:;
+}
+
+void dd_WriteSetFamilyCompressed(FILE *f, dd_SetFamilyPtr F)
+{
+ dd_bigrange i,card;
+
+ if (F==NULL){
+ fprintf(f, "WriteSetFamily: The requested family is empty\n");
+ goto _L99;
+ }
+ fprintf(f,"begin\n");
+ fprintf(f," %ld %ld\n", F->famsize, F->setsize);
+ for (i=0; i<F->famsize; i++) {
+ card=set_card(F->set[i]);
+ if (F->setsize - card >= card){
+ fprintf(f, " %ld %ld : ", i+1, card);
+ set_fwrite(f, F->set[i]);
+ } else {
+ fprintf(f, " %ld %ld : ", i+1, -card);
+ set_fwrite_compl(f, F->set[i]);
+ }
+ }
+ fprintf(f,"end\n");
+_L99:;
+}
+
+void dd_WriteMatrix(FILE *f, dd_MatrixPtr M)
+{
+ dd_rowrange i, linsize;
+
+ if (M==NULL){
+ fprintf(f, "WriteMatrix: The requested matrix is empty\n");
+ goto _L99;
+ }
+ switch (M->representation) {
+ case dd_Inequality:
+ fprintf(f, "H-representation\n"); break;
+ case dd_Generator:
+ fprintf(f, "V-representation\n"); break;
+ case dd_Unspecified:
+ break;
+ }
+ linsize=set_card(M->linset);
+ if (linsize>0) {
+ fprintf(f, "linearity %ld ", linsize);
+ for (i=1; i<=M->rowsize; i++)
+ if (set_member(i, M->linset)) fprintf(f, " %ld", i);
+ fprintf(f, "\n");
+ }
+ dd_WriteAmatrix(f, M->matrix, M->rowsize, M->colsize);
+ if (M->objective!=dd_LPnone){
+ if (M->objective==dd_LPmax)
+ fprintf(f, "maximize\n");
+ else
+ fprintf(f, "minimize\n");
+ dd_WriteArow(f, M->rowvec, M->colsize);
+ }
+_L99:;
+}
+
+void dd_WriteLP(FILE *f, dd_LPPtr lp)
+{
+ if (lp==NULL){
+ fprintf(f, "WriteLP: The requested lp is empty\n");
+ goto _L99;
+ }
+ fprintf(f, "H-representation\n");
+
+ dd_WriteAmatrix(f, lp->A, (lp->m)-1, lp->d);
+ if (lp->objective!=dd_LPnone){
+ if (lp->objective==dd_LPmax)
+ fprintf(f, "maximize\n");
+ else
+ fprintf(f, "minimize\n");
+ dd_WriteArow(f, lp->A[lp->objrow-1], lp->d);
+ }
+_L99:;
+}
+
+
+void dd_SnapToInteger(mytype y, mytype x)
+{
+ /* this is broken. It does nothing. */
+ dd_set(y,x);
+}
+
+
+void dd_WriteReal(FILE *f, mytype x)
+{
+ long ix1,ix2,ix;
+ double ax;
+
+ ax=dd_get_d(x);
+ ix1= (long) (fabs(ax) * 10000. + 0.5);
+ ix2= (long) (fabs(ax) + 0.5);
+ ix2= ix2*10000;
+ if ( ix1 == ix2) {
+ if (dd_Positive(x)) {
+ ix = (long)(ax + 0.5);
+ } else {
+ ix = (long)(-ax + 0.5);
+ ix = -ix;
+ }
+ fprintf(f, " %2ld", ix);
+ } else
+ fprintf(f, " % .9E",ax);
+}
+
+void dd_WriteNumber(FILE *f, mytype x)
+{
+#if defined GMPRATIONAL
+ fprintf(f," ");
+ mpq_out_str(f, 10, x);
+#else
+ dd_WriteReal(f, x);
+#endif
+}
+
+
+void dd_WriteIncidence(FILE *f, dd_PolyhedraPtr poly)
+{
+ dd_SetFamilyPtr I;
+
+ switch (poly->representation) {
+ case dd_Inequality:
+ fprintf(f, "ecd_file: Incidence of generators and inequalities\n");
+ break;
+ case dd_Generator:
+ fprintf(f, "icd_file: Incidence of inequalities and generators\n");
+ break;
+
+ default:
+ break;
+ }
+ I=dd_CopyIncidence(poly);
+ dd_WriteSetFamilyCompressed(f,I);
+ dd_FreeSetFamily(I);
+}
+
+void dd_WriteAdjacency(FILE *f, dd_PolyhedraPtr poly)
+{
+ dd_SetFamilyPtr A;
+
+ switch (poly->representation) {
+ case dd_Inequality:
+ fprintf(f, "ead_file: Adjacency of generators\n");
+ break;
+ case dd_Generator:
+ fprintf(f, "iad_file: Adjacency of inequalities\n");
+ break;
+
+ default:
+ break;
+ }
+ A=dd_CopyAdjacency(poly);
+ dd_WriteSetFamilyCompressed(f,A);
+ dd_FreeSetFamily(A);
+}
+
+
+void dd_ComputeAinc(dd_PolyhedraPtr poly)
+{
+/* This generates the input incidence array poly->Ainc, and
+ two sets: poly->Ared, poly->Adom.
+*/
+ dd_bigrange k;
+ dd_rowrange i,m1;
+ dd_colrange j;
+ dd_boolean redundant;
+ dd_MatrixPtr M=NULL;
+ mytype sum,temp;
+
+ dd_init(sum); dd_init(temp);
+ if (poly->AincGenerated==dd_TRUE) goto _L99;
+
+ M=dd_CopyOutput(poly);
+ poly->n=M->rowsize;
+ m1=poly->m1;
+ /* this number is same as poly->m, except when
+ poly is given by nonhomogeneous inequalty:
+ !(poly->homogeneous) && poly->representation==Inequality,
+ it is poly->m+1. See dd_ConeDataLoad.
+ */
+ poly->Ainc=(set_type*)calloc(m1, sizeof(set_type));
+ for(i=1; i<=m1; i++) set_initialize(&(poly->Ainc[i-1]),poly->n);
+ set_initialize(&(poly->Ared), m1);
+ set_initialize(&(poly->Adom), m1);
+
+ for (k=1; k<=poly->n; k++){
+ for (i=1; i<=poly->m; i++){
+ dd_set(sum,dd_purezero);
+ for (j=1; j<=poly->d; j++){
+ dd_mul(temp,poly->A[i-1][j-1],M->matrix[k-1][j-1]);
+ dd_add(sum,sum,temp);
+ }
+ if (dd_EqualToZero(sum)) {
+ set_addelem(poly->Ainc[i-1], k);
+ }
+ }
+ if (!(poly->homogeneous) && poly->representation==dd_Inequality){
+ if (dd_EqualToZero(M->matrix[k-1][0])) {
+ set_addelem(poly->Ainc[m1-1], k); /* added infinity inequality (1,0,0,...,0) */
+ }
+ }
+ }
+
+ for (i=1; i<=m1; i++){
+ if (set_card(poly->Ainc[i-1])==M->rowsize){
+ set_addelem(poly->Adom, i);
+ }
+ }
+ for (i=m1; i>=1; i--){
+ if (set_card(poly->Ainc[i-1])==0){
+ redundant=dd_TRUE;
+ set_addelem(poly->Ared, i);
+ }else {
+ redundant=dd_FALSE;
+ for (k=1; k<=m1; k++) {
+ if (k!=i && !set_member(k, poly->Ared) && !set_member(k, poly->Adom) &&
+ set_subset(poly->Ainc[i-1], poly->Ainc[k-1])){
+ if (!redundant){
+ redundant=dd_TRUE;
+ }
+ set_addelem(poly->Ared, i);
+ }
+ }
+ }
+ }
+ dd_FreeMatrix(M);
+ poly->AincGenerated=dd_TRUE;
+_L99:;
+ dd_clear(sum); dd_clear(temp);
+}
+
+dd_boolean dd_InputAdjacentQ(dd_PolyhedraPtr poly,
+ dd_rowrange i1, dd_rowrange i2)
+/* Before calling this function, RedundantSet must be
+ a set of row indices whose removal results in a minimal
+ nonredundant system to represent the input polyhedron,
+ DominantSet must be the set of row indices which are
+ active at every extreme points/rays.
+*/
+{
+ dd_boolean adj=dd_TRUE;
+ dd_rowrange i;
+ static set_type common;
+ static long lastn=0;
+
+ if (poly->AincGenerated==dd_FALSE) dd_ComputeAinc(poly);
+ if (lastn!=poly->n){
+ if (lastn >0) set_free(common);
+ set_initialize(&common, poly->n);
+ lastn=poly->n;
+ }
+ if (set_member(i1, poly->Ared) || set_member(i2, poly->Ared)){
+ adj=dd_FALSE;
+ goto _L99;
+ }
+ if (set_member(i1, poly->Adom) || set_member(i2, poly->Adom)){
+ // dominant inequality is considered adjacencent to all others.
+ adj=dd_TRUE;
+ goto _L99;
+ }
+ set_int(common, poly->Ainc[i1-1], poly->Ainc[i2-1]);
+ i=0;
+ while (i<poly->m1 && adj==dd_TRUE){
+ i++;
+ if (i!=i1 && i!=i2 && !set_member(i, poly->Ared) &&
+ !set_member(i, poly->Adom) && set_subset(common,poly->Ainc[i-1])){
+ adj=dd_FALSE;
+ }
+ }
+_L99:;
+ return adj;
+}
+
+
+void dd_WriteInputIncidence(FILE *f, dd_PolyhedraPtr poly)
+{
+ dd_SetFamilyPtr I;
+
+ if (poly->AincGenerated==dd_FALSE) dd_ComputeAinc(poly);
+ switch (poly->representation) {
+ case dd_Inequality:
+ fprintf(f,"icd_file: Incidence of inequalities and generators\n");
+ break;
+
+ case dd_Generator:
+ fprintf(f,"ecd_file: Incidence of generators and inequalities\n");
+ break;
+
+ default:
+ break;
+ }
+
+ I=dd_CopyInputIncidence(poly);
+ dd_WriteSetFamilyCompressed(f,I);
+ dd_FreeSetFamily(I);
+}
+
+void dd_WriteInputAdjacency(FILE *f, dd_PolyhedraPtr poly)
+{
+ dd_SetFamilyPtr A;
+
+ if (poly->AincGenerated==dd_FALSE){
+ dd_ComputeAinc(poly);
+ }
+ switch (poly->representation) {
+ case dd_Inequality:
+ fprintf(f, "iad_file: Adjacency of inequalities\n");
+ break;
+
+ case dd_Generator:
+ fprintf(f, "ead_file: Adjacency of generators\n");
+ break;
+
+ default:
+ break;
+ }
+ A=dd_CopyInputAdjacency(poly);
+ dd_WriteSetFamilyCompressed(f,A);
+ dd_FreeSetFamily(A);
+}
+
+
+void dd_WriteProgramDescription(FILE *f)
+{
+ fprintf(f, "* cddlib: a double description library:%s\n", dd_DDVERSION);
+ fprintf(f, "* compiled for %s arithmetic.\n", dd_ARITHMETIC);
+ fprintf(f,"* %s\n",dd_COPYRIGHT);
+}
+
+void dd_WriteTimes(FILE *f, time_t starttime, time_t endtime)
+{
+ long ptime,ptime_sec,ptime_minu, ptime_hour;
+
+/*
+ ptime=difftime(endtime,starttime);
+ This function is ANSI standard, but not available sometime
+*/
+ ptime=(endtime - starttime);
+ /* This is to replace the line above, but it may not give
+ correct time in seconds */
+ ptime_hour=ptime/3600;
+ ptime_minu=(ptime-ptime_hour*3600)/60;
+ ptime_sec=ptime%60;
+ fprintf(f,"* Computation started at %s",asctime(localtime(&starttime)));
+ fprintf(f,"* ended at %s",asctime(localtime(&endtime)));
+ fprintf(f,"* Total processor time = %ld seconds\n",ptime);
+ fprintf(f,"* = %ld h %ld m %ld s\n",ptime_hour, ptime_minu, ptime_sec);
+}
+
+void dd_WriteDDTimes(FILE *f, dd_PolyhedraPtr poly)
+{
+ dd_WriteTimes(f,poly->child->starttime,poly->child->endtime);
+}
+
+void dd_WriteLPTimes(FILE *f, dd_LPPtr lp)
+{
+ dd_WriteTimes(f,lp->starttime,lp->endtime);
+}
+
+void dd_WriteLPStats(FILE *f)
+{
+ time_t currenttime;
+
+ time(¤ttime);
+
+ fprintf(f, "\n*--- Statistics of pivots ---\n");
+#if defined GMPRATIONAL
+ fprintf(f, "* f0 = %ld (float basis finding pivots)\n",ddf_statBApivots);
+ fprintf(f, "* fc = %ld (float CC pivots)\n",ddf_statCCpivots);
+ fprintf(f, "* f1 = %ld (float dual simplex phase I pivots)\n",ddf_statDS1pivots);
+ fprintf(f, "* f2 = %ld (float dual simplex phase II pivots)\n",ddf_statDS2pivots);
+ fprintf(f, "* f3 = %ld (float anticycling CC pivots)\n",ddf_statACpivots);
+ fprintf(f, "* e0 = %ld (exact basis finding pivots)\n",dd_statBApivots);
+ fprintf(f, "* ec = %ld (exact CC pivots)\n",dd_statCCpivots);
+ fprintf(f, "* e1 = %ld (exact dual simplex phase I pivots)\n",dd_statDS1pivots);
+ fprintf(f, "* e2 = %ld (exact dual simplex phase II pivots)\n",dd_statDS2pivots);
+ fprintf(f, "* e3 = %ld (exact anticycling CC pivots)\n",dd_statACpivots);
+ fprintf(f, "* e4 = %ld (exact basis verification pivots)\n",dd_statBSpivots);
+#else
+ fprintf(f, "f0 = %ld (float basis finding pivots)\n",dd_statBApivots);
+ fprintf(f, "fc = %ld (float CC pivots)\n",dd_statCCpivots);
+ fprintf(f, "f1 = %ld (float dual simplex phase I pivots)\n",dd_statDS1pivots);
+ fprintf(f, "f2 = %ld (float dual simplex phase II pivots)\n",dd_statDS2pivots);
+ fprintf(f, "f3 = %ld (float anticycling CC pivots)\n",dd_statACpivots);
+#endif
+ dd_WriteLPMode(f);
+ dd_WriteTimes(f,dd_statStartTime, currenttime);
+}
+
+void dd_WriteLPMode(FILE *f)
+{
+ fprintf(f, "\n* LP solver: ");
+ switch (dd_choiceLPSolverDefault) {
+ case dd_DualSimplex:
+ fprintf(f, "DualSimplex\n");
+ break;
+ case dd_CrissCross:
+ fprintf(f, "Criss-Cross\n");
+ break;
+ default: break;
+ }
+
+ fprintf(f, "* Redundancy cheking solver: ");
+ switch (dd_choiceRedcheckAlgorithm) {
+ case dd_DualSimplex:
+ fprintf(f, "DualSimplex\n");
+ break;
+ case dd_CrissCross:
+ fprintf(f, "Criss-Cross\n");
+ break;
+ default: break;
+ }
+
+ fprintf(f, "* Lexicographic pivot: ");
+ if (dd_choiceLexicoPivotQ) fprintf(f, " on\n");
+ else fprintf(f, " off\n");
+
+}
+
+
+void dd_WriteRunningMode(FILE *f, dd_PolyhedraPtr poly)
+{
+ if (poly->child!=NULL){
+ fprintf(f,"* roworder: ");
+ switch (poly->child->HalfspaceOrder) {
+
+ case dd_MinIndex:
+ fprintf(f, "minindex\n");
+ break;
+
+ case dd_MaxIndex:
+ fprintf(f, "maxindex\n");
+ break;
+
+ case dd_MinCutoff:
+ fprintf(f, "mincutoff\n");
+ break;
+
+ case dd_MaxCutoff:
+ fprintf(f, "maxcutoff\n");
+ break;
+
+ case dd_MixCutoff:
+ fprintf(f, "mixcutoff\n");
+ break;
+
+ case dd_LexMin:
+ fprintf(f, "lexmin\n");
+ break;
+
+ case dd_LexMax:
+ fprintf(f, "lexmax\n");
+ break;
+
+ case dd_RandomRow:
+ fprintf(f, "random %d\n",poly->child->rseed);
+ break;
+
+ default: break;
+ }
+ }
+}
+
+
+void dd_WriteCompletionStatus(FILE *f, dd_ConePtr cone)
+{
+ if (cone->Iteration<cone->m && cone->CompStatus==dd_AllFound) {
+ fprintf(f,"*Computation completed at Iteration %4ld.\n", cone->Iteration);
+ }
+ if (cone->CompStatus == dd_RegionEmpty) {
+ fprintf(f,"*Computation completed at Iteration %4ld because the region found empty.\n",cone->Iteration);
+ }
+}
+
+void dd_WritePolyFile(FILE *f, dd_PolyhedraPtr poly)
+{
+ dd_WriteAmatrix(f,poly->A,poly->m,poly->d);
+}
+
+
+void dd_WriteErrorMessages(FILE *f, dd_ErrorType Error)
+{
+ switch (Error) {
+
+ case dd_DimensionTooLarge:
+ fprintf(f, "*Input Error: Input matrix is too large:\n");
+ fprintf(f, "*Please increase MMAX and/or NMAX in the source code and recompile.\n");
+ break;
+
+ case dd_IFileNotFound:
+ fprintf(f, "*Input Error: Specified input file does not exist.\n");
+ break;
+
+ case dd_OFileNotOpen:
+ fprintf(f, "*Output Error: Specified output file cannot be opened.\n");
+ break;
+
+ case dd_NegativeMatrixSize:
+ fprintf(f, "*Input Error: Input matrix has a negative size:\n");
+ fprintf(f, "*Please check rowsize or colsize.\n");
+ break;
+
+ case dd_ImproperInputFormat:
+ fprintf(f,"*Input Error: Input format is not correct.\n");
+ fprintf(f,"*Format:\n");
+ fprintf(f," begin\n");
+ fprintf(f," m n NumberType(real, rational or integer)\n");
+ fprintf(f," b -A\n");
+ fprintf(f," end\n");
+ break;
+
+ case dd_EmptyVrepresentation:
+ fprintf(f, "*Input Error: V-representation is empty:\n");
+ fprintf(f, "*cddlib does not accept this trivial case for which output can be any inconsistent system.\n");
+ break;
+
+ case dd_EmptyHrepresentation:
+ fprintf(f, "*Input Error: H-representation is empty.\n");
+ break;
+
+ case dd_EmptyRepresentation:
+ fprintf(f, "*Input Error: Representation is empty.\n");
+ break;
+
+ case dd_NoLPObjective:
+ fprintf(f, "*LP Error: No LP objective (max or min) is set.\n");
+ break;
+
+ case dd_NoRealNumberSupport:
+ fprintf(f, "*LP Error: The binary (with GMP Rational) does not support Real number input.\n");
+ fprintf(f, " : Use a binary compiled without -DGMPRATIONAL option.\n");
+ break;
+
+ case dd_NotAvailForH:
+ fprintf(f, "*Error: A function is called with H-rep which does not support an H-representation.\n");
+ break;
+
+ case dd_NotAvailForV:
+ fprintf(f, "*Error: A function is called with V-rep which does not support an V-representation.\n");
+ break;
+
+ case dd_CannotHandleLinearity:
+ fprintf(f, "*Error: The function called cannot handle linearity.\n");
+ break;
+
+ case dd_RowIndexOutOfRange:
+ fprintf(f, "*Error: Specified row index is out of range\n");
+ break;
+
+ case dd_ColIndexOutOfRange:
+ fprintf(f, "*Error: Specified column index is out of range\n");
+ break;
+
+ case dd_LPCycling:
+ fprintf(f, "*Error: Possibly an LP cycling occurs. Use the Criss-Cross method.\n");
+ break;
+
+ case dd_NumericallyInconsistent:
+ fprintf(f, "*Error: Numerical inconsistency is found. Use the GMP exact arithmetic.\n");
+ break;
+
+ case dd_NoError:
+ fprintf(f,"*No Error found.\n");
+ break;
+ }
+}
+
+
+dd_SetFamilyPtr dd_CopyIncidence(dd_PolyhedraPtr poly)
+{
+ dd_SetFamilyPtr F=NULL;
+ dd_bigrange k;
+ dd_rowrange i;
+
+ if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) goto _L99;
+ if (poly->AincGenerated==dd_FALSE) dd_ComputeAinc(poly);
+ F=dd_CreateSetFamily(poly->n, poly->m1);
+ for (i=1; i<=poly->m1; i++)
+ for (k=1; k<=poly->n; k++)
+ if (set_member(k,poly->Ainc[i-1])) set_addelem(F->set[k-1],i);
+_L99:;
+ return F;
+}
+
+dd_SetFamilyPtr dd_CopyInputIncidence(dd_PolyhedraPtr poly)
+{
+ dd_rowrange i;
+ dd_SetFamilyPtr F=NULL;
+
+ if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) goto _L99;
+ if (poly->AincGenerated==dd_FALSE) dd_ComputeAinc(poly);
+ F=dd_CreateSetFamily(poly->m1, poly->n);
+ for(i=0; i< poly->m1; i++){
+ set_copy(F->set[i], poly->Ainc[i]);
+ }
+_L99:;
+ return F;
+}
+
+dd_SetFamilyPtr dd_CopyAdjacency(dd_PolyhedraPtr poly)
+{
+ dd_RayPtr RayPtr1,RayPtr2;
+ dd_SetFamilyPtr F=NULL;
+ long pos1, pos2;
+ dd_bigrange lstart,k,n;
+ set_type linset,allset;
+ dd_boolean adj;
+
+ if (poly->n==0 && poly->homogeneous && poly->representation==dd_Inequality){
+ n=1; /* the origin (the unique vertex) should be output. */
+ } else n=poly->n;
+ set_initialize(&linset, n);
+ set_initialize(&allset, n);
+ if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) goto _L99;
+ F=dd_CreateSetFamily(n, n);
+ if (n<=0) goto _L99;
+ poly->child->LastRay->Next=NULL;
+ for (RayPtr1=poly->child->FirstRay, pos1=1;RayPtr1 != NULL;
+ RayPtr1 = RayPtr1->Next, pos1++){
+ for (RayPtr2=poly->child->FirstRay, pos2=1; RayPtr2 != NULL;
+ RayPtr2 = RayPtr2->Next, pos2++){
+ if (RayPtr1!=RayPtr2){
+ dd_CheckAdjacency(poly->child, &RayPtr1, &RayPtr2, &adj);
+ if (adj){
+ set_addelem(F->set[pos1-1], pos2);
+ }
+ }
+ }
+ }
+ lstart=poly->n - poly->ldim + 1;
+ set_compl(allset,allset); /* allset is set to the ground set. */
+ for (k=lstart; k<=poly->n; k++){
+ set_addelem(linset,k); /* linearity set */
+ set_copy(F->set[k-1],allset); /* linearity generator is adjacent to all */
+ }
+ for (k=1; k<lstart; k++){
+ set_uni(F->set[k-1],F->set[k-1],linset);
+ /* every generator is adjacent to all linearity generators */
+ }
+_L99:;
+ set_free(allset); set_free(linset);
+ return F;
+}
+
+dd_SetFamilyPtr dd_CopyInputAdjacency(dd_PolyhedraPtr poly)
+{
+ dd_rowrange i,j;
+ dd_SetFamilyPtr F=NULL;
+
+ if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) goto _L99;
+ if (poly->AincGenerated==dd_FALSE) dd_ComputeAinc(poly);
+ F=dd_CreateSetFamily(poly->m1, poly->m1);
+ for (i=1; i<=poly->m1; i++){
+ for (j=1; j<=poly->m1; j++){
+ if (i!=j && dd_InputAdjacentQ(poly, i, j)) {
+ set_addelem(F->set[i-1],j);
+ }
+ }
+ }
+_L99:;
+ return F;
+}
+
+dd_MatrixPtr dd_CopyOutput(dd_PolyhedraPtr poly)
+{
+ dd_RayPtr RayPtr;
+ dd_MatrixPtr M=NULL;
+ dd_rowrange i=0,total;
+ dd_colrange j,j1;
+ mytype b;
+ dd_RepresentationType outputrep=dd_Inequality;
+ dd_boolean outputorigin=dd_FALSE;
+
+ dd_init(b);
+ total=poly->child->LinearityDim + poly->child->FeasibleRayCount;
+
+ if (poly->child->d<=0 || poly->child->newcol[1]==0) total=total-1;
+ if (poly->representation==dd_Inequality) outputrep=dd_Generator;
+ if (total==0 && poly->homogeneous && poly->representation==dd_Inequality){
+ total=1;
+ outputorigin=dd_TRUE;
+ /* the origin (the unique vertex) should be output. */
+ }
+ if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) goto _L99;
+
+ M=dd_CreateMatrix(total, poly->d);
+ RayPtr = poly->child->FirstRay;
+ while (RayPtr != NULL) {
+ if (RayPtr->feasible) {
+ dd_CopyRay(M->matrix[i], poly->d, RayPtr, outputrep, poly->child->newcol);
+ i++; /* 086 */
+ }
+ RayPtr = RayPtr->Next;
+ }
+ for (j=2; j<=poly->d; j++){
+ if (poly->child->newcol[j]==0){
+ /* original column j is dependent on others and removed for the cone */
+ dd_set(b,poly->child->Bsave[0][j-1]);
+ if (outputrep==dd_Generator && dd_Positive(b)){
+ dd_set(M->matrix[i][0],dd_one); /* dd_Normalize */
+ for (j1=1; j1<poly->d; j1++)
+ dd_div(M->matrix[i][j1],(poly->child->Bsave[j1][j-1]),b);
+ } else {
+ for (j1=0; j1<poly->d; j1++)
+ dd_set(M->matrix[i][j1],poly->child->Bsave[j1][j-1]);
+ }
+ set_addelem(M->linset, i+1);
+ i++;
+ }
+ }
+ if (outputorigin){
+ /* output the origin for homogeneous H-polyhedron with no rays. */
+ dd_set(M->matrix[0][0],dd_one);
+ for (j=1; j<poly->d; j++){
+ dd_set(M->matrix[0][j],dd_purezero);
+ }
+ }
+ dd_MatrixIntegerFilter(M);
+ if (poly->representation==dd_Inequality)
+ M->representation=dd_Generator;
+ else
+ M->representation=dd_Inequality;
+_L99:;
+ dd_clear(b);
+ return M;
+}
+
+dd_MatrixPtr dd_CopyInput(dd_PolyhedraPtr poly)
+{
+ dd_MatrixPtr M=NULL;
+ dd_rowrange i;
+
+ M=dd_CreateMatrix(poly->m, poly->d);
+ dd_CopyAmatrix(M->matrix, poly->A, poly->m, poly->d);
+ for (i=1; i<=poly->m; i++)
+ if (poly->EqualityIndex[i]==1) set_addelem(M->linset,i);
+ dd_MatrixIntegerFilter(M);
+ if (poly->representation==dd_Generator)
+ M->representation=dd_Generator;
+ else
+ M->representation=dd_Inequality;
+ return M;
+}
+
+dd_MatrixPtr dd_CopyGenerators(dd_PolyhedraPtr poly)
+{
+ dd_MatrixPtr M=NULL;
+
+ if (poly->representation==dd_Generator){
+ M=dd_CopyInput(poly);
+ } else {
+ M=dd_CopyOutput(poly);
+ }
+ return M;
+}
+
+dd_MatrixPtr dd_CopyInequalities(dd_PolyhedraPtr poly)
+{
+ dd_MatrixPtr M=NULL;
+
+ if (poly->representation==dd_Inequality){
+ M=dd_CopyInput(poly);
+ } else {
+ M=dd_CopyOutput(poly);
+ }
+ return M;
+}
+
+/****************************************************************************************/
+/* rational number (a/b) read is taken from Vinci by Benno Bueeler and Andreas Enge */
+/****************************************************************************************/
+void dd_sread_rational_value (const char *s, mytype value)
+ /* reads a rational value from the specified string "s" and assigns it to "value" */
+
+{
+ char *numerator_s=NULL, *denominator_s=NULL, *position;
+ int sign = 1;
+ double numerator, denominator;
+#if defined GMPRATIONAL
+ mpz_t znum, zden;
+#else
+ double rvalue;
+#endif
+
+ /* determine the sign of the number */
+ numerator_s = s;
+ if (s [0] == '-')
+ { sign = -1;
+ numerator_s++;
+ }
+ else if (s [0] == '+')
+ numerator_s++;
+
+ /* look for a sign '/' and eventually split the number in numerator and denominator */
+ position = strchr (numerator_s, '/');
+ if (position != NULL)
+ { *position = '\0'; /* terminates the numerator */
+ denominator_s = position + 1;
+ };
+
+ /* determine the floating point values of numerator and denominator */
+ numerator=atol (numerator_s);
+
+ if (position != NULL)
+ {
+ denominator=atol (denominator_s);
+ }
+ else denominator = 1;
+
+/*
+ fprintf(stderr,"\nrational_read: numerator %f\n",numerator);
+ fprintf(stderr,"rational_read: denominator %f\n",denominator);
+ fprintf(stderr,"rational_read: sign %d\n",sign);
+*/
+
+#if defined GMPRATIONAL
+ mpz_init_set_str(znum,numerator_s,10);
+ if (sign<0) mpz_neg(znum,znum);
+ mpz_init(zden); mpz_set_ui(zden,1);
+ if (denominator_s!=NULL) mpz_init_set_str(zden,denominator_s,10);
+ mpq_set_num(value,znum); mpq_set_den(value,zden);
+ mpq_canonicalize(value);
+ mpz_clear(znum); mpz_clear(zden);
+ /* num=(long)sign * numerator; */
+ /* den=(unsigned long) denominator; */
+ /* mpq_set_si(value, num, den); */
+#elif defined GMPFLOAT
+ rvalue=sign * numerator/ (signed long) denominator;
+ mpf_set_d(value, rvalue);
+#else
+ rvalue=sign * numerator/ (signed long) denominator;
+ ddd_set_d(value, rvalue);
+#endif
+ if (dd_debug) {
+ fprintf(stderr,"rational_read: ");
+ dd_WriteNumber(stderr,value); fprintf(stderr,"\n");
+ }
+}
+
+
+void dd_fread_rational_value (FILE *f, mytype value)
+ /* reads a rational value from the specified file "f" and assigns it to "value" */
+
+{
+ char number_s [dd_wordlenmax];
+ mytype rational_value;
+
+ dd_init(rational_value);
+ fscanf(f, "%s ", number_s);
+ dd_sread_rational_value (number_s, rational_value);
+ dd_set(value,rational_value);
+ dd_clear(rational_value);
+}
+
+/****************************************************************************************/
+
+
+/* end of cddio.c */
+
diff --git a/third_party/cddlib/lib-src/cddlib.c b/third_party/cddlib/lib-src/cddlib.c
new file mode 100644
index 0000000..ca9469f
--- /dev/null
+++ b/third_party/cddlib/lib-src/cddlib.c
@@ -0,0 +1,392 @@
+/* cddlib.c: cdd library (library version of cdd)
+ written by Komei Fukuda, fukuda@math.ethz.ch
+ Version 0.94h, April 30, 2015
+ Standard ftp site: ftp.ifor.math.ethz.ch, Directory: pub/fukuda/cdd
+*/
+
+/* cdd : C-Implementation of the double description method for
+ computing all vertices and extreme rays of the polyhedron
+ P= {x : b - A x >= 0}.
+ Please read COPYING (GNU General Public Licence) and
+ the manual cddlibman.tex for detail.
+*/
+
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* The first version C0.21 was created on November 10,1993
+ with Dave Gillespie's p2c translator
+ from the Pascal program pdd.p written by Komei Fukuda.
+*/
+
+#include "setoper.h"
+ /* set operation library header (Ver. June 1, 2000 or later) */
+#include "cdd.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+
+/* Global Variables */
+dd_boolean dd_debug =dd_FALSE;
+dd_boolean dd_log =dd_FALSE;
+/* GLOBAL CONSTANTS and STATICS VARIABLES (to be set by dd_set_global_constants() */
+mytype dd_zero;
+mytype dd_one;
+mytype dd_purezero;
+mytype dd_minuszero;
+mytype dd_minusone;
+
+time_t dd_statStartTime; /* cddlib starting time */
+long dd_statBApivots; /* basis finding pivots */
+long dd_statCCpivots; /* criss-cross pivots */
+long dd_statDS1pivots; /* phase 1 pivots */
+long dd_statDS2pivots; /* phase 2 pivots */
+long dd_statACpivots; /* anticycling (cc) pivots */
+#ifdef GMPRATIONAL
+long dd_statBSpivots; /* basis status checking pivots */
+#endif
+dd_LPSolverType dd_choiceLPSolverDefault; /* Default LP solver Algorithm */
+dd_LPSolverType dd_choiceRedcheckAlgorithm; /* Redundancy Checking Algorithm */
+dd_boolean dd_choiceLexicoPivotQ; /* whether to use the lexicographic pivot */
+
+/* #include <profile.h> THINK C PROFILER */
+/* #include <console.h> THINK C PROFILER */
+
+void dd_DDInit(dd_ConePtr cone)
+{
+ cone->Error=dd_NoError;
+ cone->CompStatus=dd_InProgress;
+ cone->RayCount = 0;
+ cone->TotalRayCount = 0;
+ cone->FeasibleRayCount = 0;
+ cone->WeaklyFeasibleRayCount = 0;
+ cone->EdgeCount=0; /* active edge count */
+ cone->TotalEdgeCount=0; /* active edge count */
+ dd_SetInequalitySets(cone);
+ dd_ComputeRowOrderVector(cone);
+ cone->RecomputeRowOrder=dd_FALSE;
+}
+
+void dd_DDMain(dd_ConePtr cone)
+{
+ dd_rowrange hh, itemp, otemp;
+ dd_boolean locallog=dd_log; /* if dd_log=dd_FALSE, no log will be written. */
+
+ if (cone->d<=0){
+ cone->Iteration=cone->m;
+ cone->FeasibleRayCount=0;
+ cone->CompStatus=dd_AllFound;
+ goto _L99;
+ }
+ if (locallog) {
+ fprintf(stderr,"(Initially added rows ) = ");
+ set_fwrite(stderr,cone->InitialHalfspaces);
+ }
+ while (cone->Iteration <= cone->m) {
+ dd_SelectNextHalfspace(cone, cone->WeaklyAddedHalfspaces, &hh);
+ if (set_member(hh,cone->NonequalitySet)){ /* Skip the row hh */
+ if (dd_debug) {
+ fprintf(stderr,"*The row # %3ld should be inactive and thus skipped.\n", hh);
+ }
+ set_addelem(cone->WeaklyAddedHalfspaces, hh);
+ } else {
+ if (cone->PreOrderedRun)
+ dd_AddNewHalfspace2(cone, hh);
+ else{
+ dd_AddNewHalfspace1(cone, hh);
+ }
+ set_addelem(cone->AddedHalfspaces, hh);
+ set_addelem(cone->WeaklyAddedHalfspaces, hh);
+ }
+ if (!cone->PreOrderedRun){
+ for (itemp=1; cone->OrderVector[itemp]!=hh; itemp++);
+ otemp=cone->OrderVector[cone->Iteration];
+ cone->OrderVector[cone->Iteration]=hh;
+ /* store the dynamic ordering in ordervec */
+ cone->OrderVector[itemp]=otemp;
+ /* store the dynamic ordering in ordervec */
+ }
+ if (locallog){
+ fprintf(stderr,"(Iter, Row, #Total, #Curr, #Feas)= %5ld %5ld %9ld %6ld %6ld\n",
+ cone->Iteration, hh, cone->TotalRayCount, cone->RayCount,
+ cone->FeasibleRayCount);
+ }
+ if (cone->CompStatus==dd_AllFound||cone->CompStatus==dd_RegionEmpty) {
+ set_addelem(cone->AddedHalfspaces, hh);
+ goto _L99;
+ }
+ (cone->Iteration)++;
+ }
+ _L99:;
+ if (cone->d<=0 || cone->newcol[1]==0){ /* fixing the number of output */
+ cone->parent->n=cone->LinearityDim + cone->FeasibleRayCount -1;
+ cone->parent->ldim=cone->LinearityDim - 1;
+ } else {
+ cone->parent->n=cone->LinearityDim + cone->FeasibleRayCount;
+ cone->parent->ldim=cone->LinearityDim;
+ }
+}
+
+
+void dd_InitialDataSetup(dd_ConePtr cone)
+{
+ long j, r;
+ dd_rowset ZSet;
+ static dd_Arow Vector1,Vector2;
+ static dd_colrange last_d=0;
+
+ if (last_d < cone->d){
+ if (last_d>0) {
+ for (j=0; j<last_d; j++){
+ dd_clear(Vector1[j]);
+ dd_clear(Vector2[j]);
+ }
+ free(Vector1); free(Vector2);
+ }
+ Vector1=(mytype*)calloc(cone->d,sizeof(mytype));
+ Vector2=(mytype*)calloc(cone->d,sizeof(mytype));
+ for (j=0; j<cone->d; j++){
+ dd_init(Vector1[j]);
+ dd_init(Vector2[j]);
+ }
+ last_d=cone->d;
+ }
+
+ cone->RecomputeRowOrder=dd_FALSE;
+ cone->ArtificialRay = NULL;
+ cone->FirstRay = NULL;
+ cone->LastRay = NULL;
+ set_initialize(&ZSet,cone->m);
+ dd_AddArtificialRay(cone);
+ set_copy(cone->AddedHalfspaces, cone->InitialHalfspaces);
+ set_copy(cone->WeaklyAddedHalfspaces, cone->InitialHalfspaces);
+ dd_UpdateRowOrderVector(cone, cone->InitialHalfspaces);
+ for (r = 1; r <= cone->d; r++) {
+ for (j = 0; j < cone->d; j++){
+ dd_set(Vector1[j], cone->B[j][r-1]);
+ dd_neg(Vector2[j], cone->B[j][r-1]);
+ }
+ dd_Normalize(cone->d, Vector1);
+ dd_Normalize(cone->d, Vector2);
+ dd_ZeroIndexSet(cone->m, cone->d, cone->A, Vector1, ZSet);
+ if (set_subset(cone->EqualitySet, ZSet)){
+ if (dd_debug) {
+ fprintf(stderr,"add an initial ray with zero set:");
+ set_fwrite(stderr,ZSet);
+ }
+ dd_AddRay(cone, Vector1);
+ if (cone->InitialRayIndex[r]==0) {
+ dd_AddRay(cone, Vector2);
+ if (dd_debug) {
+ fprintf(stderr,"and add its negative also.\n");
+ }
+ }
+ }
+ }
+ dd_CreateInitialEdges(cone);
+ cone->Iteration = cone->d + 1;
+ if (cone->Iteration > cone->m) cone->CompStatus=dd_AllFound; /* 0.94b */
+ set_free(ZSet);
+}
+
+dd_boolean dd_CheckEmptiness(dd_PolyhedraPtr poly, dd_ErrorType *err)
+{
+ dd_rowset R, S;
+ dd_MatrixPtr M=NULL;
+ dd_boolean answer=dd_FALSE;
+
+ *err=dd_NoError;
+
+ if (poly->representation==dd_Inequality){
+ M=dd_CopyInequalities(poly);
+ set_initialize(&R, M->rowsize);
+ set_initialize(&S, M->rowsize);
+ if (!dd_ExistsRestrictedFace(M, R, S, err)){
+ poly->child->CompStatus=dd_AllFound;
+ poly->IsEmpty=dd_TRUE;
+ poly->n=0;
+ answer=dd_TRUE;
+ }
+ set_free(R);
+ set_free(S);
+ dd_FreeMatrix(M);
+ } else if (poly->representation==dd_Generator && poly->m<=0){
+ *err=dd_EmptyVrepresentation;
+ poly->IsEmpty=dd_TRUE;
+ poly->child->CompStatus=dd_AllFound;
+ answer=dd_TRUE;
+ poly->child->Error=*err;
+ }
+
+ return answer;
+}
+
+
+dd_boolean dd_DoubleDescription(dd_PolyhedraPtr poly, dd_ErrorType *err)
+{
+ dd_ConePtr cone=NULL;
+ dd_boolean found=dd_FALSE;
+
+ *err=dd_NoError;
+
+ if (poly!=NULL && (poly->child==NULL || poly->child->CompStatus!=dd_AllFound)){
+ cone=dd_ConeDataLoad(poly);
+ /* create a cone associated with poly by homogenization */
+ time(&cone->starttime);
+ dd_DDInit(cone);
+ if (poly->representation==dd_Generator && poly->m<=0){
+ *err=dd_EmptyVrepresentation;
+ cone->Error=*err;
+ goto _L99;
+ }
+ /* Check emptiness of the polyhedron */
+ dd_CheckEmptiness(poly,err);
+
+ if (cone->CompStatus!=dd_AllFound){
+ dd_FindInitialRays(cone, &found);
+ if (found) {
+ dd_InitialDataSetup(cone);
+ if (cone->CompStatus==dd_AllFound) goto _L99;
+ dd_DDMain(cone);
+ if (cone->FeasibleRayCount!=cone->RayCount) *err=dd_NumericallyInconsistent; /* cddlib-093d */
+ }
+ }
+ time(&cone->endtime);
+ }
+
+_L99: ;
+
+ return found;
+}
+
+dd_boolean dd_DoubleDescription2(dd_PolyhedraPtr poly, dd_RowOrderType horder, dd_ErrorType *err)
+{
+ dd_ConePtr cone=NULL;
+ dd_boolean found=dd_FALSE;
+
+ *err=dd_NoError;
+
+ if (poly!=NULL && (poly->child==NULL || poly->child->CompStatus!=dd_AllFound)){
+ cone=dd_ConeDataLoad(poly);
+ /* create a cone associated with poly by homogenization */
+ cone->HalfspaceOrder=horder; /* set the row order */
+ time(&cone->starttime);
+ dd_DDInit(cone);
+ if (poly->representation==dd_Generator && poly->m<=0){
+ *err=dd_EmptyVrepresentation;
+ cone->Error=*err;
+ goto _L99;
+ }
+ /* Check emptiness of the polyhedron */
+ dd_CheckEmptiness(poly,err);
+
+ if (cone->CompStatus!=dd_AllFound){
+ dd_FindInitialRays(cone, &found);
+ if (found) {
+ dd_InitialDataSetup(cone);
+ if (cone->CompStatus==dd_AllFound) goto _L99;
+ dd_DDMain(cone);
+ if (cone->FeasibleRayCount!=cone->RayCount) *err=dd_NumericallyInconsistent; /* cddlib-093d */
+ }
+ }
+ time(&cone->endtime);
+ }
+
+_L99: ;
+
+ return found;
+}
+
+dd_boolean dd_DDInputAppend(dd_PolyhedraPtr *poly, dd_MatrixPtr M,
+ dd_ErrorType *err)
+{
+ /* This is imcomplete. It simply solves the problem from scratch. */
+ dd_boolean found;
+ dd_ErrorType error;
+
+ if ((*poly)->child!=NULL) dd_FreeDDMemory(*poly);
+ dd_AppendMatrix2Poly(poly, M);
+ (*poly)->representation=dd_Inequality;
+ found=dd_DoubleDescription(*poly, &error);
+ *err=error;
+ return found;
+}
+
+dd_boolean dd_DDFile2File(char *ifile, char *ofile, dd_ErrorType *err)
+{
+ /* The representation conversion from an input file to an outfile. */
+ /* modified by D. Avis to allow stdin/stdout */
+ dd_boolean found=dd_TRUE;
+ FILE *reading=NULL,*writing=NULL;
+ dd_PolyhedraPtr poly;
+ dd_MatrixPtr M, A, G;
+
+ if (strcmp(ifile,"**stdin") == 0 )
+ reading = stdin;
+ else if ( ( reading = fopen(ifile, "r") )!= NULL) {
+ fprintf(stderr,"input file %s is open\n", ifile);
+ }
+ else{
+ fprintf(stderr,"The input file %s not found\n",ifile);
+ found=dd_FALSE;
+ *err=dd_IFileNotFound;
+ goto _L99;
+ }
+
+ if (found){
+ if (strcmp(ofile,"**stdout") == 0 )
+ writing = stdout;
+ else if ( (writing = fopen(ofile, "w") ) != NULL){
+ fprintf(stderr,"output file %s is open\n",ofile);
+ found=dd_TRUE;
+ } else {
+ fprintf(stderr,"The output file %s cannot be opened\n",ofile);
+ found=dd_FALSE;
+ *err=dd_OFileNotOpen;
+ goto _L99;
+ }
+ }
+
+ M=dd_PolyFile2Matrix(reading, err);
+ if (*err!=dd_NoError){
+ goto _L99;
+ } poly=dd_DDMatrix2Poly(M, err); /* compute the second representation */ dd_FreeMatrix(M);
+
+ if (*err==dd_NoError) {
+ dd_WriteRunningMode(writing, poly);
+ A=dd_CopyInequalities(poly);
+ G=dd_CopyGenerators(poly);
+
+ if (poly->representation==dd_Inequality) {
+ dd_WriteMatrix(writing,G);
+ } else {
+ dd_WriteMatrix(writing,A);
+ }
+
+ dd_FreePolyhedra(poly);
+ dd_FreeMatrix(A);
+ dd_FreeMatrix(G);
+ }
+
+_L99: ;
+ if (*err!=dd_NoError) dd_WriteErrorMessages(stderr,*err);
+ if (reading!=NULL) fclose(reading);
+ if (writing!=NULL) fclose(writing);
+ return found;
+}
+
+/* end of cddlib.c */
diff --git a/third_party/cddlib/lib-src/cddlp.c b/third_party/cddlib/lib-src/cddlp.c
new file mode 100644
index 0000000..46f98b5
--- /dev/null
+++ b/third_party/cddlib/lib-src/cddlp.c
@@ -0,0 +1,3779 @@
+/* cddlp.c: dual simplex method c-code
+ written by Komei Fukuda, fukuda@math.ethz.ch
+ Version 0.94h, April 30, 2015
+*/
+
+/* cddlp.c : C-Implementation of the dual simplex method for
+ solving an LP: max/min A_(m-1).x subject to x in P, where
+ P= {x : A_i.x >= 0, i=0,...,m-2, and x_0=1}, and
+ A_i is the i-th row of an m x n matrix A.
+ Please read COPYING (GNU General Public Licence) and
+ the manual cddlibman.tex for detail.
+*/
+
+#include "setoper.h" /* set operation library header (Ver. May 18, 2000 or later) */
+#include "cdd.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+
+#if defined GMPRATIONAL
+#include "cdd_f.h"
+#endif
+
+#define dd_CDDLPVERSION "Version 0.94b (August 25, 2005)"
+
+#define dd_FALSE 0
+#define dd_TRUE 1
+
+typedef set_type rowset; /* set_type defined in setoper.h */
+typedef set_type colset;
+
+void dd_CrissCrossSolve(dd_LPPtr lp,dd_ErrorType *);
+void dd_DualSimplexSolve(dd_LPPtr lp,dd_ErrorType *);
+void dd_CrissCrossMinimize(dd_LPPtr,dd_ErrorType *);
+void dd_CrissCrossMaximize(dd_LPPtr,dd_ErrorType *);
+void dd_DualSimplexMinimize(dd_LPPtr,dd_ErrorType *);
+void dd_DualSimplexMaximize(dd_LPPtr,dd_ErrorType *);
+void dd_FindLPBasis(dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,dd_rowindex,dd_rowset,
+ dd_colindex,dd_rowindex,dd_rowrange,dd_colrange,
+ dd_colrange *,int *,dd_LPStatusType *,long *);
+void dd_FindDualFeasibleBasis(dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,dd_rowindex,
+ dd_colindex,long *,dd_rowrange,dd_colrange,dd_boolean,
+ dd_colrange *,dd_ErrorType *,dd_LPStatusType *,long *, long maxpivots);
+
+
+#ifdef GMPRATIONAL
+void dd_BasisStatus(ddf_LPPtr lpf, dd_LPPtr lp, dd_boolean*);
+void dd_BasisStatusMinimize(dd_rowrange,dd_colrange, dd_Amatrix,dd_Bmatrix,dd_rowset,
+ dd_rowrange,dd_colrange,ddf_LPStatusType,mytype *,dd_Arow,dd_Arow,dd_rowset,ddf_colindex,
+ ddf_rowrange,ddf_colrange,dd_colrange *,long *, int *, int *);
+void dd_BasisStatusMaximize(dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,dd_rowset,
+ dd_rowrange,dd_colrange,ddf_LPStatusType,mytype *,dd_Arow,dd_Arow,dd_rowset,ddf_colindex,
+ ddf_rowrange,ddf_colrange,dd_colrange *,long *, int *, int *);
+#endif
+
+void dd_WriteBmatrix(FILE *f,dd_colrange d_size,dd_Bmatrix T);
+void dd_SetNumberType(char *line,dd_NumberType *number,dd_ErrorType *Error);
+void dd_ComputeRowOrderVector2(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,
+ dd_rowindex OV,dd_RowOrderType ho,unsigned int rseed);
+void dd_SelectPreorderedNext2(dd_rowrange m_size,dd_colrange d_size,
+ rowset excluded,dd_rowindex OV,dd_rowrange *hnext);
+void dd_SetSolutions(dd_rowrange,dd_colrange,
+ dd_Amatrix,dd_Bmatrix,dd_rowrange,dd_colrange,dd_LPStatusType,
+ mytype *,dd_Arow,dd_Arow,dd_rowset,dd_colindex,dd_rowrange,dd_colrange,dd_rowindex);
+
+void dd_WriteTableau(FILE *,dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,
+ dd_colindex,dd_rowindex);
+
+void dd_WriteSignTableau(FILE *,dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,
+ dd_colindex,dd_rowindex);
+
+
+dd_LPSolutionPtr dd_CopyLPSolution(dd_LPPtr lp)
+{
+ dd_LPSolutionPtr lps;
+ dd_colrange j;
+ long i;
+
+ lps=(dd_LPSolutionPtr) calloc(1,sizeof(dd_LPSolutionType));
+ for (i=1; i<=dd_filenamelen; i++) lps->filename[i-1]=lp->filename[i-1];
+ lps->objective=lp->objective;
+ lps->solver=lp->solver;
+ lps->m=lp->m;
+ lps->d=lp->d;
+ lps->numbtype=lp->numbtype;
+
+ lps->LPS=lp->LPS; /* the current solution status */
+ dd_init(lps->optvalue);
+ dd_set(lps->optvalue,lp->optvalue); /* optimal value */
+ dd_InitializeArow(lp->d+1,&(lps->sol));
+ dd_InitializeArow(lp->d+1,&(lps->dsol));
+ lps->nbindex=(long*) calloc((lp->d)+1,sizeof(long)); /* dual solution */
+ for (j=0; j<=lp->d; j++){
+ dd_set(lps->sol[j],lp->sol[j]);
+ dd_set(lps->dsol[j],lp->dsol[j]);
+ lps->nbindex[j]=lp->nbindex[j];
+ }
+ lps->pivots[0]=lp->pivots[0];
+ lps->pivots[1]=lp->pivots[1];
+ lps->pivots[2]=lp->pivots[2];
+ lps->pivots[3]=lp->pivots[3];
+ lps->pivots[4]=lp->pivots[4];
+ lps->total_pivots=lp->total_pivots;
+
+ return lps;
+}
+
+
+dd_LPPtr dd_CreateLPData(dd_LPObjectiveType obj,
+ dd_NumberType nt,dd_rowrange m,dd_colrange d)
+{
+ dd_LPType *lp;
+
+ lp=(dd_LPPtr) calloc(1,sizeof(dd_LPType));
+ lp->solver=dd_choiceLPSolverDefault; /* set the default lp solver */
+ lp->d=d;
+ lp->m=m;
+ lp->numbtype=nt;
+ lp->objrow=m;
+ lp->rhscol=1L;
+ lp->objective=dd_LPnone;
+ lp->LPS=dd_LPSundecided;
+ lp->eqnumber=0; /* the number of equalities */
+
+ lp->nbindex=(long*) calloc(d+1,sizeof(long));
+ lp->given_nbindex=(long*) calloc(d+1,sizeof(long));
+ set_initialize(&(lp->equalityset),m);
+ /* i must be in the set iff i-th row is equality . */
+
+ lp->redcheck_extensive=dd_FALSE; /* this is on only for RedundantExtensive */
+ lp->ired=0;
+ set_initialize(&(lp->redset_extra),m);
+ /* i is in the set if i-th row is newly recognized redundant (during the checking the row ired). */
+ set_initialize(&(lp->redset_accum),m);
+ /* i is in the set if i-th row is recognized redundant (during the checking the row ired). */
+ set_initialize(&(lp->posset_extra),m);
+ /* i is in the set if i-th row is recognized non-linearity (during the course of computation). */
+ lp->lexicopivot=dd_choiceLexicoPivotQ; /* dd_choice... is set in dd_set_global_constants() */
+
+ lp->m_alloc=lp->m+2;
+ lp->d_alloc=lp->d+2;
+ lp->objective=obj;
+ dd_InitializeBmatrix(lp->d_alloc,&(lp->B));
+ dd_InitializeAmatrix(lp->m_alloc,lp->d_alloc,&(lp->A));
+ dd_InitializeArow(lp->d_alloc,&(lp->sol));
+ dd_InitializeArow(lp->d_alloc,&(lp->dsol));
+ dd_init(lp->optvalue);
+ return lp;
+}
+
+
+dd_LPPtr dd_Matrix2LP(dd_MatrixPtr M, dd_ErrorType *err)
+{
+ dd_rowrange m, i, irev, linc;
+ dd_colrange d, j;
+ dd_LPType *lp;
+ dd_boolean localdebug=dd_FALSE;
+
+ *err=dd_NoError;
+ linc=set_card(M->linset);
+ m=M->rowsize+1+linc;
+ /* We represent each equation by two inequalities.
+ This is not the best way but makes the code simple. */
+ d=M->colsize;
+ if (localdebug) fprintf(stderr,"number of equalities = %ld\n", linc);
+
+ lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
+ lp->Homogeneous = dd_TRUE;
+ lp->eqnumber=linc; /* this records the number of equations */
+
+ irev=M->rowsize; /* the first row of the linc reversed inequalities. */
+ for (i = 1; i <= M->rowsize; i++) {
+ if (set_member(i, M->linset)) {
+ irev=irev+1;
+ set_addelem(lp->equalityset,i); /* it is equality. */
+ /* the reversed row irev is not in the equality set. */
+ for (j = 1; j <= M->colsize; j++) {
+ dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-1]);
+ } /*of j*/
+ if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
+ }
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-1]);
+ if (j==1 && i<M->rowsize && dd_Nonzero(M->matrix[i-1][j-1])) lp->Homogeneous = dd_FALSE;
+ } /*of j*/
+ } /*of i*/
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(lp->A[m-1][j-1],M->rowvec[j-1]); /* objective row */
+ } /*of j*/
+
+ return lp;
+}
+
+dd_LPPtr dd_Matrix2Feasibility(dd_MatrixPtr M, dd_ErrorType *err)
+/* Load a matrix to create an LP object for feasibility. It is
+ essentially the dd_Matrix2LP except that the objject function
+ is set to identically ZERO (maximization).
+
+*/
+ /* 094 */
+{
+ dd_rowrange m, linc;
+ dd_colrange j;
+ dd_LPType *lp;
+
+ *err=dd_NoError;
+ linc=set_card(M->linset);
+ m=M->rowsize+1+linc;
+ /* We represent each equation by two inequalities.
+ This is not the best way but makes the code simple. */
+
+ lp=dd_Matrix2LP(M, err);
+ lp->objective = dd_LPmax; /* since the objective is zero, this is not important */
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(lp->A[m-1][j-1],dd_purezero); /* set the objective to zero. */
+ } /*of j*/
+
+ return lp;
+}
+
+dd_LPPtr dd_Matrix2Feasibility2(dd_MatrixPtr M, dd_rowset R, dd_rowset S, dd_ErrorType *err)
+/* Load a matrix to create an LP object for feasibility with additional equality and
+ strict inequality constraints given by R and S. There are three types of inequalities:
+
+ b_r + A_r x = 0 Linearity (Equations) specified by M
+ b_s + A_s x > 0 Strict Inequalities specified by row index set S
+ b_t + A_t x >= 0 The rest inequalities in M
+
+ Where the linearity is considered here as the union of linearity specified by
+ M and the additional set R. When S contains any linearity rows, those
+ rows are considered linearity (equation). Thus S does not overlide linearity.
+ To find a feasible solution, we set an LP
+
+ maximize z
+ subject to
+ b_r + A_r x = 0 all r in Linearity
+ b_s + A_s x - z >= 0 for all s in S
+ b_t + A_t x >= 0 for all the rest rows t
+ 1 - z >= 0 to make the LP bounded.
+
+ Clearly, the feasibility problem has a solution iff the LP has a positive optimal value.
+ The variable z will be the last variable x_{d+1}.
+
+*/
+/* 094 */
+{
+ dd_rowrange m, i, irev, linc;
+ dd_colrange d, j;
+ dd_LPType *lp;
+ dd_rowset L;
+ dd_boolean localdebug=dd_FALSE;
+
+ *err=dd_NoError;
+ set_initialize(&L, M->rowsize);
+ set_uni(L,M->linset,R);
+ linc=set_card(L);
+ m=M->rowsize+1+linc+1;
+ /* We represent each equation by two inequalities.
+ This is not the best way but makes the code simple. */
+ d=M->colsize+1;
+ if (localdebug) fprintf(stderr,"number of equalities = %ld\n", linc);
+
+ lp=dd_CreateLPData(dd_LPmax, M->numbtype, m, d);
+ lp->Homogeneous = dd_TRUE;
+ lp->eqnumber=linc; /* this records the number of equations */
+
+ irev=M->rowsize; /* the first row of the linc reversed inequalities. */
+ for (i = 1; i <= M->rowsize; i++) {
+ if (set_member(i, L)) {
+ irev=irev+1;
+ set_addelem(lp->equalityset,i); /* it is equality. */
+ /* the reversed row irev is not in the equality set. */
+ for (j = 1; j <= M->colsize; j++) {
+ dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-1]);
+ } /*of j*/
+ if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
+ } else if (set_member(i, S)) {
+ dd_set(lp->A[i-1][M->colsize],dd_minusone);
+ }
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-1]);
+ if (j==1 && i<M->rowsize && dd_Nonzero(M->matrix[i-1][j-1])) lp->Homogeneous = dd_FALSE;
+ } /*of j*/
+ } /*of i*/
+ for (j = 1; j <= d; j++) {
+ dd_set(lp->A[m-2][j-1],dd_purezero); /* initialize */
+ } /*of j*/
+ dd_set(lp->A[m-2][0],dd_one); /* the bounding constraint. */
+ dd_set(lp->A[m-2][M->colsize],dd_minusone); /* the bounding constraint. */
+ for (j = 1; j <= d; j++) {
+ dd_set(lp->A[m-1][j-1],dd_purezero); /* initialize */
+ } /*of j*/
+ dd_set(lp->A[m-1][M->colsize],dd_one); /* maximize z */
+
+ set_free(L);
+ return lp;
+}
+
+
+
+void dd_FreeLPData(dd_LPPtr lp)
+{
+ if ((lp)!=NULL){
+ dd_clear(lp->optvalue);
+ dd_FreeArow(lp->d_alloc,lp->dsol);
+ dd_FreeArow(lp->d_alloc,lp->sol);
+ dd_FreeBmatrix(lp->d_alloc,lp->B);
+ dd_FreeAmatrix(lp->m_alloc,lp->d_alloc,lp->A);
+ set_free(lp->equalityset);
+ set_free(lp->redset_extra);
+ set_free(lp->redset_accum);
+ set_free(lp->posset_extra);
+ free(lp->nbindex);
+ free(lp->given_nbindex);
+ free(lp);
+ }
+}
+
+void dd_FreeLPSolution(dd_LPSolutionPtr lps)
+{
+ if (lps!=NULL){
+ free(lps->nbindex);
+ dd_FreeArow(lps->d+1,lps->dsol);
+ dd_FreeArow(lps->d+1,lps->sol);
+ dd_clear(lps->optvalue);
+
+ free(lps);
+ }
+}
+
+int dd_LPReverseRow(dd_LPPtr lp, dd_rowrange i)
+{
+ dd_colrange j;
+ int success=0;
+
+ if (i>=1 && i<=lp->m){
+ lp->LPS=dd_LPSundecided;
+ for (j=1; j<=lp->d; j++) {
+ dd_neg(lp->A[i-1][j-1],lp->A[i-1][j-1]);
+ /* negating the i-th constraint of A */
+ }
+ success=1;
+ }
+ return success;
+}
+
+int dd_LPReplaceRow(dd_LPPtr lp, dd_rowrange i, dd_Arow a)
+{
+ dd_colrange j;
+ int success=0;
+
+ if (i>=1 && i<=lp->m){
+ lp->LPS=dd_LPSundecided;
+ for (j=1; j<=lp->d; j++) {
+ dd_set(lp->A[i-1][j-1],a[j-1]);
+ /* replacing the i-th constraint by a */
+ }
+ success=1;
+ }
+ return success;
+}
+
+dd_Arow dd_LPCopyRow(dd_LPPtr lp, dd_rowrange i)
+{
+ dd_colrange j;
+ dd_Arow a;
+
+ if (i>=1 && i<=lp->m){
+ dd_InitializeArow(lp->d, &a);
+ for (j=1; j<=lp->d; j++) {
+ dd_set(a[j-1],lp->A[i-1][j-1]);
+ /* copying the i-th row to a */
+ }
+ }
+ return a;
+}
+
+
+void dd_SetNumberType(char *line,dd_NumberType *number,dd_ErrorType *Error)
+{
+ if (strncmp(line,"integer",7)==0) {
+ *number = dd_Integer;
+ return;
+ }
+ else if (strncmp(line,"rational",8)==0) {
+ *number = dd_Rational;
+ return;
+ }
+ else if (strncmp(line,"real",4)==0) {
+ *number = dd_Real;
+ return;
+ }
+ else {
+ *number=dd_Unknown;
+ *Error=dd_ImproperInputFormat;
+ }
+}
+
+
+void dd_WriteTableau(FILE *f,dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
+ dd_colindex nbindex,dd_rowindex bflag)
+/* Write the tableau A.T */
+{
+ dd_colrange j;
+ dd_rowrange i;
+ mytype x;
+
+ dd_init(x);
+ fprintf(f," %ld %ld real\n",m_size,d_size);
+ fprintf(f," |");
+ for (j=1; j<= d_size; j++) {
+ fprintf(f," %ld",nbindex[j]);
+ } fprintf(f,"\n");
+ for (j=1; j<= d_size+1; j++) {
+ fprintf(f," ----");
+ } fprintf(f,"\n");
+ for (i=1; i<= m_size; i++) {
+ fprintf(f," %3ld(%3ld) |",i,bflag[i]);
+ for (j=1; j<= d_size; j++) {
+ dd_TableauEntry(&x,m_size,d_size,A,T,i,j);
+ dd_WriteNumber(f,x);
+ }
+ fprintf(f,"\n");
+ }
+ fprintf(f,"end\n");
+ dd_clear(x);
+}
+
+void dd_WriteSignTableau(FILE *f,dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
+ dd_colindex nbindex,dd_rowindex bflag)
+/* Write the sign tableau A.T */
+{
+ dd_colrange j;
+ dd_rowrange i;
+ mytype x;
+
+ dd_init(x);
+ fprintf(f," %ld %ld real\n",m_size,d_size);
+ fprintf(f," |");
+ for (j=1; j<= d_size; j++) {
+ fprintf(f,"%3ld",nbindex[j]);
+ } fprintf(f,"\n ------- | ");
+ for (j=1; j<= d_size; j++) {
+ fprintf(f,"---");
+ } fprintf(f,"\n");
+ for (i=1; i<= m_size; i++) {
+ fprintf(f," %3ld(%3ld) |",i,bflag[i]);
+ for (j=1; j<= d_size; j++) {
+ dd_TableauEntry(&x,m_size,d_size,A,T,i,j);
+ if (dd_Positive(x)) fprintf(f, " +");
+ else if (dd_Negative(x)) fprintf(f, " -");
+ else fprintf(f, " 0");
+ }
+ fprintf(f,"\n");
+ }
+ fprintf(f,"end\n");
+ dd_clear(x);
+}
+
+void dd_WriteSignTableau2(FILE *f,dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
+ dd_colindex nbindex_ref, dd_colindex nbindex,dd_rowindex bflag)
+/* Write the sign tableau A.T and the reference basis */
+{
+ dd_colrange j;
+ dd_rowrange i;
+ mytype x;
+
+ dd_init(x);
+ fprintf(f," %ld %ld real\n",m_size,d_size);
+ fprintf(f," |");
+ for (j=1; j<= d_size; j++) fprintf(f,"%3ld",nbindex_ref[j]);
+ fprintf(f,"\n |");
+ for (j=1; j<= d_size; j++) {
+ fprintf(f,"%3ld",nbindex[j]);
+ } fprintf(f,"\n ------- | ");
+ for (j=1; j<= d_size; j++) {
+ fprintf(f,"---");
+ } fprintf(f,"\n");
+ for (i=1; i<= m_size; i++) {
+ fprintf(f," %3ld(%3ld) |",i,bflag[i]);
+ for (j=1; j<= d_size; j++) {
+ dd_TableauEntry(&x,m_size,d_size,A,T,i,j);
+ if (dd_Positive(x)) fprintf(f, " +");
+ else if (dd_Negative(x)) fprintf(f, " -");
+ else fprintf(f, " 0");
+ }
+ fprintf(f,"\n");
+ }
+ fprintf(f,"end\n");
+ dd_clear(x);
+}
+
+
+void dd_GetRedundancyInformation(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
+ dd_colindex nbindex,dd_rowindex bflag, dd_rowset redset)
+/* Some basic variables that are forced to be nonnegative will be output. These are
+ variables whose dictionary row components are all nonnegative. */
+{
+ dd_colrange j;
+ dd_rowrange i;
+ mytype x;
+ dd_boolean red=dd_FALSE,localdebug=dd_FALSE;
+ long numbred=0;
+
+ dd_init(x);
+ for (i=1; i<= m_size; i++) {
+ red=dd_TRUE;
+ for (j=1; j<= d_size; j++) {
+ dd_TableauEntry(&x,m_size,d_size,A,T,i,j);
+ if (red && dd_Negative(x)) red=dd_FALSE;
+ }
+ if (bflag[i]<0 && red) {
+ numbred+=1;
+ set_addelem(redset,i);
+ }
+ }
+ if (localdebug) fprintf(stderr,"\ndd_GetRedundancyInformation: %ld redundant rows over %ld\n",numbred, m_size);
+ dd_clear(x);
+}
+
+
+void dd_SelectDualSimplexPivot(dd_rowrange m_size,dd_colrange d_size,
+ int Phase1,dd_Amatrix A,dd_Bmatrix T,dd_rowindex OV,
+ dd_colindex nbindex_ref, dd_colindex nbindex,dd_rowindex bflag,
+ dd_rowrange objrow,dd_colrange rhscol, dd_boolean lexicopivot,
+ dd_rowrange *r,dd_colrange *s,int *selected,dd_LPStatusType *lps)
+{
+ /* selects a dual simplex pivot (*r,*s) if the current
+ basis is dual feasible and not optimal. If not dual feasible,
+ the procedure returns *selected=dd_FALSE and *lps=LPSundecided.
+ If Phase1=dd_TRUE, the RHS column will be considered as the negative
+ of the column of the largest variable (==m_size). For this case, it is assumed
+ that the caller used the auxiliary row (with variable m_size) to make the current
+ dictionary dual feasible before calling this routine so that the nonbasic
+ column for m_size corresponds to the auxiliary variable.
+ */
+ dd_boolean colselected=dd_FALSE,rowselected=dd_FALSE,
+ dualfeasible=dd_TRUE,localdebug=dd_FALSE;
+ dd_rowrange i,iref;
+ dd_colrange j,k;
+ mytype val,valn, minval,rat,minrat;
+ static dd_Arow rcost;
+ static dd_colrange d_last=0;
+ static dd_colset tieset,stieset; /* store the column indices with tie */
+
+ dd_init(val); dd_init(valn); dd_init(minval); dd_init(rat); dd_init(minrat);
+ if (d_last<d_size) {
+ if (d_last>0) {
+ for (j=1; j<=d_last; j++){ dd_clear(rcost[j-1]);}
+ free(rcost);
+ set_free(tieset);
+ set_free(stieset);
+ }
+ rcost=(mytype*) calloc(d_size,sizeof(mytype));
+ for (j=1; j<=d_size; j++){ dd_init(rcost[j-1]);}
+ set_initialize(&tieset,d_size);
+ set_initialize(&stieset,d_size);
+ d_last=d_size;
+ }
+
+ *r=0; *s=0;
+ *selected=dd_FALSE;
+ *lps=dd_LPSundecided;
+ for (j=1; j<=d_size; j++){
+ if (j!=rhscol){
+ dd_TableauEntry(&(rcost[j-1]),m_size,d_size,A,T,objrow,j);
+ if (dd_Positive(rcost[j-1])) {
+ dualfeasible=dd_FALSE;
+ }
+ }
+ }
+ if (dualfeasible){
+ while ((*lps==dd_LPSundecided) && (!rowselected) && (!colselected)) {
+ for (i=1; i<=m_size; i++) {
+ if (i!=objrow && bflag[i]==-1) { /* i is a basic variable */
+ if (Phase1){
+ dd_TableauEntry(&val, m_size,d_size,A,T,i,bflag[m_size]);
+ dd_neg(val,val);
+ /* for dual Phase I. The RHS (dual objective) is the negative of the auxiliary variable column. */
+ }
+ else {dd_TableauEntry(&val,m_size,d_size,A,T,i,rhscol);}
+ if (dd_Smaller(val,minval)) {
+ *r=i;
+ dd_set(minval,val);
+ }
+ }
+ }
+ if (dd_Nonnegative(minval)) {
+ *lps=dd_Optimal;
+ }
+ else {
+ rowselected=dd_TRUE;
+ set_emptyset(tieset);
+ for (j=1; j<=d_size; j++){
+ dd_TableauEntry(&val,m_size,d_size,A,T,*r,j);
+ if (j!=rhscol && dd_Positive(val)) {
+ dd_div(rat,rcost[j-1],val);
+ dd_neg(rat,rat);
+ if (*s==0 || dd_Smaller(rat,minrat)){
+ dd_set(minrat,rat);
+ *s=j;
+ set_emptyset(tieset);
+ set_addelem(tieset, j);
+ } else if (dd_Equal(rat,minrat)){
+ set_addelem(tieset,j);
+ }
+ }
+ }
+ if (*s>0) {
+ if (!lexicopivot || set_card(tieset)==1){
+ colselected=dd_TRUE; *selected=dd_TRUE;
+ } else { /* lexicographic rule with respect to the given reference cobasis. */
+ if (localdebug) {printf("Tie occurred at:"); set_write(tieset); printf("\n");
+ dd_WriteTableau(stderr,m_size,d_size,A,T,nbindex,bflag);
+ }
+ *s=0;
+ k=2; /* k runs through the column indices except RHS. */
+ do {
+ iref=nbindex_ref[k]; /* iref runs though the reference basic indices */
+ if (iref>0) {
+ j=bflag[iref];
+ if (j>0) {
+ if (set_member(j,tieset) && set_card(tieset)==1) {
+ *s=j;
+ colselected=dd_TRUE;
+ } else {
+ set_delelem(tieset, j);
+ /* iref is cobasic, and the corresponding col is not the pivot column except it is the last one. */
+ }
+ } else {
+ *s=0;
+ for (j=1; j<=d_size; j++){
+ if (set_member(j,tieset)) {
+ dd_TableauEntry(&val,m_size,d_size,A,T,*r,j);
+ dd_TableauEntry(&valn,m_size,d_size,A,T,iref,j);
+ if (j!=rhscol && dd_Positive(val)) {
+ dd_div(rat,valn,val);
+ if (*s==0 || dd_Smaller(rat,minrat)){
+ dd_set(minrat,rat);
+ *s=j;
+ set_emptyset(stieset);
+ set_addelem(stieset, j);
+ } else if (dd_Equal(rat,minrat)){
+ set_addelem(stieset,j);
+ }
+ }
+ }
+ }
+ set_copy(tieset,stieset);
+ if (set_card(tieset)==1) colselected=dd_TRUE;
+ }
+ }
+ k+=1;
+ } while (!colselected && k<=d_size);
+ *selected=dd_TRUE;
+ }
+ } else *lps=dd_Inconsistent;
+ }
+ } /* end of while */
+ }
+ if (localdebug) {
+ if (Phase1) fprintf(stderr,"Phase 1 : select %ld,%ld\n",*r,*s);
+ else fprintf(stderr,"Phase 2 : select %ld,%ld\n",*r,*s);
+ }
+ dd_clear(val); dd_clear(valn); dd_clear(minval); dd_clear(rat); dd_clear(minrat);
+}
+
+void dd_TableauEntry(mytype *x,dd_rowrange m_size, dd_colrange d_size, dd_Amatrix X, dd_Bmatrix T,
+ dd_rowrange r, dd_colrange s)
+/* Compute the (r,s) entry of X.T */
+{
+ dd_colrange j;
+ mytype temp;
+
+ dd_init(temp);
+ dd_set(*x,dd_purezero);
+ for (j=0; j< d_size; j++) {
+ dd_mul(temp,X[r-1][j], T[j][s-1]);
+ dd_add(*x, *x, temp);
+ }
+ dd_clear(temp);
+}
+
+void dd_SelectPivot2(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
+ dd_RowOrderType roworder,dd_rowindex ordervec, rowset equalityset,
+ dd_rowrange rowmax,rowset NopivotRow,
+ colset NopivotCol,dd_rowrange *r,dd_colrange *s,
+ dd_boolean *selected)
+/* Select a position (*r,*s) in the matrix A.T such that (A.T)[*r][*s] is nonzero
+ The choice is feasible, i.e., not on NopivotRow and NopivotCol, and
+ best with respect to the specified roworder
+ */
+{
+ int stop;
+ dd_rowrange i,rtemp;
+ rowset rowexcluded;
+ mytype Xtemp;
+ dd_boolean localdebug=dd_FALSE;
+
+ stop = dd_FALSE;
+ localdebug=dd_debug;
+ dd_init(Xtemp);
+ set_initialize(&rowexcluded,m_size);
+ set_copy(rowexcluded,NopivotRow);
+ for (i=rowmax+1;i<=m_size;i++) {
+ set_addelem(rowexcluded,i); /* cannot pivot on any row > rmax */
+ }
+ *selected = dd_FALSE;
+ do {
+ rtemp=0; i=1;
+ while (i<=m_size && rtemp==0) { /* equalityset vars have highest priorities */
+ if (set_member(i,equalityset) && !set_member(i,rowexcluded)){
+ if (localdebug) fprintf(stderr,"marked set %ld chosen as a candidate\n",i);
+ rtemp=i;
+ }
+ i++;
+ }
+ if (rtemp==0) dd_SelectPreorderedNext2(m_size,d_size,rowexcluded,ordervec,&rtemp);;
+ if (rtemp>=1) {
+ *r=rtemp;
+ *s=1;
+ while (*s <= d_size && !*selected) {
+ dd_TableauEntry(&Xtemp,m_size,d_size,A,T,*r,*s);
+ if (!set_member(*s,NopivotCol) && dd_Nonzero(Xtemp)) {
+ *selected = dd_TRUE;
+ stop = dd_TRUE;
+ } else {
+ (*s)++;
+ }
+ }
+ if (!*selected) {
+ set_addelem(rowexcluded,rtemp);
+ }
+ }
+ else {
+ *r = 0;
+ *s = 0;
+ stop = dd_TRUE;
+ }
+ } while (!stop);
+ set_free(rowexcluded); dd_clear(Xtemp);
+}
+
+void dd_GaussianColumnPivot(dd_rowrange m_size, dd_colrange d_size,
+ dd_Amatrix X, dd_Bmatrix T, dd_rowrange r, dd_colrange s)
+/* Update the Transformation matrix T with the pivot operation on (r,s)
+ This procedure performs a implicit pivot operation on the matrix X by
+ updating the dual basis inverse T.
+ */
+{
+ dd_colrange j, j1;
+ mytype Xtemp0, Xtemp1, Xtemp;
+ static dd_Arow Rtemp;
+ static dd_colrange last_d=0;
+
+ dd_init(Xtemp0); dd_init(Xtemp1); dd_init(Xtemp);
+ if (last_d!=d_size){
+ if (last_d>0) {
+ for (j=1; j<=last_d; j++) dd_clear(Rtemp[j-1]);
+ free(Rtemp);
+ }
+ Rtemp=(mytype*)calloc(d_size,sizeof(mytype));
+ for (j=1; j<=d_size; j++) dd_init(Rtemp[j-1]);
+ last_d=d_size;
+ }
+
+ for (j=1; j<=d_size; j++) {
+ dd_TableauEntry(&(Rtemp[j-1]), m_size, d_size, X, T, r,j);
+ }
+ dd_set(Xtemp0,Rtemp[s-1]);
+ for (j = 1; j <= d_size; j++) {
+ if (j != s) {
+ dd_div(Xtemp,Rtemp[j-1],Xtemp0);
+ dd_set(Xtemp1,dd_purezero);
+ for (j1 = 1; j1 <= d_size; j1++){
+ dd_mul(Xtemp1,Xtemp,T[j1-1][s - 1]);
+ dd_sub(T[j1-1][j-1],T[j1-1][j-1],Xtemp1);
+ /* T[j1-1][j-1] -= T[j1-1][s - 1] * Xtemp / Xtemp0; */
+ }
+ }
+ }
+ for (j = 1; j <= d_size; j++)
+ dd_div(T[j-1][s - 1],T[j-1][s - 1],Xtemp0);
+
+ dd_clear(Xtemp0); dd_clear(Xtemp1); dd_clear(Xtemp);
+}
+
+void dd_GaussianColumnPivot2(dd_rowrange m_size,dd_colrange d_size,
+ dd_Amatrix A,dd_Bmatrix T,dd_colindex nbindex,dd_rowindex bflag,dd_rowrange r,dd_colrange s)
+/* Update the Transformation matrix T with the pivot operation on (r,s)
+ This procedure performs a implicit pivot operation on the matrix A by
+ updating the dual basis inverse T.
+ */
+{
+ int localdebug=dd_FALSE;
+ long entering;
+
+ if (dd_debug) localdebug=dd_debug;
+ dd_GaussianColumnPivot(m_size,d_size,A,T,r,s);
+ entering=nbindex[s];
+ bflag[r]=s; /* the nonbasic variable r corresponds to column s */
+ nbindex[s]=r; /* the nonbasic variable on s column is r */
+
+ if (entering>0) bflag[entering]=-1;
+ /* original variables have negative index and should not affect the row index */
+
+ if (localdebug) {
+ fprintf(stderr,"dd_GaussianColumnPivot2\n");
+ fprintf(stderr," pivot: (leaving, entering) = (%ld, %ld)\n", r,entering);
+ fprintf(stderr, " bflag[%ld] is set to %ld\n", r, s);
+ }
+}
+
+
+void dd_ResetTableau(dd_rowrange m_size,dd_colrange d_size,dd_Bmatrix T,
+ dd_colindex nbindex,dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol)
+{
+ dd_rowrange i;
+ dd_colrange j;
+
+ /* Initialize T and nbindex */
+ for (j=1; j<=d_size; j++) nbindex[j]=-j;
+ nbindex[rhscol]=0;
+ /* RHS is already in nonbasis and is considered to be associated
+ with the zero-th row of input. */
+ dd_SetToIdentity(d_size,T);
+
+ /* Set the bflag according to nbindex */
+ for (i=1; i<=m_size; i++) bflag[i]=-1;
+ /* all basic variables have index -1 */
+ bflag[objrow]= 0;
+ /* bflag of the objective variable is 0,
+ different from other basic variables which have -1 */
+ for (j=1; j<=d_size; j++) if (nbindex[j]>0) bflag[nbindex[j]]=j;
+ /* bflag of a nonbasic variable is its column number */
+
+}
+
+void dd_SelectCrissCrossPivot(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
+ dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol,
+ dd_rowrange *r,dd_colrange *s,
+ int *selected,dd_LPStatusType *lps)
+{
+ int colselected=dd_FALSE,rowselected=dd_FALSE;
+ dd_rowrange i;
+ mytype val;
+
+ dd_init(val);
+ *selected=dd_FALSE;
+ *lps=dd_LPSundecided;
+ while ((*lps==dd_LPSundecided) && (!rowselected) && (!colselected)) {
+ for (i=1; i<=m_size; i++) {
+ if (i!=objrow && bflag[i]==-1) { /* i is a basic variable */
+ dd_TableauEntry(&val,m_size,d_size,A,T,i,rhscol);
+ if (dd_Negative(val)) {
+ rowselected=dd_TRUE;
+ *r=i;
+ break;
+ }
+ }
+ else if (bflag[i] >0) { /* i is nonbasic variable */
+ dd_TableauEntry(&val,m_size,d_size,A,T,objrow,bflag[i]);
+ if (dd_Positive(val)) {
+ colselected=dd_TRUE;
+ *s=bflag[i];
+ break;
+ }
+ }
+ }
+ if ((!rowselected) && (!colselected)) {
+ *lps=dd_Optimal;
+ return;
+ }
+ else if (rowselected) {
+ for (i=1; i<=m_size; i++) {
+ if (bflag[i] >0) { /* i is nonbasic variable */
+ dd_TableauEntry(&val,m_size,d_size,A,T,*r,bflag[i]);
+ if (dd_Positive(val)) {
+ colselected=dd_TRUE;
+ *s=bflag[i];
+ *selected=dd_TRUE;
+ break;
+ }
+ }
+ }
+ }
+ else if (colselected) {
+ for (i=1; i<=m_size; i++) {
+ if (i!=objrow && bflag[i]==-1) { /* i is a basic variable */
+ dd_TableauEntry(&val,m_size,d_size,A,T,i,*s);
+ if (dd_Negative(val)) {
+ rowselected=dd_TRUE;
+ *r=i;
+ *selected=dd_TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if (!rowselected) {
+ *lps=dd_DualInconsistent;
+ }
+ else if (!colselected) {
+ *lps=dd_Inconsistent;
+ }
+ }
+ dd_clear(val);
+}
+
+void dd_CrissCrossSolve(dd_LPPtr lp, dd_ErrorType *err)
+{
+ switch (lp->objective) {
+ case dd_LPmax:
+ dd_CrissCrossMaximize(lp,err);
+ break;
+
+ case dd_LPmin:
+ dd_CrissCrossMinimize(lp,err);
+ break;
+
+ case dd_LPnone: *err=dd_NoLPObjective; break;
+ }
+
+}
+
+void dd_DualSimplexSolve(dd_LPPtr lp, dd_ErrorType *err)
+{
+ switch (lp->objective) {
+ case dd_LPmax:
+ dd_DualSimplexMaximize(lp,err);
+ break;
+
+ case dd_LPmin:
+ dd_DualSimplexMinimize(lp,err);
+ break;
+
+ case dd_LPnone: *err=dd_NoLPObjective; break;
+ }
+}
+
+#ifdef GMPRATIONAL
+
+dd_LPStatusType LPSf2LPS(ddf_LPStatusType lpsf)
+{
+ dd_LPStatusType lps=dd_LPSundecided;
+
+ switch (lpsf) {
+ case ddf_LPSundecided: lps=dd_LPSundecided; break;
+ case ddf_Optimal: lps=dd_Optimal; break;
+ case ddf_Inconsistent: lps=dd_Inconsistent; break;
+ case ddf_DualInconsistent: lps=dd_DualInconsistent; break;
+ case ddf_StrucInconsistent: lps=dd_StrucInconsistent; break;
+ case ddf_StrucDualInconsistent: lps=dd_StrucDualInconsistent; break;
+ case ddf_Unbounded: lps=dd_Unbounded; break;
+ case ddf_DualUnbounded: lps=dd_DualUnbounded; break;
+ }
+ return lps;
+}
+
+
+void dd_BasisStatus(ddf_LPPtr lpf, dd_LPPtr lp, dd_boolean *LPScorrect)
+{
+ int i;
+ dd_colrange se, j;
+ dd_boolean basisfound;
+
+ switch (lp->objective) {
+ case dd_LPmax:
+ dd_BasisStatusMaximize(lp->m,lp->d,lp->A,lp->B,lp->equalityset,lp->objrow,lp->rhscol,
+ lpf->LPS,&(lp->optvalue),lp->sol,lp->dsol,lp->posset_extra,lpf->nbindex,lpf->re,lpf->se,&se,lp->pivots,
+ &basisfound, LPScorrect);
+ if (*LPScorrect) {
+ /* printf("BasisStatus Check: the current basis is verified with GMP\n"); */
+ lp->LPS=LPSf2LPS(lpf->LPS);
+ lp->re=lpf->re;
+ lp->se=se;
+ for (j=1; j<=lp->d; j++) lp->nbindex[j]=lpf->nbindex[j];
+ }
+ for (i=1; i<=5; i++) lp->pivots[i-1]+=lpf->pivots[i-1];
+ break;
+ case dd_LPmin:
+ dd_BasisStatusMinimize(lp->m,lp->d,lp->A,lp->B,lp->equalityset,lp->objrow,lp->rhscol,
+ lpf->LPS,&(lp->optvalue),lp->sol,lp->dsol,lp->posset_extra,lpf->nbindex,lpf->re,lpf->se,&se,lp->pivots,
+ &basisfound, LPScorrect);
+ if (*LPScorrect) {
+ /* printf("BasisStatus Check: the current basis is verified with GMP\n"); */
+ lp->LPS=LPSf2LPS(lpf->LPS);
+ lp->re=lpf->re;
+ lp->se=se;
+ for (j=1; j<=lp->d; j++) lp->nbindex[j]=lpf->nbindex[j];
+ }
+ for (i=1; i<=5; i++) lp->pivots[i-1]+=lpf->pivots[i-1];
+ break;
+ case dd_LPnone: break;
+ }
+}
+#endif
+
+void dd_FindLPBasis(dd_rowrange m_size,dd_colrange d_size,
+ dd_Amatrix A, dd_Bmatrix T,dd_rowindex OV,dd_rowset equalityset, dd_colindex nbindex,
+ dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol,
+ dd_colrange *cs,int *found,dd_LPStatusType *lps,long *pivot_no)
+{
+ /* Find a LP basis using Gaussian pivots.
+ If the problem has an LP basis,
+ the procedure returns *found=dd_TRUE,*lps=LPSundecided and an LP basis.
+ If the constraint matrix A (excluding the rhs and objective) is not
+ column independent, there are two cases. If the dependency gives a dual
+ inconsistency, this returns *found=dd_FALSE, *lps=dd_StrucDualInconsistent and
+ the evidence column *s. Otherwise, this returns *found=dd_TRUE,
+ *lps=LPSundecided and an LP basis of size less than d_size. Columns j
+ that do not belong to the basis (i.e. cannot be chosen as pivot because
+ they are all zero) will be indicated in nbindex vector: nbindex[j] will
+ be negative and set to -j.
+ */
+ int chosen,stop;
+ long pivots_p0=0,rank;
+ colset ColSelected;
+ rowset RowSelected;
+ mytype val;
+
+ dd_rowrange r;
+ dd_colrange j,s;
+
+ dd_init(val);
+ *found=dd_FALSE; *cs=0; rank=0;
+ stop=dd_FALSE;
+ *lps=dd_LPSundecided;
+
+ set_initialize(&RowSelected,m_size);
+ set_initialize(&ColSelected,d_size);
+ set_addelem(RowSelected,objrow);
+ set_addelem(ColSelected,rhscol);
+
+ stop=dd_FALSE;
+ do { /* Find a LP basis */
+ dd_SelectPivot2(m_size,d_size,A,T,dd_MinIndex,OV,equalityset,
+ m_size,RowSelected,ColSelected,&r,&s,&chosen);
+ if (chosen) {
+ set_addelem(RowSelected,r);
+ set_addelem(ColSelected,s);
+ dd_GaussianColumnPivot2(m_size,d_size,A,T,nbindex,bflag,r,s);
+ pivots_p0++;
+ rank++;
+ } else {
+ for (j=1;j<=d_size && *lps==dd_LPSundecided; j++) {
+ if (j!=rhscol && nbindex[j]<0){
+ dd_TableauEntry(&val,m_size,d_size,A,T,objrow,j);
+ if (dd_Nonzero(val)){ /* dual inconsistent */
+ *lps=dd_StrucDualInconsistent;
+ *cs=j;
+ /* dual inconsistent because the nonzero reduced cost */
+ }
+ }
+ }
+ if (*lps==dd_LPSundecided) *found=dd_TRUE;
+ /* dependent columns but not dual inconsistent. */
+ stop=dd_TRUE;
+ }
+ /* printf("d_size=%ld, rank=%ld\n",d_size,rank); */
+ if (rank==d_size-1) {
+ stop = dd_TRUE;
+ *found=dd_TRUE;
+ }
+ } while (!stop);
+
+ *pivot_no=pivots_p0;
+ dd_statBApivots+=pivots_p0;
+ set_free(RowSelected);
+ set_free(ColSelected);
+ dd_clear(val);
+}
+
+
+void dd_FindLPBasis2(dd_rowrange m_size,dd_colrange d_size,
+ dd_Amatrix A, dd_Bmatrix T,dd_rowindex OV,dd_rowset equalityset, dd_colindex nbindex,
+ dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol,
+ dd_colrange *cs,int *found,long *pivot_no)
+{
+ /* Similar to dd_FindLPBasis but it is much simpler. This tries to recompute T for
+ the specified basis given by nbindex. It will return *found=dd_FALSE if the specified
+ basis is not a basis.
+ */
+ int chosen,stop;
+ long pivots_p0=0,rank;
+ dd_colset ColSelected,DependentCols;
+ dd_rowset RowSelected, NopivotRow;
+ mytype val;
+ dd_boolean localdebug=dd_FALSE;
+
+ dd_rowrange r,negcount=0;
+ dd_colrange j,s;
+
+ dd_init(val);
+ *found=dd_FALSE; *cs=0; rank=0;
+
+ set_initialize(&RowSelected,m_size);
+ set_initialize(&DependentCols,d_size);
+ set_initialize(&ColSelected,d_size);
+ set_initialize(&NopivotRow,m_size);
+ set_addelem(RowSelected,objrow);
+ set_addelem(ColSelected,rhscol);
+ set_compl(NopivotRow, NopivotRow); /* set NopivotRow to be the groundset */
+
+ for (j=2; j<=d_size; j++)
+ if (nbindex[j]>0)
+ set_delelem(NopivotRow, nbindex[j]);
+ else if (nbindex[j]<0){
+ negcount++;
+ set_addelem(DependentCols, -nbindex[j]);
+ set_addelem(ColSelected, -nbindex[j]);
+ }
+
+ set_uni(RowSelected, RowSelected, NopivotRow); /* RowSelected is the set of rows not allowed to poviot on */
+
+ stop=dd_FALSE;
+ do { /* Find a LP basis */
+ dd_SelectPivot2(m_size,d_size,A,T,dd_MinIndex,OV,equalityset, m_size,RowSelected,ColSelected,&r,&s,&chosen);
+ if (chosen) {
+ set_addelem(RowSelected,r);
+ set_addelem(ColSelected,s);
+
+ dd_GaussianColumnPivot2(m_size,d_size,A,T,nbindex,bflag,r,s);
+ if (localdebug && m_size <=10){
+ dd_WriteBmatrix(stderr,d_size,T);
+ dd_WriteTableau(stderr,m_size,d_size,A,T,nbindex,bflag);
+ }
+ pivots_p0++;
+ rank++;
+ } else{
+ *found=dd_FALSE; /* cannot pivot on any of the spacified positions. */
+ stop=dd_TRUE;
+ }
+ if (rank==d_size-1-negcount) {
+ if (negcount){
+ /* Now it tries to pivot on rows that are supposed to be dependent. */
+ set_diff(ColSelected, ColSelected, DependentCols);
+ dd_SelectPivot2(m_size,d_size,A,T,dd_MinIndex,OV,equalityset, m_size,RowSelected,ColSelected,&r,&s,&chosen);
+ if (chosen) *found=dd_FALSE; /* not supposed to be independent */
+ else *found=dd_TRUE;
+ if (localdebug){
+ printf("Try to check the dependent cols:");
+ set_write(DependentCols);
+ if (chosen) printf("They are not dependent. Can still pivot on (%ld, %ld)\n",r, s);
+ else printf("They are indeed dependent.\n");
+ }
+ } else {
+ *found=dd_TRUE;
+ }
+ stop = dd_TRUE;
+ }
+ } while (!stop);
+
+ for (j=1; j<=d_size; j++) if (nbindex[j]>0) bflag[nbindex[j]]=j;
+ *pivot_no=pivots_p0;
+ set_free(RowSelected);
+ set_free(ColSelected);
+ set_free(NopivotRow);
+ set_free(DependentCols);
+ dd_clear(val);
+}
+
+void dd_FindDualFeasibleBasis(dd_rowrange m_size,dd_colrange d_size,
+ dd_Amatrix A,dd_Bmatrix T,dd_rowindex OV,
+ dd_colindex nbindex,dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol, dd_boolean lexicopivot,
+ dd_colrange *s,dd_ErrorType *err,dd_LPStatusType *lps,long *pivot_no, long maxpivots)
+{
+ /* Find a dual feasible basis using Phase I of Dual Simplex method.
+ If the problem is dual feasible,
+ the procedure returns *err=NoError, *lps=LPSundecided and a dual feasible
+ basis. If the problem is dual infeasible, this returns
+ *err=NoError, *lps=DualInconsistent and the evidence column *s.
+ Caution: matrix A must have at least one extra row: the row space A[m_size] must
+ have been allocated.
+ */
+ dd_boolean phase1,dualfeasible=dd_TRUE;
+ dd_boolean localdebug=dd_FALSE,chosen,stop;
+ dd_LPStatusType LPSphase1;
+ long pivots_p1=0;
+ dd_rowrange i,r_val;
+ dd_colrange j,l,ms=0,s_val,local_m_size;
+ mytype x,val,maxcost,axvalue,maxratio;
+ static dd_colrange d_last=0;
+ static dd_Arow rcost;
+ static dd_colindex nbindex_ref; /* to be used to store the initial feasible basis for lexico rule */
+
+ mytype scaling,svalue; /* random scaling mytype value */
+ mytype minval;
+
+ if (dd_debug) localdebug=dd_debug;
+ dd_init(x); dd_init(val); dd_init(scaling); dd_init(svalue); dd_init(axvalue);
+ dd_init(maxcost); dd_set(maxcost,dd_minuszero);
+ dd_init(maxratio); dd_set(maxratio,dd_minuszero);
+ if (d_last<d_size) {
+ if (d_last>0) {
+ for (j=1; j<=d_last; j++){ dd_clear(rcost[j-1]);}
+ free(rcost);
+ free(nbindex_ref);
+ }
+ rcost=(mytype*) calloc(d_size,sizeof(mytype));
+ nbindex_ref=(long*) calloc(d_size+1,sizeof(long));
+ for (j=1; j<=d_size; j++){ dd_init(rcost[j-1]);}
+ d_last=d_size;
+ }
+
+ *err=dd_NoError; *lps=dd_LPSundecided; *s=0;
+ local_m_size=m_size+1; /* increase m_size by 1 */
+
+ ms=0; /* ms will be the index of column which has the largest reduced cost */
+ for (j=1; j<=d_size; j++){
+ if (j!=rhscol){
+ dd_TableauEntry(&(rcost[j-1]),local_m_size,d_size,A,T,objrow,j);
+ if (dd_Larger(rcost[j-1],maxcost)) {dd_set(maxcost,rcost[j-1]); ms = j;}
+ }
+ }
+ if (dd_Positive(maxcost)) dualfeasible=dd_FALSE;
+
+ if (!dualfeasible){
+ for (j=1; j<=d_size; j++){
+ dd_set(A[local_m_size-1][j-1], dd_purezero);
+ for (l=1; l<=d_size; l++){
+ if (nbindex[l]>0) {
+ dd_set_si(scaling,l+10);
+ dd_mul(svalue,A[nbindex[l]-1][j-1],scaling);
+ dd_sub(A[local_m_size-1][j-1],A[local_m_size-1][j-1],svalue);
+ /* To make the auxiliary row (0,-11,-12,...,-d-10).
+ It is likely to be better than (0, -1, -1, ..., -1)
+ to avoid a degenerate LP. Version 093c. */
+ }
+ }
+ }
+
+ if (localdebug){
+ fprintf(stderr,"\ndd_FindDualFeasibleBasis: curruent basis is not dual feasible.\n");
+ fprintf(stderr,"because of the column %ld assoc. with var %ld dual cost =",
+ ms,nbindex[ms]);
+ dd_WriteNumber(stderr, maxcost);
+ if (localdebug) {
+ if (m_size <=100 && d_size <=30){
+ printf("\ndd_FindDualFeasibleBasis: the starting dictionary.\n");
+ dd_WriteTableau(stdout,m_size+1,d_size,A,T,nbindex,bflag);
+ }
+ }
+ }
+
+ ms=0;
+ /* Ratio Test: ms will be now the index of column which has the largest reduced cost
+ over the auxiliary row entry */
+ for (j=1; j<=d_size; j++){
+ if ((j!=rhscol) && dd_Positive(rcost[j-1])){
+ dd_TableauEntry(&axvalue,local_m_size,d_size,A,T,local_m_size,j);
+ if (dd_Nonnegative(axvalue)) {
+ *err=dd_NumericallyInconsistent;
+ /* This should not happen as they are set negative above. Quit the phase I.*/
+ if (localdebug) fprintf(stderr,"dd_FindDualFeasibleBasis: Numerical Inconsistency detected.\n");
+ goto _L99;
+ }
+ dd_neg(axvalue,axvalue);
+ dd_div(axvalue,rcost[j-1],axvalue); /* axvalue is the negative of ratio that is to be maximized. */
+ if (dd_Larger(axvalue,maxratio)) {
+ dd_set(maxratio,axvalue);
+ ms = j;
+ }
+ }
+ }
+
+ if (ms==0) {
+ *err=dd_NumericallyInconsistent; /* This should not happen. Quit the phase I.*/
+ if (localdebug) fprintf(stderr,"dd_FindDualFeasibleBasis: Numerical Inconsistency detected.\n");
+ goto _L99;
+ }
+
+ /* Pivot on (local_m_size,ms) so that the dual basic solution becomes feasible */
+ dd_GaussianColumnPivot2(local_m_size,d_size,A,T,nbindex,bflag,local_m_size,ms);
+ pivots_p1=pivots_p1+1;
+ if (localdebug) {
+ printf("\ndd_FindDualFeasibleBasis: Pivot on %ld %ld.\n",local_m_size,ms);
+ }
+
+ for (j=1; j<=d_size; j++) nbindex_ref[j]=nbindex[j];
+ /* set the reference basis to be the current feasible basis. */
+ if (localdebug){
+ fprintf(stderr, "Store the current feasible basis:");
+ for (j=1; j<=d_size; j++) fprintf(stderr, " %ld", nbindex_ref[j]);
+ fprintf(stderr, "\n");
+ if (m_size <=100 && d_size <=30)
+ dd_WriteSignTableau2(stdout,m_size+1,d_size,A,T,nbindex_ref,nbindex,bflag);
+ }
+
+ phase1=dd_TRUE; stop=dd_FALSE;
+ do { /* Dual Simplex Phase I */
+ chosen=dd_FALSE; LPSphase1=dd_LPSundecided;
+ if (pivots_p1>maxpivots) {
+ *err=dd_LPCycling;
+ fprintf(stderr,"max number %ld of pivots performed in Phase I. Switch to the anticycling phase.\n", maxpivots);
+ goto _L99; /* failure due to max no. of pivots performed */
+ }
+ dd_SelectDualSimplexPivot(local_m_size,d_size,phase1,A,T,OV,nbindex_ref,nbindex,bflag,
+ objrow,rhscol,lexicopivot,&r_val,&s_val,&chosen,&LPSphase1);
+ if (!chosen) {
+ /* The current dictionary is terminal. There are two cases:
+ dd_TableauEntry(local_m_size,d_size,A,T,objrow,ms) is negative or zero.
+ The first case implies dual infeasible,
+ and the latter implies dual feasible but local_m_size is still in nonbasis.
+ We must pivot in the auxiliary variable local_m_size.
+ */
+ dd_TableauEntry(&x,local_m_size,d_size,A,T,objrow,ms);
+ if (dd_Negative(x)){
+ *err=dd_NoError; *lps=dd_DualInconsistent; *s=ms;
+ }
+ if (localdebug) {
+ fprintf(stderr,"\ndd_FindDualFeasibleBasis: the auxiliary variable was forced to enter the basis (# pivots = %ld).\n",pivots_p1);
+ fprintf(stderr," -- objrow %ld, ms %ld entry: ",objrow,ms);
+ dd_WriteNumber(stderr, x); fprintf(stderr,"\n");
+ if (dd_Negative(x)){
+ fprintf(stderr,"->The basis is dual inconsistent. Terminate.\n");
+ } else {
+ fprintf(stderr,"->The basis is feasible. Go to phase II.\n");
+ }
+ }
+
+ dd_init(minval);
+ r_val=0;
+ for (i=1; i<=local_m_size; i++){
+ if (bflag[i]<0) {
+ /* i is basic and not the objective variable */
+ dd_TableauEntry(&val,local_m_size,d_size,A,T,i,ms); /* auxiliary column*/
+ if (dd_Smaller(val, minval)) {
+ r_val=i;
+ dd_set(minval,val);
+ }
+ }
+ }
+ dd_clear(minval);
+
+ if (r_val==0) {
+ *err=dd_NumericallyInconsistent; /* This should not happen. Quit the phase I.*/
+ if (localdebug) fprintf(stderr,"dd_FindDualFeasibleBasis: Numerical Inconsistency detected (r_val is 0).\n");
+ goto _L99;
+ }
+
+ dd_GaussianColumnPivot2(local_m_size,d_size,A,T,nbindex,bflag,r_val,ms);
+ pivots_p1=pivots_p1+1;
+ if (localdebug) {
+ printf("\ndd_FindDualFeasibleBasis: make the %ld-th pivot on %ld %ld to force the auxiliary variable to enter the basis.\n",pivots_p1,r_val,ms);
+ if (m_size <=100 && d_size <=30)
+ dd_WriteSignTableau2(stdout,m_size+1,d_size,A,T,nbindex_ref,nbindex,bflag);
+ }
+
+ stop=dd_TRUE;
+
+ } else {
+ dd_GaussianColumnPivot2(local_m_size,d_size,A,T,nbindex,bflag,r_val,s_val);
+ pivots_p1=pivots_p1+1;
+ if (localdebug) {
+ printf("\ndd_FindDualFeasibleBasis: make a %ld-th pivot on %ld %ld\n",pivots_p1,r_val,s_val);
+ if (m_size <=100 && d_size <=30)
+ dd_WriteSignTableau2(stdout,local_m_size,d_size,A,T,nbindex_ref,nbindex,bflag);
+ }
+
+
+ if (bflag[local_m_size]<0) {
+ stop=dd_TRUE;
+ if (localdebug)
+ fprintf(stderr,"\nDualSimplex Phase I: the auxiliary variable entered the basis (# pivots = %ld).\nGo to phase II\n",pivots_p1);
+ }
+ }
+ } while(!stop);
+ }
+_L99:
+ *pivot_no=pivots_p1;
+ dd_statDS1pivots+=pivots_p1;
+ dd_clear(x); dd_clear(val); dd_clear(maxcost); dd_clear(maxratio);
+ dd_clear(scaling); dd_clear(svalue); dd_clear(axvalue);
+}
+
+void dd_DualSimplexMinimize(dd_LPPtr lp,dd_ErrorType *err)
+{
+ dd_colrange j;
+
+ *err=dd_NoError;
+ for (j=1; j<=lp->d; j++)
+ dd_neg(lp->A[lp->objrow-1][j-1],lp->A[lp->objrow-1][j-1]);
+ dd_DualSimplexMaximize(lp,err);
+ dd_neg(lp->optvalue,lp->optvalue);
+ for (j=1; j<=lp->d; j++){
+ if (lp->LPS!=dd_Inconsistent) {
+ /* Inconsistent certificate stays valid for minimization, 0.94e */
+ dd_neg(lp->dsol[j-1],lp->dsol[j-1]);
+ }
+ dd_neg(lp->A[lp->objrow-1][j-1],lp->A[lp->objrow-1][j-1]);
+ }
+}
+
+void dd_DualSimplexMaximize(dd_LPPtr lp,dd_ErrorType *err)
+/*
+When LP is inconsistent then lp->re returns the evidence row.
+When LP is dual-inconsistent then lp->se returns the evidence column.
+*/
+{
+ int stop,chosen,phase1,found;
+ long pivots_ds=0,pivots_p0=0,pivots_p1=0,pivots_pc=0,maxpivots,maxpivfactor=20;
+ dd_boolean localdebug=dd_FALSE,localdebug1=dd_FALSE;
+
+#if !defined GMPRATIONAL
+ long maxccpivots,maxccpivfactor=100;
+ /* criss-cross should not cycle, but with floating-point arithmetics, it happens
+ (very rarely). Jorg Rambau reported such an LP, in August 2003. Thanks Jorg!
+ */
+#endif
+
+ dd_rowrange i,r;
+ dd_colrange j,s;
+ static dd_rowindex bflag;
+ static long mlast=0,nlast=0;
+ static dd_rowindex OrderVector; /* the permutation vector to store a preordered row indeces */
+ static dd_colindex nbindex_ref; /* to be used to store the initial feasible basis for lexico rule */
+
+ double redpercent=0,redpercent_prev=0,redgain=0;
+ unsigned int rseed=1;
+
+ /* *err=dd_NoError; */
+ if (dd_debug) localdebug=dd_debug;
+ set_emptyset(lp->redset_extra);
+ for (i=0; i<= 4; i++) lp->pivots[i]=0;
+ maxpivots=maxpivfactor*lp->d; /* maximum pivots to be performed before cc pivot is applied. */
+#if !defined GMPRATIONAL
+ maxccpivots=maxccpivfactor*lp->d; /* maximum pivots to be performed with emergency cc pivots. */
+#endif
+ if (mlast!=lp->m || nlast!=lp->d){
+ if (mlast>0) { /* called previously with different lp->m */
+ free(OrderVector);
+ free(bflag);
+ free(nbindex_ref);
+ }
+ OrderVector=(long *)calloc(lp->m+1,sizeof(*OrderVector));
+ bflag=(long *) calloc(lp->m+2,sizeof(*bflag)); /* one more element for an auxiliary variable */
+ nbindex_ref=(long*) calloc(lp->d+1,sizeof(long));
+ mlast=lp->m;nlast=lp->d;
+ }
+ /* Initializing control variables. */
+ dd_ComputeRowOrderVector2(lp->m,lp->d,lp->A,OrderVector,dd_MinIndex,rseed);
+
+ lp->re=0; lp->se=0;
+
+ dd_ResetTableau(lp->m,lp->d,lp->B,lp->nbindex,bflag,lp->objrow,lp->rhscol);
+
+ dd_FindLPBasis(lp->m,lp->d,lp->A,lp->B,OrderVector,lp->equalityset,lp->nbindex,bflag,
+ lp->objrow,lp->rhscol,&s,&found,&(lp->LPS),&pivots_p0);
+ lp->pivots[0]=pivots_p0;
+
+ if (!found){
+ lp->se=s;
+ goto _L99;
+ /* No LP basis is found, and thus Inconsistent.
+ Output the evidence column. */
+ }
+
+ dd_FindDualFeasibleBasis(lp->m,lp->d,lp->A,lp->B,OrderVector,lp->nbindex,bflag,
+ lp->objrow,lp->rhscol,lp->lexicopivot,&s, err,&(lp->LPS),&pivots_p1, maxpivots);
+ lp->pivots[1]=pivots_p1;
+
+ for (j=1; j<=lp->d; j++) nbindex_ref[j]=lp->nbindex[j];
+ /* set the reference basis to be the current feasible basis. */
+ if (localdebug){
+ fprintf(stderr, "dd_DualSimplexMaximize: Store the current feasible basis:");
+ for (j=1; j<=lp->d; j++) fprintf(stderr, " %ld", nbindex_ref[j]);
+ fprintf(stderr, "\n");
+ if (lp->m <=100 && lp->d <=30)
+ dd_WriteSignTableau2(stdout,lp->m+1,lp->d,lp->A,lp->B,nbindex_ref,lp->nbindex,bflag);
+ }
+
+ if (*err==dd_LPCycling || *err==dd_NumericallyInconsistent){
+ if (localdebug) fprintf(stderr, "Phase I failed and thus switch to the Criss-Cross method\n");
+ dd_CrissCrossMaximize(lp,err);
+ return;
+ }
+
+ if (lp->LPS==dd_DualInconsistent){
+ lp->se=s;
+ goto _L99;
+ /* No dual feasible basis is found, and thus DualInconsistent.
+ Output the evidence column. */
+ }
+
+ /* Dual Simplex Method */
+ stop=dd_FALSE;
+ do {
+ chosen=dd_FALSE; lp->LPS=dd_LPSundecided; phase1=dd_FALSE;
+ if (pivots_ds<maxpivots) {
+ dd_SelectDualSimplexPivot(lp->m,lp->d,phase1,lp->A,lp->B,OrderVector,nbindex_ref,lp->nbindex,bflag,
+ lp->objrow,lp->rhscol,lp->lexicopivot,&r,&s,&chosen,&(lp->LPS));
+ }
+ if (chosen) {
+ pivots_ds=pivots_ds+1;
+ if (lp->redcheck_extensive) {
+ dd_GetRedundancyInformation(lp->m,lp->d,lp->A,lp->B,lp->nbindex, bflag, lp->redset_extra);
+ set_uni(lp->redset_accum, lp->redset_accum,lp->redset_extra);
+ redpercent=100*(double)set_card(lp->redset_extra)/(double)lp->m;
+ redgain=redpercent-redpercent_prev;
+ redpercent_prev=redpercent;
+ if (localdebug1){
+ fprintf(stderr,"\ndd_DualSimplexMaximize: Phase II pivot %ld on (%ld, %ld).\n",pivots_ds,r,s);
+ fprintf(stderr," redundancy %f percent: redset size = %ld\n",redpercent,set_card(lp->redset_extra));
+ }
+ }
+ }
+ if (!chosen && lp->LPS==dd_LPSundecided) {
+ if (localdebug1){
+ fprintf(stderr,"Warning: an emergency CC pivot in Phase II is performed\n");
+ /* In principle this should not be executed because we already have dual feasibility
+ attained and dual simplex pivot should have been chosen. This might occur
+ under floating point computation, or the case of cycling.
+ */
+ if (localdebug && lp->m <=100 && lp->d <=30){
+ fprintf(stderr,"\ndd_DualSimplexMaximize: The current dictionary.\n");
+ dd_WriteSignTableau2(stdout,lp->m,lp->d,lp->A,lp->B,nbindex_ref,lp->nbindex,bflag);
+ }
+ }
+
+#if !defined GMPRATIONAL
+ if (pivots_pc>maxccpivots) {
+ *err=dd_LPCycling;
+ stop=dd_TRUE;
+ goto _L99;
+ }
+#endif
+
+ dd_SelectCrissCrossPivot(lp->m,lp->d,lp->A,lp->B,bflag,
+ lp->objrow,lp->rhscol,&r,&s,&chosen,&(lp->LPS));
+ if (chosen) pivots_pc=pivots_pc+1;
+ }
+ if (chosen) {
+ dd_GaussianColumnPivot2(lp->m,lp->d,lp->A,lp->B,lp->nbindex,bflag,r,s);
+ if (localdebug && lp->m <=100 && lp->d <=30){
+ fprintf(stderr,"\ndd_DualSimplexMaximize: The current dictionary.\n");
+ dd_WriteSignTableau2(stdout,lp->m,lp->d,lp->A,lp->B,nbindex_ref,lp->nbindex,bflag);
+ }
+ } else {
+ switch (lp->LPS){
+ case dd_Inconsistent: lp->re=r;
+ case dd_DualInconsistent: lp->se=s;
+
+ default: break;
+ }
+ stop=dd_TRUE;
+ }
+ } while(!stop);
+_L99:
+ lp->pivots[2]=pivots_ds;
+ lp->pivots[3]=pivots_pc;
+ dd_statDS2pivots+=pivots_ds;
+ dd_statACpivots+=pivots_pc;
+
+ dd_SetSolutions(lp->m,lp->d,lp->A,lp->B,lp->objrow,lp->rhscol,lp->LPS,&(lp->optvalue),lp->sol,lp->dsol,lp->posset_extra,lp->nbindex,lp->re,lp->se,bflag);
+
+}
+
+
+
+void dd_CrissCrossMinimize(dd_LPPtr lp,dd_ErrorType *err)
+{
+ dd_colrange j;
+
+ *err=dd_NoError;
+ for (j=1; j<=lp->d; j++)
+ dd_neg(lp->A[lp->objrow-1][j-1],lp->A[lp->objrow-1][j-1]);
+ dd_CrissCrossMaximize(lp,err);
+ dd_neg(lp->optvalue,lp->optvalue);
+ for (j=1; j<=lp->d; j++){
+ if (lp->LPS!=dd_Inconsistent) {
+ /* Inconsistent certificate stays valid for minimization, 0.94e */
+ dd_neg(lp->dsol[j-1],lp->dsol[j-1]);
+ }
+ dd_neg(lp->A[lp->objrow-1][j-1],lp->A[lp->objrow-1][j-1]);
+ }
+}
+
+void dd_CrissCrossMaximize(dd_LPPtr lp,dd_ErrorType *err)
+/*
+When LP is inconsistent then lp->re returns the evidence row.
+When LP is dual-inconsistent then lp->se returns the evidence column.
+*/
+{
+ int stop,chosen,found;
+ long pivots0,pivots1;
+#if !defined GMPRATIONAL
+ long maxpivots,maxpivfactor=1000;
+ /* criss-cross should not cycle, but with floating-point arithmetics, it happens
+ (very rarely). Jorg Rambau reported such an LP, in August 2003. Thanks Jorg!
+ */
+#endif
+
+ dd_rowrange i,r;
+ dd_colrange s;
+ static dd_rowindex bflag;
+ static long mlast=0;
+ static dd_rowindex OrderVector; /* the permutation vector to store a preordered row indeces */
+ unsigned int rseed=1;
+ dd_colindex nbtemp;
+
+ *err=dd_NoError;
+#if !defined GMPRATIONAL
+ maxpivots=maxpivfactor*lp->d; /* maximum pivots to be performed when floating-point arithmetics is used. */
+#endif
+ nbtemp=(long *) calloc(lp->d+1,sizeof(long));
+ for (i=0; i<= 4; i++) lp->pivots[i]=0;
+ if (bflag==NULL || mlast!=lp->m){
+ if (mlast!=lp->m && mlast>0) {
+ free(bflag); /* called previously with different lp->m */
+ free(OrderVector);
+ }
+ bflag=(long *) calloc(lp->m+1,sizeof(long));
+ OrderVector=(long *)calloc(lp->m+1,sizeof(long));
+ /* initialize only for the first time or when a larger space is needed */
+
+ mlast=lp->m;
+ }
+ /* Initializing control variables. */
+ dd_ComputeRowOrderVector2(lp->m,lp->d,lp->A,OrderVector,dd_MinIndex,rseed);
+
+ lp->re=0; lp->se=0; pivots1=0;
+
+ dd_ResetTableau(lp->m,lp->d,lp->B,lp->nbindex,bflag,lp->objrow,lp->rhscol);
+
+ dd_FindLPBasis(lp->m,lp->d,lp->A,lp->B,OrderVector,lp->equalityset,
+ lp->nbindex,bflag,lp->objrow,lp->rhscol,&s,&found,&(lp->LPS),&pivots0);
+ lp->pivots[0]+=pivots0;
+
+ if (!found){
+ lp->se=s;
+ goto _L99;
+ /* No LP basis is found, and thus Inconsistent.
+ Output the evidence column. */
+ }
+
+ stop=dd_FALSE;
+ do { /* Criss-Cross Method */
+#if !defined GMPRATIONAL
+ if (pivots1>maxpivots) {
+ *err=dd_LPCycling;
+ fprintf(stderr,"max number %ld of pivots performed by the criss-cross method. Most likely due to the floating-point arithmetics error.\n", maxpivots);
+ goto _L99; /* failure due to max no. of pivots performed */
+ }
+#endif
+
+ dd_SelectCrissCrossPivot(lp->m,lp->d,lp->A,lp->B,bflag,
+ lp->objrow,lp->rhscol,&r,&s,&chosen,&(lp->LPS));
+ if (chosen) {
+ dd_GaussianColumnPivot2(lp->m,lp->d,lp->A,lp->B,lp->nbindex,bflag,r,s);
+ pivots1++;
+ } else {
+ switch (lp->LPS){
+ case dd_Inconsistent: lp->re=r;
+ case dd_DualInconsistent: lp->se=s;
+
+ default: break;
+ }
+ stop=dd_TRUE;
+ }
+ } while(!stop);
+
+_L99:
+ lp->pivots[1]+=pivots1;
+ dd_statCCpivots+=pivots1;
+ dd_SetSolutions(lp->m,lp->d,lp->A,lp->B,
+ lp->objrow,lp->rhscol,lp->LPS,&(lp->optvalue),lp->sol,lp->dsol,lp->posset_extra,lp->nbindex,lp->re,lp->se,bflag);
+ free(nbtemp);
+}
+
+void dd_SetSolutions(dd_rowrange m_size,dd_colrange d_size,
+ dd_Amatrix A,dd_Bmatrix T,
+ dd_rowrange objrow,dd_colrange rhscol,dd_LPStatusType LPS,
+ mytype *optvalue,dd_Arow sol,dd_Arow dsol,dd_rowset posset, dd_colindex nbindex,
+ dd_rowrange re,dd_colrange se,dd_rowindex bflag)
+/*
+Assign the solution vectors to sol,dsol,*optvalue after solving
+the LP.
+*/
+{
+ dd_rowrange i;
+ dd_colrange j;
+ mytype x,sw;
+ int localdebug=dd_FALSE;
+
+ dd_init(x); dd_init(sw);
+ if (localdebug) fprintf(stderr,"SetSolutions:\n");
+ switch (LPS){
+ case dd_Optimal:
+ for (j=1;j<=d_size; j++) {
+ dd_set(sol[j-1],T[j-1][rhscol-1]);
+ dd_TableauEntry(&x,m_size,d_size,A,T,objrow,j);
+ dd_neg(dsol[j-1],x);
+ dd_TableauEntry(optvalue,m_size,d_size,A,T,objrow,rhscol);
+ if (localdebug) {fprintf(stderr,"dsol[%ld]= ",nbindex[j]); dd_WriteNumber(stderr, dsol[j-1]); }
+ }
+ for (i=1; i<=m_size; i++) {
+ if (bflag[i]==-1) { /* i is a basic variable */
+ dd_TableauEntry(&x,m_size,d_size,A,T,i,rhscol);
+ if (dd_Positive(x)) set_addelem(posset, i);
+ }
+ }
+
+ break;
+ case dd_Inconsistent:
+ if (localdebug) fprintf(stderr,"SetSolutions: LP is inconsistent.\n");
+ for (j=1;j<=d_size; j++) {
+ dd_set(sol[j-1],T[j-1][rhscol-1]);
+ dd_TableauEntry(&x,m_size,d_size,A,T,re,j);
+ dd_neg(dsol[j-1],x);
+ if (localdebug) {fprintf(stderr,"dsol[%ld]=",nbindex[j]);
+ dd_WriteNumber(stderr,dsol[j-1]);
+ fprintf(stderr,"\n");
+ }
+ }
+ break;
+
+ case dd_DualInconsistent:
+ if (localdebug) printf( "SetSolutions: LP is dual inconsistent.\n");
+ for (j=1;j<=d_size; j++) {
+ dd_set(sol[j-1],T[j-1][se-1]);
+ dd_TableauEntry(&x,m_size,d_size,A,T,objrow,j);
+ dd_neg(dsol[j-1],x);
+ if (localdebug) {fprintf(stderr,"dsol[%ld]=",nbindex[j]);
+ dd_WriteNumber(stderr,dsol[j-1]);
+ fprintf(stderr,"\n");
+ }
+ }
+ break;
+
+ case dd_StrucDualInconsistent:
+ dd_TableauEntry(&x,m_size,d_size,A,T,objrow,se);
+ if (dd_Positive(x)) dd_set(sw,dd_one);
+ else dd_neg(sw,dd_one);
+ for (j=1;j<=d_size; j++) {
+ dd_mul(sol[j-1],sw,T[j-1][se-1]);
+ dd_TableauEntry(&x,m_size,d_size,A,T,objrow,j);
+ dd_neg(dsol[j-1],x);
+ if (localdebug) {fprintf(stderr,"dsol[%ld]= ",nbindex[j]);dd_WriteNumber(stderr,dsol[j-1]);}
+ }
+ if (localdebug) fprintf(stderr,"SetSolutions: LP is dual inconsistent.\n");
+ break;
+
+ default:break;
+ }
+ dd_clear(x); dd_clear(sw);
+}
+
+
+void dd_RandomPermutation2(dd_rowindex OV,long t,unsigned int seed)
+{
+ long k,j,ovj;
+ double u,xk,r,rand_max=(double) RAND_MAX;
+ int localdebug=dd_FALSE;
+
+ srand(seed);
+ for (j=t; j>1 ; j--) {
+ r=rand();
+ u=r/rand_max;
+ xk=(double)(j*u +1);
+ k=(long)xk;
+ if (localdebug) fprintf(stderr,"u=%g, k=%ld, r=%g, randmax= %g\n",u,k,r,rand_max);
+ ovj=OV[j];
+ OV[j]=OV[k];
+ OV[k]=ovj;
+ if (localdebug) fprintf(stderr,"row %ld is exchanged with %ld\n",j,k);
+ }
+}
+
+void dd_ComputeRowOrderVector2(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,
+ dd_rowindex OV,dd_RowOrderType ho,unsigned int rseed)
+{
+ long i,itemp;
+
+ OV[0]=0;
+ switch (ho){
+ case dd_MaxIndex:
+ for(i=1; i<=m_size; i++) OV[i]=m_size-i+1;
+ break;
+
+ case dd_LexMin:
+ for(i=1; i<=m_size; i++) OV[i]=i;
+ dd_QuickSort(OV,1,m_size,A,d_size);
+ break;
+
+ case dd_LexMax:
+ for(i=1; i<=m_size; i++) OV[i]=i;
+ dd_QuickSort(OV,1,m_size,A,d_size);
+ for(i=1; i<=m_size/2;i++){ /* just reverse the order */
+ itemp=OV[i];
+ OV[i]=OV[m_size-i+1];
+ OV[m_size-i+1]=itemp;
+ }
+ break;
+
+ case dd_RandomRow:
+ for(i=1; i<=m_size; i++) OV[i]=i;
+ if (rseed<=0) rseed=1;
+ dd_RandomPermutation2(OV,m_size,rseed);
+ break;
+
+ case dd_MinIndex:
+ for(i=1; i<=m_size; i++) OV[i]=i;
+ break;
+
+ default:
+ for(i=1; i<=m_size; i++) OV[i]=i;
+ break;
+ }
+}
+
+void dd_SelectPreorderedNext2(dd_rowrange m_size,dd_colrange d_size,
+ rowset excluded,dd_rowindex OV,dd_rowrange *hnext)
+{
+ dd_rowrange i,k;
+
+ *hnext=0;
+ for (i=1; i<=m_size && *hnext==0; i++){
+ k=OV[i];
+ if (!set_member(k,excluded)) *hnext=k ;
+ }
+}
+
+#ifdef GMPRATIONAL
+
+ddf_LPObjectiveType Obj2Obj(dd_LPObjectiveType obj)
+{
+ ddf_LPObjectiveType objf=ddf_LPnone;
+
+ switch (obj) {
+ case dd_LPnone: objf=ddf_LPnone; break;
+ case dd_LPmax: objf=ddf_LPmax; break;
+ case dd_LPmin: objf=ddf_LPmin; break;
+ }
+ return objf;
+}
+
+ddf_LPPtr dd_LPgmp2LPf(dd_LPPtr lp)
+{
+ dd_rowrange i;
+ dd_colrange j;
+ ddf_LPType *lpf;
+ double val;
+ dd_boolean localdebug=dd_FALSE;
+
+ if (localdebug) fprintf(stderr,"Converting a GMP-LP to a float-LP.\n");
+
+ lpf=ddf_CreateLPData(Obj2Obj(lp->objective), ddf_Real, lp->m, lp->d);
+ lpf->Homogeneous = lp->Homogeneous;
+ lpf->eqnumber=lp->eqnumber; /* this records the number of equations */
+
+ for (i = 1; i <= lp->m; i++) {
+ if (set_member(i, lp->equalityset)) set_addelem(lpf->equalityset,i);
+ /* it is equality. Its reversed row will not be in this set */
+ for (j = 1; j <= lp->d; j++) {
+ val=mpq_get_d(lp->A[i-1][j-1]);
+ ddf_set_d(lpf->A[i-1][j-1],val);
+ } /*of j*/
+ } /*of i*/
+
+ return lpf;
+}
+
+
+#endif
+
+
+dd_boolean dd_LPSolve(dd_LPPtr lp,dd_LPSolverType solver,dd_ErrorType *err)
+/*
+The current version of dd_LPSolve that solves an LP with floating-arithmetics first
+and then with the specified arithimetics if it is GMP.
+
+When LP is inconsistent then *re returns the evidence row.
+When LP is dual-inconsistent then *se returns the evidence column.
+*/
+{
+ int i;
+ dd_boolean found=dd_FALSE;
+#ifdef GMPRATIONAL
+ ddf_LPPtr lpf;
+ ddf_ErrorType errf;
+ dd_boolean LPScorrect=dd_FALSE;
+ dd_boolean localdebug=dd_FALSE;
+ if (dd_debug) localdebug=dd_debug;
+#endif
+
+ *err=dd_NoError;
+ lp->solver=solver;
+
+ time(&lp->starttime);
+
+#ifndef GMPRATIONAL
+ switch (lp->solver) {
+ case dd_CrissCross:
+ dd_CrissCrossSolve(lp,err);
+ break;
+ case dd_DualSimplex:
+ dd_DualSimplexSolve(lp,err);
+ break;
+ }
+#else
+ lpf=dd_LPgmp2LPf(lp);
+ switch (lp->solver) {
+ case dd_CrissCross:
+ ddf_CrissCrossSolve(lpf,&errf); /* First, run with double float. */
+ if (errf==ddf_NoError){ /* 094a: fix for a bug reported by Dima Pasechnik */
+ dd_BasisStatus(lpf,lp, &LPScorrect); /* Check the basis. */
+ } else {LPScorrect=dd_FALSE;}
+ if (!LPScorrect) {
+ if (localdebug) printf("BasisStatus: the current basis is NOT verified with GMP. Rerun with GMP.\n");
+ dd_CrissCrossSolve(lp,err); /* Rerun with GMP if fails. */
+ } else {
+ if (localdebug) printf("BasisStatus: the current basis is verified with GMP. The LP Solved.\n");
+ }
+ break;
+ case dd_DualSimplex:
+ ddf_DualSimplexSolve(lpf,&errf); /* First, run with double float. */
+ if (errf==ddf_NoError){ /* 094a: fix for a bug reported by Dima Pasechnik */
+ dd_BasisStatus(lpf,lp, &LPScorrect); /* Check the basis. */
+ } else {LPScorrect=dd_FALSE;}
+ if (!LPScorrect){
+ if (localdebug) printf("BasisStatus: the current basis is NOT verified with GMP. Rerun with GMP.\n");
+ dd_DualSimplexSolve(lp,err); /* Rerun with GMP if fails. */
+ if (localdebug){
+ printf("*total number pivots = %ld (ph0 = %ld, ph1 = %ld, ph2 = %ld, ph3 = %ld, ph4 = %ld)\n",
+ lp->total_pivots,lp->pivots[0],lp->pivots[1],lp->pivots[2],lp->pivots[3],lp->pivots[4]);
+ ddf_WriteLPResult(stdout, lpf, errf);
+ dd_WriteLP(stdout, lp);
+ }
+ } else {
+ if (localdebug) printf("BasisStatus: the current basis is verified with GMP. The LP Solved.\n");
+ }
+ break;
+ }
+ ddf_FreeLPData(lpf);
+#endif
+
+ time(&lp->endtime);
+ lp->total_pivots=0;
+ for (i=0; i<=4; i++) lp->total_pivots+=lp->pivots[i];
+ if (*err==dd_NoError) found=dd_TRUE;
+ return found;
+}
+
+
+dd_boolean dd_LPSolve0(dd_LPPtr lp,dd_LPSolverType solver,dd_ErrorType *err)
+/*
+The original version of dd_LPSolve that solves an LP with specified arithimetics.
+
+When LP is inconsistent then *re returns the evidence row.
+When LP is dual-inconsistent then *se returns the evidence column.
+*/
+{
+ int i;
+ dd_boolean found=dd_FALSE;
+
+ *err=dd_NoError;
+ lp->solver=solver;
+ time(&lp->starttime);
+
+ switch (lp->solver) {
+ case dd_CrissCross:
+ dd_CrissCrossSolve(lp,err);
+ break;
+ case dd_DualSimplex:
+ dd_DualSimplexSolve(lp,err);
+ break;
+ }
+
+ time(&lp->endtime);
+ lp->total_pivots=0;
+ for (i=0; i<=4; i++) lp->total_pivots+=lp->pivots[i];
+ if (*err==dd_NoError) found=dd_TRUE;
+ return found;
+}
+
+
+dd_LPPtr dd_MakeLPforInteriorFinding(dd_LPPtr lp)
+/* Delete the objective row,
+ add an extra column with -1's to the matrix A,
+ add an extra row with (bceil, 0,...,0,-1),
+ add an objective row with (0,...,0,1), and
+ rows & columns, and change m_size and d_size accordingly, to output new_A.
+ This sets up the LP:
+ maximize x_{d+1}
+ s.t. A x + x_{d+1} <= b
+ x_{d+1} <= bm * bmax,
+ where bm is set to 2 by default, and bmax=max{1, b[1],...,b[m_size]}.
+ Note that the equalitions (linearity) in the input lp will be ignored.
+*/
+{
+ dd_rowrange m;
+ dd_colrange d;
+ dd_NumberType numbtype;
+ dd_LPObjectiveType obj;
+ dd_LPType *lpnew;
+ dd_rowrange i;
+ dd_colrange j;
+ mytype bm,bmax,bceil;
+ int localdebug=dd_FALSE;
+
+ dd_init(bm); dd_init(bmax); dd_init(bceil);
+ dd_add(bm,dd_one,dd_one); dd_set(bmax,dd_one);
+ numbtype=lp->numbtype;
+ m=lp->m+1;
+ d=lp->d+1;
+ obj=dd_LPmax;
+
+ lpnew=dd_CreateLPData(obj, numbtype, m, d);
+
+ for (i=1; i<=lp->m; i++) {
+ if (dd_Larger(lp->A[i-1][lp->rhscol-1],bmax))
+ dd_set(bmax,lp->A[i-1][lp->rhscol-1]);
+ }
+ dd_mul(bceil,bm,bmax);
+ if (localdebug) {fprintf(stderr,"bceil is set to "); dd_WriteNumber(stderr, bceil);}
+
+ for (i=1; i <= lp->m; i++) {
+ for (j=1; j <= lp->d; j++) {
+ dd_set(lpnew->A[i-1][j-1],lp->A[i-1][j-1]);
+ }
+ }
+
+ for (i=1;i<=lp->m; i++){
+ dd_neg(lpnew->A[i-1][lp->d],dd_one); /* new column with all minus one's */
+ }
+
+ for (j=1;j<=lp->d;j++){
+ dd_set(lpnew->A[m-2][j-1],dd_purezero); /* new row (bceil, 0,...,0,-1) */
+ }
+ dd_set(lpnew->A[m-2][0],bceil); /* new row (bceil, 0,...,0,-1) */
+
+ for (j=1;j<= d-1;j++) {
+ dd_set(lpnew->A[m-1][j-1],dd_purezero); /* new obj row with (0,...,0,1) */
+ }
+ dd_set(lpnew->A[m-1][d-1],dd_one); /* new obj row with (0,...,0,1) */
+
+ if (localdebug) dd_WriteAmatrix(stderr, lp->A, lp->m, lp->d);
+ if (localdebug) dd_WriteAmatrix(stderr, lpnew->A, lpnew->m, lpnew->d);
+ dd_clear(bm); dd_clear(bmax); dd_clear(bceil);
+
+ return lpnew;
+}
+
+
+void dd_WriteLPResult(FILE *f,dd_LPPtr lp,dd_ErrorType err)
+{
+ long j;
+
+ fprintf(f,"* cdd LP solver result\n");
+
+ if (err!=dd_NoError) {
+ dd_WriteErrorMessages(f,err);
+ goto _L99;
+ }
+
+ dd_WriteProgramDescription(f);
+
+ fprintf(f,"* #constraints = %ld\n",lp->m-1);
+ fprintf(f,"* #variables = %ld\n",lp->d-1);
+
+ switch (lp->solver) {
+ case dd_DualSimplex:
+ fprintf(f,"* Algorithm: dual simplex algorithm\n");break;
+ case dd_CrissCross:
+ fprintf(f,"* Algorithm: criss-cross method\n");break;
+ }
+
+ switch (lp->objective) {
+ case dd_LPmax:
+ fprintf(f,"* maximization is chosen\n");break;
+ case dd_LPmin:
+ fprintf(f,"* minimization is chosen\n");break;
+ case dd_LPnone:
+ fprintf(f,"* no objective type (max or min) is chosen\n");break;
+ }
+
+ if (lp->objective==dd_LPmax||lp->objective==dd_LPmin){
+ fprintf(f,"* Objective function is\n");
+ for (j=0; j<lp->d; j++){
+ if (j>0 && dd_Nonnegative(lp->A[lp->objrow-1][j]) ) fprintf(f," +");
+ if (j>0 && (j % 5) == 0) fprintf(f,"\n");
+ dd_WriteNumber(f,lp->A[lp->objrow-1][j]);
+ if (j>0) fprintf(f," X[%3ld]",j);
+ }
+ fprintf(f,"\n");
+ }
+
+ switch (lp->LPS){
+ case dd_Optimal:
+ fprintf(f,"* LP status: a dual pair (x,y) of optimal solutions found.\n");
+ fprintf(f,"begin\n");
+ fprintf(f," primal_solution\n");
+ for (j=1; j<lp->d; j++) {
+ fprintf(f," %3ld : ",j);
+ dd_WriteNumber(f,lp->sol[j]);
+ fprintf(f,"\n");
+ }
+ fprintf(f," dual_solution\n");
+ for (j=1; j<lp->d; j++){
+ if (lp->nbindex[j+1]>0) {
+ fprintf(f," %3ld : ",lp->nbindex[j+1]);
+ dd_WriteNumber(f,lp->dsol[j]); fprintf(f,"\n");
+ }
+ }
+ fprintf(f," optimal_value : "); dd_WriteNumber(f,lp->optvalue);
+ fprintf(f,"\nend\n");
+ break;
+
+ case dd_Inconsistent:
+ fprintf(f,"* LP status: LP is inconsistent.\n");
+ fprintf(f,"* The positive combination of original inequalities with\n");
+ fprintf(f,"* the following coefficients will prove the inconsistency.\n");
+ fprintf(f,"begin\n");
+ fprintf(f," dual_direction\n");
+ fprintf(f," %3ld : ",lp->re);
+ dd_WriteNumber(f,dd_one); fprintf(f,"\n");
+ for (j=1; j<lp->d; j++){
+ if (lp->nbindex[j+1]>0) {
+ fprintf(f," %3ld : ",lp->nbindex[j+1]);
+ dd_WriteNumber(f,lp->dsol[j]); fprintf(f,"\n");
+ }
+ }
+ fprintf(f,"end\n");
+ break;
+
+ case dd_DualInconsistent: case dd_StrucDualInconsistent:
+ fprintf(f,"* LP status: LP is dual inconsistent.\n");
+ fprintf(f,"* The linear combination of columns with\n");
+ fprintf(f,"* the following coefficients will prove the dual inconsistency.\n");
+ fprintf(f,"* (It is also an unbounded direction for the primal LP.)\n");
+ fprintf(f,"begin\n");
+ fprintf(f," primal_direction\n");
+ for (j=1; j<lp->d; j++) {
+ fprintf(f," %3ld : ",j);
+ dd_WriteNumber(f,lp->sol[j]);
+ fprintf(f,"\n");
+ }
+ fprintf(f,"end\n");
+ break;
+
+ default:
+ break;
+ }
+ fprintf(f,"* number of pivot operations = %ld (ph0 = %ld, ph1 = %ld, ph2 = %ld, ph3 = %ld, ph4 = %ld)\n",lp->total_pivots,lp->pivots[0],lp->pivots[1],lp->pivots[2],lp->pivots[3],lp->pivots[4]);
+ dd_WriteLPTimes(f, lp);
+_L99:;
+}
+
+dd_LPPtr dd_CreateLP_H_ImplicitLinearity(dd_MatrixPtr M)
+{
+ dd_rowrange m, i, irev, linc;
+ dd_colrange d, j;
+ dd_LPPtr lp;
+ dd_boolean localdebug=dd_FALSE;
+
+ linc=set_card(M->linset);
+ m=M->rowsize+1+linc+1;
+ /* We represent each equation by two inequalities.
+ This is not the best way but makes the code simple. */
+ d=M->colsize+1;
+
+ lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
+ lp->Homogeneous = dd_TRUE;
+ lp->objective = dd_LPmax;
+ lp->eqnumber=linc; /* this records the number of equations */
+ lp->redcheck_extensive=dd_FALSE; /* this is default */
+
+ irev=M->rowsize; /* the first row of the linc reversed inequalities. */
+ for (i = 1; i <= M->rowsize; i++) {
+ if (set_member(i, M->linset)) {
+ irev=irev+1;
+ set_addelem(lp->equalityset,i); /* it is equality. */
+ /* the reversed row irev is not in the equality set. */
+ for (j = 1; j <= M->colsize; j++) {
+ dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-1]);
+ } /*of j*/
+ } else {
+ dd_set(lp->A[i-1][d-1],dd_minusone); /* b_I + A_I x - 1 z >= 0 (z=x_d) */
+ }
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-1]);
+ if (j==1 && i<M->rowsize && dd_Nonzero(M->matrix[i-1][j-1])) lp->Homogeneous = dd_FALSE;
+ } /*of j*/
+ } /*of i*/
+ dd_set(lp->A[m-2][0],dd_one); dd_set(lp->A[m-2][d-1],dd_minusone);
+ /* make the LP bounded. */
+
+ dd_set(lp->A[m-1][d-1],dd_one);
+ /* objective is to maximize z. */
+
+ if (localdebug) {
+ fprintf(stderr,"dd_CreateLP_H_ImplicitLinearity: an new lp is\n");
+ dd_WriteLP(stderr,lp);
+ }
+
+ return lp;
+}
+
+dd_LPPtr dd_CreateLP_V_ImplicitLinearity(dd_MatrixPtr M)
+{
+ dd_rowrange m, i, irev, linc;
+ dd_colrange d, j;
+ dd_LPPtr lp;
+ dd_boolean localdebug=dd_FALSE;
+
+ linc=set_card(M->linset);
+ m=M->rowsize+1+linc+1;
+ /* We represent each equation by two inequalities.
+ This is not the best way but makes the code simple. */
+ d=(M->colsize)+2;
+ /* Two more columns. This is different from the H-reprentation case */
+
+/* The below must be modified for V-representation!!! */
+
+ lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
+ lp->Homogeneous = dd_FALSE;
+ lp->objective = dd_LPmax;
+ lp->eqnumber=linc; /* this records the number of equations */
+ lp->redcheck_extensive=dd_FALSE; /* this is default */
+
+ irev=M->rowsize; /* the first row of the linc reversed inequalities. */
+ for (i = 1; i <= M->rowsize; i++) {
+ dd_set(lp->A[i-1][0],dd_purezero); /* It is almost completely degerate LP */
+ if (set_member(i, M->linset)) {
+ irev=irev+1;
+ set_addelem(lp->equalityset,i); /* it is equality. */
+ /* the reversed row irev is not in the equality set. */
+ for (j = 2; j <= (M->colsize)+1; j++) {
+ dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-2]);
+ } /*of j*/
+ if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
+ } else {
+ dd_set(lp->A[i-1][d-1],dd_minusone); /* b_I x_0 + A_I x - 1 z >= 0 (z=x_d) */
+ }
+ for (j = 2; j <= (M->colsize)+1; j++) {
+ dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-2]);
+ } /*of j*/
+ } /*of i*/
+ dd_set(lp->A[m-2][0],dd_one); dd_set(lp->A[m-2][d-1],dd_minusone);
+ /* make the LP bounded. */
+ dd_set(lp->A[m-1][d-1],dd_one);
+ /* objective is to maximize z. */
+
+ if (localdebug) {
+ fprintf(stderr,"dd_CreateLP_V_ImplicitLinearity: an new lp is\n");
+ dd_WriteLP(stderr,lp);
+ }
+
+ return lp;
+}
+
+
+dd_LPPtr dd_CreateLP_H_Redundancy(dd_MatrixPtr M, dd_rowrange itest)
+{
+ dd_rowrange m, i, irev, linc;
+ dd_colrange d, j;
+ dd_LPPtr lp;
+ dd_boolean localdebug=dd_FALSE;
+
+ linc=set_card(M->linset);
+ m=M->rowsize+1+linc;
+ /* We represent each equation by two inequalities.
+ This is not the best way but makes the code simple. */
+ d=M->colsize;
+
+ lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
+ lp->Homogeneous = dd_TRUE;
+ lp->objective = dd_LPmin;
+ lp->eqnumber=linc; /* this records the number of equations */
+ lp->redcheck_extensive=dd_FALSE; /* this is default */
+
+ irev=M->rowsize; /* the first row of the linc reversed inequalities. */
+ for (i = 1; i <= M->rowsize; i++) {
+ if (set_member(i, M->linset)) {
+ irev=irev+1;
+ set_addelem(lp->equalityset,i); /* it is equality. */
+ /* the reversed row irev is not in the equality set. */
+ for (j = 1; j <= M->colsize; j++) {
+ dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-1]);
+ } /*of j*/
+ if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
+ }
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-1]);
+ if (j==1 && i<M->rowsize && dd_Nonzero(M->matrix[i-1][j-1])) lp->Homogeneous = dd_FALSE;
+ } /*of j*/
+ } /*of i*/
+ for (j = 1; j <= M->colsize; j++) {
+ dd_set(lp->A[m-1][j-1],M->matrix[itest-1][j-1]);
+ /* objective is to violate the inequality in question. */
+ } /*of j*/
+ dd_add(lp->A[itest-1][0],lp->A[itest-1][0],dd_one); /* relax the original inequality by one */
+
+ return lp;
+}
+
+
+dd_LPPtr dd_CreateLP_V_Redundancy(dd_MatrixPtr M, dd_rowrange itest)
+{
+ dd_rowrange m, i, irev, linc;
+ dd_colrange d, j;
+ dd_LPPtr lp;
+ dd_boolean localdebug=dd_FALSE;
+
+ linc=set_card(M->linset);
+ m=M->rowsize+1+linc;
+ /* We represent each equation by two inequalities.
+ This is not the best way but makes the code simple. */
+ d=(M->colsize)+1;
+ /* One more column. This is different from the H-reprentation case */
+
+/* The below must be modified for V-representation!!! */
+
+ lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
+ lp->Homogeneous = dd_FALSE;
+ lp->objective = dd_LPmin;
+ lp->eqnumber=linc; /* this records the number of equations */
+ lp->redcheck_extensive=dd_FALSE; /* this is default */
+
+ irev=M->rowsize; /* the first row of the linc reversed inequalities. */
+ for (i = 1; i <= M->rowsize; i++) {
+ if (i==itest){
+ dd_set(lp->A[i-1][0],dd_one); /* this is to make the LP bounded, ie. the min >= -1 */
+ } else {
+ dd_set(lp->A[i-1][0],dd_purezero); /* It is almost completely degerate LP */
+ }
+ if (set_member(i, M->linset)) {
+ irev=irev+1;
+ set_addelem(lp->equalityset,i); /* it is equality. */
+ /* the reversed row irev is not in the equality set. */
+ for (j = 2; j <= (M->colsize)+1; j++) {
+ dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-2]);
+ } /*of j*/
+ if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
+ }
+ for (j = 2; j <= (M->colsize)+1; j++) {
+ dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-2]);
+ } /*of j*/
+ } /*of i*/
+ for (j = 2; j <= (M->colsize)+1; j++) {
+ dd_set(lp->A[m-1][j-1],M->matrix[itest-1][j-2]);
+ /* objective is to violate the inequality in question. */
+ } /*of j*/
+ dd_set(lp->A[m-1][0],dd_purezero); /* the constant term for the objective is zero */
+
+ if (localdebug) dd_WriteLP(stdout, lp);
+
+ return lp;
+}
+
+
+dd_LPPtr dd_CreateLP_V_SRedundancy(dd_MatrixPtr M, dd_rowrange itest)
+{
+/*
+ V-representation (=boundary problem)
+ g* = maximize
+ 1^T b_{I-itest} x_0 + 1^T A_{I-itest} (the sum of slacks)
+ subject to
+ b_itest x_0 + A_itest x = 0 (the point has to lie on the boundary)
+ b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators in one side)
+ 1^T b_{I-itest} x_0 + 1^T A_{I-itest} x <= 1 (to make an LP bounded)
+ b_L x_0 + A_L x = 0. (linearity generators)
+
+ The redundant row is strongly redundant if and only if g* is zero.
+*/
+
+ dd_rowrange m, i, irev, linc;
+ dd_colrange d, j;
+ dd_LPPtr lp;
+ dd_boolean localdebug=dd_FALSE;
+
+ linc=set_card(M->linset);
+ m=M->rowsize+1+linc+2;
+ /* We represent each equation by two inequalities.
+ This is not the best way but makes the code simple.
+ Two extra constraints are for the first equation and the bouding inequality.
+ */
+ d=(M->colsize)+1;
+ /* One more column. This is different from the H-reprentation case */
+
+/* The below must be modified for V-representation!!! */
+
+ lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
+ lp->Homogeneous = dd_FALSE;
+ lp->objective = dd_LPmax;
+ lp->eqnumber=linc; /* this records the number of equations */
+
+ irev=M->rowsize; /* the first row of the linc reversed inequalities. */
+ for (i = 1; i <= M->rowsize; i++) {
+ if (i==itest){
+ dd_set(lp->A[i-1][0],dd_purezero); /* this is a half of the boundary constraint. */
+ } else {
+ dd_set(lp->A[i-1][0],dd_purezero); /* It is almost completely degerate LP */
+ }
+ if (set_member(i, M->linset) || i==itest) {
+ irev=irev+1;
+ set_addelem(lp->equalityset,i); /* it is equality. */
+ /* the reversed row irev is not in the equality set. */
+ for (j = 2; j <= (M->colsize)+1; j++) {
+ dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-2]);
+ } /*of j*/
+ if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
+ }
+ for (j = 2; j <= (M->colsize)+1; j++) {
+ dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-2]);
+ dd_add(lp->A[m-1][j-1],lp->A[m-1][j-1],lp->A[i-1][j-1]); /* the objective is the sum of all ineqalities */
+ } /*of j*/
+ } /*of i*/
+ for (j = 2; j <= (M->colsize)+1; j++) {
+ dd_neg(lp->A[m-2][j-1],lp->A[m-1][j-1]);
+ /* to make an LP bounded. */
+ } /*of j*/
+ dd_set(lp->A[m-2][0],dd_one); /* the constant term for the bounding constraint is 1 */
+
+ if (localdebug) dd_WriteLP(stdout, lp);
+
+ return lp;
+}
+
+dd_boolean dd_Redundant(dd_MatrixPtr M, dd_rowrange itest, dd_Arow certificate, dd_ErrorType *error)
+ /* 092 */
+{
+ /* Checks whether the row itest is redundant for the representation.
+ All linearity rows are not checked and considered NONredundant.
+ This code works for both H- and V-representations. A certificate is
+ given in the case of non-redundancy, showing a solution x violating only the itest
+ inequality for H-representation, a hyperplane RHS and normal (x_0, x) that
+ separates the itest from the rest. More explicitly, the LP to be setup is
+
+ H-representation
+ f* = minimize
+ b_itest + A_itest x
+ subject to
+ b_itest + 1 + A_itest x >= 0 (relaxed inequality to make an LP bounded)
+ b_{I-itest} + A_{I-itest} x >= 0 (all inequalities except for itest)
+ b_L + A_L x = 0. (linearity)
+
+ V-representation (=separation problem)
+ f* = minimize
+ b_itest x_0 + A_itest x
+ subject to
+ b_itest x_0 + A_itest x >= -1 (to make an LP bounded)
+ b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators except for itest in one side)
+ b_L x_0 + A_L x = 0. (linearity generators)
+
+ Here, the input matrix is considered as (b, A), i.e. b corresponds to the first column of input
+ and the row indices of input is partitioned into I and L where L is the set of linearity.
+ In both cases, the itest data is nonredundant if and only if the optimal value f* is negative.
+ The certificate has dimension one more for V-representation case.
+ */
+
+ dd_colrange j;
+ dd_LPPtr lp;
+ dd_LPSolutionPtr lps;
+ dd_ErrorType err=dd_NoError;
+ dd_boolean answer=dd_FALSE,localdebug=dd_FALSE;
+
+ *error=dd_NoError;
+ if (set_member(itest, M->linset)){
+ if (localdebug) printf("The %ld th row is linearity and redundancy checking is skipped.\n",itest);
+ goto _L99;
+ }
+
+ /* Create an LP data for redundancy checking */
+ if (M->representation==dd_Generator){
+ lp=dd_CreateLP_V_Redundancy(M, itest);
+ } else {
+ lp=dd_CreateLP_H_Redundancy(M, itest);
+ }
+
+ dd_LPSolve(lp,dd_choiceRedcheckAlgorithm,&err);
+ if (err!=dd_NoError){
+ *error=err;
+ goto _L999;
+ } else {
+ lps=dd_CopyLPSolution(lp);
+
+ for (j=0; j<lps->d; j++) {
+ dd_set(certificate[j], lps->sol[j]);
+ }
+
+ if (dd_Negative(lps->optvalue)){
+ answer=dd_FALSE;
+ if (localdebug) fprintf(stderr,"==> %ld th row is nonredundant.\n",itest);
+ } else {
+ answer=dd_TRUE;
+ if (localdebug) fprintf(stderr,"==> %ld th row is redundant.\n",itest);
+ }
+ dd_FreeLPSolution(lps);
+ }
+ _L999:
+ dd_FreeLPData(lp);
+_L99:
+ return answer;
+}
+
+dd_boolean dd_RedundantExtensive(dd_MatrixPtr M, dd_rowrange itest, dd_Arow certificate,
+dd_rowset *redset,dd_ErrorType *error)
+ /* 094 */
+{
+ /* This uses the same LP construction as dd_Reduandant. But, while it is checking
+ the redundancy of itest, it also tries to find some other variable that are
+ redundant (i.e. forced to be nonnegative). This is expensive as it used
+ the complete tableau information at each DualSimplex pivot. The redset must
+ be initialized before this function is called.
+ */
+
+ dd_colrange j;
+ dd_LPPtr lp;
+ dd_LPSolutionPtr lps;
+ dd_ErrorType err=dd_NoError;
+ dd_boolean answer=dd_FALSE,localdebug=dd_FALSE;
+
+ *error=dd_NoError;
+ if (set_member(itest, M->linset)){
+ if (localdebug) printf("The %ld th row is linearity and redundancy checking is skipped.\n",itest);
+ goto _L99;
+ }
+
+ /* Create an LP data for redundancy checking */
+ if (M->representation==dd_Generator){
+ lp=dd_CreateLP_V_Redundancy(M, itest);
+ } else {
+ lp=dd_CreateLP_H_Redundancy(M, itest);
+ }
+
+ lp->redcheck_extensive=dd_TRUE;
+
+ dd_LPSolve0(lp,dd_DualSimplex,&err);
+ if (err!=dd_NoError){
+ *error=err;
+ goto _L999;
+ } else {
+ set_copy(*redset,lp->redset_extra);
+ set_delelem(*redset, itest);
+ /* itest row might be redundant in the lp but this has nothing to do with its redundancy
+ in the original system M. Thus we must delete it. */
+ if (localdebug){
+ fprintf(stderr, "dd_RedundantExtensive: checking for %ld, extra redset with cardinality %ld (%ld)\n",itest,set_card(*redset),set_card(lp->redset_extra));
+ set_fwrite(stderr, *redset); fprintf(stderr, "\n");
+ }
+ lps=dd_CopyLPSolution(lp);
+
+ for (j=0; j<lps->d; j++) {
+ dd_set(certificate[j], lps->sol[j]);
+ }
+
+ if (dd_Negative(lps->optvalue)){
+ answer=dd_FALSE;
+ if (localdebug) fprintf(stderr,"==> %ld th row is nonredundant.\n",itest);
+ } else {
+ answer=dd_TRUE;
+ if (localdebug) fprintf(stderr,"==> %ld th row is redundant.\n",itest);
+ }
+ dd_FreeLPSolution(lps);
+ }
+ _L999:
+ dd_FreeLPData(lp);
+_L99:
+ return answer;
+}
+
+dd_rowset dd_RedundantRows(dd_MatrixPtr M, dd_ErrorType *error) /* 092 */
+{
+ dd_rowrange i,m;
+ dd_colrange d;
+ dd_rowset redset;
+ dd_MatrixPtr Mcopy;
+ dd_Arow cvec; /* certificate */
+ dd_boolean localdebug=dd_TRUE;
+
+ m=M->rowsize;
+ if (M->representation==dd_Generator){
+ d=(M->colsize)+1;
+ } else {
+ d=M->colsize;
+ }
+ Mcopy=dd_MatrixCopy(M);
+ dd_InitializeArow(d,&cvec);
+ set_initialize(&redset, m);
+ for (i=m; i>=1; i--) {
+ if (dd_Redundant(Mcopy, i, cvec, error)) {
+ if (localdebug) printf("Iteration %ld: the row %ld is redundant.\n",m-i+1,i);
+ set_addelem(redset, i);
+ dd_MatrixRowRemove(&Mcopy, i);
+ } else {
+ if (localdebug) printf("Iteration %ld: the row %ld is essential.\n",m-i+1, i);
+ }
+ if (*error!=dd_NoError) goto _L99;
+ }
+_L99:
+ dd_FreeMatrix(Mcopy);
+ dd_FreeArow(d, cvec);
+ return redset;
+}
+
+
+dd_boolean dd_MatrixRedundancyRemove(dd_MatrixPtr *M, dd_rowset *redset,dd_rowindex *newpos, dd_ErrorType *error) /* 094 */
+{
+ /* It returns the set of all redundant rows. This should be called after all
+ implicit linearity are recognized with dd_MatrixCanonicalizeLinearity.
+ */
+
+
+ dd_rowrange i,k,m,m1;
+ dd_colrange d;
+ dd_rowset redset1;
+ dd_rowindex newpos1;
+ dd_MatrixPtr M1=NULL;
+ dd_Arow cvec; /* certificate */
+ dd_boolean success=dd_FALSE, localdebug=dd_FALSE;
+
+ m=(*M)->rowsize;
+ set_initialize(redset, m);
+ M1=dd_MatrixSortedUniqueCopy(*M,newpos);
+ for (i=1; i<=m; i++){
+ if ((*newpos)[i]<=0) set_addelem(*redset,i);
+ if (localdebug) printf(" %ld:%ld",i,(*newpos)[i]);
+ }
+ if (localdebug) printf("\n");
+
+ if ((*M)->representation==dd_Generator){
+ d=((*M)->colsize)+1;
+ } else {
+ d=(*M)->colsize;
+ }
+ m1=M1->rowsize;
+ if (localdebug){
+ fprintf(stderr,"dd_MatrixRedundancyRemove: By sorting, %ld rows have been removed. The remaining has %ld rows.\n",m-m1,m1);
+ /* dd_WriteMatrix(stdout,M1); */
+ }
+ dd_InitializeArow(d,&cvec);
+ set_initialize(&redset1, M1->rowsize);
+ k=1;
+ do {
+ if (dd_RedundantExtensive(M1, k, cvec, &redset1,error)) {
+ set_addelem(redset1, k);
+ dd_MatrixRowsRemove2(&M1,redset1,&newpos1);
+ for (i=1; i<=m; i++){
+ if ((*newpos)[i]>0){
+ if (set_member((*newpos)[i],redset1)){
+ set_addelem(*redset,i);
+ (*newpos)[i]=0; /* now the original row i is recognized redundant and removed from M1 */
+ } else {
+ (*newpos)[i]=newpos1[(*newpos)[i]]; /* update the new pos vector */
+ }
+ }
+ }
+ set_free(redset1);
+ set_initialize(&redset1, M1->rowsize);
+ if (localdebug) {
+ printf("dd_MatrixRedundancyRemove: the row %ld is redundant. The new matrix has %ld rows.\n", k, M1->rowsize);
+ /* dd_WriteMatrix(stderr, M1); */
+ }
+ free(newpos1);
+ } else {
+ if (set_card(redset1)>0) {
+ dd_MatrixRowsRemove2(&M1,redset1,&newpos1);
+ for (i=1; i<=m; i++){
+ if ((*newpos)[i]>0){
+ if (set_member((*newpos)[i],redset1)){
+ set_addelem(*redset,i);
+ (*newpos)[i]=0; /* now the original row i is recognized redundant and removed from M1 */
+ } else {
+ (*newpos)[i]=newpos1[(*newpos)[i]]; /* update the new pos vector */
+ }
+ }
+ }
+ set_free(redset1);
+ set_initialize(&redset1, M1->rowsize);
+ free(newpos1);
+ }
+ if (localdebug) {
+ printf("dd_MatrixRedundancyRemove: the row %ld is essential. The new matrix has %ld rows.\n", k, M1->rowsize);
+ /* dd_WriteMatrix(stderr, M1); */
+ }
+ k=k+1;
+ }
+ if (*error!=dd_NoError) goto _L99;
+ } while (k<=M1->rowsize);
+ if (localdebug) dd_WriteMatrix(stderr, M1);
+ success=dd_TRUE;
+
+_L99:
+ dd_FreeMatrix(*M);
+ *M=M1;
+ dd_FreeArow(d, cvec);
+ set_free(redset1);
+ return success;
+}
+
+
+dd_boolean dd_SRedundant(dd_MatrixPtr M, dd_rowrange itest, dd_Arow certificate, dd_ErrorType *error)
+ /* 093a */
+{
+ /* Checks whether the row itest is strongly redundant for the representation.
+ A row is strongly redundant in H-representation if every point in
+ the polyhedron satisfies it with strict inequality.
+ A row is strongly redundant in V-representation if this point is in
+ the interior of the polyhedron.
+
+ All linearity rows are not checked and considered NOT strongly redundant.
+ This code works for both H- and V-representations. A certificate is
+ given in the case of non-redundancy, showing a solution x violating only the itest
+ inequality for H-representation, a hyperplane RHS and normal (x_0, x) that
+ separates the itest from the rest. More explicitly, the LP to be setup is
+
+ H-representation
+ f* = minimize
+ b_itest + A_itest x
+ subject to
+ b_itest + 1 + A_itest x >= 0 (relaxed inequality to make an LP bounded)
+ b_{I-itest} + A_{I-itest} x >= 0 (all inequalities except for itest)
+ b_L + A_L x = 0. (linearity)
+
+ V-representation (=separation problem)
+ f* = minimize
+ b_itest x_0 + A_itest x
+ subject to
+ b_itest x_0 + A_itest x >= -1 (to make an LP bounded)
+ b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators except for itest in one side)
+ b_L x_0 + A_L x = 0. (linearity generators)
+
+ Here, the input matrix is considered as (b, A), i.e. b corresponds to the first column of input
+ and the row indices of input is partitioned into I and L where L is the set of linearity.
+ In H-representation, the itest data is strongly redundant if and only if the optimal value f* is positive.
+ In V-representation, the itest data is redundant if and only if the optimal value f* is zero (as the LP
+ is homogeneous and the optimal value is always non-positive). To recognize strong redundancy, one
+ can set up a second LP
+
+ V-representation (=boundary problem)
+ g* = maximize
+ 1^T b_{I-itest} x_0 + 1^T A_{I-itest} (the sum of slacks)
+ subject to
+ b_itest x_0 + A_itest x = 0 (the point has to lie on the boundary)
+ b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators in one side)
+ 1^T b_{I-itest} x_0 + 1^T A_{I-itest} x <= 1 (to make an LP bounded)
+ b_L x_0 + A_L x = 0. (linearity generators)
+
+ The redundant row is strongly redundant if and only if g* is zero.
+
+ The certificate has dimension one more for V-representation case.
+ */
+
+ dd_colrange j;
+ dd_LPPtr lp;
+ dd_LPSolutionPtr lps;
+ dd_ErrorType err=dd_NoError;
+ dd_boolean answer=dd_FALSE,localdebug=dd_FALSE;
+
+ *error=dd_NoError;
+ if (set_member(itest, M->linset)){
+ if (localdebug) printf("The %ld th row is linearity and strong redundancy checking is skipped.\n",itest);
+ goto _L99;
+ }
+
+ /* Create an LP data for redundancy checking */
+ if (M->representation==dd_Generator){
+ lp=dd_CreateLP_V_Redundancy(M, itest);
+ } else {
+ lp=dd_CreateLP_H_Redundancy(M, itest);
+ }
+
+ dd_LPSolve(lp,dd_choiceRedcheckAlgorithm,&err);
+ if (err!=dd_NoError){
+ *error=err;
+ goto _L999;
+ } else {
+ lps=dd_CopyLPSolution(lp);
+
+ for (j=0; j<lps->d; j++) {
+ dd_set(certificate[j], lps->sol[j]);
+ }
+
+ if (localdebug){
+ printf("Optimum value:");
+ dd_WriteNumber(stdout, lps->optvalue);
+ printf("\n");
+ }
+
+ if (M->representation==dd_Inequality){
+ if (dd_Positive(lps->optvalue)){
+ answer=dd_TRUE;
+ if (localdebug) fprintf(stderr,"==> %ld th inequality is strongly redundant.\n",itest);
+ } else {
+ answer=dd_FALSE;
+ if (localdebug) fprintf(stderr,"==> %ld th inequality is not strongly redundant.\n",itest);
+ }
+ } else {
+ if (dd_Negative(lps->optvalue)){
+ answer=dd_FALSE;
+ if (localdebug) fprintf(stderr,"==> %ld th point is not strongly redundant.\n",itest);
+ } else {
+ /* for V-representation, we have to solve another LP */
+ dd_FreeLPData(lp);
+ dd_FreeLPSolution(lps);
+ lp=dd_CreateLP_V_SRedundancy(M, itest);
+ dd_LPSolve(lp,dd_DualSimplex,&err);
+ lps=dd_CopyLPSolution(lp);
+ if (localdebug) dd_WriteLPResult(stdout,lp,err);
+ if (dd_Positive(lps->optvalue)){
+ answer=dd_FALSE;
+ if (localdebug) fprintf(stderr,"==> %ld th point is not strongly redundant.\n",itest);
+ } else {
+ answer=dd_TRUE;
+ if (localdebug) fprintf(stderr,"==> %ld th point is strongly redundant.\n",itest);
+ }
+ }
+ }
+ dd_FreeLPSolution(lps);
+ }
+ _L999:
+ dd_FreeLPData(lp);
+_L99:
+ return answer;
+}
+
+dd_rowset dd_SRedundantRows(dd_MatrixPtr M, dd_ErrorType *error) /* 093a */
+{
+ dd_rowrange i,m;
+ dd_colrange d;
+ dd_rowset redset;
+ dd_MatrixPtr Mcopy;
+ dd_Arow cvec; /* certificate */
+ dd_boolean localdebug=dd_FALSE;
+
+ m=M->rowsize;
+ if (M->representation==dd_Generator){
+ d=(M->colsize)+1;
+ } else {
+ d=M->colsize;
+ }
+ Mcopy=dd_MatrixCopy(M);
+ dd_InitializeArow(d,&cvec);
+ set_initialize(&redset, m);
+ for (i=m; i>=1; i--) {
+ if (dd_SRedundant(Mcopy, i, cvec, error)) {
+ if (localdebug) printf("dd_SRedundantRows: the row %ld is strongly redundant.\n", i);
+ set_addelem(redset, i);
+ dd_MatrixRowRemove(&Mcopy, i);
+ } else {
+ if (localdebug) printf("dd_SRedundantRows: the row %ld is not strongly redundant.\n", i);
+ }
+ if (*error!=dd_NoError) goto _L99;
+ }
+_L99:
+ dd_FreeMatrix(Mcopy);
+ dd_FreeArow(d, cvec);
+ return redset;
+}
+
+dd_rowset dd_RedundantRowsViaShooting(dd_MatrixPtr M, dd_ErrorType *error) /* 092 */
+{
+ /*
+ For H-representation only and not quite reliable,
+ especially when floating-point arithmetic is used.
+ Use the ordinary (slower) method dd_RedundantRows.
+ */
+
+ dd_rowrange i,m, ired, irow=0;
+ dd_colrange j,k,d;
+ dd_rowset redset;
+ dd_rowindex rowflag;
+ /* ith comp is negative if the ith inequality (i-1 st row) is redundant.
+ zero if it is not decided.
+ k > 0 if it is nonredundant and assigned to the (k-1)th row of M1.
+ */
+ dd_MatrixPtr M1;
+ dd_Arow shootdir, cvec=NULL;
+ dd_LPPtr lp0, lp;
+ dd_LPSolutionPtr lps;
+ dd_ErrorType err;
+ dd_LPSolverType solver=dd_DualSimplex;
+ dd_boolean localdebug=dd_TRUE;
+
+ m=M->rowsize;
+ d=M->colsize;
+ M1=dd_CreateMatrix(m,d);
+ M1->rowsize=0; /* cheat the rowsize so that smaller matrix can be stored */
+ set_initialize(&redset, m);
+ dd_InitializeArow(d, &shootdir);
+ dd_InitializeArow(d, &cvec);
+
+ rowflag=(long *)calloc(m+1, sizeof(long));
+
+ /* First find some (likely) nonredundant inequalities by Interior Point Find. */
+ lp0=dd_Matrix2LP(M, &err);
+ lp=dd_MakeLPforInteriorFinding(lp0);
+ dd_FreeLPData(lp0);
+ dd_LPSolve(lp, solver, &err); /* Solve the LP */
+ lps=dd_CopyLPSolution(lp);
+
+ if (dd_Positive(lps->optvalue)){
+ /* An interior point is found. Use rayshooting to find some nonredundant
+ inequalities. */
+ for (j=1; j<d; j++){
+ for (k=1; k<=d; k++) dd_set(shootdir[k-1], dd_purezero);
+ dd_set(shootdir[j], dd_one); /* j-th unit vector */
+ ired=dd_RayShooting(M, lps->sol, shootdir);
+ if (localdebug) printf("nonredundant row %3ld found by shooting.\n", ired);
+ if (ired>0 && rowflag[ired]<=0) {
+ irow++;
+ rowflag[ired]=irow;
+ for (k=1; k<=d; k++) dd_set(M1->matrix[irow-1][k-1], M->matrix[ired-1][k-1]);
+ }
+
+ dd_neg(shootdir[j], dd_one); /* negative of the j-th unit vector */
+ ired=dd_RayShooting(M, lps->sol, shootdir);
+ if (localdebug) printf("nonredundant row %3ld found by shooting.\n", ired);
+ if (ired>0 && rowflag[ired]<=0) {
+ irow++;
+ rowflag[ired]=irow;
+ for (k=1; k<=d; k++) dd_set(M1->matrix[irow-1][k-1], M->matrix[ired-1][k-1]);
+ }
+ }
+
+ M1->rowsize=irow;
+ if (localdebug) {
+ printf("The initial nonredundant set is:");
+ for (i=1; i<=m; i++) if (rowflag[i]>0) printf(" %ld", i);
+ printf("\n");
+ }
+
+ i=1;
+ while(i<=m){
+ if (rowflag[i]==0){ /* the ith inequality is not yet checked */
+ if (localdebug) fprintf(stderr, "Checking redundancy of %ld th inequality\n", i);
+ irow++; M1->rowsize=irow;
+ for (k=1; k<=d; k++) dd_set(M1->matrix[irow-1][k-1], M->matrix[i-1][k-1]);
+ if (!dd_Redundant(M1, irow, cvec, &err)){
+ for (k=1; k<=d; k++) dd_sub(shootdir[k-1], cvec[k-1], lps->sol[k-1]);
+ ired=dd_RayShooting(M, lps->sol, shootdir);
+ rowflag[ired]=irow;
+ for (k=1; k<=d; k++) dd_set(M1->matrix[irow-1][k-1], M->matrix[ired-1][k-1]);
+ if (localdebug) {
+ fprintf(stderr, "The %ld th inequality is nonredundant for the subsystem\n", i);
+ fprintf(stderr, "The nonredundancy of %ld th inequality is found by shooting.\n", ired);
+ }
+ } else {
+ if (localdebug) fprintf(stderr, "The %ld th inequality is redundant for the subsystem and thus for the whole.\n", i);
+ rowflag[i]=-1;
+ set_addelem(redset, i);
+ i++;
+ }
+ } else {
+ i++;
+ }
+ } /* endwhile */
+ } else {
+ /* No interior point is found. Apply the standard LP technique. */
+ if (localdebug) printf("No interior-point is found and thus the standard LP technique will be used.\n", ired);
+ redset=dd_RedundantRows(M, error);
+ }
+
+ dd_FreeLPData(lp);
+ dd_FreeLPSolution(lps);
+
+ M1->rowsize=m; M1->colsize=d; /* recover the original sizes */
+ dd_FreeMatrix(M1);
+ dd_FreeArow(d, shootdir);
+ dd_FreeArow(d, cvec);
+ free(rowflag);
+ return redset;
+}
+
+dd_SetFamilyPtr dd_Matrix2Adjacency(dd_MatrixPtr M, dd_ErrorType *error) /* 093 */
+{
+ /* This is to generate the (facet) graph of a polyheron (H) V-represented by M using LPs.
+ Since it does not use the representation conversion, it should work for a large
+ scale problem.
+ */
+ dd_rowrange i,m;
+ dd_colrange d;
+ dd_rowset redset;
+ dd_MatrixPtr Mcopy;
+ dd_SetFamilyPtr F=NULL;
+
+ m=M->rowsize;
+ d=M->colsize;
+ if (m<=0 ||d<=0) {
+ *error=dd_EmptyRepresentation;
+ goto _L999;
+ }
+ Mcopy=dd_MatrixCopy(M);
+ F=dd_CreateSetFamily(m, m);
+ for (i=1; i<=m; i++) {
+ if (!set_member(i, M->linset)){
+ set_addelem(Mcopy->linset, i);
+ redset=dd_RedundantRows(Mcopy, error); /* redset should contain all nonadjacent ones */
+ set_uni(redset, redset, Mcopy->linset); /* all linearity elements should be nonadjacent */
+ set_compl(F->set[i-1], redset); /* set the adjacency list of vertex i */
+ set_delelem(Mcopy->linset, i);
+ set_free(redset);
+ if (*error!=dd_NoError) goto _L99;
+ }
+ }
+_L99:
+ dd_FreeMatrix(Mcopy);
+_L999:
+ return F;
+}
+
+dd_SetFamilyPtr dd_Matrix2WeakAdjacency(dd_MatrixPtr M, dd_ErrorType *error) /* 093a */
+{
+ /* This is to generate the weak-adjacency (facet) graph of a polyheron (H) V-represented by M using LPs.
+ Since it does not use the representation conversion, it should work for a large
+ scale problem.
+ */
+ dd_rowrange i,m;
+ dd_colrange d;
+ dd_rowset redset;
+ dd_MatrixPtr Mcopy;
+ dd_SetFamilyPtr F=NULL;
+
+ m=M->rowsize;
+ d=M->colsize;
+ if (m<=0 ||d<=0) {
+ *error=dd_EmptyRepresentation;
+ goto _L999;
+ }
+ Mcopy=dd_MatrixCopy(M);
+ F=dd_CreateSetFamily(m, m);
+ for (i=1; i<=m; i++) {
+ if (!set_member(i, M->linset)){
+ set_addelem(Mcopy->linset, i);
+ redset=dd_SRedundantRows(Mcopy, error); /* redset should contain all weakly nonadjacent ones */
+ set_uni(redset, redset, Mcopy->linset); /* all linearity elements should be nonadjacent */
+ set_compl(F->set[i-1], redset); /* set the adjacency list of vertex i */
+ set_delelem(Mcopy->linset, i);
+ set_free(redset);
+ if (*error!=dd_NoError) goto _L99;
+ }
+ }
+_L99:
+ dd_FreeMatrix(Mcopy);
+_L999:
+ return F;
+}
+
+
+dd_boolean dd_ImplicitLinearity(dd_MatrixPtr M, dd_rowrange itest, dd_Arow certificate, dd_ErrorType *error)
+ /* 092 */
+{
+ /* Checks whether the row itest is implicit linearity for the representation.
+ All linearity rows are not checked and considered non implicit linearity (dd_FALSE).
+ This code works for both H- and V-representations. A certificate is
+ given in the case of dd_FALSE, showing a feasible solution x satisfying the itest
+ strict inequality for H-representation, a hyperplane RHS and normal (x_0, x) that
+ separates the itest from the rest. More explicitly, the LP to be setup is
+ the same thing as redundancy case but with maximization:
+
+ H-representation
+ f* = maximize
+ b_itest + A_itest x
+ subject to
+ b_itest + 1 + A_itest x >= 0 (relaxed inequality. This is not necessary but kept for simplicity of the code)
+ b_{I-itest} + A_{I-itest} x >= 0 (all inequalities except for itest)
+ b_L + A_L x = 0. (linearity)
+
+ V-representation (=separation problem)
+ f* = maximize
+ b_itest x_0 + A_itest x
+ subject to
+ b_itest x_0 + A_itest x >= -1 (again, this is not necessary but kept for simplicity.)
+ b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators except for itest in one side)
+ b_L x_0 + A_L x = 0. (linearity generators)
+
+ Here, the input matrix is considered as (b, A), i.e. b corresponds to the first column of input
+ and the row indices of input is partitioned into I and L where L is the set of linearity.
+ In both cases, the itest data is implicit linearity if and only if the optimal value f* is nonpositive.
+ The certificate has dimension one more for V-representation case.
+ */
+
+ dd_colrange j;
+ dd_LPPtr lp;
+ dd_LPSolutionPtr lps;
+ dd_ErrorType err=dd_NoError;
+ dd_boolean answer=dd_FALSE,localdebug=dd_FALSE;
+
+ *error=dd_NoError;
+ if (set_member(itest, M->linset)){
+ if (localdebug) printf("The %ld th row is linearity and redundancy checking is skipped.\n",itest);
+ goto _L99;
+ }
+
+ /* Create an LP data for redundancy checking */
+ if (M->representation==dd_Generator){
+ lp=dd_CreateLP_V_Redundancy(M, itest);
+ } else {
+ lp=dd_CreateLP_H_Redundancy(M, itest);
+ }
+
+ lp->objective = dd_LPmax; /* the lp->objective is set by CreateLP* to LPmin */
+ dd_LPSolve(lp,dd_choiceRedcheckAlgorithm,&err);
+ if (err!=dd_NoError){
+ *error=err;
+ goto _L999;
+ } else {
+ lps=dd_CopyLPSolution(lp);
+
+ for (j=0; j<lps->d; j++) {
+ dd_set(certificate[j], lps->sol[j]);
+ }
+
+ if (lps->LPS==dd_Optimal && dd_EqualToZero(lps->optvalue)){
+ answer=dd_TRUE;
+ if (localdebug) fprintf(stderr,"==> %ld th data is an implicit linearity.\n",itest);
+ } else {
+ answer=dd_FALSE;
+ if (localdebug) fprintf(stderr,"==> %ld th data is not an implicit linearity.\n",itest);
+ }
+ dd_FreeLPSolution(lps);
+ }
+ _L999:
+ dd_FreeLPData(lp);
+_L99:
+ return answer;
+}
+
+
+int dd_FreeOfImplicitLinearity(dd_MatrixPtr M, dd_Arow certificate, dd_rowset *imp_linrows, dd_ErrorType *error)
+ /* 092 */
+{
+ /* Checks whether the matrix M constains any implicit linearity at all.
+ It returns 1 if it is free of any implicit linearity. This means that
+ the present linearity rows define the linearity correctly. It returns
+ nonpositive values otherwise.
+
+
+ H-representation
+ f* = maximize z
+ subject to
+ b_I + A_I x - 1 z >= 0
+ b_L + A_L x = 0 (linearity)
+ z <= 1.
+
+ V-representation (=separation problem)
+ f* = maximize z
+ subject to
+ b_I x_0 + A_I x - 1 z >= 0 (all nonlinearity generators in one side)
+ b_L x_0 + A_L x = 0 (linearity generators)
+ z <= 1.
+
+ Here, the input matrix is considered as (b, A), i.e. b corresponds to the first column of input
+ and the row indices of input is partitioned into I and L where L is the set of linearity.
+ In both cases, any implicit linearity exists if and only if the optimal value f* is nonpositive.
+ The certificate has dimension one more for V-representation case.
+ */
+
+ dd_LPPtr lp;
+ dd_rowrange i,m;
+ dd_colrange j,d1;
+ dd_ErrorType err=dd_NoError;
+ dd_Arow cvec; /* certificate for implicit linearity */
+
+ int answer=0,localdebug=dd_FALSE;
+
+ *error=dd_NoError;
+ /* Create an LP data for redundancy checking */
+ if (M->representation==dd_Generator){
+ lp=dd_CreateLP_V_ImplicitLinearity(M);
+ } else {
+ lp=dd_CreateLP_H_ImplicitLinearity(M);
+ }
+
+ dd_LPSolve(lp,dd_choiceRedcheckAlgorithm,&err);
+ if (err!=dd_NoError){
+ *error=err;
+ goto _L999;
+ } else {
+
+ for (j=0; j<lp->d; j++) {
+ dd_set(certificate[j], lp->sol[j]);
+ }
+
+ if (localdebug) dd_WriteLPResult(stderr,lp,err);
+
+ /* *posset contains a set of row indices that are recognized as nonlinearity. */
+ if (localdebug) {
+ fprintf(stderr,"==> The following variables are not implicit linearity:\n");
+ set_fwrite(stderr, lp->posset_extra);
+ fprintf(stderr,"\n");
+ }
+
+ if (M->representation==dd_Generator){
+ d1=(M->colsize)+1;
+ } else {
+ d1=M->colsize;
+ }
+ m=M->rowsize;
+ dd_InitializeArow(d1,&cvec);
+ set_initialize(imp_linrows,m);
+
+ if (lp->LPS==dd_Optimal){
+ if (dd_Positive(lp->optvalue)){
+ answer=1;
+ if (localdebug) fprintf(stderr,"==> The matrix has no implicit linearity.\n");
+ } else if (dd_Negative(lp->optvalue)) {
+ answer=-1;
+ if (localdebug) fprintf(stderr,"==> The matrix defines the trivial system.\n");
+ } else {
+ answer=0;
+ if (localdebug) fprintf(stderr,"==> The matrix has some implicit linearity.\n");
+ }
+ } else {
+ answer=-2;
+ if (localdebug) fprintf(stderr,"==> The LP fails.\n");
+ }
+ if (answer==0){
+ /* List the implicit linearity rows */
+ for (i=m; i>=1; i--) {
+ if (!set_member(i,lp->posset_extra)) {
+ if (dd_ImplicitLinearity(M, i, cvec, error)) {
+ set_addelem(*imp_linrows, i);
+ if (localdebug) {
+ fprintf(stderr," row %ld is implicit linearity\n",i);
+ fprintf(stderr,"\n");
+ }
+ }
+ if (*error!=dd_NoError) goto _L999;
+ }
+ }
+ } /* end of if (answer==0) */
+ if (answer==-1) {
+ for (i=m; i>=1; i--) set_addelem(*imp_linrows, i);
+ } /* all rows are considered implicit linearity */
+
+ dd_FreeArow(d1,cvec);
+ }
+ _L999:
+ dd_FreeLPData(lp);
+
+ return answer;
+}
+
+
+dd_rowset dd_ImplicitLinearityRows(dd_MatrixPtr M, dd_ErrorType *error) /* 092 */
+{
+ dd_colrange d;
+ dd_rowset imp_linset;
+ dd_Arow cvec; /* certificate */
+ int foi;
+ dd_boolean localdebug=dd_FALSE;
+
+ if (M->representation==dd_Generator){
+ d=(M->colsize)+2;
+ } else {
+ d=M->colsize+1;
+ }
+
+ dd_InitializeArow(d,&cvec);
+ if (localdebug) fprintf(stdout, "\ndd_ImplicitLinearityRows: Check whether the system contains any implicit linearity.\n");
+ foi=dd_FreeOfImplicitLinearity(M, cvec, &imp_linset, error);
+ if (localdebug){
+ switch (foi) {
+ case 1:
+ fprintf(stdout, " It is free of implicit linearity.\n");
+ break;
+
+ case 0:
+ fprintf(stdout, " It is not free of implicit linearity.\n");
+ break;
+
+ case -1:
+ fprintf(stdout, " The input system is trivial (i.e. the empty H-polytope or the V-rep of the whole space.\n");
+ break;
+
+ default:
+ fprintf(stdout, " The LP was not solved correctly.\n");
+ break;
+
+ }
+ }
+
+ if (localdebug){
+ fprintf(stderr, " Implicit linearity rows are:\n");
+ set_fwrite(stderr,imp_linset);
+ fprintf(stderr, "\n");
+ }
+ dd_FreeArow(d, cvec);
+ return imp_linset;
+}
+
+dd_boolean dd_MatrixCanonicalizeLinearity(dd_MatrixPtr *M, dd_rowset *impl_linset,dd_rowindex *newpos,
+dd_ErrorType *error) /* 094 */
+{
+/* This is to recongnize all implicit linearities, and put all linearities at the top of
+ the matrix. All implicit linearities will be returned by *impl_linset.
+*/
+ dd_rowrange rank;
+ dd_rowset linrows,ignoredrows,basisrows;
+ dd_colset ignoredcols,basiscols;
+ dd_rowrange i,k,m;
+ dd_rowindex newpos1;
+ dd_boolean success=dd_FALSE;
+
+ linrows=dd_ImplicitLinearityRows(*M, error);
+ if (*error!=dd_NoError) goto _L99;
+
+ m=(*M)->rowsize;
+
+ set_uni((*M)->linset, (*M)->linset, linrows);
+ /* add the implicit linrows to the explicit linearity rows */
+
+ /* To remove redundancy of the linearity part,
+ we need to compute the rank and a basis of the linearity part. */
+ set_initialize(&ignoredrows, (*M)->rowsize);
+ set_initialize(&ignoredcols, (*M)->colsize);
+ set_compl(ignoredrows, (*M)->linset);
+ rank=dd_MatrixRank(*M,ignoredrows,ignoredcols,&basisrows,&basiscols);
+ set_diff(ignoredrows, (*M)->linset, basisrows);
+ dd_MatrixRowsRemove2(M,ignoredrows,newpos);
+
+ dd_MatrixShiftupLinearity(M,&newpos1);
+
+ for (i=1; i<=m; i++){
+ k=(*newpos)[i];
+ if (k>0) {
+ (*newpos)[i]=newpos1[k];
+ }
+ }
+
+ *impl_linset=linrows;
+ success=dd_TRUE;
+ free(newpos1);
+ set_free(basisrows);
+ set_free(basiscols);
+ set_free(ignoredrows);
+ set_free(ignoredcols);
+_L99:
+ return success;
+}
+
+dd_boolean dd_MatrixCanonicalize(dd_MatrixPtr *M, dd_rowset *impl_linset, dd_rowset *redset,
+dd_rowindex *newpos, dd_ErrorType *error) /* 094 */
+{
+/* This is to find a canonical representation of a matrix *M by
+ recognizing all implicit linearities and all redundancies.
+ All implicit linearities will be returned by *impl_linset and
+ redundancies will be returned by *redset.
+*/
+ dd_rowrange i,k,m;
+ dd_rowindex newpos1,revpos;
+ dd_rowset redset1;
+ dd_boolean success=dd_TRUE;
+
+ m=(*M)->rowsize;
+ set_initialize(redset, m);
+ revpos=(long *)calloc(m+1,sizeof(long));
+
+ success=dd_MatrixCanonicalizeLinearity(M, impl_linset, newpos, error);
+
+ if (!success) goto _L99;
+
+ for (i=1; i<=m; i++){
+ k=(*newpos)[i];
+ if (k>0) revpos[k]=i; /* inverse of *newpos[] */
+ }
+
+ success=dd_MatrixRedundancyRemove(M, &redset1, &newpos1, error); /* 094 */
+
+ if (!success) goto _L99;
+
+ for (i=1; i<=m; i++){
+ k=(*newpos)[i];
+ if (k>0) {
+ (*newpos)[i]=newpos1[k];
+ if (newpos1[k]<0) (*newpos)[i]=-revpos[-newpos1[k]]; /* update the certificate of its duplicate removal. */
+ if (set_member(k,redset1)) set_addelem(*redset, i);
+ }
+ }
+
+_L99:
+ set_free(redset1);
+ free(newpos1);
+ free(revpos);
+ return success;
+}
+
+
+dd_boolean dd_ExistsRestrictedFace(dd_MatrixPtr M, dd_rowset R, dd_rowset S, dd_ErrorType *err)
+/* 0.94 */
+{
+/* This function checkes if there is a point that satifies all the constraints of
+the matrix M (interpreted as an H-representation) with additional equality contraints
+specified by R and additional strict inequality constraints specified by S.
+The set S is supposed to be disjoint from both R and M->linset. When it is not,
+the set S will be considered as S\(R U M->linset).
+*/
+ dd_boolean answer=dd_FALSE;
+ dd_LPPtr lp=NULL;
+
+/*
+ printf("\n--- ERF ---\n");
+ printf("R = "); set_write(R);
+ printf("S = "); set_write(S);
+*/
+
+ lp=dd_Matrix2Feasibility2(M, R, S, err);
+
+ if (*err!=dd_NoError) goto _L99;
+
+/* Solve the LP by cdd LP solver. */
+ dd_LPSolve(lp, dd_DualSimplex, err); /* Solve the LP */
+ if (*err!=dd_NoError) goto _L99;
+ if (lp->LPS==dd_Optimal && dd_Positive(lp->optvalue)) {
+ answer=dd_TRUE;
+ }
+
+ dd_FreeLPData(lp);
+_L99:
+ return answer;
+}
+
+dd_boolean dd_ExistsRestrictedFace2(dd_MatrixPtr M, dd_rowset R, dd_rowset S, dd_LPSolutionPtr *lps, dd_ErrorType *err)
+/* 0.94 */
+{
+/* This function checkes if there is a point that satifies all the constraints of
+the matrix M (interpreted as an H-representation) with additional equality contraints
+specified by R and additional strict inequality constraints specified by S.
+The set S is supposed to be disjoint from both R and M->linset. When it is not,
+the set S will be considered as S\(R U M->linset).
+
+This function returns a certificate of the answer in terms of the associated LP solutions.
+*/
+ dd_boolean answer=dd_FALSE;
+ dd_LPPtr lp=NULL;
+
+/*
+ printf("\n--- ERF ---\n");
+ printf("R = "); set_write(R);
+ printf("S = "); set_write(S);
+*/
+
+ lp=dd_Matrix2Feasibility2(M, R, S, err);
+
+ if (*err!=dd_NoError) goto _L99;
+
+/* Solve the LP by cdd LP solver. */
+ dd_LPSolve(lp, dd_DualSimplex, err); /* Solve the LP */
+ if (*err!=dd_NoError) goto _L99;
+ if (lp->LPS==dd_Optimal && dd_Positive(lp->optvalue)) {
+ answer=dd_TRUE;
+ }
+
+
+ (*lps)=dd_CopyLPSolution(lp);
+ dd_FreeLPData(lp);
+_L99:
+ return answer;
+}
+
+dd_boolean dd_FindRelativeInterior(dd_MatrixPtr M, dd_rowset *ImL, dd_rowset *Lbasis, dd_LPSolutionPtr *lps, dd_ErrorType *err)
+/* 0.94 */
+{
+/* This function computes a point in the relative interior of the H-polyhedron given by M.
+Even the representation is V-representation, it simply interprete M as H-representation.
+lps returns the result of solving an LP whose solution is a relative interior point.
+ImL returns all row indices of M that are implicit linearities, i.e. their inqualities
+are satisfied by equality by all points in the polyhedron. Lbasis returns a row basis
+of the submatrix of M consisting of all linearities and implicit linearities. This means
+that the dimension of the polyhedron is M->colsize - set_card(Lbasis) -1.
+*/
+
+ dd_rowset S;
+ dd_colset T, Lbasiscols;
+ dd_boolean success=dd_FALSE;
+ dd_rowrange i;
+ dd_colrange rank;
+
+
+ *ImL=dd_ImplicitLinearityRows(M, err);
+
+ if (*err!=dd_NoError) goto _L99;
+
+ set_initialize(&S, M->rowsize); /* the empty set */
+ for (i=1; i <=M->rowsize; i++) {
+ if (!set_member(i, M->linset) && !set_member(i, *ImL)){
+ set_addelem(S, i); /* all nonlinearity rows go to S */
+ }
+ }
+ if (dd_ExistsRestrictedFace2(M, *ImL, S, lps, err)){
+ /* printf("a relative interior point found\n"); */
+ success=dd_TRUE;
+ }
+
+ set_initialize(&T, M->colsize); /* empty set */
+ rank=dd_MatrixRank(M,S,T,Lbasis,&Lbasiscols); /* the rank of the linearity submatrix of M. */
+
+ set_free(S);
+ set_free(T);
+ set_free(Lbasiscols);
+
+_L99:
+ return success;
+}
+
+
+dd_rowrange dd_RayShooting(dd_MatrixPtr M, dd_Arow p, dd_Arow r)
+{
+/* 092, find the first inequality "hit" by a ray from an intpt. */
+ dd_rowrange imin=-1,i,m;
+ dd_colrange j, d;
+ dd_Arow vecmin, vec;
+ mytype min,t1,t2,alpha, t1min;
+ dd_boolean started=dd_FALSE;
+ dd_boolean localdebug=dd_FALSE;
+
+ m=M->rowsize;
+ d=M->colsize;
+ if (!dd_Equal(dd_one, p[0])){
+ fprintf(stderr, "Warning: RayShooting is called with a point with first coordinate not 1.\n");
+ dd_set(p[0],dd_one);
+ }
+ if (!dd_EqualToZero(r[0])){
+ fprintf(stderr, "Warning: RayShooting is called with a direction with first coordinate not 0.\n");
+ dd_set(r[0],dd_purezero);
+ }
+
+ dd_init(alpha); dd_init(min); dd_init(t1); dd_init(t2); dd_init(t1min);
+ dd_InitializeArow(d,&vecmin);
+ dd_InitializeArow(d,&vec);
+
+ for (i=1; i<=m; i++){
+ dd_InnerProduct(t1, d, M->matrix[i-1], p);
+ if (dd_Positive(t1)) {
+ dd_InnerProduct(t2, d, M->matrix[i-1], r);
+ dd_div(alpha, t2, t1);
+ if (!started){
+ imin=i; dd_set(min, alpha);
+ dd_set(t1min, t1); /* store the denominator. */
+ started=dd_TRUE;
+ if (localdebug) {
+ fprintf(stderr," Level 1: imin = %ld and min = ", imin);
+ dd_WriteNumber(stderr, min);
+ fprintf(stderr,"\n");
+ }
+ } else {
+ if (dd_Smaller(alpha, min)){
+ imin=i; dd_set(min, alpha);
+ dd_set(t1min, t1); /* store the denominator. */
+ if (localdebug) {
+ fprintf(stderr," Level 2: imin = %ld and min = ", imin);
+ dd_WriteNumber(stderr, min);
+ fprintf(stderr,"\n");
+ }
+ } else {
+ if (dd_Equal(alpha, min)) { /* tie break */
+ for (j=1; j<= d; j++){
+ dd_div(vecmin[j-1], M->matrix[imin-1][j-1], t1min);
+ dd_div(vec[j-1], M->matrix[i-1][j-1], t1);
+ }
+ if (dd_LexSmaller(vec,vecmin, d)){
+ imin=i; dd_set(min, alpha);
+ dd_set(t1min, t1); /* store the denominator. */
+ if (localdebug) {
+ fprintf(stderr," Level 3: imin = %ld and min = ", imin);
+ dd_WriteNumber(stderr, min);
+ fprintf(stderr,"\n");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ dd_clear(alpha); dd_clear(min); dd_clear(t1); dd_clear(t2); dd_clear(t1min);
+ dd_FreeArow(d, vecmin);
+ dd_FreeArow(d, vec);
+ return imin;
+}
+
+#ifdef GMPRATIONAL
+void dd_BasisStatusMaximize(dd_rowrange m_size,dd_colrange d_size,
+ dd_Amatrix A,dd_Bmatrix T,dd_rowset equalityset,
+ dd_rowrange objrow,dd_colrange rhscol,ddf_LPStatusType LPS,
+ mytype *optvalue,dd_Arow sol,dd_Arow dsol,dd_rowset posset, ddf_colindex nbindex,
+ ddf_rowrange re,ddf_colrange se, dd_colrange *nse, long *pivots, int *found, int *LPScorrect)
+/* This is just to check whether the status LPS of the basis given by
+nbindex with extra certificates se or re is correct. It is done
+by recomputing the basis inverse matrix T. It does not solve the LP
+when the status *LPS is undecided. Thus the input is
+m_size, d_size, A, equalityset, LPS, nbindex, re and se.
+Other values will be recomputed from scratch.
+
+The main purpose of the function is to verify the correctness
+of the result of floating point computation with the GMP rational
+arithmetics.
+*/
+{
+ long pivots0,pivots1,fbasisrank;
+ dd_rowrange i,is;
+ dd_colrange s,senew,j;
+ static dd_rowindex bflag;
+ static long mlast=0;
+ static dd_rowindex OrderVector; /* the permutation vector to store a preordered row indices */
+ unsigned int rseed=1;
+ mytype val;
+ dd_colindex nbtemp;
+ dd_LPStatusType ddlps;
+ dd_boolean localdebug=dd_FALSE;
+
+ if (dd_debug) localdebug=dd_debug;
+ if (localdebug){
+ printf("\nEvaluating dd_BasisStatusMaximize:\n");
+ }
+ dd_init(val);
+ nbtemp=(long *) calloc(d_size+1,sizeof(long));
+ for (i=0; i<= 4; i++) pivots[i]=0;
+ if (bflag==NULL || mlast!=m_size){
+ if (mlast!=m_size && mlast>0) {
+ free(bflag); /* called previously with different m_size */
+ free(OrderVector);
+ }
+ bflag=(long *) calloc(m_size+1,sizeof(long));
+ OrderVector=(long *)calloc(m_size+1,sizeof(long));
+ /* initialize only for the first time or when a larger space is needed */
+ mlast=m_size;
+ }
+
+ /* Initializing control variables. */
+ dd_ComputeRowOrderVector2(m_size,d_size,A,OrderVector,dd_MinIndex,rseed);
+
+ pivots1=0;
+
+ dd_ResetTableau(m_size,d_size,T,nbtemp,bflag,objrow,rhscol);
+
+ if (localdebug){
+ printf("\nnbindex:");
+ for (j=1; j<=d_size; j++) printf(" %ld", nbindex[j]);
+ printf("\n");
+ printf("re = %ld, se=%ld\n", re, se);
+ }
+
+ is=nbindex[se];
+ if (localdebug) printf("se=%ld, is=%ld\n", se, is);
+
+ fbasisrank=d_size-1;
+ for (j=1; j<=d_size; j++){
+ if (nbindex[j]<0) fbasisrank=fbasisrank-1;
+ /* fbasisrank=the basis rank computed by floating-point */
+ }
+
+ if (fbasisrank<d_size-1) {
+ if (localdebug) {
+ printf("d_size = %ld, the size of basis = %ld\n", d_size, fbasisrank);
+ printf("dd_BasisStatusMaximize: the size of basis is smaller than d-1.\nIt is safer to run the LP solver with GMP\n");
+ }
+ *found=dd_FALSE;
+ goto _L99;
+ /* Suspicious case. Rerun the LP solver with GMP. */
+ }
+
+
+
+ dd_FindLPBasis2(m_size,d_size,A,T,OrderVector, equalityset,nbindex,bflag,
+ objrow,rhscol,&s,found,&pivots0);
+
+/* set up the new se column and corresponding variable */
+ senew=bflag[is];
+ is=nbindex[senew];
+ if (localdebug) printf("new se=%ld, is=%ld\n", senew, is);
+
+ pivots[4]=pivots0; /*GMP postopt pivots */
+ dd_statBSpivots+=pivots0;
+
+ if (!(*found)){
+ if (localdebug) {
+ printf("dd_BasisStatusMaximize: a specified basis DOES NOT exist.\n");
+ }
+
+ goto _L99;
+ /* No speficied LP basis is found. */
+ }
+
+ if (localdebug) {
+ printf("dd_BasisStatusMaximize: a specified basis exists.\n");
+ if (m_size <=100 && d_size <=30)
+ dd_WriteTableau(stdout,m_size,d_size,A,T,nbindex,bflag);
+ }
+
+ /* Check whether a recomputed basis is of the type specified by LPS */
+ *LPScorrect=dd_TRUE;
+ switch (LPS){
+ case dd_Optimal:
+ for (i=1; i<=m_size; i++) {
+ if (i!=objrow && bflag[i]==-1) { /* i is a basic variable */
+ dd_TableauEntry(&val,m_size,d_size,A,T,i,rhscol);
+ if (dd_Negative(val)) {
+ if (localdebug) printf("RHS entry for %ld is negative\n", i);
+ *LPScorrect=dd_FALSE;
+ break;
+ }
+ } else if (bflag[i] >0) { /* i is nonbasic variable */
+ dd_TableauEntry(&val,m_size,d_size,A,T,objrow,bflag[i]);
+ if (dd_Positive(val)) {
+ if (localdebug) printf("Reduced cost entry for %ld is positive\n", i);
+ *LPScorrect=dd_FALSE;
+ break;
+ }
+ }
+ };
+ break;
+ case dd_Inconsistent:
+ for (j=1; j<=d_size; j++){
+ dd_TableauEntry(&val,m_size,d_size,A,T,re,j);
+ if (j==rhscol){
+ if (dd_Nonnegative(val)){
+ if (localdebug) printf("RHS entry for %ld is nonnegative\n", re);
+ *LPScorrect=dd_FALSE;
+ break;
+ }
+ } else if (dd_Positive(val)){
+ if (localdebug) printf("the row entry for(%ld, %ld) is positive\n", re, j);
+ *LPScorrect=dd_FALSE;
+ break;
+ }
+ };
+ break;
+ case dd_DualInconsistent:
+ for (i=1; i<=m_size; i++){
+ dd_TableauEntry(&val,m_size,d_size,A,T,i,bflag[is]);
+ if (i==objrow){
+ if (dd_Nonpositive(val)){
+ if (localdebug) printf("Reduced cost entry for %ld is nonpositive\n", bflag[is]);
+ *LPScorrect=dd_FALSE;
+ break;
+ }
+ } else if (dd_Negative(val)){
+ if (localdebug) printf("the column entry for(%ld, %ld) is positive\n", i, bflag[is]);
+ *LPScorrect=dd_FALSE;
+ break;
+ }
+ };
+ break;
+;
+ default: break;
+ }
+
+ ddlps=LPSf2LPS(LPS);
+
+ dd_SetSolutions(m_size,d_size,A,T,
+ objrow,rhscol,ddlps,optvalue,sol,dsol,posset,nbindex,re,senew,bflag);
+ *nse=senew;
+
+
+_L99:
+ dd_clear(val);
+ free(nbtemp);
+}
+
+void dd_BasisStatusMinimize(dd_rowrange m_size,dd_colrange d_size,
+ dd_Amatrix A,dd_Bmatrix T,dd_rowset equalityset,
+ dd_rowrange objrow,dd_colrange rhscol,ddf_LPStatusType LPS,
+ mytype *optvalue,dd_Arow sol,dd_Arow dsol, dd_rowset posset, ddf_colindex nbindex,
+ ddf_rowrange re,ddf_colrange se,dd_colrange *nse,long *pivots, int *found, int *LPScorrect)
+{
+ dd_colrange j;
+
+ for (j=1; j<=d_size; j++) dd_neg(A[objrow-1][j-1],A[objrow-1][j-1]);
+ dd_BasisStatusMaximize(m_size,d_size,A,T,equalityset, objrow,rhscol,
+ LPS,optvalue,sol,dsol,posset,nbindex,re,se,nse,pivots,found,LPScorrect);
+ dd_neg(*optvalue,*optvalue);
+ for (j=1; j<=d_size; j++){
+ if (LPS!=dd_Inconsistent) {
+ /* Inconsistent certificate stays valid for minimization, 0.94e */
+ dd_neg(dsol[j-1],dsol[j-1]);
+ }
+ dd_neg(A[objrow-1][j-1],A[objrow-1][j-1]);
+ }
+}
+#endif
+
+/* end of cddlp.c */
+
diff --git a/third_party/cddlib/lib-src/cddmp.c b/third_party/cddlib/lib-src/cddmp.c
new file mode 100644
index 0000000..fe04849
--- /dev/null
+++ b/third_party/cddlib/lib-src/cddmp.c
@@ -0,0 +1,185 @@
+/* cddmp.c (cddlib arithmetic operations using gmp)
+ written by Komei Fukuda, fukuda@math.ethz.ch
+ Version 0.94h, April 30, 2015
+*/
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "setoper.h" /* set operation library header (Ver. March 16,1995 or later) */
+#include "cdd.h"
+
+void dd_set_global_constants()
+{
+ dd_init(dd_zero);
+ dd_init(dd_minuszero);
+ dd_init(dd_one);
+ dd_init(dd_minusone);
+ dd_init(dd_purezero);
+
+ time(&dd_statStartTime); /* cddlib starting time */
+ dd_statBApivots=0; /* basis finding pivots */
+ dd_statCCpivots=0; /* criss-cross pivots */
+ dd_statDS1pivots=0; /* phase 1 pivots */
+ dd_statDS2pivots=0; /* phase 2 pivots */
+ dd_statACpivots=0; /* anticycling (cc) pivots */
+
+ dd_choiceLPSolverDefault=dd_DualSimplex; /* Default LP solver Algorithm */
+ dd_choiceRedcheckAlgorithm=dd_DualSimplex; /* Redundancy Checking Algorithm */
+ dd_choiceLexicoPivotQ=dd_TRUE; /* whether to use the lexicographic pivot */
+
+#if defined GMPRATIONAL
+ dd_statBSpivots=0; /* basis status checking pivots */
+ mpq_set_ui(dd_zero,0U,1U);
+ mpq_set_ui(dd_purezero,0U,1U);
+ mpq_set_ui(dd_one,1U,1U);
+ mpq_set_si(dd_minusone,-1L,1U);
+ ddf_set_global_constants();
+#elif defined GMPFLOAT
+ mpf_set_d(dd_zero,dd_almostzero);
+ mpf_set_ui(dd_purezero,0U);
+ mpf_set_ui(dd_one,1U);
+ mpf_set_si(dd_minusone,-1L,1U);
+#else
+ dd_zero[0]= dd_almostzero; /*real zero */
+ dd_purezero[0]= 0.0;
+ dd_one[0]= 1L;
+ dd_minusone[0]= -1L;
+#endif
+ dd_neg(dd_minuszero,dd_zero);
+}
+
+void dd_free_global_constants()
+{
+ dd_clear(dd_zero);
+ dd_clear(dd_minuszero);
+ dd_clear(dd_one);
+ dd_clear(dd_minusone);
+ dd_clear(dd_purezero);
+
+ time(&dd_statStartTime); /* cddlib starting time */
+ dd_statBApivots=0; /* basis finding pivots */
+ dd_statCCpivots=0; /* criss-cross pivots */
+ dd_statDS1pivots=0; /* phase 1 pivots */
+ dd_statDS2pivots=0; /* phase 2 pivots */
+ dd_statACpivots=0; /* anticycling (cc) pivots */
+
+ dd_choiceLPSolverDefault=dd_DualSimplex; /* Default LP solver Algorithm */
+ dd_choiceRedcheckAlgorithm=dd_DualSimplex; /* Redundancy Checking Algorithm */
+ dd_choiceLexicoPivotQ=dd_TRUE; /* whether to use the lexicographic pivot */
+
+#if defined GMPRATIONAL
+ dd_statBSpivots=0; /* basis status checking pivots */
+ ddf_free_global_constants();
+#endif
+}
+
+
+#if defined GMPRATIONAL
+void ddd_mpq_set_si(mytype a,signed long b)
+{
+ mpz_t nz, dz;
+
+ mpz_init(nz); mpz_init(dz);
+
+ mpz_set_si(nz, b);
+ mpz_set_ui(dz, 1U);
+ mpq_set_num(a, nz);
+ mpq_set_den(a, dz);
+ mpz_clear(nz); mpz_clear(dz);
+}
+#endif
+
+#if defined dd_CDOUBLE
+void ddd_init(mytype a)
+{
+ a[0]=0L;
+}
+
+void ddd_clear(mytype a)
+{
+ /* a[0]=0L; */
+}
+
+void ddd_set(mytype a,mytype b)
+{
+ a[0]=b[0];
+}
+
+void ddd_set_d(mytype a,double b)
+{
+ a[0]=b;
+}
+
+void ddd_set_si(mytype a,signed long b)
+{
+ a[0]=(double)b;
+}
+
+void ddd_set_si2(mytype a,signed long b, unsigned long c)
+{
+ a[0]=(double)b/(double)c;
+}
+
+void ddd_add(mytype a,mytype b,mytype c)
+{
+ a[0]=b[0]+c[0];
+}
+
+void ddd_sub(mytype a,mytype b,mytype c)
+{
+ a[0]=b[0]-c[0];
+}
+
+void ddd_mul(mytype a,mytype b,mytype c)
+{
+ a[0]=b[0]*c[0];
+}
+
+void ddd_div(mytype a,mytype b,mytype c)
+{
+ a[0]=b[0]/c[0];
+}
+
+void ddd_neg(mytype a,mytype b)
+{
+ a[0]=-b[0];
+}
+
+void ddd_inv(mytype a,mytype b)
+{
+ a[0]=1/b[0];
+}
+
+int ddd_cmp(mytype a,mytype b)
+{
+ if (a[0]-b[0]>0) return 1;
+ else if (a[0]-b[0]>=0) return 0;
+ else return -1;
+}
+
+int ddd_sgn(mytype a)
+{
+ if (a[0]>0) return 1;
+ else if (a[0]>=0) return 0;
+ else return -1;
+}
+
+double ddd_get_d(mytype a)
+{
+ return a[0];
+}
+#endif
+
+/* end of cddmp.h */
diff --git a/third_party/cddlib/lib-src/cddmp.h b/third_party/cddlib/lib-src/cddmp.h
new file mode 100644
index 0000000..1ab69b0
--- /dev/null
+++ b/third_party/cddlib/lib-src/cddmp.h
@@ -0,0 +1,127 @@
+/* cddmp.h (cddlib arithmetic operations using gmp)
+ written by Komei Fukuda, fukuda@math.ethz.ch
+ Version 0.94h, April 30, 2015
+*/
+
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __CDDMP_H
+#define __CDDMP_H
+#endif /* __CDDMP_H */
+
+/**********************************/
+/* MACROS */
+/* dependent on mp implementation */
+/**********************************/
+
+#if defined GMPRATIONAL
+ #include "gmp.h"
+ #define dd_ARITHMETIC "GMP rational"
+ #define dd_init(a) mpq_init(a)
+ #define dd_clear(a) mpq_clear(a)
+ #define dd_set(a, b) mpq_set(a,b)
+ #define dd_set_si(a, b) ddd_mpq_set_si(a,b) /* defined in cddgmp.c */
+ #define dd_set_si2(a, b, c) mpq_set_si(a,b,c) /* gmp 3.1 or higher */
+ #define dd_add(a, b, c) mpq_add(a,b,c)
+ #define dd_sub(a, b, c) mpq_sub(a,b,c)
+ #define dd_mul(a, b, c) mpq_mul(a,b,c)
+ #define dd_div(a, b, c) mpq_div(a,b,c)
+ #define dd_neg(a, b) mpq_neg(a,b)
+ #define dd_inv(a, b) mpq_inv(a,b)
+ #define dd_cmp(a, b) mpq_cmp(a,b)
+ /* returns pos if a>b, 0 if a=b, negative if a<b */
+ #define dd_sgn(a) mpq_sgn(a)
+ /* returns nonzero if equal. much faster than mpq_cmp. */
+ #define dd_get_d(a) mpq_get_d(a)
+#elif defined GMPFLOAT
+ #include "gmp.h"
+ #define dd_ARITHMETIC "GMP float"
+ #define dd_init(a) mpf_init(a)
+ #define dd_clear(a) mpf_clear(a)
+ #define dd_set(a, b) mpf_set(a,b)
+ #define dd_set_d(a, b) mpf_set_d(a,b)
+ #define dd_set_si(a, b) mpf_set_si(a,b)
+ #define dd_set_si2(a, b, c) mpf_set_si(a,b,c) /* gmp 3.1 or higher */
+ #define dd_add(a, b, c) mpf_add(a,b,c)
+ #define dd_sub(a, b, c) mpf_sub(a,b,c)
+ #define dd_mul(a, b, c) mpf_mul(a,b,c)
+ #define dd_div(a, b, c) mpf_div(a,b,c)
+ #define dd_neg(a, b) mpf_neg(a,b)
+ #define dd_inv(a, b) mpf_inv(a,b)
+ #define dd_cmp(a, b) mpf_cmp(a,b)
+ /* returns pos if a>b, 0 if a=b, negative if a<b */
+ #define dd_sgn(a) mpf_sgn(a)
+ #define dd_get_d(a) mpf_get_d(a)
+#else /* built-in C double */
+ #define dd_ARITHMETIC "C double"
+ #define dd_CDOUBLE
+ #define dd_init(a) ddd_init(a)
+ #define dd_clear(a) ddd_clear(a)
+ #define dd_set(a, b) ddd_set(a,b)
+ #define dd_set_si(a, b) ddd_set_si(a,b)
+ #define dd_set_si2(a, b, c) ddd_set_si2(a,b,c)
+ #define dd_set_d(a, b) ddd_set_d(a,b)
+ #define dd_add(a, b, c) ddd_add(a,b,c)
+ #define dd_sub(a, b, c) ddd_sub(a,b,c)
+ #define dd_mul(a, b, c) ddd_mul(a,b,c)
+ #define dd_div(a, b, c) ddd_div(a,b,c)
+ #define dd_neg(a, b) ddd_neg(a,b)
+ #define dd_inv(a, b) ddd_inv(a,b)
+ #define dd_cmp(a, b) ddd_cmp(a,b)
+ /* returns pos if a>b, 0 if a=b, negative if a<b */
+ #define dd_sgn(a) ddd_sgn(a)
+ #define dd_get_d(a) ddd_get_d(a)
+#endif
+
+
+#if defined GMPRATIONAL
+ typedef mpq_t mytype;
+#elif defined GMPFLOAT
+ typedef mpf_t mytype;
+#else /* built-in C double */
+ typedef double mytype[1];
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void ddd_mpq_set_si(mytype,signed long);
+void ddd_init(mytype);
+void ddd_clear(mytype);
+void ddd_set(mytype,mytype);
+void ddd_set_d(mytype,double);
+void ddd_set_si(mytype,signed long);
+void ddd_set_si2(mytype,signed long, unsigned long);
+void ddd_add(mytype,mytype,mytype);
+void ddd_sub(mytype,mytype,mytype);
+void ddd_mul(mytype,mytype,mytype);
+void ddd_div(mytype,mytype,mytype);
+void ddd_neg(mytype,mytype);
+void ddd_inv(mytype,mytype);
+int ddd_cmp(mytype,mytype);
+int ddd_sgn(mytype);
+double ddd_get_d(mytype);
+void ddd_mpq_set_si(mytype,signed long);
+
+void dd_set_global_constants(void);
+void dd_free_global_constants(void); /* 094d */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* end of cddmp.h */
diff --git a/third_party/cddlib/lib-src/cddproj.c b/third_party/cddlib/lib-src/cddproj.c
new file mode 100644
index 0000000..2ef7e7a
--- /dev/null
+++ b/third_party/cddlib/lib-src/cddproj.c
@@ -0,0 +1,235 @@
+/* cddproj.c: Polyhedral Projections in cddlib
+ written by Komei Fukuda, fukuda@cs.mcgill.ca
+ Version 0.94, Aug. 4, 2005
+*/
+
+/* cddlib : C-library of the double description method for
+ computing all vertices and extreme rays of the polyhedron
+ P= {x : b - A x >= 0}.
+ Please read COPYING (GNU General Public Licence) and
+ the manual cddlibman.tex for detail.
+*/
+
+#include "setoper.h" /* set operation library header (Ver. June 1, 2000 or later) */
+#include "cdd.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+
+dd_MatrixPtr dd_BlockElimination(dd_MatrixPtr M, dd_colset delset, dd_ErrorType *error)
+/* Eliminate the variables (columns) delset by
+ the Block Elimination with dd_DoubleDescription algorithm.
+
+ Given (where y is to be eliminated):
+ c1 + A1 x + B1 y >= 0
+ c2 + A2 x + B2 y = 0
+
+ 1. First construct the dual system: z1^T B1 + z2^T B2 = 0, z1 >= 0.
+ 2. Compute the generators of the dual.
+ 3. Then take the linear combination of the original system with each generator.
+ 4. Remove redundant inequalies.
+
+*/
+{
+ dd_MatrixPtr Mdual=NULL, Mproj=NULL, Gdual=NULL;
+ dd_rowrange i,h,m,mproj,mdual,linsize;
+ dd_colrange j,k,d,dproj,ddual,delsize;
+ dd_colindex delindex;
+ mytype temp,prod;
+ dd_PolyhedraPtr dualpoly;
+ dd_ErrorType err=dd_NoError;
+ dd_boolean localdebug=dd_FALSE;
+
+ *error=dd_NoError;
+ m= M->rowsize;
+ d= M->colsize;
+ delindex=(long*)calloc(d+1,sizeof(long));
+ dd_init(temp);
+ dd_init(prod);
+
+ k=0; delsize=0;
+ for (j=1; j<=d; j++){
+ if (set_member(j, delset)){
+ k++; delsize++;
+ delindex[k]=j; /* stores the kth deletion column index */
+ }
+ }
+ if (localdebug) dd_WriteMatrix(stdout, M);
+
+ linsize=set_card(M->linset);
+ ddual=m+1;
+ mdual=delsize + m - linsize; /* #equalitions + dimension of z1 */
+
+ /* setup the dual matrix */
+ Mdual=dd_CreateMatrix(mdual, ddual);
+ Mdual->representation=dd_Inequality;
+ for (i = 1; i <= delsize; i++){
+ set_addelem(Mdual->linset,i); /* equality */
+ for (j = 1; j <= m; j++) {
+ dd_set(Mdual->matrix[i-1][j], M->matrix[j-1][delindex[i]-1]);
+ }
+ }
+
+ k=0;
+ for (i = 1; i <= m; i++){
+ if (!set_member(i, M->linset)){
+ /* set nonnegativity for the dual variable associated with
+ each non-linearity inequality. */
+ k++;
+ dd_set(Mdual->matrix[delsize+k-1][i], dd_one);
+ }
+ }
+
+ /* 2. Compute the generators of the dual system. */
+ dualpoly=dd_DDMatrix2Poly(Mdual, &err);
+ Gdual=dd_CopyGenerators(dualpoly);
+
+ /* 3. Take the linear combination of the original system with each generator. */
+ dproj=d-delsize;
+ mproj=Gdual->rowsize;
+ Mproj=dd_CreateMatrix(mproj, dproj);
+ Mproj->representation=dd_Inequality;
+ set_copy(Mproj->linset, Gdual->linset);
+
+ for (i=1; i<=mproj; i++){
+ k=0;
+ for (j=1; j<=d; j++){
+ if (!set_member(j, delset)){
+ k++; /* new index of the variable x_j */
+ dd_set(prod, dd_purezero);
+ for (h = 1; h <= m; h++){
+ dd_mul(temp,M->matrix[h-1][j-1],Gdual->matrix[i-1][h]);
+ dd_add(prod,prod,temp);
+ }
+ dd_set(Mproj->matrix[i-1][k-1],prod);
+ }
+ }
+ }
+ if (localdebug) printf("Size of the projection system: %ld x %ld\n", mproj, dproj);
+
+ dd_FreePolyhedra(dualpoly);
+ free(delindex);
+ dd_clear(temp);
+ dd_clear(prod);
+ dd_FreeMatrix(Mdual);
+ dd_FreeMatrix(Gdual);
+ return Mproj;
+}
+
+
+dd_MatrixPtr dd_FourierElimination(dd_MatrixPtr M,dd_ErrorType *error)
+/* Eliminate the last variable (column) from the given H-matrix using
+ the standard Fourier Elimination.
+ */
+{
+ dd_MatrixPtr Mnew=NULL;
+ dd_rowrange i,inew,ip,in,iz,m,mpos=0,mneg=0,mzero=0,mnew;
+ dd_colrange j,d,dnew;
+ dd_rowindex posrowindex, negrowindex,zerorowindex;
+ mytype temp1,temp2;
+ dd_boolean localdebug=dd_FALSE;
+
+ *error=dd_NoError;
+ m= M->rowsize;
+ d= M->colsize;
+ if (d<=1){
+ *error=dd_ColIndexOutOfRange;
+ if (localdebug) {
+ printf("The number of column is too small: %ld for Fourier's Elimination.\n",d);
+ }
+ goto _L99;
+ }
+
+ if (M->representation==dd_Generator){
+ *error=dd_NotAvailForV;
+ if (localdebug) {
+ printf("Fourier's Elimination cannot be applied to a V-polyhedron.\n");
+ }
+ goto _L99;
+ }
+
+ if (set_card(M->linset)>0){
+ *error=dd_CannotHandleLinearity;
+ if (localdebug) {
+ printf("The Fourier Elimination function does not handle equality in this version.\n");
+ }
+ goto _L99;
+ }
+
+ /* Create temporary spaces to be removed at the end of this function */
+ posrowindex=(long*)calloc(m+1,sizeof(long));
+ negrowindex=(long*)calloc(m+1,sizeof(long));
+ zerorowindex=(long*)calloc(m+1,sizeof(long));
+ dd_init(temp1);
+ dd_init(temp2);
+
+ for (i = 1; i <= m; i++) {
+ if (dd_Positive(M->matrix[i-1][d-1])){
+ mpos++;
+ posrowindex[mpos]=i;
+ } else if (dd_Negative(M->matrix[i-1][d-1])) {
+ mneg++;
+ negrowindex[mneg]=i;
+ } else {
+ mzero++;
+ zerorowindex[mzero]=i;
+ }
+ } /*of i*/
+
+ if (localdebug) {
+ dd_WriteMatrix(stdout, M);
+ printf("No of (+ - 0) rows = (%ld, %ld, %ld)\n", mpos,mneg, mzero);
+ }
+
+ /* The present code generates so many redundant inequalities and thus
+ is quite useless, except for very small examples
+ */
+ mnew=mzero+mpos*mneg; /* the total number of rows after elimination */
+ dnew=d-1;
+
+ Mnew=dd_CreateMatrix(mnew, dnew);
+ dd_CopyArow(Mnew->rowvec, M->rowvec, dnew);
+/* set_copy(Mnew->linset,M->linset); */
+ Mnew->numbtype=M->numbtype;
+ Mnew->representation=M->representation;
+ Mnew->objective=M->objective;
+
+
+ /* Copy the inequalities independent of x_d to the top of the new matrix. */
+ for (iz = 1; iz <= mzero; iz++){
+ for (j = 1; j <= dnew; j++) {
+ dd_set(Mnew->matrix[iz-1][j-1], M->matrix[zerorowindex[iz]-1][j-1]);
+ }
+ }
+
+ /* Create the new inequalities by combining x_d positive and negative ones. */
+ inew=mzero; /* the index of the last x_d zero inequality */
+ for (ip = 1; ip <= mpos; ip++){
+ for (in = 1; in <= mneg; in++){
+ inew++;
+ dd_neg(temp1, M->matrix[negrowindex[in]-1][d-1]);
+ for (j = 1; j <= dnew; j++) {
+ dd_LinearComb(temp2,M->matrix[posrowindex[ip]-1][j-1],temp1,\
+ M->matrix[negrowindex[in]-1][j-1],\
+ M->matrix[posrowindex[ip]-1][d-1]);
+ dd_set(Mnew->matrix[inew-1][j-1],temp2);
+ }
+ dd_Normalize(dnew,Mnew->matrix[inew-1]);
+ }
+ }
+
+
+ free(posrowindex);
+ free(negrowindex);
+ free(zerorowindex);
+ dd_clear(temp1);
+ dd_clear(temp2);
+
+ _L99:
+ return Mnew;
+}
+
+
+/* end of cddproj.c */
diff --git a/third_party/cddlib/lib-src/cddtypes.h b/third_party/cddlib/lib-src/cddtypes.h
new file mode 100644
index 0000000..058f83e
--- /dev/null
+++ b/third_party/cddlib/lib-src/cddtypes.h
@@ -0,0 +1,331 @@
+/* cddtypes.h: Header file for cddlib.c
+ written by Komei Fukuda, fukuda@math.ethz.ch
+ Version 0.94h, April 30, 2015
+*/
+
+/* cddlib.c : C-Implementation of the double description method for
+ computing all vertices and extreme rays of the polyhedron
+ P= {x : b - A x >= 0}.
+ Please read COPYING (GNU General Public Licence) and
+ the manual cddlibman.tex for detail.
+*/
+
+#ifndef __CDDTYPES_H
+#define __CDDTYPES_H
+#endif /* __CDDTYPES_H */
+
+#define dd_COPYRIGHT "Copyright (C) 1996, Komei Fukuda, fukuda@ifor.math.ethz.ch"
+#define dd_DDVERSION "Version 0.94g (March 23, 2012)"
+#include <time.h>
+
+#define dd_wordlenmax 1024
+#define dd_linelenmax 4096
+#define dd_datawidth 10
+#define dd_filenamelen 255
+
+#define dd_FALSE 0
+#define dd_TRUE 1
+
+typedef int dd_boolean;
+
+typedef long dd_rowrange;
+typedef long dd_colrange;
+typedef long dd_bigrange;
+
+typedef set_type dd_rowset;
+typedef set_type dd_colset;
+typedef long *dd_rowindex;
+typedef int *dd_rowflag;
+typedef long *dd_colindex;
+typedef mytype **dd_Amatrix;
+typedef mytype *dd_Arow;
+typedef set_type *dd_SetVector;
+typedef mytype **dd_Bmatrix;
+typedef set_type *dd_Aincidence;
+
+/* typedef char dd_FilenameType[dd_filenamelen]; deleted 000505*/
+typedef char dd_DataFileType[dd_filenamelen];
+typedef char dd_LineType[dd_linelenmax];
+typedef char dd_WordType[dd_wordlenmax];
+
+typedef struct dd_raydata *dd_RayPtr;
+
+typedef struct dd_raydata {
+ mytype *Ray;
+ dd_rowset ZeroSet;
+ dd_rowrange FirstInfeasIndex; /* the first inequality the ray violates */
+ dd_boolean feasible; /* flag to store the feasibility */
+ mytype ARay; /* temporary area to store some row of A*Ray */
+ dd_RayPtr Next;
+} dd_RayType;
+
+typedef struct dd_adjacencydata *dd_AdjacencyPtr;
+typedef struct dd_adjacencydata {
+ dd_RayPtr Ray1, Ray2;
+ dd_AdjacencyPtr Next;
+} dd_AdjacencyType;
+
+typedef enum {
+ dd_Combinatorial, dd_Algebraic
+} dd_AdjacencyTestType;
+
+typedef enum {
+ dd_MaxIndex, dd_MinIndex, dd_MinCutoff, dd_MaxCutoff, dd_MixCutoff,
+ dd_LexMin, dd_LexMax, dd_RandomRow
+} dd_RowOrderType;
+
+typedef enum {
+ dd_Unknown=0, dd_Real, dd_Rational, dd_Integer
+} dd_NumberType;
+
+typedef enum {
+ dd_Unspecified=0, dd_Inequality, dd_Generator
+} dd_RepresentationType;
+
+typedef enum {
+ dd_IneToGen, dd_GenToIne, dd_LPMax, dd_LPMin, dd_InteriorFind
+} dd_ConversionType;
+
+typedef enum {
+ dd_IncOff=0, dd_IncCardinality, dd_IncSet
+} dd_IncidenceOutputType;
+
+typedef enum {
+ dd_AdjOff=0, dd_AdjacencyList, dd_AdjacencyDegree
+} dd_AdjacencyOutputType;
+
+typedef enum {
+ dd_Auto, dd_SemiAuto, dd_Manual
+} dd_FileInputModeType;
+ /* Auto if a input filename is specified by command arguments */
+
+typedef enum {
+ dd_DimensionTooLarge, dd_ImproperInputFormat,
+ dd_NegativeMatrixSize, dd_EmptyVrepresentation, dd_EmptyHrepresentation, dd_EmptyRepresentation,
+ dd_IFileNotFound, dd_OFileNotOpen, dd_NoLPObjective, dd_NoRealNumberSupport,
+ dd_NotAvailForH, dd_NotAvailForV, dd_CannotHandleLinearity,
+ dd_RowIndexOutOfRange, dd_ColIndexOutOfRange,
+ dd_LPCycling, dd_NumericallyInconsistent,
+ dd_NoError
+} dd_ErrorType;
+
+typedef enum {
+ dd_InProgress, dd_AllFound, dd_RegionEmpty
+} dd_CompStatusType;
+
+/* --- LP types ---- */
+
+typedef enum {
+ dd_LPnone=0, dd_LPmax, dd_LPmin
+} dd_LPObjectiveType;
+
+typedef enum {
+ dd_CrissCross, dd_DualSimplex
+} dd_LPSolverType;
+
+typedef enum {
+ dd_LPSundecided, dd_Optimal, dd_Inconsistent, dd_DualInconsistent,
+ dd_StrucInconsistent, dd_StrucDualInconsistent,
+ dd_Unbounded, dd_DualUnbounded
+} dd_LPStatusType;
+
+typedef struct dd_lpsolution *dd_LPSolutionPtr;
+typedef struct dd_lpsolution {
+ dd_DataFileType filename;
+ dd_LPObjectiveType objective;
+ dd_LPSolverType solver;
+ dd_rowrange m;
+ dd_colrange d;
+ dd_NumberType numbtype;
+
+ dd_LPStatusType LPS; /* the current solution status */
+ mytype optvalue; /* optimal value */
+ dd_Arow sol; /* primal solution */
+ dd_Arow dsol; /* dual solution */
+ dd_colindex nbindex; /* current basis represented by nonbasic indices */
+ dd_rowrange re; /* row index as a certificate in the case of inconsistency */
+ dd_colrange se; /* col index as a certificate in the case of dual inconsistency */
+ long pivots[5];
+ /* pivots[0]=setup (to find a basis), pivots[1]=PhaseI or Criss-Cross,
+ pivots[2]=Phase II, pivots[3]=Anticycling, pivots[4]=GMP postopt. */
+ long total_pivots;
+} dd_LPSolutionType;
+
+
+typedef struct dd_lpdata *dd_LPPtr;
+typedef struct dd_lpdata {
+ dd_DataFileType filename;
+ dd_LPObjectiveType objective;
+ dd_LPSolverType solver;
+ dd_boolean Homogeneous;
+ /* The first column except for the obj row is all zeros. */
+ dd_rowrange m;
+ dd_colrange d;
+ dd_Amatrix A;
+ dd_Bmatrix B;
+ dd_rowrange objrow;
+ dd_colrange rhscol;
+ dd_NumberType numbtype;
+ dd_rowrange eqnumber; /* the number of equalities */
+ dd_rowset equalityset;
+
+ dd_boolean redcheck_extensive; /* Apply the extensive redundancy check. */
+ dd_rowrange ired; /* the row index for the redundancy checking */
+ dd_rowset redset_extra; /* a set of rows that are newly recognized redundan by the extensive search. */
+ dd_rowset redset_accum; /* the accumulated set of rows that are recognized redundant */
+ dd_rowset posset_extra; /* a set of rows that are recognized non-linearity */
+
+ dd_boolean lexicopivot; /* flag to use the lexicogrphic pivot rule (symbolic perturbation). */
+
+ dd_LPStatusType LPS; /* the current solution status */
+ dd_rowrange m_alloc; /* the allocated row size of matrix A */
+ dd_colrange d_alloc; /* the allocated col size of matrix A */
+ mytype optvalue; /* optimal value */
+ dd_Arow sol; /* primal solution */
+ dd_Arow dsol; /* dual solution */
+ dd_colindex nbindex; /* current basis represented by nonbasic indices */
+ dd_rowrange re; /* row index as a certificate in the case of inconsistency */
+ dd_colrange se; /* col index as a certificate in the case of dual inconsistency */
+ long pivots[5];
+ /* pivots[0]=setup (to find a basis), pivots[1]=PhaseI or Criss-Cross,
+ pivots[2]=Phase II, pivots[3]=Anticycling, pivots[4]=GMP postopt. */
+ long total_pivots;
+ int use_given_basis; /* switch to indicate the use of the given basis */
+ dd_colindex given_nbindex; /* given basis represented by nonbasic indices */
+ time_t starttime;
+ time_t endtime;
+} dd_LPType;
+
+
+/*---- end of LP Types ----- */
+
+
+typedef struct dd_matrixdata *dd_MatrixPtr;
+typedef struct dd_matrixdata {
+ dd_rowrange rowsize;
+ dd_rowset linset;
+ /* a subset of rows of linearity (ie, generators of
+ linearity space for V-representation, and equations
+ for H-representation. */
+ dd_colrange colsize;
+ dd_RepresentationType representation;
+ dd_NumberType numbtype;
+ dd_Amatrix matrix;
+ dd_LPObjectiveType objective;
+ dd_Arow rowvec;
+} dd_MatrixType;
+
+typedef struct dd_setfamily *dd_SetFamilyPtr;
+typedef struct dd_setfamily {
+ dd_bigrange famsize;
+ dd_bigrange setsize;
+ dd_SetVector set;
+} dd_SetFamilyType;
+
+
+typedef struct dd_nodedata *dd_NodePtr;
+typedef struct dd_nodedata {dd_bigrange key; dd_NodePtr next;} dd_NodeType;
+
+typedef struct dd_graphdata *dd_GraphPtr;
+typedef struct dd_graphdata {
+ dd_bigrange vsize;
+ dd_NodePtr *adjlist; /* should be initialized to have vsize components */
+} dd_GraphType;
+
+
+typedef struct dd_polyhedradata *dd_PolyhedraPtr;
+typedef struct dd_conedata *dd_ConePtr;
+
+typedef struct dd_polyhedradata {
+ dd_RepresentationType representation; /* given representation */
+ dd_boolean homogeneous;
+ dd_colrange d;
+ dd_rowrange m;
+ dd_Amatrix A; /* Inequality System: m times d matrix */
+ dd_NumberType numbtype;
+ dd_ConePtr child; /* pointing to the homogenized cone data */
+ dd_rowrange m_alloc; /* allocated row size of matrix A */
+ dd_colrange d_alloc; /* allocated col size of matrix A */
+ dd_Arow c; /* cost vector */
+
+ dd_rowflag EqualityIndex;
+ /* ith component is 1 if it is equality, -1 if it is strict inequality, 0 otherwise. */
+
+ dd_boolean IsEmpty; /* This is to tell whether the set is empty or not */
+
+ dd_boolean NondegAssumed;
+ dd_boolean InitBasisAtBottom;
+ dd_boolean RestrictedEnumeration;
+ dd_boolean RelaxedEnumeration;
+
+ dd_rowrange m1;
+ /* = m or m+1 (when representation=Inequality && !homogeneous)
+ This data is written after dd_ConeDataLoad is called. This
+ determines the size of Ainc. */
+ dd_boolean AincGenerated;
+ /* Indicates whether Ainc, Ared, Adom are all computed.
+ All the variables below are valid only when this is TRUE */
+ dd_colrange ldim; /* linearity dimension */
+ dd_bigrange n;
+ /* the size of output = total number of rays
+ in the computed cone + linearity dimension */
+ dd_Aincidence Ainc;
+ /* incidence of input and output */
+ dd_rowset Ared;
+ /* redundant set of rows whose removal results in a minimal system */
+ dd_rowset Adom;
+ /* dominant set of rows (those containing all rays). */
+
+} dd_PolyhedraType;
+
+
+typedef struct dd_conedata {
+ dd_RepresentationType representation;
+ dd_rowrange m;
+ dd_colrange d;
+ dd_Amatrix A;
+ dd_NumberType numbtype;
+ dd_PolyhedraPtr parent; /* pointing to the original polyhedra data */
+ dd_rowrange m_alloc; /* allocated row size of matrix A */
+ dd_colrange d_alloc; /* allocated col size of matrix A */
+
+/* CONTROL: variables to control computation */
+ dd_rowrange Iteration;
+ dd_RowOrderType HalfspaceOrder;
+ dd_RayPtr FirstRay, LastRay, ArtificialRay; /* The second description: Generator */
+ dd_RayPtr PosHead, ZeroHead, NegHead, PosLast, ZeroLast, NegLast;
+ dd_AdjacencyType **Edges; /* adjacency relation storage for iteration k */
+ unsigned int rseed; /* random seed for random row permutation */
+
+ dd_boolean ColReduced; /* flag to indicate that a column basis is computed and reduced */
+ dd_bigrange LinearityDim;
+ /* the dimension of the linearity space (when input is H), and
+ the size of a minimal system of equations to determine the space (when V). */
+ dd_colrange d_orig; /* the size d of the original matrix A */
+ dd_colindex newcol; /* the size d of the original matrix A */
+
+ dd_colindex InitialRayIndex; /* InitialRayIndex[s] (s>=1) stores the corr. row index */
+ dd_rowindex OrderVector;
+ dd_boolean RecomputeRowOrder;
+ dd_boolean PreOrderedRun;
+ dd_rowset GroundSet, EqualitySet, NonequalitySet,
+ AddedHalfspaces, WeaklyAddedHalfspaces, InitialHalfspaces;
+ long RayCount, FeasibleRayCount, WeaklyFeasibleRayCount,
+ TotalRayCount, ZeroRayCount;
+ long EdgeCount, TotalEdgeCount;
+ long count_int,count_int_good,count_int_bad; /* no. of intersection operations */
+
+ dd_Bmatrix B;
+ dd_Bmatrix Bsave; /* a copy of the dual basis inverse used to reduce the matrix A */
+
+/* STATES: variables to represent current state. */
+ dd_ErrorType Error;
+ dd_CompStatusType CompStatus; /* Computation Status */
+ time_t starttime, endtime;
+} dd_ConeType;
+
+/* Global Variables */
+extern dd_boolean dd_debug;
+extern dd_boolean dd_log;
+
+/* end of cddtypes.h */
diff --git a/third_party/cddlib/lib-src/setoper.c b/third_party/cddlib/lib-src/setoper.c
new file mode 100644
index 0000000..06f4ee5
--- /dev/null
+++ b/third_party/cddlib/lib-src/setoper.c
@@ -0,0 +1,316 @@
+/* setoper.c:
+ * A set operation library
+ * created by Komei Fukuda, Nov.14, 1993
+ * modified on December 5, 1994
+ (set_card function replaced with a better code by David Bremner)
+ * last modified on June 1, 2000
+ (set_fwrite_compl(), set_groundsize added. set_compl fixed.)
+ */
+
+#include "setoper.h"
+
+#include <limits.h>
+#define SETBITS (sizeof(long) * CHAR_BIT)
+/* (Number of chars in a long) * (number of bits in a char) */
+
+/* Definitions for optimized set_card function
+ by David Bremner bremner@cs.mcgill.ca
+*/
+
+/* Caution!!!
+ Bremner's technique depends on the assumption that CHAR_BIT == 8.
+*/
+
+#define LUTBLOCKS(set) (((set[0]-1)/SETBITS+1)*(sizeof(long)/sizeof(set_card_lut_t)))
+
+static unsigned char set_card_lut[]={
+0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
+1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
+2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
+3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
+/* End of Definitions for optimized set_card */
+
+unsigned long set_blocks(long len)
+{
+ long blocks=1L;
+
+ if (len>0) blocks=((long)len-1)/SETBITS+2;
+ return blocks;
+}
+
+void set_initialize(set_type *setp, long length)
+/* Make a set with a given bit lengths */
+{
+ long i,forlim1,len;
+
+ if (length<=0) len=1;else len=length;
+ /* if negative length is requested, it generates the shortest length */
+
+ forlim1=set_blocks(len);
+ *setp=(unsigned long *) calloc(forlim1, sizeof i);
+ (*setp)[0]=(unsigned long) len; /* size of the ground set */
+ for (i=1; i<forlim1; i++)
+ (*setp)[i]=0U;
+}
+
+void set_free(set_type set)
+/* Free the space created with the set pointer set*/
+{
+ free(set);
+}
+
+void set_emptyset(set_type set)
+/* Set set to be the emptyset */
+{
+ long i,forlim;
+
+ forlim=set_blocks(set[0])-1;
+ for (i=1; i<=forlim; i++)
+ set[i]=0U;
+}
+
+void set_copy(set_type setcopy,set_type set)
+/* Copy the set set[] to setcopy[] with setcopy[] length */
+{
+ long i,forlim;
+
+ forlim=set_blocks(setcopy[0])-1;
+ for (i=1; i<=forlim; i++)
+ setcopy[i]=set[i];
+}
+
+void set_addelem(set_type set, long elem)
+/* add elem only if it is within the set[] range */
+{
+ long i,j;
+ unsigned long change;
+ unsigned long one=1U;
+
+ if (elem<=set[0])
+ {
+ i=(elem-1)/SETBITS+1;
+ j=(elem-1)%SETBITS;
+ change= one << j; /* put 1 in jth position */
+ set[i]=set[i] | change;
+ }
+}
+
+void set_delelem(set_type set, long elem)
+/* delete elem only if it is within the set[] range */
+{
+ long i,j;
+ unsigned long change;
+ unsigned long one=1U;
+
+ if (elem<=set[0])
+ {
+ i=(elem-1)/SETBITS+1;
+ j=(elem-1)%SETBITS;
+ change=one << j; /* put 1 in jth position */
+ set[i]=(set[i] | change) ^ change;
+ }
+}
+
+void set_int(set_type set,set_type set1,set_type set2)
+/* Set intersection, assuming set1 and set2 have the same length as set */
+{
+ long i,forlim;
+
+ forlim=set_blocks(set[0])-1;
+ for (i=1;i<=forlim;i++)
+ set[i]=(set1[i] & set2[i]);
+}
+
+void set_uni(set_type set,set_type set1,set_type set2)
+/* Set union,assuming set1 and set2 have the same length as set */
+{
+ long i,forlim;
+
+ forlim=set_blocks(set[0])-1;
+ for (i=1;i<=forlim;i++)
+ set[i]=set1[i] | set2[i];
+}
+
+void set_diff(set_type set,set_type set1,set_type set2)
+/* Set difference se1/set2, assuming set1 and set2 have the same length as set */
+{
+ long i,forlim;
+
+ forlim=set_blocks(set[0])-1;
+ for (i=1;i<=forlim;i++)
+ set[i]=set1[i] & (~set2[i]);
+}
+
+void set_compl(set_type set,set_type set1)
+/* set[] will be set to the complement of set1[] */
+{
+ long i,j,l,forlim;
+ unsigned long change;
+ unsigned long one=1U;
+
+ forlim=set_blocks(set[0])-1;
+ for (i=1;i<=forlim;i++)
+ set[i]= ~set1[i];
+
+/* the following is necessary to remove 1's in the unused bits.
+ Bremner's trick counts these bits as well. (000601KF)
+*/
+ l=(set[0]-1)%SETBITS; /* the position of the last elem in the last block */
+ for (j=l+1; j<=SETBITS-1; j++){
+ change=one << j;
+ set[forlim]=(set[forlim] | change) ^ change;
+ }
+}
+
+int set_subset(set_type set1,set_type set2)
+/* Set containment check, set1 <= set2 */
+{
+ int yes=1;
+ long i,forlim;
+
+ forlim=set_blocks(set2[0])-1;
+ for (i=1;i<=forlim && yes;i++)
+ if ((set1[i] | set2[i])!=set2[i])
+ yes=0;
+ return yes;
+}
+
+int set_member(long elem, set_type set)
+/* Set membership check, elem in set */
+{
+ int yes=0;
+ long i,j;
+ unsigned long testset;
+ unsigned long one=1U;
+
+ if (elem<=set[0])
+ {
+ i=(elem-1)/SETBITS+1;
+ j=(elem-1)%SETBITS;
+ testset=set[i] | (one<<j); /* add elem to set[i] */
+ if (testset==set[i])
+ yes=1;
+ }
+ return yes;
+}
+
+/*set cardinality, modified by David Bremner bremner@cs.mcgill.ca
+ to optimize for speed.*/
+long set_card(set_type set)
+{
+ unsigned long block;
+ long car=0;
+ set_card_lut_t *p;
+
+ p=(set_card_lut_t *)&set[1];
+ for (block=0; block< LUTBLOCKS(set);block++) {
+ car+=set_card_lut[p[block]];
+ }
+ return car;
+}
+
+/* old safe cardinality code
+long set_card(set_type set)
+{
+ long elem,car=0;
+
+ for (elem=1; elem<=set[0]; elem++) {
+ if (set_member(elem,set)) car++;
+ }
+ return car;
+}
+*/
+
+long set_groundsize(set_type set)
+{
+ return set[0];
+}
+
+void set_write(set_type set)
+{
+ long elem;
+
+ for (elem=1;elem<=set[0];elem++)
+ {
+ if (set_member(elem,set))
+ printf("%ld ",elem);
+ }
+ printf("\n");
+}
+
+void set_fwrite(FILE *f,set_type set)
+{
+ long elem;
+
+ for (elem=1;elem<=set[0];elem++)
+ {
+ if (set_member(elem,set))
+ fprintf(f,"%ld ",elem);
+ }
+ fprintf(f,"\n");
+}
+
+void set_fwrite_compl(FILE *f,set_type set)
+{
+ long elem;
+
+ for (elem=1;elem<=set[0];elem++)
+ {
+ if (!set_member(elem,set))
+ fprintf(f,"%ld ",elem);
+ }
+ fprintf(f,"\n");
+}
+
+void set_binwrite(set_type set)
+{
+ int i,j;
+ long forlim;
+ unsigned long e1,e2;
+
+ printf("max element = %ld,\n",set[0]);
+ forlim=set_blocks(set[0])-1;
+ for (i=forlim;i>=1;i--)
+ {
+ e1=e2=set[i];
+ for (j=SETBITS-1;j>=0;j--)
+ {
+ e1=(e1>>j);
+ printf("%1ld",e1);
+ e1=e2-(e1<<j);
+ e2=e1;
+ }
+ printf(" ");
+ }
+ printf("\n");
+}
+
+
+void set_fbinwrite(FILE *f,set_type set)
+{
+ int i,j;
+ long forlim;
+ long e1,e2;
+
+ printf("max element = %ld,\n",set[0]);
+ forlim=set_blocks(set[0])-1;
+ for (i=forlim;i>=1;i--)
+ {
+ e1=e2=set[i];
+ for (j=SETBITS-1;j>=0;j--)
+ {
+ e1=(e1>>j);
+ fprintf(f,"%1ld",e1);
+ e1=e2-(e1<<j);
+ e2=e1;
+ }
+ fprintf(f," ");
+ }
+ fprintf(f,"\n");
+}
+
+/* End of the library: setoper.c */
diff --git a/third_party/cddlib/lib-src/setoper.h b/third_party/cddlib/lib-src/setoper.h
new file mode 100644
index 0000000..171efdb
--- /dev/null
+++ b/third_party/cddlib/lib-src/setoper.h
@@ -0,0 +1,50 @@
+/* Header file for setoper.c */
+
+/* setoper.c:
+ * A set operation library
+ * created by Komei Fukuda, Nov.14, 1993
+ * last modified on June 1, 2000
+ */
+
+#ifndef __SETOPER_H
+#define __SETOPER_H
+#endif /* __SETOPER_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef unsigned long *set_type; /* set type definition */
+
+typedef unsigned char set_card_lut_t;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+unsigned long set_blocks(long len);
+void set_initialize(set_type *setp,long len);
+void set_free(set_type set);
+void set_emptyset(set_type set);
+void set_copy(set_type setcopy,set_type set);
+void set_addelem(set_type set, long elem);
+void set_delelem(set_type set, long elem);
+void set_int(set_type set,set_type set1,set_type set2);
+void set_uni(set_type set,set_type set1,set_type set2);
+void set_diff(set_type set,set_type set1,set_type set2);
+void set_compl(set_type set,set_type set1);
+int set_subset(set_type set1,set_type set2);
+int set_member(long elem, set_type set);
+long set_card(set_type set);
+long set_groundsize(set_type set); /* output the size of the ground set */
+void set_write(set_type set);
+void set_fwrite(FILE *f,set_type set);
+void set_fwrite_compl(FILE *f,set_type set); /* write the complement */
+void set_binwrite(set_type set);
+void set_fbinwrite(FILE *f,set_type set);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/* End of File: setoper.h */
+