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(&currenttime);
+  
+  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 */
+