diff --git a/CMakeLists.txt b/CMakeLists.txt index a19e3edc920a431faf41d6ab4fcd48bdbd705a4e..2d3b4b8351fa74dc163c0eb4c9d7ea141f1954d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ option(ENABLE_ANN "Enable ANN to compute Approximate Nearest Neighbors" ON) option(ENABLE_BAMG "Enable Bamg mesh generator" ON) option(ENABLE_BFGS "Enable BFGS" ON) option(ENABLE_BLAS_LAPACK "Use BLAS/Lapack for basic linear algebra" ON) +option(ENABLE_BLOSSOM "Enable Blossom algo (based on MATCH and concorde97)" ON) option(ENABLE_CGNS "Enable CGNS mesh export" OFF) option(ENABLE_CHACO "Enable Chaco mesh partitioner" ON) option(ENABLE_DINTEGRATION "Enable discrete integration and levelsets" ON) @@ -30,7 +31,6 @@ option(ENABLE_FOURIER_MODEL "Enable Fourier geometrical models" OFF) option(ENABLE_GMM "Enable GMM linear algebra solvers" ON) option(ENABLE_GRAPHICS "Compile-in OpenGL graphics even if there is no GUI" OFF) option(ENABLE_KBIPACK "Enable Kbipack for homology solver" ON) -option(ENABLE_MATCH "Enable Minimum cost perfect matching algo" ON) option(ENABLE_MATHEX "Enable MathEx expression parser" ON) option(ENABLE_MED "Enable MED mesh and post-processing file formats" ON) option(ENABLE_MESH "Build the mesh module" ON) @@ -445,6 +445,12 @@ if(ENABLE_ANN) set_config_option(HAVE_ANN "Ann") endif(ENABLE_ANN) +if(ENABLE_BLOSSOM) + add_subdirectory(contrib/blossom) + include_directories(contrib/blossom/MATCH contrib/blossom/concorde97 + contrib/blossom/concorde97/INCLUDE) + set_config_option(HAVE_BLOSSOM "Blossom") +endif(ENABLE_BLOSSOM) if(ENABLE_CHACO) add_subdirectory(contrib/Chaco) @@ -752,20 +758,6 @@ if(ENABLE_ACIS) endif(ACIS_LIB) endif(ENABLE_ACIS) -if(ENABLE_MATCH) - find_library(MATCH_LIB blossom PATH_SUFFIXES lib) - find_library(CONCORDE_LIB concorde PATH_SUFFIXES lib) - if(MATCH_LIB AND CONCORDE_LIB) - find_path(CONCORDE_INC "concorde.h" PATH_SUFFIXES concorde97) - find_path(MATCH_INC "match.h" PATH_SUFFIXES MATCH) - if(MATCH_INC AND CONCORDE_INC) - set_config_option(HAVE_MATCH "Match") - list(APPEND EXTERNAL_LIBRARIES ${MATCH_LIB} ${CONCORDE_LIB}) - list(APPEND EXTERNAL_INCLUDES ${MATCH_INC} ${CONCORDE_INC}) - endif(MATCH_INC AND CONCORDE_INC) - endif(MATCH_LIB AND CONCORDE_LIB) -endif(ENABLE_MATCH) - if(ENABLE_OSMESA) find_library(OSMESA_LIB OSMesa) if(OSMESA_LIB) diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in index e1a831ea8d0ff3f10f022be8c2795dc8a5ed260f..30771075fba98347d1ae18c1e9db43bca4e53ec5 100644 --- a/Common/GmshConfig.h.in +++ b/Common/GmshConfig.h.in @@ -12,6 +12,7 @@ #cmakedefine HAVE_BAMG #cmakedefine HAVE_BFGS #cmakedefine HAVE_BLAS +#cmakedefine HAVE_BLOSSOM #cmakedefine HAVE_CHACO #cmakedefine HAVE_DLOPEN #cmakedefine HAVE_DINTEGRATION @@ -26,7 +27,6 @@ #cmakedefine HAVE_LIBJPEG #cmakedefine HAVE_LIBPNG #cmakedefine HAVE_LIBZ -#cmakedefine HAVE_MATCH #cmakedefine HAVE_MATHEX #cmakedefine HAVE_MED #cmakedefine HAVE_MESH diff --git a/Fltk/statisticsWindow.cpp b/Fltk/statisticsWindow.cpp index f24de26489f03bfae754657e3f2912366021c592..91800deeadef74ab628ae67f6b3e3f2325c953f4 100644 --- a/Fltk/statisticsWindow.cpp +++ b/Fltk/statisticsWindow.cpp @@ -206,6 +206,7 @@ void statisticsWindow::compute(bool elementQuality) printf("Angles = min=%g av=%g \n", minAngle, meanAngle);*/ //hack emi //Emi hack - MESH DEGREE VERTICES +#if 0 std::vector<GEntity*> entities; std::set<MEdge, Less_Edge> edges; GModel::current()->getEntities(entities); @@ -280,6 +281,7 @@ void statisticsWindow::compute(bool elementQuality) } } fclose(fp); +#endif //emi end hack int num = 0; diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp index 2ce231bbfbe443527c8b91515c0e8b1d348b6c4b..9a4f7d7ceb7f0010a5de48c7274efbebf851e6af 100644 --- a/Mesh/meshGFaceOptimize.cpp +++ b/Mesh/meshGFaceOptimize.cpp @@ -28,7 +28,7 @@ #include "PViewData.h" #endif -#if defined(HAVE_MATCH) +#if defined(HAVE_BLOSSOM) extern "C" int FAILED_NODE; extern "C" struct CCdatagroup; extern "C" int perfect_match @@ -1640,7 +1640,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1) std::set<MElement*> touched; if(CTX::instance()->mesh.algoRecombine == 1){ -#ifdef HAVE_MATCH +#if defined(HAVE_BLOSSOM) int ncount = gf->triangles.size(); if (ncount % 2 == 0) { int ecount = cubicGraph ? pairs.size() + makeGraphPeriodic.size() : pairs.size(); diff --git a/contrib/blossom/CMakeLists.txt b/contrib/blossom/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7fe702c323618320ee73a21b479c53e2b68578a --- /dev/null +++ b/contrib/blossom/CMakeLists.txt @@ -0,0 +1,117 @@ +# Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC +# concorde97/BIGGUY/bg_test.c + concorde97/BIGGUY/bigguy.c + concorde97/CUT/connect.c + concorde97/CUT/cut_st.c +# concorde97/CUT/mc_main.c + concorde97/CUT/mincut.c + concorde97/CUT/segments.c + concorde97/CUT/shrink.c + concorde97/EDGEGEN/edgegen.c +# concorde97/EDGEGEN/eg_main.c + concorde97/EDGEGEN/xnear.c +# concorde97/FMATCH/fm_main.c + concorde97/FMATCH/fmatch.c +# concorde97/KDTREE/kd_main.c + concorde97/KDTREE/kdbuild.c + concorde97/KDTREE/kdnear.c + concorde97/KDTREE/kdspan.c + concorde97/KDTREE/kdtwoopt.c +# concorde97/LINKERN/flip_ary.c +# concorde97/LINKERN/flip_bt0.c +# concorde97/LINKERN/flip_bt1.c +# concorde97/LINKERN/flip_bt2.c +# concorde97/LINKERN/flip_bt3.c +# concorde97/LINKERN/flip_bt4.c +# concorde97/LINKERN/flip_bt5.c +# concorde97/LINKERN/flip_btc.c +# concorde97/LINKERN/flip_btd.c +# concorde97/LINKERN/flip_btr.c +# concorde97/LINKERN/flip_ll0.c +# concorde97/LINKERN/flip_ll1.c +# concorde97/LINKERN/flip_ll2.c +# concorde97/LINKERN/flip_ll3.c +# concorde97/LINKERN/flip_ll4.c +# concorde97/LINKERN/flip_ll5.c +# concorde97/LINKERN/flip_ll6.c +# concorde97/LINKERN/flip_ll7.c + concorde97/LINKERN/flip_ll8.c +# concorde97/LINKERN/flip_ll9.c +# concorde97/LINKERN/flip_llA.c +# concorde97/LINKERN/flip_llB.c +# concorde97/LINKERN/flip_llC.c +# concorde97/LINKERN/flip_llD.c +# concorde97/LINKERN/flip_sg1.c +# concorde97/LINKERN/flip_sg2.c +# concorde97/LINKERN/flip_sg3.c +# concorde97/LINKERN/flip_sp1.c +# concorde97/LINKERN/flip_sp2.c +# concorde97/LINKERN/flip_try.c +# concorde97/LINKERN/flip_tw2.c +# concorde97/LINKERN/flip_two.c + concorde97/LINKERN/linkern.c +# concorde97/LINKERN/lk_main.c +# concorde97/LP/lpcplex.c + concorde97/LP/lpsolve.c + concorde97/TSP/bcontrol.c + concorde97/TSP/branch.c + concorde97/TSP/cliqhash.c + concorde97/TSP/cliqwork.c +#concorde97/TSP/concorde.c + concorde97/TSP/control.c + concorde97/TSP/cutcall.c + concorde97/TSP/cutpool.c + concorde97/TSP/edgemap.c + concorde97/TSP/ex_price.c + concorde97/TSP/generate.c +# concorde97/TSP/poolcat.c + concorde97/TSP/prob_io.c + concorde97/TSP/qsparse.c + concorde97/TSP/teething.c + concorde97/TSP/tighten.c + concorde97/TSP/tsp_lp.c + concorde97/TSP/xtour.c + concorde97/UTIL/allocrus.c + concorde97/UTIL/bgetopt.c + concorde97/UTIL/dheaps_i.c + concorde97/UTIL/edg2cyc.c + concorde97/UTIL/edgelen.c + concorde97/UTIL/fastread.c + concorde97/UTIL/genhash.c + concorde97/UTIL/getdata.c + concorde97/UTIL/priority.c + concorde97/UTIL/safe_io.c + concorde97/UTIL/sortrus.c + concorde97/UTIL/urandom.c + concorde97/UTIL/util.c + concorde97/UTIL/zeit.c + concorde97/XSTUFF/Xallcuts.c + concorde97/XSTUFF/Xblobs.c + concorde97/XSTUFF/Xblock.c + concorde97/XSTUFF/Xblossom.c + concorde97/XSTUFF/Xcclean.c + concorde97/XSTUFF/Xclique.c + concorde97/XSTUFF/Xcuthash.c + concorde97/XSTUFF/Xcutload.c + concorde97/XSTUFF/Xcuts.c + concorde97/XSTUFF/Xcututil.c + concorde97/XSTUFF/Xflow.c + concorde97/XSTUFF/Xgomhu.c + concorde97/XSTUFF/Xgraph.c + concorde97/XSTUFF/Xnecklac.c + concorde97/XSTUFF/Xnewkids.c + concorde97/XSTUFF/Xourallo.c + concorde97/XSTUFF/Xpqnew.c + concorde97/XSTUFF/Xshrink.c + concorde97/XSTUFF/Xstuff.c +# concorde97/XSTUFF/Xtest.c + MATCH/match.c MATCH/matprice.c +) + +file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +append_gmsh_src(contrib/blossom "${SRC};${HDR}") diff --git a/contrib/blossom/MATCH/00_README b/contrib/blossom/MATCH/00_README new file mode 100644 index 0000000000000000000000000000000000000000..4cbe57f37537ec09a7ba86e5d833010e03c0c390 --- /dev/null +++ b/contrib/blossom/MATCH/00_README @@ -0,0 +1,81 @@ +The file match.tar should consist of the following files: + +./MATCH/00_README this file +./MATCH/100.dat example x-y file +./MATCH/100.edge example edge-file +./MATCH/Makefile gmake Makefile +./MATCH/mat_main.c main program for blossom4 code +./MATCH/match.[ch] matching routines +./MATCH/matprice.[ch] pricing routines +./MATCH/mp_main.c main program for price4 code +./MATCH/tri_call.c program to call the triangle package + +------------------------------------------------------------ + +Installation: + +This package is an add-up to the concorde package written +by Applegate, Bixby, Chvatal and Cook and which can be +found at <http://www.concorde.com/>. + +Type 'tar xvf match.tar', the MATCH directory will be created. +Type 'cd MATCH' to get to the MATCH directory. + +To built the programs, first look at the Makefile and insert +the right compiler, compiling options and the concorde +directory (this is the directory with the concorde.a and the +concorde.h file). + +After that just type 'make' or e.g. 'make blossom4', if you +just want to get the blossom4 program. Other possibilities +are 'make price4' or 'make tri_call'. + +------------------------------------------------------------ + +Usage: + +After the programs are built, you can use them in the +following way: + +- blossom4 + Type blossom4 to see different options. + Here some standard calls: + + blossom4 -k 1000 + Calculate matching for 1000 random points. + + blossom4 -k 1000 -s 1 + Calculate matching for 1000 random points + with random seed 1. + + blossom4 -x 100.dat + Calculate matching with the points from the file + 100.dat. + + blossom4 -b -x 12345.bin -e 12345.del -5 + Calculate matching with the points from the binary + file 12345.bin, starting with the edge-set 12345.del + and working with the ATT norm. + + blossom4 -e 12345.del -B 12345.price + Calculate matching for the graph 12345.del and write + the data necessary for the pricing program to the file + 12345.price. + +- price4 + + Type price4 to see different options. + Here is a standard call: + + price4 -b -n 12345.bin -d 12345.price -o 12345.bad.edges + Calculate the bad edges for the pricing file generated + with the blossom4 call above. + +- tri_call + All the necessary information about tri_call can be found + in the header of the tri_call.c file. + +For further information about options and file-formats +see the concorde README file. + +------------------------------------------------------------ diff --git a/contrib/blossom/MATCH/100.dat b/contrib/blossom/MATCH/100.dat new file mode 100644 index 0000000000000000000000000000000000000000..64196c13ecad33aa0eea4401848b65e11704ef03 --- /dev/null +++ b/contrib/blossom/MATCH/100.dat @@ -0,0 +1,101 @@ +100 +620.000000 360.000000 +810.000000 980.000000 +850.000000 400.000000 +300.000000 730.000000 +410.000000 370.000000 +560.000000 900.000000 +250.000000 250.000000 +800.000000 850.000000 +250.000000 450.000000 +900.000000 100.000000 +550.000000 850.000000 +800.000000 580.000000 +90.000000 730.000000 +900.000000 560.000000 +480.000000 520.000000 +180.000000 140.000000 +420.000000 400.000000 +420.000000 190.000000 +230.000000 830.000000 +980.000000 890.000000 +530.000000 110.000000 +930.000000 180.000000 +130.000000 310.000000 +850.000000 510.000000 +160.000000 690.000000 +490.000000 760.000000 +340.000000 880.000000 +240.000000 480.000000 +940.000000 410.000000 +560.000000 660.000000 +170.000000 470.000000 +750.000000 520.000000 +840.000000 450.000000 +970.000000 70.000000 +120.000000 490.000000 +0.000000 740.000000 +290.000000 210.000000 +610.000000 790.000000 +510.000000 920.000000 +340.000000 610.000000 +790.000000 490.000000 +0.000000 820.000000 +350.000000 710.000000 +390.000000 900.000000 +560.000000 970.000000 +220.000000 160.000000 +710.000000 490.000000 +890.000000 790.000000 +820.000000 720.000000 +570.000000 340.000000 +800.000000 930.000000 +170.000000 550.000000 +900.000000 0.000000 +760.000000 520.000000 +530.000000 530.000000 +90.000000 40.000000 +850.000000 590.000000 +440.000000 10.000000 +760.000000 260.000000 +630.000000 50.000000 +630.000000 250.000000 +500.000000 780.000000 +690.000000 70.000000 +570.000000 740.000000 +310.000000 610.000000 +30.000000 990.000000 +390.000000 810.000000 +520.000000 750.000000 +640.000000 410.000000 +380.000000 340.000000 +950.000000 130.000000 +270.000000 510.000000 +340.000000 970.000000 +660.000000 930.000000 +800.000000 820.000000 +220.000000 80.000000 +410.000000 960.000000 +310.000000 810.000000 +540.000000 360.000000 +30.000000 150.000000 +360.000000 350.000000 +140.000000 190.000000 +580.000000 960.000000 +770.000000 340.000000 +250.000000 470.000000 +350.000000 830.000000 +460.000000 810.000000 +830.000000 550.000000 +840.000000 540.000000 +470.000000 880.000000 +530.000000 210.000000 +710.000000 160.000000 +250.000000 680.000000 +850.000000 200.000000 +230.000000 560.000000 +980.000000 300.000000 +160.000000 910.000000 +990.000000 120.000000 +670.000000 460.000000 +680.000000 790.000000 diff --git a/contrib/blossom/MATCH/100.edge b/contrib/blossom/MATCH/100.edge new file mode 100644 index 0000000000000000000000000000000000000000..dbd3a0d0b63a57e2018625b19a765ac8c4490880 --- /dev/null +++ b/contrib/blossom/MATCH/100.edge @@ -0,0 +1,287 @@ +100 286 +81 79 117 +79 15 150 +15 81 64 +79 55 125 +55 15 135 +81 22 120 +22 79 189 +15 75 72 +75 45 80 +45 15 45 +55 75 136 +45 6 95 +6 81 125 +81 45 85 +55 57 351 +57 75 231 +6 22 134 +34 22 180 +22 30 165 +30 34 54 +34 79 352 +27 30 71 +30 8 82 +8 27 32 +30 51 80 +51 34 78 +51 27 99 +27 94 81 +94 51 61 +27 71 42 +71 94 64 +94 24 148 +24 51 140 +22 8 184 +51 12 197 +12 34 242 +75 36 148 +36 45 86 +34 35 277 +35 79 591 +80 6 149 +6 36 57 +36 80 157 +69 36 158 +36 17 132 +17 69 155 +69 80 22 +17 57 181 +57 20 135 +20 17 136 +75 17 228 +57 59 194 +59 20 117 +4 69 42 +69 90 198 +90 4 200 +17 90 112 +8 71 63 +71 84 45 +84 8 20 +8 16 177 +16 71 186 +27 84 14 +80 4 54 +4 16 32 +16 80 78 +14 71 210 +16 14 134 +78 16 126 +4 78 130 +78 14 171 +8 80 149 +8 6 200 +71 64 108 +64 94 94 +29 39 226 +39 14 166 +14 29 161 +39 71 122 +24 18 157 +18 12 172 +12 24 81 +12 35 91 +94 92 122 +92 24 91 +92 18 151 +64 42 108 +42 92 104 +92 64 92 +42 3 54 +3 92 71 +39 64 30 +77 3 81 +42 77 108 +3 18 122 +41 96 184 +96 65 153 +65 41 173 +41 35 80 +12 41 127 +26 96 182 +96 18 106 +18 26 121 +12 96 193 +18 77 82 +77 26 76 +96 72 190 +72 65 311 +39 42 100 +66 25 112 +25 86 58 +86 66 70 +66 42 108 +42 25 149 +86 89 71 +89 66 106 +66 85 45 +85 77 45 +77 66 80 +25 67 32 +67 61 36 +61 25 22 +29 25 122 +42 29 216 +61 10 86 +10 86 98 +86 61 50 +10 89 85 +72 26 90 +26 43 54 +43 72 86 +85 26 51 +85 43 81 +43 89 82 +89 76 100 +76 43 63 +66 43 90 +76 38 108 +38 44 71 +44 76 150 +89 38 57 +10 38 81 +76 72 71 +44 72 220 +67 10 104 +29 67 98 +44 65 530 +20 90 100 +20 60 172 +60 90 108 +91 20 187 +59 91 136 +91 60 120 +60 49 108 +49 90 136 +91 93 146 +93 58 108 +58 91 112 +9 91 199 +91 62 92 +62 9 212 +58 60 130 +59 62 63 +59 52 275 +52 62 221 +0 60 110 +60 83 166 +83 0 151 +78 49 36 +49 0 54 +0 78 80 +78 90 150 +0 68 54 +68 78 112 +68 83 148 +83 98 156 +98 68 58 +98 46 50 +46 54 184 +54 98 157 +68 54 163 +54 78 170 +83 46 162 +58 83 81 +54 14 51 +9 70 58 +70 21 54 +21 9 85 +33 9 76 +9 52 100 +52 33 99 +21 93 82 +93 9 112 +70 33 63 +33 97 54 +97 70 41 +97 21 85 +97 95 180 +95 21 130 +83 32 130 +32 40 64 +40 83 151 +83 2 100 +2 32 51 +23 40 63 +32 23 61 +40 46 80 +93 95 164 +95 2 164 +2 93 200 +2 28 91 +28 32 108 +95 28 117 +95 19 590 +19 28 482 +83 93 161 +28 23 135 +97 19 770 +57 52 460 +40 31 50 +31 46 50 +29 63 81 +63 67 51 +46 29 227 +29 54 133 +37 63 64 +63 99 121 +99 37 70 +37 67 98 +29 11 253 +11 99 242 +99 29 177 +40 53 42 +53 31 10 +31 11 78 +29 31 236 +37 10 85 +5 44 70 +38 5 54 +37 5 121 +5 10 51 +5 82 63 +82 44 22 +5 73 104 +73 82 85 +37 73 149 +7 73 161 +73 99 141 +99 7 134 +82 1 231 +1 44 250 +73 1 158 +53 11 72 +11 87 42 +87 56 45 +56 11 51 +53 87 76 +40 87 72 +87 88 14 +88 56 51 +13 56 58 +88 13 63 +13 23 71 +28 13 155 +13 47 230 +47 56 204 +88 23 32 +40 88 71 +56 48 133 +48 11 141 +74 7 30 +99 74 124 +74 47 95 +47 7 108 +50 7 80 +7 19 184 +19 50 184 +50 73 140 +47 19 135 +47 48 99 +1 50 51 +19 1 192 +13 19 340 +74 48 102 +99 48 157 +1 65 780 diff --git a/contrib/blossom/MATCH/Makefile b/contrib/blossom/MATCH/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..47877f57efe64243996d9087bc5dea5c18b4f85d --- /dev/null +++ b/contrib/blossom/MATCH/Makefile @@ -0,0 +1,41 @@ +# Change these parameters how you want them to be + CON_PATH = ${HOME}/src/concorde97 + CC = gcc -m32 + CFLAGS = -g + +# From here nothing needs to be changed + INCDIRS = -I$(CON_PATH) + + LD = $(CC) + + LIBS = -lm + + BLOSSOM = mat_main.c match.c matprice.c + PRICE = mp_main.c matprice.c + TRI_CALL = tri_call.c + + BLOSSOMOBJS = $(BLOSSOM:.c=.o) + PRICEOBJS = $(PRICE:.c=.o) + TRI_CALLOBJS = $(TRI_CALL:.c=.o) + +all : blossom4 price4 tri_call + +blossom4 : $(BLOSSOMOBJS) + $(LD) -o $@ $(BLOSSOMOBJS) $(CON_PATH)/libconcorde.a -lm +price4 : $(PRICEOBJS) + $(LD) -o $@ $(PRICEOBJS) $(CON_PATH)/libconcorde.a -lm +tri_call : $(TRI_CALLOBJS) + $(LD) -o $@ $(TRI_CALLOBJS) -lm + +install : all + +clean : + rm -f *.o blossom4 price4 tri_call + +depend : + makedepend $(INCDIRS) $(SEQU) + +.c.o : + $(CC) $(CFLAGS) $(INCDIRS) -c $*.c + + diff --git a/contrib/blossom/MATCH/mat_main.c b/contrib/blossom/MATCH/mat_main.c new file mode 100644 index 0000000000000000000000000000000000000000..30eb3870629003e45070f113fd8fef12f600205f --- /dev/null +++ b/contrib/blossom/MATCH/mat_main.c @@ -0,0 +1,301 @@ +/************************************************************************/ +/* */ +/* ROUTINE FOR WEIGHTED PERFECT MATCHING PROBLEMS */ +/* */ +/* Written by: A. Rohe */ +/* Date: November 7, 1995 (rohe) */ +/* November 12, 1995 (rohe) */ +/* February 7, 1996 (rohe - short look at program) */ +/* July, 1996 (rohe - change from tree to forest) */ +/* October, 1996 (bico - change to concorde format) */ +/* */ +/************************************************************************/ + +#include "concorde.h" +#include "match.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + usage (char *name); +static int + parseargs (int ac, char **av); + +#else + +static void + usage (); +static int + parseargs (); + +#endif + +static int seed = 0; +static char *blossom_file = (char *) NULL; +static char *match_file = (char *) NULL; +static char *datfilename = (char *) NULL; +static char *edgefilename = (char *) NULL; +static char *edgegenfname = (char *) NULL; +static int no_frac = 0; +static int just_frac = 0; +static int use_all_trees = 0; +static int binary_in = 0; +static int tsplib_in = 0; +static int nnodes_want = 0; +static int partialprice = 0; +static int norm = CC_EUCLIDEAN; +static int no_price = 0; + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + double zero_zeit = CCutil_zeit (); + double matzeit = 0.0; + double genzeit = 0.0; + int ncount, ecount; + int *elist = (int *) NULL; + int *elen = (int *) NULL; + long l; + CCdatagroup dat, *mydat = (CCdatagroup *) NULL; + + seed = time (&l); + if (parseargs (ac, av)) + return 0; + CCutil_sprand (seed); + + if (edgefilename == (char *) NULL && datfilename == (char *) NULL && + nnodes_want == 0) { + usage (av[0]); + return 0; + } + ncount = nnodes_want; + + if (tsplib_in && datfilename != (char *) NULL) { + if (CCutil_gettsplib (datfilename, &ncount, &dat)) { + fprintf (stderr, "could not read the TSPLIB file\n"); + goto CLEANUP; + } + mydat = &dat; + norm = dat.norm; + } else if (datfilename != (char *) NULL || nnodes_want != 0) { + if (CCutil_getdata (datfilename, binary_in, norm, &ncount, &dat)) { + fprintf (stderr, "Could not create data set\n"); + goto CLEANUP; + } + mydat = &dat; + } else { + mydat = (CCdatagroup *) NULL; + } + + if (mydat) { + if (CCutil_init_dat_edgelen (mydat)) { + fprintf (stderr, "init_dat_edgelen failed\n"); + goto CLEANUP; + } + } + + if (edgefilename) { + if (CCutil_getedgelist_n (&ncount, edgefilename, &ecount, &elist, &elen)) { + fprintf (stderr, "getedgelist_n failed\n"); + goto CLEANUP; + } + } else { + CCedgegengroup plan; + int i; + + if (edgegenfname) { + if (CCedgegen_read (edgegenfname, &plan)) { + fprintf (stderr, "CCedgegen_read failed\n"); + goto CLEANUP; + } + } else { + CCedgegen_init_edgegengroup (&plan); + if ((norm & CC_NORM_BITS) != CC_KD_NORM_TYPE) { + plan.nearest = 5; + } else { + plan.quadnearest = 2; + plan.tour.nearest_count = 1; + } + } + genzeit = CCutil_zeit (); + if (CCedgegen_edges (&plan, ncount, mydat, (double *) NULL, &ecount, + &elist)) { + fprintf (stderr, "CCedgegen_edges failed\n"); + goto CLEANUP; + } + elen = CC_SAFE_MALLOC (ecount, int); + if (!elen) { + fprintf (stderr, "out of memory in main\n"); + CC_FREE (elist, int); + goto CLEANUP; + } + for (i = 0; i < ecount; i++) { + elen[i] = CCutil_dat_edgelen (elist[2*i], elist[2*i+1], mydat); + } + genzeit = CCutil_zeit () - genzeit; + } + + if (mydat != (CCdatagroup *) NULL && no_price) { + CCutil_freedatagroup (ncount, mydat); + mydat = (CCdatagroup *) NULL; + } + + printf ("ZZ nnodes: %d seed: %d\n", ncount, seed); fflush (stdout); + + if (perfect_match (ncount, mydat, ecount, &elist, &elen, + blossom_file, match_file, just_frac, no_frac, + use_all_trees, partialprice, &matzeit)) { + fprintf (stderr, "perfect_match failed\n"); + goto CLEANUP; + } + +CLEANUP: + + if (mydat != (CCdatagroup *) NULL) { + CCutil_freedatagroup (ncount, mydat); + } + + printf ("\nZZ Running Time: %.2f seconds (Edgegen %.2f, Matching %.2f)\n", + genzeit + matzeit, genzeit, matzeit); + printf ("ZZ Total Time: %.2f Seconds (includes IO and checking)\n", + CCutil_zeit () - zero_zeit); + fflush (stdout); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "bB:dD:e:fjk:lp:Ps:tTx:w:0123456789")) != EOF) + switch (c) { + case 'b': + binary_in = 1; + break; + case 'B': + blossom_file = CCutil_bix_optarg; + break; + case 'd': + use_all_trees = 2; + break; + case 'D': + edgegenfname = CCutil_bix_optarg; + break; + case 'e': + edgefilename = CCutil_bix_optarg; + break; + case 'f': + just_frac = 1; + break; + case 'j': + no_frac = 1; + break; + case 'k': + nnodes_want = atoi (CCutil_bix_optarg); + break; + case 'p': + partialprice = atoi (CCutil_bix_optarg); + break; + case 'P': + no_price = 1; + break; + case 's': + seed = atoi (CCutil_bix_optarg); + break; + case 't': + use_all_trees = 1; + break; + case 'T': + tsplib_in = 1; + break; + case 'w': + match_file = CCutil_bix_optarg; + break; + case 'x': + datfilename = CCutil_bix_optarg; + break; + case '0': + norm = CC_MAXNORM; + break; + case '1': + norm = CC_EUCLIDEAN_CEIL; + break; + case '2': + norm = CC_EUCLIDEAN; + break; + case '3': + norm = CC_EUCLIDEAN_3D; + break; + case '4': + norm = CC_IBM; + break; + case '5': + norm = CC_ATT; + break; + case '6': + norm = CC_GEOGRAPHIC; + break; + case '7': + norm = CC_MATRIXNORM; + break; + case '8': + norm = CC_DSJRANDNORM; + break; + case '9': + norm = CC_CRYSTAL; + break; + case CC_BIX_GETOPT_UNKNOWN: + case '?': + default: + usage (av[0]); + return 1; + } + + if (CCutil_bix_optind != ac) { + usage (av[0]); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *name) +#else +static void usage (name) +char *name; +#endif +{ + fprintf (stderr, "Usage: %s [-see below-]\n", name); + fprintf (stderr, " -b datfile in integer binary format\n"); + fprintf (stderr, " -B f blossom-tree-file (for writing)\n"); + fprintf (stderr, " -d grow a single tree\n"); + fprintf (stderr, " -D f edgegen description file (initial edges)\n"); + fprintf (stderr, " -e f edge_file\n"); + fprintf (stderr, " -f just fractional\n"); + fprintf (stderr, " -j no fractional jumpstart\n"); + fprintf (stderr, " -k # number of nodes for random problem\n"); + fprintf (stderr, " -p # number of neighbors in partial pricing\n"); + fprintf (stderr, " -P do not do pricing (just solve initial set)\n"); + fprintf (stderr, " -s # random seed\n"); + fprintf (stderr, " -t make same dual change to all trees\n"); + fprintf (stderr, " -T the dat file is a TSPLIB file\n"); + fprintf (stderr, " -w f match_file (for writing)\n"); + fprintf (stderr, " -x f datfile for pricing\n"); + fprintf (stderr, " -0 Max norm for edge lengths\n"); + fprintf (stderr, " -1 Ceiling Euclidean norm - from DSJ\n"); + fprintf (stderr, " -2 Rounded Euclidean norm (default)\n"); + fprintf (stderr, " -3 Rounded Euclidean 3D norm\n"); + fprintf (stderr, " -(4 5 6 7 8 9) IBM ATT GEO MATRIX DSJRAND CRYSTAL norm\n"); +} diff --git a/contrib/blossom/MATCH/match.c b/contrib/blossom/MATCH/match.c new file mode 100644 index 0000000000000000000000000000000000000000..4ff66a2f2d0df47fdb7c16cfea3e56c2c814b658 --- /dev/null +++ b/contrib/blossom/MATCH/match.c @@ -0,0 +1,3885 @@ +/************************************************************************/ +/* */ +/* ROUTINE FOR WEIGHTED PERFECT MATCHING PROBLEMS */ +/* */ +/* Written by: A. Rohe */ +/* Date: November 7, 1995 (rohe) */ +/* November 12, 1995 (rohe) */ +/* February 7, 1996 (rohe - short look at program) */ +/* July, 1996 (rohe - change from tree to forest) */ +/* October, 1996 (bico - change to concorde format) */ +/* */ +/* */ +/* EXPORTED FUNCTION: */ +/* int perfect_match (int ncount, CCdatagroup *dat, int ecount, */ +/* int **elist, int **elen, char *blo_filename, */ +/* char *mat_filename, int just_fractional, int no_fractional, */ +/* int use_all_trees, int use_tree, int partialprice, */ +/* double *totalzeit) */ +/* COMPUTES a minumum weight perfect matching. */ +/* -ncount is the number of nodes in the graph */ +/* -dat gives the data to generate edge lengths (if the */ +/* matching is over the complete graph), it can be NULL */ +/* -ecount is the number of edges in the initial edge set */ +/* -elist is a pointer to an array of edges in end end format, */ +/* this array will be freed by perfect_match to save on */ +/* memory */ +/* -elen is a pointer to an array of edge lengths for the edges */ +/* in elist, it will be freed by the perfect_match */ +/* -blo_filename is the name of a file (it can be NULL), if it */ +/* is not NULL then the blossoms and weights will be written */ +/* to it */ +/* -mat_filename is the name of a file (it can be NULL), if it */ +/* is not null, then the matching will be writtien to it */ +/* -just_fractional should be 0 to compute a matching, and 1 */ +/* to only compute a fractional matching */ +/* -if no_fractional is nonzero, then a fractional jumpstart */ +/* will not be used */ +/* -if use_all_trees is 1, then a common delta is */ +/* computed for all trees in the forest; if it is 2, then */ +/* a single tree is grown */ +/* -if partialprice is > 0, then the pricing routine will first */ +/* price the partialprice nearest neighbors before moving to */ +/* the complete edge set */ +/* -totalzeit will return the time used by the matching routine */ +/* (excluding the time needed for a final check that the */ +/* matching is indeed optimal, if this checking is turned */ +/* on) */ +/* */ +/* NOTES: */ +/* */ +/* Returns 0 if it worked and 1 otherwise (for example, when one */ +/* of the mallocs failed). The nodes in the graph should be named */ +/* 0 through #nodes - 1. */ +/* */ +/************************************************************************/ +#include "concorde.h" +#include "match.h" +#define NDEBUG /* remove this to turn assertions on */ +#include <assert.h> + +#define CARELESS_REPAIRS +/* #define BALL_DERIGS_REPAIRS */ +#define GREEDY_DUAL_CHANGE +#define SWITCH_LEVEL 32 +#define MAX_BAD_PORTION 0.25 + +#define PRINT_LEVEL 0 +#define SHRINKS_SIZE 1000 +/* infinity */ +#define INTEGER_MIN -999999999 +#define INTEGER_MAX 999999999 +/* for labels */ +#define NIX 0 +#define PLUS 1 +#define MINUS 2 +/* for status */ +#define UNMATCHED 0 +#define HALVES 1 +#define MATCHED 2 +/* for x */ +#define HALF 2 + +int FAILED_NODE; + +/* +#define OTHEREND(e,n,list) ((list) + (e)->nod1 + (e)->nod2 - ((n) - (list))) +*/ +#define OTHEREND(e,n,list) (((e)->nod1 + (list)) == (n) ? \ + (e)->nod2 + (list) : (e)->nod1 + (list)) +#define OTHEREND_INT(e,n) ((e)->nod1 + (e)->nod2 - (n)) + +#define FIND_SURFACE(n) { \ + while((n)->blossom_parent != -1) { \ + (n)=G->nodelist+(n)->blossom_parent; \ + } \ + } + +#define SHRINK_SORT_CONST 3 +#define BADCOUNT_CONST 10000 +#define PNODE(n) (G->nodelist + (n)) +#define PEDGE(e) (G->edgelist + (e)) + +#define INODE(n) ((n) - G->nodelist) +#define IEDGE(e) ((e) - G->edgelist) + +typedef struct edge { + int slack; + char mark; + char x; + int ptrs[2]; + int nod1; + int nod2; + int orig_nod1; + int orig_nod2; +} edge; + +typedef struct node { + int edg_list; + int matched_edge; + + /* These are for the augmenting path tree */ + int child; + int sibling; + int parent; + int parent_edge; + + /* These are for the blossom_tree */ + int blossom_next; + int blossom_parent; + int blossom_root; + int blossom_next_edge; + int penultimate; + + int pi; + int mark; /* unused pseudo nodes are linked by mark */ + int tree_root; + + char status; + char label; + char hit; + + int dummy; /* just to pad to multiple of 8 bytes */ +} node; + +typedef struct nodeptr { + int next; + int surf; + int delta; + int dad; + int sum; + int status; +#ifdef GREEDY_DUAL_CHANGE + char tree_processed; + int gnext; /* used to pad to multiple of 8 bytes and in reordering */ +#endif +} nodeptr; + +typedef struct shrink_ary_T { + int node_i; + int node_j; + int node_k; + int edge; + int size; + int next; +} shrink_ary_T; + +typedef struct shrink_T { + shrink_ary_T *ary; + int length; +} shrink_T; + +typedef struct expand_T { + int *node; + int length; +} expand_T; + +typedef struct stats { + int expand_count; + int shrink_count; + int dualchange_count; + int dualzero_count; +} stats; + +typedef struct graph { + edge *edgelist; + node *nodelist; + int nnodes; + int nedges; + int max_nedges; + int unused; + int unmatched; + nodeptr *roots; + int unmatched_count; +}graph; + +typedef struct srkstuff { + expand_T expands; + shrink_T shrinks; + int shrinks_max; + int expands_max; + int shrinks_[SHRINKS_SIZE]; +} srkstuff; + +typedef struct stack { + int* ary; + int count; +} stack; + +#ifdef CC_PROTOTYPE_ANSI + +static void + adjust_match (graph *G), + print_node (graph *G, node *n), + print_edges (graph *G), + init_tree (graph *G, node *n), + clear_tree (graph *G, node *n), + make_cycle_halves (graph *G, node *node_i, node *node_j, node *node_k, + edge *e), + shrink_tree (graph *G, node *newnode), + label_penultimate (graph *G, node *n, int label), + fix_matching (graph *G, node *oldnode, node *x), + fix_tree (graph *G, node *oldnode, node *x, node *y), + flip_cycle (graph *G, node *node_i), + augment_path (graph *G, node *node_i, int fractional), + vereinigung (graph *G, int x, int y), + set_vereinigung (graph *G, node *n), + unmatch_edge (graph *G, edge *e), + dual_match_len (graph *G, int fractional, double *val), + fix_match (graph *G, int blossom); + +static int + build_graph (graph *G, int ncount, int ecount, int *elist, int *elen), + init (graph *G, srkstuff *srk), + match_main_frac (graph *G, stats *scount, srkstuff *srk), + match_main (graph *G, stats *scount, srkstuff *srk, int use_all), + augment_blossom (graph *G, edge *, int fractional, srkstuff *srk), + lower_edges (graph *G, node *old), + expand_blossom (graph *G, node *oldnode, stats *scount), + lift_edges (graph *G, node *newnode), + add_to_tree (graph *G, edge *e, node *node_i, node *node_j, int fractional), + checkout_node (graph *G, node *n, int fractional, srkstuff *srk), + grow_tree_no_shrink (graph *G, node *n, int fractional, srkstuff *srk), + grow_tree (graph *G, node *n, int fractional, stats *scount, srkstuff *srk, + int *found_aug), + apply_dual_change (graph *G, node *n, int delta), + find_parity_sum (graph *G, int n), + parity_correction (graph *G, stats *scount), + find_single_dual_change (graph *G, node *n), + find_dual_change_forest (graph *G, node *n), + make_dual_change_forest (graph *G, stats *scount), + match_main_more_in_forest (graph *G, stats *scount, srkstuff *srk), + match_main_forest (graph *G, stats *scount, srkstuff *srk), + match_main_tree (graph *G, stats *scount, srkstuff *srk), + make_match (graph *G), + test_matching (graph *G, CCdatagroup *dat, int *elen, int fractional, + int *bad), + price_repair (graph *G, int *finished, CCdatagroup *dat, stats *scount, + srkstuff *srk, int partialprice), + pricing (graph *G, CCdatagroup *dat, stats *scount, srkstuff *srk, + int *badcount, int **badlist, int **badlen, CCtsp_edgegenerator *eg, + int usehit), + bring_to_surface (graph *G, node *p, stats *scount, srkstuff *srk), + add_repair_edge (graph *G, int n1, int n2, int len, stats *scount, + srkstuff *srk), + run_repair (graph *G, int badcount,int* badlist,int* badlen, stats *scount, + srkstuff *srk), + add_edges (graph *G, CCdatagroup *dat, int badcount,int* badlist,int* badlen), + write_match (graph *G, CCdatagroup *dat, int *elen, char* match_file, int *outp), + write_blossom_tree (graph *G, char* blossom_tree_file); + +static node + *shrink_blossom (graph *G, node *node_i, node *node_j, node *node_k, + edge *e, stats *scount), + *common_parent (graph *G, node *node_i, node *node_j, int *size), + *find_below (graph *G, node *n, int blossom); + +#else + +static void + adjust_match (), + print_node (), + print_edges (), + init_tree (), + clear_tree (), + make_cycle_halves (), + shrink_tree (), + label_penultimate (), + fix_matching (), + fix_tree (), + flip_cycle (), + augment_path (), + vereinigung (), + set_vereinigung (), + unmatch_edge (), + dual_match_len (), + fix_match (); + +static int + build_graph (), + init (), + match_main_frac (), + match_main (), + augment_blossom (), + lower_edges (), + expand_blossom (), + lift_edges (), + add_to_tree (), + checkout_node (), + grow_tree_no_shrink (), + grow_tree (), + apply_dual_change (), + find_parity_sum (), + parity_correction (), + find_single_dual_change (), + find_dual_change_forest (), + make_dual_change_forest (), + make_match (), + match_main_more_in_forest (), + match_main_forest (), + match_main_tree (), + test_matching (), + price_repair (), + pricing (), + add_repair_edge (), + bring_to_surface (), + run_repair (), + add_edges (), + write_match (), + write_blossom_tree (); + +static node + *shrink_blossom (), + *common_parent (), + *find_below (); + +#endif + +#if PRINT_LEVEL +static graph *PG = (graph *) NULL; +#endif + +#ifdef CC_PROTOTYPE_ANSI +int perfect_match (int ncount, CCdatagroup *dat, int ecount, int **elist, + int **elen, char *blo_filename, char *mat_filename, + int just_fractional, int no_fractional, + int use_all_trees, int partialprice, double *totalzeit) +#else +int perfect_match (ncount, dat, ecount, elist, elen, blo_filename, + mat_filename, just_fractional, no_fractional, + use_all_trees, partialprice, totalzeit) +int ncount; +CCdatagroup *dat; +int ecount; +int **elist, **elen; +char *blo_filename, *mat_filename; +int use_all_trees; +int partialprice; +double *totalzeit; +#endif +{ + graph G; + srkstuff srk; + stats scount; + double val, startzeit; + int finished = 1; + int bad; + int sedges = 0; + double zero_zeit = CCutil_zeit (); + +#if PRINT_LEVEL + PG = &G; +#endif + + int status = 0; + + *totalzeit = 0.0; + + G.edgelist = (edge *) NULL; + G.nodelist = (node *) NULL; + G.unused = -1; + G.unmatched = -1; + G.roots = (nodeptr *) NULL; + + srk.expands.node = (int *) NULL; + srk.shrinks.ary = (shrink_ary_T *) NULL; + + if (build_graph (&G, ncount, ecount, *elist, *elen)) { + // fprintf (stderr, "build_graph failed\n"); + CC_FREE (*elist, int); + CC_FREE (*elen, int); + status = 1; + goto CLEANUP; + } + CC_FREE (*elist, int); + if (dat) { + CC_FREE (*elen, int); + } + sedges = G.nedges; + + do { + // printf (" Starting Init..."); + fflush (stdout); + startzeit = CCutil_zeit (); + if (init (&G, &srk)) { + // fprintf (stderr, "init failed\n"); + status = 1; + goto CLEANUP; + } + // printf (" ... ready in %.2f sec !! \n", CCutil_zeit () - startzeit); + fflush (stdout); + + if (no_fractional == 0) { + // printf (" Matching with %i nodes and %i edges ...\n", + // G.nnodes, G.nedges); + // fflush (stdout); + // printf (" Make a fractional Matching...\n"); + fflush (stdout); + startzeit = CCutil_zeit (); + scount.expand_count = 0; + scount.shrink_count = 0; + scount.dualchange_count = 0; + scount.dualzero_count = 0; + if (match_main_frac (&G, &scount, &srk)) { + // fprintf (stderr, "match_main_frac failed\n"); + status = 1; + goto CLEANUP; + } + // printf (" ... ready in %.2f sec !! \n", CCutil_zeit () - startzeit); + // fflush (stdout); + } + + if (just_fractional == 0) { + // printf (" Make an integral Matching ...\n"); + // fflush (stdout); + startzeit = CCutil_zeit (); + if (make_match (&G)) { + // fprintf (stderr, "make_match failed\n"); + // fflush (stdout); + } + // printf (" ... ready in %.2f sec !! \n", CCutil_zeit () - startzeit); + // fflush (stdout); + + // printf (" Starting Integral Matching-Code...\n"); + // fflush (stdout); + startzeit = CCutil_zeit (); + scount.expand_count = 0; + scount.shrink_count = 0; + scount.dualchange_count = 0; + scount.dualzero_count = 0; + if (match_main (&G, &scount, &srk, use_all_trees)) { + // fprintf (stderr, "match_main failed\n"); + status = 1; + goto CLEANUP; + } + // printf (" ... ready in %.2f sec !! \n", CCutil_zeit () - startzeit); + // fflush (stdout); + dual_match_len (&G, 0, &val); + // printf (" Dual Matching Length: %.1f\n", val); + // fflush (stdout); + if (dat) { + // printf ("Start Price-Repair Phase ...\n"); + // fflush (stdout); + startzeit = CCutil_zeit (); + if (price_repair (&G, &finished, dat, &scount, &srk, + partialprice)) { + // fprintf (stderr, "pricing failed\n"); + return 1; + } + if (finished && partialprice > 0) { + // printf ("Nearest %d are correct, now try complete graph\n", + // partialprice); + // fflush (stdout); + if (price_repair (&G, &finished, dat, &scount, &srk, 0)) { + // fprintf (stderr, "pricing failed\n"); + return 1; + } + } + // printf (" ... ready in %.2f sec !! \n", CCutil_zeit () - startzeit); + // fflush (stdout); + } + CC_IFFREE (G.roots, nodeptr); + } + if (blo_filename != (char *) NULL) { + if (write_blossom_tree (&G, blo_filename)) { + // fprintf (stderr, "write_blossom_tree failed\n"); + status = 1; + goto CLEANUP; + } + } + CC_IFFREE (srk.expands.node, int); + CC_IFFREE (srk.shrinks.ary, shrink_ary_T); + } while (!finished); + + // printf (" Adjust found Matching...\n"); + // fflush (stdout); + startzeit = CCutil_zeit (); + adjust_match (&G); + // printf (" ... ready in %.2f sec !! \n", CCutil_zeit () - startzeit); + // fflush (stdout); + + *totalzeit = CCutil_zeit () - zero_zeit; + // printf ("Matching Time: %.2f Seconds\n", *totalzeit); + // fflush (stdout); + + if (dat) { + // printf ("Testing the solution...\n"); + // fflush (stdout); + startzeit = CCutil_zeit (); + if (test_matching (&G, dat, *elen, just_fractional, &bad)) { + // fprintf (stderr, "test matching failed\n"); + status = 1; + goto CLEANUP; + } + if (bad) { + // printf ("ERROR: A problem was detected in the matching\n"); + status = 1; + goto CLEANUP; + } + // printf ("Testing Time: %.2f sec\n", CCutil_zeit () - startzeit); + // fflush (stdout); + } + + // printf ("ZZ Edges: %d (starting) %d (total)\n", sedges, G.nedges); + + if (mat_filename != (char *) NULL) { + *elist = (int*)malloc((3*ncount+1)*sizeof(int));// over allocated + if (write_match (&G, dat, *elen, mat_filename,*elist)) { + status = 1; + // fprintf (stderr, "write_match failed\n"); + goto CLEANUP; + } + } + +CLEANUP: + + CC_IFFREE (G.nodelist, node); + CC_IFFREE (G.edgelist, edge); + CC_IFFREE (G.roots, nodeptr); + CC_IFFREE (srk.expands.node, int); + CC_IFFREE (srk.shrinks.ary, shrink_ary_T); + if (!dat) { + CC_FREE (*elen, int); + } + + return status; +} + +#ifdef CC_PROTOTYPE_ANSI +static void print_node (graph *G, node *n) +#else +static void print_node (G, n) +graph *G; +node *n; +#endif +{ + edge *e; + int ei; + int c; + node *nodelist = G->nodelist; + edge *edgelist = G->edgelist; + + printf ("Node %d, Pi %d", (int) INODE(n), n->pi); + if (n->label == PLUS) printf (" label +"); + if (n->label == MINUS) printf (" label -"); + if (n->label == NIX) printf (" label 0"); + if (n->status == MATCHED) + printf (" MATCHED (%d,%d)\n", + edgelist[n->matched_edge].nod1, + edgelist[n->matched_edge].nod2); + if (n->status == UNMATCHED) printf (" UNMATCHED\n"); + if (n->status == HALVES) + printf (" HALVES (%i,%i)\n", + edgelist[n->matched_edge].nod1, edgelist[n->matched_edge].nod2); + fflush (stdout); + if (n->label != NIX) { + printf ("TreeRoot %d ", n->tree_root); + if (n->parent) + printf ("TreeParent = %d ", n->parent); + printf ("Children: "); + for (c = n->child; c != -1; c = nodelist[c].sibling) + printf ("%d ", c); + printf ("\n"); + } + if (n->blossom_parent != -1) { + printf ("BlossomNode %i, Parent %i, Next %i\n", (int) INODE(n), + n->blossom_parent, n->blossom_next); + } + if (n->blossom_root != -1) { + printf ("BlossomParent %i, Root %i\n", (int) INODE(n), n->blossom_root); + } + for (ei = n->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + printf ("| Edge (%i,%i)", e->nod1, e->nod2); + printf ("| %4i is ", e->nod1); + if (nodelist[e->nod1].label == PLUS) printf ("+"); + if (nodelist[e->nod1].label == MINUS) printf ("-"); + if (nodelist[e->nod1].label == NIX) printf ("0"); + printf ("| %4i is ", e->nod2); + if (nodelist[e->nod2].label == PLUS) printf ("+"); + if (nodelist[e->nod2].label == MINUS) printf ("-"); + if (nodelist[e->nod2].label == NIX) printf ("0"); + printf ("| edg Slack %d, x=%d\n", e->slack, (int) e->x); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void print_edges (graph *G) +#else +static void print_edges (G) +graph *G; +#endif +{ + int i; + + printf (" %i nodes, %i edges\n", G->nnodes, G->nedges); + for (i = 0; i <= 3 * G->nnodes / 2 && i >= 0; i++) { + if (G->nodelist[i].edg_list != -1) + print_node (G, PNODE(i)); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int init (graph *G, srkstuff *srk) +#else +static int init (G, srk) +graph *G; +srkstuff *srk; +#endif +{ + int i, count; + node *n; + edge *e; + int ei; + int delta; + node *nodelist = G->nodelist; + int ncount = G->nnodes; + int ecount = G->nedges; + + /* set all the pi s */ + for (i = 0; i < ncount; i++) + nodelist[i].pi = INTEGER_MAX; + for (i = ncount; i <= 3 * ncount / 2; i++) + nodelist[i].pi = 0; + + for (i = 0, e = G->edgelist; i < ecount; i++, e++) { + if (nodelist[e->nod1].pi > e->slack) { + nodelist[e->nod1].pi = e->slack; + } + if (nodelist[e->nod2].pi > e->slack) { + nodelist[e->nod2].pi = e->slack; + } + } + + for (i = 0; i < ncount; i++) + nodelist[i].pi /= 2; + + /* calculate the slacks with the pi's and set rest to zero/nothing */ + + for (i = 0, e = G->edgelist; i < ecount; i++, e++) { + e->slack = e->slack - nodelist[e->nod1].pi - nodelist[e->nod2].pi; + e->x = 0; + } + + for (i = 0, n = nodelist; i <= 3 * ncount / 2; i++, n++) { + n->child = -1; + n->sibling = -1; + n->parent = -1; + n->label = NIX; + n->parent_edge = -1; + n->matched_edge = -1; + n->status = UNMATCHED; + n->blossom_root = -1; + n->blossom_next = -1; + n->blossom_next_edge = -1; + n->blossom_parent = -1; + n->tree_root = -1; + n->hit = 0; + } +#if 0 + /* Take all 0-slack edges directly, old version */ + count = 0; + for (i = 0, e = G->edgelist; i < ecount; i++, e++) { + if (e->slack == 0) { + if ((nodelist[e->nod1].status == UNMATCHED) && + (nodelist[e->nod2].status == UNMATCHED)) { + e->x = 1; + nodelist[e->nod1].matched_edge = i; + nodelist[e->nod2].matched_edge = i; + nodelist[e->nod1].status = MATCHED; + nodelist[e->nod2].status = MATCHED; + count += 2; + } + } + } +#else + /* Take all 0-slack edges directly & make better pi, new version */ + count = 0; + for (i = 0, n = nodelist; i < ncount; i++, n++) { + delta = INTEGER_MAX; + if (n->status == UNMATCHED) { + for (ei = n->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + if (e->slack <= delta) { + if (e->slack == 0) { + if ((nodelist[e->nod1].status == UNMATCHED) && + (nodelist[e->nod2].status == UNMATCHED)) { + e->x = 1; + nodelist[e->nod1].matched_edge = IEDGE(e); + nodelist[e->nod2].matched_edge = IEDGE(e); + nodelist[e->nod1].status = MATCHED; + nodelist[e->nod2].status = MATCHED; + count += 2; + } + } + delta = e->slack; + } + } + if (delta != 0) { + n->pi += delta; + for (ei = n->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + e->slack -= delta; + } + } + } + } +#endif + // printf (" %i nodes ", count); fflush (stdout); + + G->unmatched_count = ncount - count; + + srk->shrinks_max = ncount / 10 + 10; /* was just ncount */ + srk->shrinks.ary = CC_SAFE_MALLOC (srk->shrinks_max, shrink_ary_T); + srk->expands_max = ncount / 10 + 10; + srk->expands.node = CC_SAFE_MALLOC (srk->expands_max, int); + + if (!srk->shrinks.ary || !srk->expands.node) { + fprintf (stderr, "out of memory in init\n"); + CC_IFFREE (srk->shrinks.ary, shrink_ary_T); + CC_IFFREE (srk->expands.node, int); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void init_tree (graph *G, node *n) +#else +static void init_tree (G, n) +graph *G; +node *n; +#endif +{ +#if PRINT_LEVEL + printf (" init_tree %i\n", (int) (n - PG->nodelist)); fflush (stdout); +#endif + n->child = -1; + n->sibling = -1; + n->parent = -1; + n->parent_edge = -1; + n->label = PLUS; +} + +#ifdef CC_PROTOTYPE_ANSI +static void clear_tree (graph *G, node *n) +#else +static void clear_tree (G, n) +graph *G; +node *n; +#endif +{ + node *c = n; + node *stop = G->nodelist -1; + + while (1) { + c->mark = 0; + c->label = NIX; + c->tree_root = -1; /* ??? */ + + /* go to next c */ + if (c->child!=-1) { + c=PNODE(c->child); + } + else { + while (PNODE(c->sibling)==stop) { + if (c==n) return ; /* this if is for an n without childs */ + c=PNODE(c->parent); + if (c==n) return ; + } + c=PNODE(c->sibling); + } + } +} + +/* make_cycle_halves - edge from i to j, k is the "root" */ +#ifdef CC_PROTOTYPE_ANSI +static void make_cycle_halves (graph *G, node *node_i, node *node_j, + node *node_k, edge *e) +#else +static void make_cycle_halves (G, node_i, node_j, node_k, e) +graph *G; +node *node_i, *node_j, *node_k; +edge *e; +#endif +{ + edge *edgelist = G->edgelist; + node *parent; + +#if PRINT_LEVEL + printf (" Make cycle halves: root %i ends %i and %i:", + (int) (node_k - PG->nodelist), (int) (node_i - PG->nodelist), + (int) (node_j - PG->nodelist)); + fflush (stdout); +#endif + + /* set matched_edge for node_j */ + node_j->status = HALVES; + node_j->matched_edge = e - edgelist; + e->x = HALF; + + /* path from i to k : matched_edges are the parent_edges */ + for (; node_i != node_k; node_i = PNODE(node_i->parent)) { + edgelist[node_i->parent_edge].x = HALF; + node_i->matched_edge = node_i->parent_edge; + node_i->status = HALVES; + } + + /* path from j to k : matched_edges are the "child_edges" */ + for (; node_j != node_k; node_j = parent) { + parent = PNODE(node_j->parent); + edgelist[node_j->parent_edge].x = HALF; + parent->matched_edge = node_j->parent_edge; + parent->status = HALVES; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int lift_edges (graph *G, node *newnode) +#else +static int lift_edges (G, newnode) +graph *G; +node *newnode; +#endif +{ + node *n, *node_k; + node *nodelist = G->nodelist; + int nn = INODE(newnode); + edge *e; + int ei, einext; + +#if PRINT_LEVEL + printf ("Lift edges %i\n", nn); fflush (stdout); +#endif + + n = node_k = PNODE(newnode->blossom_root); + do { + ei = n->edg_list; + n->edg_list = -1; + for (; ei != -1; ei = einext) { + e = PEDGE(ei/2); + einext = e->ptrs[ei % 2]; + if ((nodelist[e->nod1].blossom_parent == nn) && + (nodelist[e->nod2].blossom_parent == nn)) { + e->ptrs[ei % 2] = n->edg_list; + n->edg_list = ei; + } else { + if (e->nod1 == INODE(n)) { /* nod1 is in new blossom */ + e->nod1 = nn; + } else { /* nod2 is in new blossom */ + e->nod2 = nn; + } + e->ptrs[ei % 2] = newnode->edg_list; + newnode->edg_list = ei; + } + } + n = PNODE(n->blossom_next); + } while (n != node_k); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void shrink_tree (graph *G, node *newnode) +#else +static void shrink_tree (G, newnode) +graph *G; +node *newnode; +#endif +{ + node *n, *node_k, *cnode; + int c, csibling, p; + +#if PRINT_LEVEL + printf (" Shrink-Tree %i\n", (int) (newnode - PG->nodelist)); + fflush (stdout); +#endif + + n = node_k = PNODE(newnode->blossom_root); + do { + for (c = n->child; c != -1; c = csibling) { + cnode = PNODE(c); + csibling = cnode->sibling; + if (cnode->blossom_parent != INODE(newnode)) { + cnode->parent = INODE(newnode); + cnode->sibling = newnode->child; + newnode->child = c; + } + } + n = PNODE(n->blossom_next); + } while (n != node_k); + + /* set other items for newnode */ + p = node_k->parent; + + newnode->sibling = -1; /* Plus node, has no siblings */ + newnode->parent = p; + newnode->parent_edge = node_k->parent_edge; + newnode->matched_edge = node_k->matched_edge; + newnode->label = PLUS; + + if (p != -1) /* _p has just one child, so this is ok */ + G->nodelist[p].child = INODE(newnode); +} + +/* shrink blossom - edge from i to j, k is the "root" */ + +#ifdef CC_PROTOTYPE_ANSI +static node *shrink_blossom (graph *G, node *node_i, node *node_j, + node *node_k, edge *e, stats *scount) +#else +static node *shrink_blossom (G, node_i, node_j, node_k, e, scount) +graph *G; +node *node_i, *node_j, *node_k; +edge *e; +stats *scount; +#endif +{ + node *newnode; + node *parent; + +#if PRINT_LEVEL + printf (" Shrink blossom: root %i ends %i and %i:\n", + (int) (node_k - PG->nodelist), (int) (node_i - PG->nodelist), + (int) (node_j - PG->nodelist)); + fflush (stdout); +#endif + + scount->shrink_count++; + + newnode = PNODE(G->unused); + G->unused = newnode->mark; + newnode->mark = 0; + newnode->edg_list = -1; + + if (node_k->status == UNMATCHED) { + G->roots[node_k->tree_root].surf = INODE(newnode); + } + + /* set blossom_next,next_edge,parent for node_j */ + /* blossom_root has to stay the same */ + + node_j->blossom_next = INODE(node_i); + node_j->blossom_next_edge = IEDGE(e); + node_j->blossom_parent = INODE(newnode); + + /* path from i to k : blossom_next_edges are the parent_edges */ + + for (; node_i != node_k; node_i = PNODE(node_i->parent)) { + node_i->blossom_next_edge = node_i->parent_edge; + node_i->blossom_next = node_i->parent; + node_i->blossom_parent = INODE(newnode); + } + + /* path from j to k : blossom_next_edges are the "child_edges" */ + + for (; node_j != node_k; node_j = parent) { + parent = PNODE(node_j->parent); + parent->blossom_next_edge = node_j->parent_edge; + parent->blossom_next = INODE(node_j); + parent->blossom_parent = INODE(newnode); + } + + newnode->blossom_root = INODE(node_k); + newnode->blossom_next = -1; + newnode->blossom_next_edge = -1; + newnode->blossom_parent = -1; + + newnode->mark = 0; + newnode->pi = 0; + newnode->status = node_k->status; + newnode->tree_root = node_k->tree_root; + + shrink_tree (G, newnode); + if (lift_edges (G, newnode)) { + fprintf (stderr, "lift_edges failed\n"); + return (node *) NULL; + } + + return newnode; +} + +#ifdef CC_PROTOTYPE_ANSI +static void label_penultimate (graph *G, node *n, int label) +#else +static void label_penultimate (G, n, label) +graph *G; +node *n; +int label; +#endif +{ + /* all the leafs of the blossom_tree under n get the penultimate label */ + node *n2; + + if (n->blossom_root == -1) { + n->penultimate = label; + return; + } + + n2 = n; + while (1) { + if (n2->blossom_root != -1) { + n2 = PNODE(n2->blossom_root); + } else { + n2->penultimate = label; + while (n2->blossom_next == + PNODE(n2->blossom_parent)->blossom_root) { + n2 = PNODE(n2->blossom_parent); + if (n2 == n) return; + } + n2 = PNODE(n2->blossom_next); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int lower_edges (graph *G, node *old) +#else +static int lower_edges (G, old) +graph *G; +node *old; +#endif +{ + edge *e; + int ei, einext; + node *x; + +#if PRINT_LEVEL + printf ("Lower edges %i !\n", (int) (old - PG->nodelist)); + fflush (stdout); +#endif + + for (ei = old->edg_list; ei != -1; ei = einext) { + e = PEDGE(ei/2); + einext = e->ptrs[ei % 2]; + if (e->nod1 == INODE(old)) { + x = PNODE(e->orig_nod1); + e->nod1 = x->penultimate; + } else { + x = PNODE(e->orig_nod2); + e->nod2 = x->penultimate; + } + e->ptrs[ei % 2] = PNODE(x->penultimate)->edg_list; + PNODE(x->penultimate)->edg_list = ei; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void fix_matching (graph *G, node *oldnode, node *x) +#else +static void fix_matching (G, oldnode, x) +graph *G; +node *oldnode, *x; +#endif +{ + node *n, *memo; + node *nodelist = G->nodelist; + edge *e; + +#if PRINT_LEVEL + printf (" Fix Matching %i; x = %i\n", + (int) (oldnode - PG->nodelist), (int) (x - PG->nodelist)); + fflush (stdout); +#endif + + if (x->blossom_next_edge == x->matched_edge) { + n = x; + memo = PNODE(oldnode->blossom_root); + } else { + n = PNODE(oldnode->blossom_root); + memo = x; + } + + for (; n != memo; n = PNODE(n->blossom_next)) { + e = PEDGE(n->blossom_next_edge); + e->x = 1 - e->x; + if (e->x == 1) { + nodelist[e->nod1].status = MATCHED; + nodelist[e->nod2].status = MATCHED; + nodelist[e->nod1].matched_edge = IEDGE(e); + nodelist[e->nod2].matched_edge = IEDGE(e); + } + } + + oldnode->blossom_root = INODE(x); + x->matched_edge = oldnode->matched_edge; + x->status = MATCHED; +} + +#ifdef CC_PROTOTYPE_ANSI +static void fix_tree (graph *G, node *oldnode, node *x, node *y) +#else +static void fix_tree (G, oldnode, x, y) +graph *G; +node *oldnode, *x, *y; +#endif +{ + node *p, *n, *cnode; + int c, label_help; + + p = PNODE(oldnode->parent); + +#if PRINT_LEVEL + printf (" Fix Tree %i; x = %i; y = %i\n", + (int) (oldnode - PG->nodelist), (int) (x - PG->nodelist), + (int) (y - PG->nodelist)); + fflush (stdout); +#endif + + /* Restore child-sibling list for p */ + + if (p->child == INODE(oldnode)) { + y->sibling = oldnode->sibling; + p->child = INODE(y); + } else { + for (c = p->child; c != -1; c = cnode->sibling) { + cnode = PNODE(c); + if (cnode->sibling == INODE(oldnode)) { + cnode->sibling = INODE(y); + y->sibling = oldnode->sibling; + break; + } + } + assert (c != -1); + } + + y->parent = INODE(p); + y->parent_edge = oldnode->parent_edge; + G->nodelist[oldnode->child].parent = INODE(x); + x->child = oldnode->child; + + label_help = MINUS; + if (y->blossom_next_edge == y->matched_edge) { + /* From y to x */ + for (n = y; n != x; n = PNODE(n->blossom_next)) { + n->child = n->blossom_next; + G->nodelist[n->blossom_next].parent = INODE(n); + G->nodelist[n->blossom_next].parent_edge = n->blossom_next_edge; + n->label = label_help; + if (label_help == MINUS) { + label_help = PLUS; + } else { + label_help = MINUS; + } + } + x->label = MINUS; /* This is not set in for-loop */ + } else { + for (n = x; n != y; n = PNODE(n->blossom_next)) { + /* From x to y */ + n->parent = n->blossom_next; + n->parent_edge = n->blossom_next_edge; + G->nodelist[n->blossom_next].child = INODE(n); + n->label = label_help; + if (label_help == MINUS) { + label_help = PLUS; + } else { + label_help = MINUS; + } + } + y->label = MINUS; /* This is not set in for-loop */ + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int expand_blossom (graph *G, node *oldnode, stats *scount) +#else +static int expand_blossom (G, oldnode, scount) +graph *G; +node *oldnode; +stats *scount; +#endif +{ + node *memo, *x, *y, *n; + int child, parent; + + scount->expand_count++; + +#if PRINT_LEVEL + printf (" Expand blossom %i \n", (int) (oldnode - PG->nodelist)); + fflush (stdout); +#endif + + child = oldnode->child; + parent = oldnode->parent; + + n = memo = PNODE(oldnode->blossom_root); + do { + label_penultimate (G, n, INODE(n)); + n = PNODE(n->blossom_next); + } while (n != memo); + + if (G->edgelist[oldnode->matched_edge].nod1 == INODE(oldnode)) + x = PNODE(G->edgelist[oldnode->matched_edge].orig_nod1); + else + x = PNODE(G->edgelist[oldnode->matched_edge].orig_nod2); + + if (G->edgelist[oldnode->parent_edge].nod1 == INODE(oldnode)) + y = PNODE(G->edgelist[oldnode->parent_edge].orig_nod1); + else + y = PNODE(G->edgelist[oldnode->parent_edge].orig_nod2); + + if (lower_edges (G, oldnode)) { + fprintf (stderr, "lower_edges failed\n"); + return 1; + } + fix_matching (G, oldnode, PNODE(x->penultimate)); + + n = memo; + do { + /* Clear tree structure of nodes in oldnodes blossom */ + n->blossom_parent = -1; + n->child = -1; + n->parent = -1; + n->sibling = -1; + n->parent_edge = -1; + n->label = NIX; + + n = PNODE(n->blossom_next); + n->hit = n->hit | oldnode->hit; + } while (n != memo); + + fix_tree (G, oldnode, PNODE(x->penultimate), PNODE(y->penultimate)); + + /* update tree roots */ + + for (child = G->nodelist[child].parent; child != parent; + child = G->nodelist[child].parent) { + G->nodelist[child].tree_root = G->nodelist[parent].tree_root; + } + + /* clear oldnode */ + + oldnode->edg_list = -1; + oldnode->pi = 0; + oldnode->status = UNMATCHED; + oldnode->matched_edge = -1; + oldnode->child = -1; + oldnode->sibling = -1; + oldnode->parent = -1; + oldnode->parent_edge = -1; + oldnode->label = NIX; + oldnode->blossom_root = -1; + oldnode->blossom_next = -1; + oldnode->blossom_next_edge = -1; + oldnode->blossom_parent = -1; + oldnode->penultimate = -1; + oldnode->tree_root = -1; + oldnode->hit = 0; + + /* put oldnode on unused list */ + + oldnode->mark = G->unused; + G->unused = oldnode - G->nodelist; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static node *common_parent (graph *G, node *p, node *q, int *size) +#else +static node *common_parent (G, p, q, size) +graph *G; +node *p, *q; +int *size; +#endif +{ + int count; + node *n; + node *stop = G->nodelist - 1; + +#if PRINT_LEVEL + printf (" Common-parent from %i and %i is ", + (int) (p - PG->nodelist), (int) (q - PG->nodelist)); + fflush (stdout); +#endif + + for (count = 0, n = p; n != stop; n = PNODE(n->parent)) { + count++; + n->mark = count; + } + + for (count = 0; q != stop; q = PNODE(q->parent)) { + if (q->mark) { + *size = (count + q->mark); + for (n = p; n != stop; n = PNODE(n->parent)) + n->mark = 0; + return q; + } + count++; + } + for (n = p; n != stop; n = PNODE(n->parent)) + n->mark = 0; + + *size = 0; + return (node *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static void flip_cycle (graph *G, node *node_i) +#else +static void flip_cycle (G, node_i) +graph *G; +node *node_i; +#endif +{ + int count = 0, ok = 1; + node *node_j, *node_k; + edge *e, *memo; + +#if PRINT_LEVEL + printf (" Flip cycle with root %i: ", (int) (node_i - PG->nodelist)); + fflush (stdout); +#endif + + /* init start (node_j, node_k, e) */ + + e = PEDGE(node_i->matched_edge); + node_j = node_i; + node_k = OTHEREND (e, node_i, G->nodelist); + + while (ok) { + /* test if last edge */ + if (node_k == node_i) + ok = 0; + + e->x = (count % 2); + memo = PEDGE(node_k->matched_edge); + + if (count % 2) { + node_j->matched_edge = node_k->matched_edge = IEDGE(e); + node_j->status = MATCHED; + node_k->status = MATCHED; + } + + e = memo; + node_j = node_k; + node_k = OTHEREND (e, node_j, G->nodelist); + count++; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void augment_path (graph *G, node *n, int fractional) +#else +static void augment_path (G, n, fractional) +graph *G; +node *n; +int fractional; +#endif +{ + edge *edgelist = G->edgelist; + node *nodelist = G->nodelist; + +#if PRINT_LEVEL + printf (" Augment path %i", (int) (n - PG->nodelist)); + fflush (stdout); +#endif + + if (n->parent != -1) { + for (; n->parent_edge != -1; n = PNODE(n->parent)) { + edgelist[n->parent_edge].x = 1 - edgelist[n->parent_edge].x; + if (edgelist[n->parent_edge].x == 1) { + nodelist[edgelist[n->parent_edge].nod1].matched_edge = + n->parent_edge; + nodelist[edgelist[n->parent_edge].nod2].matched_edge = + n->parent_edge; + } + } + } + n->status = MATCHED; /* This will be corrected in HALVES case */ + if (!fractional) + G->roots[n->tree_root].status = MATCHED; + clear_tree (G, n); /* n is the root */ +} + +#ifdef CC_PROTOTYPE_ANSI +static int augment_blossom (graph *G, edge *e, int fractional, srkstuff *srk) +#else +static int augment_blossom (G, e, fractional, srk) +graph *G; +edge *e; +int fractional; +srkstuff *srk; +#endif +{ + node *node_i = PNODE(e->nod1); + node *node_j = PNODE(e->nod2); + node *node_k; + int size; + shrink_ary_T *ary = srk->shrinks.ary; + +#if PRINT_LEVEL + printf (" Augment blossom with ends %i & %i \n", e->nod1, e->nod2); + fflush (stdout); +#endif + + node_k = common_parent (G, node_i, node_j, &size); + if (node_k == (node *) NULL) { /* more then one tree */ + e->x = 1; + node_i->matched_edge = e -G->edgelist; + node_j->matched_edge = e -G->edgelist; + G->unmatched_count -= 2; + augment_path (G, node_i, fractional); + augment_path (G, node_j, fractional); + return 1; + } else { + if (fractional) { + make_cycle_halves (G, node_i, node_j, node_k, e); + augment_path (G, node_k, fractional); + node_k->status = HALVES; + G->unmatched_count--; + return 1; + } else { + if (srk->shrinks.length < srk->shrinks_max) { + ary[srk->shrinks.length].node_i = node_i - G->nodelist; + ary[srk->shrinks.length].node_j = node_j - G->nodelist; + ary[srk->shrinks.length].node_k = node_k - G->nodelist; + ary[srk->shrinks.length].edge = e - G->edgelist; + ary[srk->shrinks.length].size = size; + srk->shrinks.length++; + if (srk->shrinks.length == srk->shrinks_max) { + printf (" WARNING: shrinks.length==shrinks_max=%i\n", + srk->shrinks_max); + fflush (stdout); + } + } + return 0; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_to_tree (graph *G, edge *e, node *node_i, node *node_j, + int fractional) +#else +static int add_to_tree (G, e, node_i, node_j, fractional) +graph *G; +edge *e; +node *node_i, *node_j; +int fractional; +#endif +{ + node *node_k; + edge *f; + +#if PRINT_LEVEL + printf (" Add (%i,%i)=(%i,%i) to tree \n", e->nod1, + e->nod2, (int) (node_i - PG->nodelist), (int) (node_j - PG->nodelist)); + fflush (stdout); +#endif + + if (node_j->status == UNMATCHED) { + e->x = 1; + node_j->status = MATCHED; + node_i->matched_edge = e - G->edgelist; + node_j->matched_edge = e - G->edgelist; + G->unmatched_count -= 2; + if (!fractional) + G->roots[node_j->tree_root].status = MATCHED; + augment_path (G, node_i, fractional); + return 1; + } else if (node_j->status == HALVES) { + flip_cycle (G, node_j); + e->x = 1; + node_i->status = MATCHED; + node_j->status = MATCHED; + node_i->matched_edge = e - G->edgelist; + node_j->matched_edge = e - G->edgelist; + augment_path (G, node_i, fractional); + G->unmatched_count--; + return 1; + } else { + /* set node_j in tree */ + node_j->sibling = node_i->child; + node_j->parent = INODE(node_i); + node_j->tree_root = node_i->tree_root; + node_j->parent_edge = IEDGE(e); + node_j->label = MINUS; + + /* set child for node_i */ + node_i->child = INODE(node_j); + + /* set child for node_j */ + f = PEDGE(node_j->matched_edge); + node_k = OTHEREND (f, node_j, G->nodelist); + node_j->child = INODE(node_k); + + /* set node_k in tree */ + node_k->child = -1; + node_k->sibling = -1; + node_k->parent = INODE(node_j); + node_k->parent_edge = IEDGE(f); + node_k->label = PLUS; + node_k->tree_root = node_j->tree_root; + + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int checkout_node (graph *G, node *n, int fractional, srkstuff *srk) +#else +static int checkout_node (G, n, fractional, srk) +graph *G; +node *n; +int fractional; +srkstuff *srk; +#endif +{ + node *m; + int augmented; + edge *e; + int ei; + +#if PRINT_LEVEL + printf (" Checkout node %i ...\n", (int) (n - PG->nodelist)); + fflush (stdout); +#endif + + for (ei = n->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + if (e->slack == 0) { + m = OTHEREND (e, n, G->nodelist); + if (m->label == PLUS) { + return augment_blossom (G, e, fractional, srk); + } + if (m->label == NIX) { + if ((augmented = add_to_tree (G, e, n, m, fractional)) != 0) { + return augmented; + } + } + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int grow_tree_no_shrink (graph *G, node *n, int fractional, + srkstuff *srk) +#else +static int grow_tree_no_shrink (G, n, fractional, srk) +graph *G; +node *n; +int fractional; +srkstuff *srk; +#endif +{ + int augmented; + expand_T *expands = &(srk->expands); + int expands_max = srk->expands_max; + node *c=n; + node *stop = G->nodelist - 1; + +#if PRINT_LEVEL + printf (" growtree no shrink %i\n", (int) (c - PG->nodelist)); + fflush (stdout); +#endif + + while (1) { + if (c->label == PLUS) { + if ((augmented = checkout_node (G, c, fractional, srk)) > 0) { + return augmented; + } + } else { /* MINUS node */ + if (c->blossom_root != -1 && c->pi == 0) { + if (expands->length < expands_max) { + expands->node[expands->length] = c - G->nodelist; + expands->length++; + if (expands->length == expands_max) { + printf (" WARNING: expands = expands_max = %i\n", + expands_max); + fflush (stdout); + } + } + } + } + /* go to next c */ + if (c->child!=-1) { + c=PNODE(c->child); + } else { + while (PNODE(c->sibling) == stop) { + if (c == n) return 0; /* this if is for childless n */ + c = PNODE(c->parent); + if (c == n) return 0; + } + c = PNODE(c->sibling); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int grow_tree (graph *G, node *n, int fractional, stats *scount, + srkstuff *srk, int *found_aug) +#else +static int grow_tree (G, n, fractional, scount, srk, found_aug) +graph *G; +node *n; +int fractional; +stats *scount; +srkstuff *srk; +int *found_aug; +#endif +{ + int i, size; + node *node_i, *node_j, *node_k, *newnode; + edge *e; + shrink_ary_T *ary = srk->shrinks.ary; + expand_T *expands = &(srk->expands); + int *shrinks_ = srk->shrinks_; + shrink_T *shrinks = &(srk->shrinks); + int old_shrinks_len; + + *found_aug = 0; + + do { + FIND_SURFACE (n); + shrinks->length = 0; + expands->length = 0; + + if (grow_tree_no_shrink (G, n, fractional, srk)) { + *found_aug = 1; + return 0; + } + + /* found no new match edge, so do shrinks */ + + while (shrinks->length) { + old_shrinks_len = shrinks->length; + if (shrinks->length > 4) { + /* build buckets for all different sizes */ + for (i = 0; i < SHRINKS_SIZE; i++) + shrinks_[i] = -1; + for (i = 0; i < shrinks->length; i++) { + size = ary[i].size; + if (size >= SHRINKS_SIZE) + size = SHRINKS_SIZE - 1; + if (shrinks_[size] == -1) { + shrinks_[size] = i; + ary[i].next = -1; + } else { + ary[i].next = shrinks_[size]; + shrinks_[size] = i; + } + } + for (size = SHRINKS_SIZE - 1; size >= 3; size -= 2) { + for (i = shrinks_[size]; i != -1; i = ary[i].next) { + node_i = PNODE(ary[i].node_i); + node_j = PNODE(ary[i].node_j); + node_k = PNODE(ary[i].node_k); + e = PEDGE(ary[i].edge); + FIND_SURFACE (node_i); + FIND_SURFACE (node_j); + FIND_SURFACE (node_k); + if (node_i != node_j) { + newnode = shrink_blossom (G, node_i, node_j, + node_k, e, scount); + if ((checkout_node(G,newnode,fractional,srk)) >0) { + *found_aug = 1; + return 0; + } + } + } + } + } else { /* just do all of the stupid shrinks */ + for (i = 0; i < shrinks->length; i++) { + node_i = PNODE(ary[i].node_i); + node_j = PNODE(ary[i].node_j); + node_k = PNODE(ary[i].node_k); + e = PEDGE(ary[i].edge); + FIND_SURFACE (node_i); + FIND_SURFACE (node_j); + FIND_SURFACE (node_k); + if (node_i != node_j) { + newnode = shrink_blossom (G, node_i, node_j, + node_k, e, scount); + if ((checkout_node (G, newnode, fractional, srk)) > 0) { + *found_aug = 1; + return 0; + } + } + } + } + if (shrinks->length > old_shrinks_len) { + size = shrinks->length - old_shrinks_len; + for (i = 0; i < size; i++) { + ary[i].node_i = ary[i + old_shrinks_len].node_i; + ary[i].node_j = ary[i + old_shrinks_len].node_j; + ary[i].node_k = ary[i + old_shrinks_len].node_k; + ary[i].edge = ary[i + old_shrinks_len].edge; + ary[i].size = ary[i + old_shrinks_len].size; + } + shrinks->length = size; + } else { + shrinks->length = 0; + } + } + for (i = 0; i < expands->length; i++) { + /* blossom_root != -1 is necessary because expand + * of this node might have happened here before */ + /* blossom_parent == -1 is necessary because + * this node might be shrunk already */ + if (G->nodelist[expands->node[i]].blossom_root != -1 && + G->nodelist[expands->node[i]].blossom_parent == -1) { + if (expand_blossom (G, G->nodelist+expands->node[i], scount)) { + fprintf (stderr, "expand_blossom failed\n"); + return 1; + } + } + } + } while (expands->length > 0); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int apply_dual_change (graph *G, node *n, int delta) +#else +static int apply_dual_change (G, n, delta) +graph *G; +node *n; +int delta; +#endif +{ + int ei; + edge *e; + node *c=n; + node *stop = G->nodelist - 1; + + if (delta == INTEGER_MAX) { + // fprintf (stderr, "\ndelta=Infinity, node=%i\n", (int) (n-G->nodelist)); + // fprintf (stderr, "There seems to be no perfect matching\n"); + // FAILED_NODE = (int)INODE(n); + // print_node (G, n); + return 1; + } + + while (1) { + if (c->label == PLUS) { + c->hit = 1; + c->pi += delta; + for (ei = c->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + e->slack -= delta; + } + } else if (c->label == MINUS) { + c->pi -= delta; + for (ei = c->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + e->slack += delta; + } + } + + /* go to next c */ + + if (c->child != -1) { + c = PNODE(c->child); + } else { + while (PNODE(c->sibling) == stop) { + if (c == n) return 0; /* this if is for childless n */ + c = PNODE(c->parent); + if (c == n) return 0; + } + c = PNODE(c->sibling); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_single_dual_change (graph *G, node *n) +#else +static int find_single_dual_change (G, n) +graph *G; +node *n; +#endif +{ + edge *e; + int ei; + int lab; + int delta; + node *c = n; + node *stop = G->nodelist - 1; + +#if PRINT_LEVEL + printf (" %i", (int) (n - PG->nodelist)); + fflush (stdout); +#endif + + delta = INTEGER_MAX; + + while (1) { + if (c->label == PLUS) { + for (ei = c->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + if (e->slack < 2 * delta) { + lab = OTHEREND (e, c, G->nodelist)->label; + if (lab == PLUS) { + delta = e->slack / 2; + } else if (lab == NIX) { + if (e->slack < delta) { + delta = e->slack; + } + } + } + } + } else if (c->label == MINUS) { + if (c->blossom_root != -1 && c->pi < delta) { + delta = c->pi; + } + } + + /* go to next c */ + + if (c->child != -1) { + c = PNODE(c->child); + } else { + while (PNODE(c->sibling) == stop) { + if (c == n) return delta ; /* this if is for childless n */ + c = PNODE(c->parent); + if (c == n) return delta; + } + c = PNODE(c->sibling); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_dual_change_forest (graph *G, node *n) +#else +static int find_dual_change_forest (G, n) +graph *G; +node *n; +#endif +{ + edge *e; + int ei; + int delta; + nodeptr *roots = G->roots; + node *c = n, *o; + node *stop = G->nodelist - 1; + +#if PRINT_LEVEL + printf (" %i", (int) (c - PG->nodelist)); + fflush (stdout); +#endif + + delta = INTEGER_MAX; + + while (1) { + if (c->label == PLUS) { + for (ei = c->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + o = OTHEREND (e, c, G->nodelist); + switch (o->label) { +#ifdef GREEDY_DUAL_CHANGE + case PLUS: + if (roots[c->tree_root].dad != roots[o->tree_root].dad ) { + /* two trees, not connected with vereinigung */ + if (roots[o->tree_root].tree_processed) { + if (delta > e->slack - + roots[roots[o->tree_root].dad].delta) { + delta = e->slack - + roots[roots[o->tree_root].dad].delta; + } + } else { + if (e->slack < delta) { + delta = e->slack; + } + } + } else { + if (e->slack < 2 * delta) { + delta = e->slack / 2; + } + } + break; + case NIX: + if (e->slack < delta) { + delta = e->slack; + } + break; + case MINUS: + if (roots[c->tree_root].dad != roots[o->tree_root].dad) { + /* two trees, not connected with vereinigung */ + if (roots[o->tree_root].tree_processed) { + if (delta > e->slack + + roots[roots[o->tree_root].dad].delta) { + delta = e->slack + + roots[roots[o->tree_root].dad].delta; + } + } else { + if (e->slack < delta ) { + delta = e->slack; + } + } + } + } +#else /* GREEDY_DUAL_CHANGE */ + case PLUS: + if (e->slack < 2 * delta) { + delta = e->slack / 2; + } + break; + case NIX: + if (e->slack < delta) { + delta = e->slack; + } + break; + case MINUS: + if (roots[c->tree_root].dad != roots[o->tree_root].dad) { + if (e->slack < delta ) { + delta = e->slack; + } + } + } +#endif /* GREEDY_DUAL_CHANGE */ + } + } else if (c->label == MINUS) { + if (c->blossom_root != -1 && c->pi <= delta) { + delta = c->pi; + } + } + + /* go to next c */ + + if (c->child != -1) { + c = PNODE(c->child); + } else { + while (PNODE(c->sibling) == stop) { + if (c == n) return delta ; /* this is for childless n */ + c = PNODE(c->parent); + if (c == n) return delta; + } + c = PNODE(c->sibling); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void vereinigung (graph *G, int x, int y) +#else +static void vereinigung (G, x, y) +graph *G; +int x, y; +#endif +{ + int xroot, yroot, dad; + nodeptr *roots = G->roots; + +#if PRINT_LEVEL + printf (" vereinigung (%i,%i)", x, y); fflush (stdout); +#endif + + xroot = x; + while (roots[xroot].dad >= 0) + xroot = roots[xroot].dad; + while (roots[x].dad >= 0) { + dad = roots[x].dad; + roots[x].dad = xroot; + x = dad; + } + + yroot = y; + while (roots[yroot].dad >= 0) + yroot = roots[yroot].dad; + while (roots[y].dad >= 0) { + dad = roots[y].dad; + roots[y].dad = yroot; + y = dad; + } + + if (xroot != yroot) { + if (roots[yroot].dad < roots[xroot].dad) { + roots[yroot].dad += roots[xroot].dad; + roots[xroot].dad = yroot; + } else { + roots[xroot].dad += roots[yroot].dad; + roots[yroot].dad = xroot; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void set_vereinigung (graph *G, node *n) +#else +static void set_vereinigung (G, n) +graph *G; +node *n; +#endif +{ + edge *e; + int ei; + node *nod = G->nodelist; + node *c = n; + node *stop = G->nodelist - 1; + +#if PRINT_LEVEL + printf (" set_vereinigung (%i)", (int) (n - PG->nodelist)); + fflush (stdout); +#endif + + /* this is called only for PLUS nodes */ + + while (1) { + for (ei = c->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + if (nod[e->nod1].tree_root != nod[e->nod2].tree_root) { + if (e->slack == 0) { + if (OTHEREND (e, c, nod)->label == MINUS) { + vereinigung (G, nod[e->nod1].tree_root, + nod[e->nod2].tree_root); + } + } + } + } + + /* now check the chilren of c's children (these are PLUS nodes) */ + + if (c->child != -1) { + c = PNODE(PNODE(c->child)->child); + } else { + if (c == n) return; /* this if is for childless n */ + c = PNODE(c->parent); + while (PNODE(c->sibling) == stop) { + c = PNODE(c->parent); + if (c == n) return; + c = PNODE(c->parent); + } + c = PNODE(PNODE(c->sibling)->child); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_parity_sum (graph *G, int n) +#else +static int find_parity_sum (G, n) +graph *G; +int n; +#endif +{ + node *v; + int sum, ei; + edge *e; + + ei = PNODE(n)->edg_list; + e = PEDGE(ei/2); + + if (e->nod1 == n) { + v = PNODE(e->orig_nod1); + } else { + v = PNODE(e->orig_nod2); + } + + sum = v->pi; + while (v->blossom_parent != -1) { + v = PNODE(v->blossom_parent); + sum += v->pi; + } + + return sum; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parity_correction (graph *G, stats *scount) +#else +static int parity_correction (G, scount) +graph *G; +stats *scount; +#endif +{ + nodeptr *np, *npprev = (nodeptr *) NULL; + int hitme = 0; + nodeptr *roots = G->roots; + nodeptr *rstop = G->roots - 1; + +#if PRINT_LEVEL + printf (" parity_correction ...\n"); + fflush (stdout); +#endif + + np = roots + G->unmatched; + while (np->status != UNMATCHED) + np = roots + np->next; + G->unmatched = np - roots; + + while (np != rstop) { + if (np->status != UNMATCHED) { + npprev->next = np->next; + } else { + if (np->sum % 2) { + hitme = 1; + scount->dualchange_count++; + if (apply_dual_change (G, PNODE(np->surf), 1)) { + // fprintf (stderr, "apply_dual_change failed\n"); + return -1; + } + np->sum += 1; + } + npprev = np; + } + np = roots + np->next; + } + return hitme; +} + +#ifdef CC_PROTOTYPE_ANSI +static int make_dual_change_forest (graph *G, stats *scount) +#else +static int make_dual_change_forest (G, scount) +graph *G; +stats *scount; +#endif +{ + nodeptr *np; + int t; + int delta; + nodeptr *roots = G->roots; + nodeptr *rstop = G->roots - 1; + +#if PRINT_LEVEL + printf ("\n make_dual_change_forest ...\n"); + fflush (stdout); +#endif + + if (parity_correction (G, scount) == -1) { + fprintf (stderr, "parity_correction failed\n"); + return -1; + } + + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) + np->dad = -1; /* Set dad for all trees to -1 */ + + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) + set_vereinigung (G, PNODE(np->surf)); + + /* Set roots to point to theirselves */ + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) { + if (np->dad < 0) { + np->dad = np - roots; + np->delta = INTEGER_MAX; + } + } + + /* Set others to point to root */ + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) { + t = np - roots; + while (roots[t].dad != t) + t = roots[t].dad; + np->dad = t; + } + +#ifdef GREEDY_DUAL_CHANGE + { + int npnext; + int glist = -1; + + /* order the unmatched nodes so that each union appears consecutively */ + + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) { + np->tree_processed = 0; + if (np->dad == np - roots) { + np->gnext = glist; + glist = np - roots; + } + } + + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) { + if (np->dad != np - roots) { + np->gnext = roots[np->dad].gnext; + roots[np->dad].gnext = np - roots; + } + } + + for (np = roots + G->unmatched; np != rstop; np = roots + npnext) { + npnext = np->next; + np->next = np->gnext; + } + G->unmatched = glist; + } +#endif + + /* Set delta for all vereinigung trees */ + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) { + delta = find_dual_change_forest (G, PNODE(np->surf)); + if (delta < roots[np->dad].delta) + roots[np->dad].delta = delta; +#ifdef GREEDY_DUAL_CHANGE + np->tree_processed = 1; +#endif + } + + /* Apply_dual_change for all vereinigung trees */ + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) { + delta = roots[np->dad].delta; + scount->dualchange_count++; + if (delta == 0) { + scount->dualzero_count++; + } else { + if (apply_dual_change (G, PNODE(np->surf), delta)) { + // fprintf (stderr, "apply_dual_change failed\n"); + return -1; + } + } + np->sum += delta; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int match_main_frac (graph *G, stats *scount, srkstuff *srk) +#else +static int match_main_frac (G, scount, srk) +graph *G; +stats *scount; +srkstuff *srk; +#endif +{ + node *n; + int i, delta; + int found_aug = 0; + + /* Just work with one tree */ + + for (i = 0, n = G->nodelist; i < G->nnodes; i++, n++) { + if (n->status == UNMATCHED) { + init_tree (G, n); + if (grow_tree (G, n, 1, scount, srk, &found_aug)) { + fprintf (stderr, "grow_tree failed\n"); + return 1; + } + while (!found_aug) { + scount->dualchange_count++; + delta = find_single_dual_change (G, n); + if (delta != 0) { + if (apply_dual_change (G, n, delta)) { + // fprintf (stderr, "apply_dual_change failed\n"); + return 1; + } + } else { + scount->dualzero_count++; + } + if (grow_tree (G, n, 1, scount, srk, &found_aug)) { + fprintf (stderr, "grow_tree failed\n"); + return 1; + } + } +#if PRINT_LEVEL + printf ("."); fflush (stdout); +#endif + } + } + // printf (" %i Dual Changes, %i with delta=0 ", + // scount->dualchange_count, scount->dualzero_count); + // fflush (stdout); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int match_main_more_in_forest (graph *G, stats *scount, srkstuff *srk) +#else +static int match_main_more_in_forest (G, scount, srk) +graph *G; +stats *scount; +srkstuff *srk; +#endif +{ + nodeptr *np; + node *n; + int i, ni, ninext; + int grow_status_forest; + int found_aug = 0; + nodeptr *roots, *rstop; + + /* The unmatched surface nodes should be linked using the mark */ + /* fields, with G->unmatched pointing to the start of the list. */ + /* G->umatched is assumed to be accurate. */ + + if (G->unmatched_count == 0) + return 0; + + /* ********************************* */ + /* First init all forests */ + /* ********************************* */ + + G->roots = CC_SAFE_MALLOC (G->unmatched_count, nodeptr); + if (!G->roots) { + // fprintf (stderr, "out of memory in match_main_more_in_forest\n"); + return 1; + } + roots = G->roots; + rstop = G->roots - 1; + + for (i = 0, ni = G->unmatched; ni != -1; ni = ninext, i++) { + n = PNODE(ni); + ninext = n->mark; + n->mark = 0; + roots[i].status = UNMATCHED; + roots[i].surf = ni; + roots[i].sum = find_parity_sum (G, ni); + roots[i].next = i+1; + init_tree (G, n); + n->tree_root = i; + } + roots[i - 1].next = -1; + G->unmatched = 0; + + // printf ("\nTry to grow the trees in the forest directly\n"); + // fflush (stdout); + + /* ************************************ */ + /* Try to grow all forests directly */ + /* ************************************ */ + + for (np = roots + G->unmatched; np != rstop; np = roots + np->next) { + n = PNODE(np->surf); + if (np->status == UNMATCHED) { + if (grow_tree (G, n, 0, scount, srk, &found_aug)) { + // fprintf (stderr, "grow_tree failed\n"); + return 1; + } + if (found_aug) { + // printf ("."); fflush (stdout); + if (G->unmatched_count == 0) { + return 0; + } + } + } + } + + /* *************************** */ + /* Work with tree-vereinigung */ + /* *************************** */ + + // printf ("\nNow work on tree-vereinigung in a forest (%i points)\n", + // G->unmatched_count / 2); + // fflush (stdout); + + /* first make sure that all trees have the correct parity */ + + if (parity_correction (G, scount) == -1) { + // fprintf (stderr, "parity_correction failed\n"); + return 1; + } + + while (G->unmatched_count > 0) { + if (make_dual_change_forest (G, scount) == -1) { + // fprintf (stderr, "make_dual_change_forest failed\n"); + return 1; + } + do { + grow_status_forest = 0; + for (np = roots + G->unmatched; np != rstop; np = roots+np->next) { + n = PNODE(np->surf); + if (np->status == UNMATCHED) { + if (grow_tree (G, n, 0, scount, srk, &found_aug)) { + // fprintf (stderr, "grow_tree failed\n"); + return 1; + } + if (found_aug) { + // printf ("."); fflush (stdout); + if (G->unmatched_count == 0) { + goto DONE; + } + grow_status_forest = 1; + } + } + } + } while (grow_status_forest); + } + +DONE: + + G->unmatched = -1; + CC_IFFREE (G->roots, nodeptr); + + // printf ("\n %i Dual Changes, %i with delta=0 ", + // scount->dualchange_count, scount->dualzero_count); + // printf ("| %i Expands ", scount->expand_count); + // printf ("| %i Shrinks ", scount->shrink_count); + // fflush (stdout); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int match_main_forest (graph *G, stats *scount, srkstuff *srk) +#else +static int match_main_forest (G, scount, srk) +graph *G; +stats *scount; +srkstuff *srk; +#endif +{ + nodeptr *np; + node *n; + int i, ni, ninext; + int grow_status_forest; + int found_aug = 0; + int delta, delta2; + int do_parity = 1; + nodeptr *roots, *rstop; + + // printf ("match_main_forest (%d points)\n", G->unmatched_count / 2); + // fflush (stdout); + + if (G->unmatched_count == 0) { + return 0; + } + + /* ********************************* */ + /* First init all forests */ + /* ********************************* */ + + G->roots = CC_SAFE_MALLOC (G->unmatched_count, nodeptr); + if (!G->roots) { + fprintf (stderr, "out of memory in match_main_more_in_forest\n"); + return 1; + } + roots = G->roots; + rstop = G->roots - 1; + + for (i = 0, ni = G->unmatched; ni != -1; ni = ninext, i++) { + n = PNODE(ni); + ninext = n->mark; + n->mark = 0; + roots[i].status = UNMATCHED; + roots[i].surf = ni; + roots[i].sum = find_parity_sum (G, ni); + roots[i].next = i+1; + init_tree (G, n); + n->tree_root = i; + } + roots[i - 1].next = -1; + G->unmatched = 0; + + /* ********************************* */ + /* Work with a forest */ + /* ********************************* */ + + while (G->unmatched_count > 0) { + do { + grow_status_forest = 0; + for (np = roots + G->unmatched; np != rstop; np = roots+np->next) { + n = PNODE(np->surf); + if (np->status == UNMATCHED) { + if (grow_tree (G, n, 0, scount, srk, &found_aug)) { + // fprintf (stderr, "grow_tree failed\n"); + return 1; + } + if (found_aug) { + printf ("."); fflush (stdout); + if (G->unmatched_count == 0) { + goto DONE; + } + grow_status_forest = 1; + } + } + } + } while (grow_status_forest); + + if (G->unmatched_count > 0 && do_parity) { + if (parity_correction (G, scount) == -1) { + // fprintf (stderr, "parity_correction failed\n"); + return 1; + } + do_parity = 0; + } + + if (G->unmatched_count > 0 && !do_parity) { + delta = INTEGER_MAX; + scount->dualchange_count++; + for (np = roots + G->unmatched; np != rstop; np = roots+np->next) { + n = PNODE(np->surf); + if (np->status == UNMATCHED) { + delta2 = find_single_dual_change (G, n); + if (delta2 < delta) { + delta = delta2; + } + } + } + + if (delta == 0) { + scount->dualzero_count++; + } else { + for (np = roots+G->unmatched; np!=rstop; np = roots+np->next) { + n = PNODE(np->surf); + if (np->status == UNMATCHED) { + if (apply_dual_change (G, n, delta)) { + // fprintf (stderr, "apply_dual_change failed\n"); + return 1; + } + np->sum += delta; + } + } + } + } + } + +DONE: + + G->unmatched = -1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int match_main_tree (graph *G, stats *scount, srkstuff *srk) +#else +static int match_main_tree (G, scount, srk) +graph *G; +stats *scount; +srkstuff *srk; +#endif +{ + nodeptr *np; + node *n; + int i, ni, ninext; + int found_aug = 0; + int delta; + nodeptr *roots, *rstop; + + // printf ("match_main_tree (%d points)\n", G->unmatched_count / 2); + // fflush (stdout); + + if (G->unmatched_count == 0) { + return 0; + } + + /* ********************************* */ + /* First init all forests */ + /* ********************************* */ + + G->roots = CC_SAFE_MALLOC (G->unmatched_count, nodeptr); + if (!G->roots) { + // fprintf (stderr, "out of memory in match_main_more_in_forest\n"); + return 1; + } + roots = G->roots; + rstop = G->roots - 1; + + for (i = 0, ni = G->unmatched; ni != -1; ni = ninext, i++) { + n = PNODE(ni); + ninext = n->mark; + n->mark = 0; + roots[i].status = UNMATCHED; + roots[i].surf = ni; + roots[i].sum = find_parity_sum (G, ni); + roots[i].next = i+1; + /* init_tree (G, n); */ + n->tree_root = i; + } + roots[i - 1].next = -1; + G->unmatched = 0; + + /* ********************************* */ + /* Work with a tree */ + /* ********************************* */ + + while (G->unmatched_count > 0) { + np = roots + G->unmatched; + while (np->status != UNMATCHED) { + np = roots + np->next; + } + G->unmatched = np - roots; + np = roots + G->unmatched; + n = PNODE(np->surf); + init_tree (G, n); + do { + if (grow_tree (G, n, 0, scount, srk, &found_aug)) { + // fprintf (stderr, "grow_tree failed\n"); + return 1; + } + if (found_aug) { + printf ("."); fflush (stdout); + if (G->unmatched_count == 0) { + goto DONE; + } + } else { + scount->dualchange_count++; + n = PNODE(np->surf); + delta = find_single_dual_change (G, n); + + if (delta == 0) { + scount->dualzero_count++; + } else { + if (apply_dual_change (G, n, delta)) { + // fprintf (stderr, "apply_dual_change failed\n"); + return 1; + } + } + } + } while (!found_aug); + } + +DONE: + + G->unmatched = -1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int match_main (graph *G, stats *scount, srkstuff *srk, int use_all) +#else +static int match_main (G, scount, srk, use_all) +graph *G; +stats *scount; +srkstuff *srk; +int use_all; +#endif +{ + double szeit; + + szeit = CCutil_zeit (); + // printf (" Need to find %i edges ...\n", G->unmatched_count / 2); + // fflush (stdout); + + if (!G->unmatched_count) + return 0; + + if (use_all == 2) { + if (match_main_tree (G, scount, srk)) { + // fprintf (stderr, "match_main_tree failed\n"); + return 1; + } + } else if (use_all == 1) { + if (match_main_forest (G, scount, srk)) { + // fprintf (stderr, "match_main_forest failed\n"); + return 1; + } + } else { + if (match_main_more_in_forest (G, scount, srk)) { + // fprintf (stderr, "match_main_more_in_forest failed\n"); + return 1; + } + } + // printf ("\n %i Dual Changes, %i with delta=0 \n", + // scount->dualchange_count, scount->dualzero_count); + // printf (" %i Expands \n", scount->expand_count); + // printf (" %i Shrinks \n", scount->shrink_count); + // printf (" Running Time in match_main: %.2f\n", CCutil_zeit () - szeit); + // fflush (stdout); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static node *find_below (graph *G, node *n, int blossom) +#else +static node *find_below (G, n, blossom) +graph *G; +node *n; +int blossom; +#endif +{ + if (!n) + return (node *) NULL; + + for (; n->blossom_parent != blossom; n = PNODE(n->blossom_parent)) { + if (n->blossom_parent == -1) + return (node *) NULL; + } + return n; +} + +#ifdef CC_PROTOTYPE_ANSI +static void fix_match (graph *G, int blossom) +#else +static void fix_match (G, blossom) +graph *G; +int blossom; +#endif +{ + node *x, *n; + node *b = blossom + G->nodelist; + +#if PRINT_LEVEL + printf (" Fixing blossom %i ", blossom); + fflush (stdout); +#endif + + x = find_below (G, PNODE(G->edgelist[b->matched_edge].orig_nod1), + blossom); + if (x == (node *) NULL) { + x = find_below (G, PNODE(G->edgelist[b->matched_edge].orig_nod2), + blossom); + } + /* x is now something like the match_edge->nod(1 or 2)->penultimate */ + fix_matching (G, b, x); + b->mark = 1; + + n = PNODE(b->blossom_root); + do { + if (n->blossom_root != -1) /* if n is a real blossom */ + fix_match (G, INODE(n)); /* call fix match again */ + n = PNODE(n->blossom_next); + } while (n != PNODE(b->blossom_root)); +} + +#ifdef CC_PROTOTYPE_ANSI +static void adjust_match (graph *G) +#else +static void adjust_match (G) +graph *G; +#endif +{ + node *n, *b; + int i; + int ncount = G->nnodes; + node *nodelist = G->nodelist; + + for (i = 0; i < ncount; i++) { + n = PNODE(i); + if (n->blossom_parent != -1 && nodelist[n->blossom_parent].mark == 0) { + for (b = n; b->blossom_parent != -1 && + nodelist[b->blossom_parent].mark == 0; + b = PNODE(b->blossom_parent)); + fix_match (G, INODE(b)); + } + } +} + +#ifdef CARELESS_REPAIRS +#ifdef CC_PROTOTYPE_ANSI +static int bring_to_surface (graph *G, node *p, stats *scount, srkstuff *srk) +#else +static int bring_to_surface (G, p, scount, srk) +graph *G; +node *p; +stats *scount; +srkstuff *srk; +#endif +{ + node *psurf, *n, *memo, *x; + edge *e; + int ei; + + if (p->blossom_parent == -1) + return 0; + + psurf = p; + while (psurf->blossom_parent != -1) { + psurf = PNODE(psurf->blossom_parent); + } + + while (p != psurf) { + scount->expand_count++; + + /* Mark edge to be unmatched later */ + G->edgelist[psurf->matched_edge].mark = 1; + + for (ei = psurf->edg_list; ei != -1; ei = e->ptrs[ei % 2]) { + e = PEDGE(ei/2); + e->slack += psurf->pi; + } + + n = memo = PNODE(psurf->blossom_root); + do { + label_penultimate (G, n, INODE(n)); + n = PNODE(n->blossom_next); + } while (n != memo); + + if (G->edgelist[psurf->matched_edge].nod1 == (psurf - G->nodelist)) + x = PNODE(G->edgelist[psurf->matched_edge].orig_nod1); + else + x = PNODE(G->edgelist[psurf->matched_edge].orig_nod2); + + if (lower_edges (G, psurf)) { + fprintf (stderr, "lower_edges failed\n"); + return 1; + } + fix_matching (G, psurf, PNODE(x->penultimate)); + + n = memo; + do { + /* Clear tree structure of nodes in psurf's blossom */ + n->blossom_parent = -1; + n->child = -1; + n->parent = -1; + n->sibling = -1; + n->parent_edge = -1; + n->label = NIX; + n = PNODE(n->blossom_next); + n->hit = n->hit | psurf->hit; + } while (n != memo); + + /* clear oldnode */ + + psurf->edg_list = -1; + psurf->pi = 0; + psurf->status = UNMATCHED; + psurf->matched_edge = -1; + psurf->child = -1; + psurf->sibling = -1; + psurf->parent = -1; + psurf->parent_edge = -1; + psurf->label = NIX; + psurf->blossom_root = -1; + psurf->blossom_next = -1; + psurf->blossom_next_edge = -1; + psurf->blossom_parent = -1; + psurf->penultimate = -1; + psurf->tree_root = -1; + psurf->hit = 0; + + /* add psurf to unused list */ + + psurf->mark = G->unused; + G->unused = psurf - G->nodelist; + + psurf = PNODE(p->penultimate); + } + + return 0; +} +#endif /* CARELESS_REPAIRS */ + +#ifdef BALL_DERIGS_REPAIRS +#ifdef CC_PROTOTYPE_ANSI +static int bring_to_surface (graph *G, node *p, stats *scount, srkstuff *srk) +#else +static int bring_to_surface (G, p, scount, srk) +graph *G; +node *p; +stats *scount; +srkstuff *srk; +#endif +{ + node *n, *newnode; + node *stop = G->nodelist - 1; + edge *e, *f; + int sum, delta; + int found_aug = 0; + + printf ("bring to surface (%d) ...\n", p - G->nodelist); + fflush (stdout); + + if (p->blossom_parent == -1) { + return 0; + } + + /* Take newnode from unused list */ + + newnode = PNODE(G->unused); + G->unused = newnode->mark; + newnode->mark = 0; + + /* Initialize newnode */ + + sum = 0; + for (n = p; n != stop; n = PNODE(n->blossom_parent)) + sum += n->pi; + + newnode->matched_edge = -1; + newnode->status = UNMATCHED; + newnode->pi = sum % 2; + + /* Add the edge (newnode, p) */ + + if (G->nedges >= G->max_nedges) { + fprintf (stderr, "number of edges exceeds max_nedges\n"); + return 1; + } + e = PEDGE(G->nedges); + e->slack = 0; + e->x = 0; + e->orig_nod1 = e->nod1 = newnode - G->nodelist; + e->orig_nod2 = p - G->nodelist; + n = p; + while (n->blossom_parent != -1) + n = PNODE(n->blossom_parent); + e->nod2 = INODE(n); + + /* Attach the new edge to the edg_lists of newnode and n */ + + e->ptrs[0] = n->edg_list; + n->edg_list = 2*G->nedges; + e->ptrs[1] = -1; + newnode->edg_list = 2*G->nedges + 1; + + G->nedges++; + + init_tree (G, newnode); + newnode->tree_root = INODE(newnode); + + if (grow_tree (G, newnode, 0, scount, srk, &found_aug)) { + fprintf (stderr, "grow_tree failed\n"); + return 1; + } + if (found_aug) { + fprintf (stderr, "found an augmentation in bring_to_surface\n"); + return 1; + } + + while (p->blossom_parent != -1) { + delta = find_single_dual_change (G, newnode); + fflush (stdout); + if (delta == 0) { + printf ("O"); fflush (stdout); + } + if (apply_dual_change (G, newnode, delta)) { + // fprintf (stderr, "apply_dual_change failed\n"); + return 1; + } + if (grow_tree (G, newnode, 0, scount, srk, &found_aug)) { + fprintf (stderr, "grow_tree failed\n"); + return 1; + } + if (found_aug) { + fprintf (stderr, "found an augmentation in bring_to_surface\n"); + return 1; + } + } + + clear_tree (G, newnode); + + /* reset newnode */ + + newnode->edg_list = -1; + newnode->pi = 0; + newnode->status = UNMATCHED; + newnode->matched_edge = -1; + newnode->child = -1; + newnode->sibling = -1; + newnode->parent = -1; + newnode->parent_edge = -1; + newnode->label = NIX; + newnode->blossom_root = -1; + newnode->blossom_next = -1; + newnode->blossom_next_edge = -1; + newnode->blossom_parent = -1; + newnode->penultimate = -1; + newnode->tree_root = -1; + newnode->hit = 0; + + /* Delete the added edge */ + + f = PEDGE (p->edg_list/2); + if (f == e) { + p->edg_list = e->ptrs[p->edg_list % 2]; + } else { + int ei, eiprev = p->edg_list; + + for (ei = f->ptrs[p->edg_list % 2]; ei != -1; ei = f->ptrs[ei % 2]) { + f = PEDGE(ei/2); + if (f == e) { + G->edgelist[eiprev/2].ptrs[eiprev % 2] = f->ptrs[ei % 2]; + break; + } + eiprev = ei; + } + if (ei == -1) { + fprintf (stderr, "Screw up in bring_to_surface\n"); + return 1; + } + } + G->nedges--; + + /* Return newnode from unused list */ + + newnode->mark = G->unused; + G->unused = newnode - G->nodelist; + + return 0; +} +#endif /* BALL_DERIGS_REPAIRS */ + +#ifdef CC_PROTOTYPE_ANSI +static int add_repair_edge (graph *G, int n1, int n2, int len, + stats *scount, srkstuff *srk) +#else +static int add_repair_edge (G, n1, n2, len, scount, srk) +graph *G; +int n1, n2, len; +stats *scount; +srkstuff *srk; +#endif +{ + edge *e, *f = (edge *) NULL; + node *n1surf, *n2surf; + int ei, eiprev = -1, sum2; + + n1surf = PNODE(n1); + n2surf = PNODE(n2); + sum2 = n2surf->pi; + while (n2surf->blossom_parent != -1) { + n2surf = PNODE(n2surf->blossom_parent); + sum2 += n2surf->pi; + } + + if (G->nedges >= G->max_nedges) { + fprintf (stderr, "number of edges exceeds max_nedges\n"); + return 1; + } + e = PEDGE(G->nedges); + e->slack = len - n1surf->pi - sum2; + e->mark = 0; + e->x = 0; + e->orig_nod1 = n1; + e->orig_nod2 = n2; + e->nod1 = n1surf - G->nodelist; + e->nod2 = n2surf - G->nodelist; + + for (ei = n1surf->edg_list; ei != -1; ei = f->ptrs[ei % 2]) { + f = PEDGE(ei/2); + eiprev = ei; + } + f->ptrs[eiprev % 2] = 2*G->nedges; + e->ptrs[0] = -1; + + for (ei = n2surf->edg_list; ei != -1; ei = f->ptrs[ei % 2]) { + f = PEDGE(ei/2); + eiprev = ei; + } + f->ptrs[eiprev % 2] = 2*G->nedges + 1; + e->ptrs[1] = -1; + + G->nedges++; + + if (e->slack < 0) { + n1surf->pi += e->slack; + for (ei = n1surf->edg_list; ei != -1; ei = f->ptrs[ei % 2]) { + f = PEDGE(ei/2); + f->slack -= e->slack; + } + } + +#ifdef BALL_DERIGS_REPAIRS + if (n1surf->matched_edge != -1) { + unmatch_edge (G, PEDGE(n1surf->matched_edge)); + if (match_main_more_in_forest (G, scount, srk)) { + /* if (match_main_forest (G, scount, srk)) { */ + fprintf (stderr, "match_main_more_in_forest failed\n"); + return 1; + } + } +#endif +#ifdef CARELESS_REPAIRS + if (n1surf->matched_edge != -1) { + /* mark edges to be unmatched later */ + G->edgelist[n1surf->matched_edge].mark = 1; + } +#endif + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void unmatch_edge (graph *G, edge *e) +#else +static void unmatch_edge (G, e) +graph *G; +edge *e; +#endif +{ + G->nodelist[e->nod1].status = UNMATCHED; + G->nodelist[e->nod2].status = UNMATCHED; + e->x = 0; + G->nodelist[e->nod1].matched_edge = -1; + G->nodelist[e->nod2].matched_edge = -1; + G->unmatched_count += 2; + + G->nodelist[e->nod1].mark = G->unmatched; + G->nodelist[e->nod2].mark = e->nod1; + G->unmatched = e->nod2; +} + +#ifdef CC_PROTOTYPE_ANSI +static int run_repair (graph *G, int badcount, int *badlist, int *badlen, + stats *scount, srkstuff *srk) +#else +static int run_repair (G, badcount, badlist, badlen, scount, srk) +graph *G; +int badcount; +int *badlist; +int *badlen; +stats *scount; +srkstuff *srk; +#endif +{ + int i, sum1, sum2; + int n1, n2; + node *n; + edge *e, *lastedge; + + for (i = 0; i < badcount; i++) { +#ifdef PRINT_REPAIRS + printf ("Bad Edge [%d, %d]\n", badlist[2*i], badlist[2*i + 1]); + fflush (stdout); +#endif + sum1 = 0; + n = PNODE(badlist[2*i]); + while (n->blossom_parent != -1) { + n = PNODE(n->blossom_parent); + sum1 += n->pi; + } + sum2 = 0; + n = PNODE(badlist[2*i + 1]); + while (n->blossom_parent != -1) { + n = PNODE(n->blossom_parent); + sum2 += n->pi; + } + if (sum1 < sum2) { + n1 = badlist[2*i]; + n2 = badlist[2*i + 1]; + } else { + n1 = badlist[2*i + 1]; + n2 = badlist[2*i]; + } + if (bring_to_surface (G, PNODE(n1), scount, srk)){ + fprintf (stderr, "bring_to_surface failed\n"); + return 1; + } + if (add_repair_edge (G, n1, n2, 2 * badlen[i], scount, srk)) { + fprintf (stderr, "add_repair_edge failed\n"); + return 1; + } + printf ("+"); fflush (stdout); + } + printf ("\n"); + + lastedge = PEDGE(G->nedges); + for (e = G->edgelist; e != lastedge; e++) { + if (e->mark) { + e->mark = 0; + if (e->x == 1) { + unmatch_edge (G, e); + } + } + } + + if (G->unmatched_count > 0) { +/* + if (match_main_forest (G, scount, srk)) { + fprintf (stderr, "match_main_forest failed\n"); + return 1; + } +*/ + if (match_main_more_in_forest (G, scount, srk)) { + fprintf (stderr, "match_main_more_in_forest failed\n"); + return 1; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_edges (graph *G, CCdatagroup *dat, int badcount, int *badlist, + int *badlen) +#else +static int add_edges (G, dat, badcount, badlist, badlen) +graph *G; +CCdatagroup *dat; +int badcount; +int *badlist; +int *badlen; +#endif +{ + int i,j; + int ncount = G->nnodes; + int ecount = G->nedges; + edge *e; + edge *edgelist = G->edgelist; + node *nodelist = G->nodelist; + int maxbad = G->nnodes * MAX_BAD_PORTION; + + /* init unused */ + j = 3*ncount/2; + for (i = ncount; i < j; i++) { + nodelist[i].mark = i + 1; + } + nodelist[j].mark = -1; + G->unused = ncount; + + /* Init edg_list */ + for (i = 0; i < 3*ncount/2; i++) { + nodelist[i].edg_list = -1; + } + + /* correct old edges */ + for (i = 0, e = edgelist; i < ecount; i++, e++) { + e->nod1 = e->orig_nod1; + e->nod2 = e->orig_nod2; + e->slack = 2 * CCutil_dat_edgelen (e->nod1, e->nod2, dat); + } + + if (badcount <= maxbad) { + for (i = 0; i < badcount; i++) { + if (ecount + 1 < G->max_nedges) { + edgelist[ecount].orig_nod1 = + edgelist[ecount].nod1 = badlist[2*i]; + edgelist[ecount].orig_nod2 = + edgelist[ecount].nod2 = badlist[2*i+1]; + edgelist[ecount].slack = 2 * badlen[i]; + ecount++; + } else { + fprintf(stderr, "Exceeded limit on the number of edges\n"); + G->nedges = ecount; + return 1; + } + } + } else { + printf ("Using only %.2f of the bad edges\n", + ((double) maxbad) / ((double) badcount)); + fflush (stdout); + for (i = 0; i < badcount; i++) { + if (CCutil_lprand () % badcount < maxbad) { + if (ecount + 1 < G->max_nedges) { + edgelist[ecount].orig_nod1 = + edgelist[ecount].nod1 = badlist[2*i]; + edgelist[ecount].orig_nod2 = + edgelist[ecount].nod2 = badlist[2*i+1]; + edgelist[ecount].slack = 2 * badlen[i]; + ecount++; + } else { + fprintf(stderr, "Exceeded limit on the number of edges\n"); + G->nedges = ecount; + return 1; + } + } + } + } + + printf(" Added %i edges ", ecount - G->nedges); + fflush (stdout); + + G->nedges = ecount; + + /* build the edg_lists */ + + for (i = 0, e = edgelist; i < ecount; i++, e++) { + e->ptrs[0] = nodelist[e->nod1].edg_list; + nodelist[e->nod1].edg_list = 2*i; + e->ptrs[1] = nodelist[e->nod2].edg_list; + nodelist[e->nod2].edg_list = 2*i + 1; + } + for (i = 0; i < ncount; i++) { + G->nodelist[i].mark = 0; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int price_repair (graph *G, int *finished, CCdatagroup *dat, stats *scount, + srkstuff *srk, int partialprice) +#else +static int price_repair (G, finished, dat, scount, srk, partialprice) +graph *G; +int *finished; +CCdatagroup *dat; +stats *scount; +srkstuff *srk; +int partialprice; +#endif +{ + int badcount = 0; + int *badlist = (int *) NULL; + int *badlen = (int *) NULL; + int i; + CCtsp_edgegenerator eg; + CCtsp_edgegenerator *myeg = (CCtsp_edgegenerator *) NULL; + + *finished = 0; + + if (partialprice > 0) { + printf ("Price using the nearest %d neighbor graph\n", partialprice); + fflush (stdout); + if (CCtsp_init_edgegenerator (&eg, G->nnodes, dat, (CCtsp_genadj *) NULL, + partialprice)) { + fprintf (stderr, "init_edgegenerator failed\n"); + return 1; + } + myeg = ⪚ + } + + if (pricing (G, dat, scount, srk, &badcount, &badlist, &badlen, myeg, 0)) { + fprintf (stderr, "pricing failed\n"); + if (myeg) + CCtsp_free_edgegenerator (myeg); + return 1; + } + + while (badcount > 0) { + if (badcount > G->nnodes / SWITCH_LEVEL /* 10000 */) { + if (myeg) + CCtsp_free_edgegenerator (myeg); + if (add_edges (G, dat, badcount, badlist, badlen)) { + fprintf (stderr, "add_edges failed\n"); + CC_IFFREE (badlist, int); + CC_IFFREE (badlen, int); + return 1; + } else { + CC_IFFREE (badlist, int); + CC_IFFREE (badlen, int); + return 0; + } + } else { + for (i = 0; i < 3 * G->nnodes / 2; i++) + G->nodelist[i].hit = 0; + if (run_repair (G, badcount, badlist, badlen, scount, srk)) { + fprintf (stderr, "run_repair failed\n"); + CC_IFFREE (badlist, int); + CC_IFFREE (badlen, int); + if (myeg) + CCtsp_free_edgegenerator (myeg); + return 1; + } + } + CC_IFFREE (badlist, int); + CC_IFFREE (badlen, int); + + if (pricing(G,dat,scount,srk, &badcount, &badlist, &badlen, myeg, 1)) { + fprintf (stderr, "pricing failed\n"); + if (myeg) + CCtsp_free_edgegenerator (myeg); + return 1; + } + } + + *finished = 1; + if (myeg) + CCtsp_free_edgegenerator (myeg); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int pricing (graph *G, CCdatagroup *dat, stats *scount, srkstuff *srk, + int *badcount, int **badlist, int **badlen, + CCtsp_edgegenerator *eg, int usehit) +#else +static int pricing (G, dat, scount, srk, badcount, badlist, badlen, eg, usehit) +graph *G; +CCdatagroup *dat; +stats *scount; +srkstuff *srk; +int *badcount; +int **badlist, **badlen; +CCtsp_edgegenerator *eg; +int usehit; +#endif +{ + int i, k; + double szeit, penalty; + double *orig_pi = (double *) NULL; + int *orig_parent = (int *) NULL; + int rval = 0; + int ncount = G->nnodes; + node *nodelist = G->nodelist; + char *hit = (char *) NULL; + + szeit = CCutil_zeit(); + printf ("Pricing ...\n"); + fflush (stdout); + + orig_pi = CC_SAFE_MALLOC (ncount*3/2+1, double); + orig_parent = CC_SAFE_MALLOC (ncount*3/2+1, int); + if (!orig_pi || !orig_parent) { + fprintf (stderr, "out of memory in pricing\n"); + rval = 1; goto CLEANUP; + } + + if (usehit) { + hit = CC_SAFE_MALLOC (ncount*3/2 + 1, char); + if (!hit) { + fprintf (stderr, "out of memory in pricing\n"); + rval = 1; goto CLEANUP; + } + } + + for (i = 0; i < 3*ncount/2; i++) { + k = nodelist[i].blossom_parent; + orig_parent[i] = k; + orig_pi[i] = ((double) nodelist[i].pi) / 2.0; + if (hit) { + hit[i] = nodelist[i].hit; + } + } + + if (matching_price (ncount, dat, orig_pi, orig_parent, badcount, + badlist, badlen, &penalty, eg, hit) ) { + fprintf (stderr, "matching_price failed\n"); + rval = 1; goto CLEANUP; + } + + printf("\n%i Edges are wrong in the extra graph, penalty=%.4f\n", + *badcount, penalty); + + printf (" Total time in pricing: %.2f seconds\n", CCutil_zeit () - szeit); + fflush(stdout); + +CLEANUP: + + CC_IFFREE (orig_pi, double); + CC_IFFREE (orig_parent, int); + CC_IFFREE (hit, char); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int test_matching (graph *G, CCdatagroup *dat, int *elen, int fractional, + int *bad) +#else +static int test_matching (G, dat, elen, fractional, bad) +graph *G; +CCdatagroup *dat; +int *elen; +int fractional; +int *bad; +#endif +{ + int i, c, len; + double a = 0.0, b = 0.0; + edge *e; + int ncount = G->nnodes; + node *nodelist = G->nodelist; + + *bad = 0; + + if (dat) { + if (fractional) { + for (i = 0; i < G->nedges; i++) { + e = G->edgelist + i; + if (e->x == 1) { + a += (double) CCutil_dat_edgelen (e->orig_nod1, e->orig_nod2, dat); + a += (double) CCutil_dat_edgelen (e->orig_nod1, e->orig_nod2, dat); + } else if (e->x == HALF) { + a += (double) CCutil_dat_edgelen (e->orig_nod1, e->orig_nod2, dat); + } + } + for (i = 0; i < ncount; i++) + b += (double) nodelist[i].pi; + } else { + for (i = 0; i < ncount; i++) { + e = nodelist[i].matched_edge + G->edgelist; + a += (double) CCutil_dat_edgelen (e->orig_nod1, e->orig_nod2, dat); + } + for (i = 0; i <= 3*ncount/2; i++) + b += (double) nodelist[i].pi; + } + } else { + if (fractional) { + for (i = 0; i < ncount; i++) { + a += (double) elen[nodelist[i].matched_edge]; + b += (double) nodelist[i].pi; + } + } else { + for (i = 0; i < ncount; i++) { + a += (double) elen[nodelist[i].matched_edge]; + } + for (i = 0; i <= 3*ncount/2; i++) + b += (double) nodelist[i].pi; + } + } + b /= 2.0; + a /= 2.0; + printf(" Matching Length: %.1f, Dual %.1f\n", a, b); + fflush (stdout); + + if (a != b) { + printf ("ERROR: the primal and dual values do not agree\n"); + fflush (stdout); + *bad = 1; + return 0; + } + + if (fractional) { + for (i = 0, e = G->edgelist; i < G->nedges; i++, e++) { + if (dat) { + len = 2 * CCutil_dat_edgelen (e->orig_nod1, e->orig_nod2, dat); + } else { + len = 2 * elen[i]; + } + if ((c = len - nodelist[e->nod1].pi-nodelist[e->nod2].pi) < 0) { + printf("ERROR: Edge %i %i has slack < 0\n", e->nod1, e->nod2); + fflush (stdout); + *bad = 1; + return 0; + } + if (e->x != 0 && c > 0) { + printf("ERROR: Edge %i %i has x != 0 and slack > 0\n", + e->nod1, e->nod2); + fflush (stdout); + *bad = 1; + return 0; + } + } + } else { + int *mlist = (int *) NULL; + int *mlen = (int *) NULL; + double *pi = (double *) NULL; + int *parent = (int *) NULL; + int csbad, k; + int *badlist = (int *) NULL; + int *badlen = (int *) NULL; + int badcount = 0; + double penalty; + + mlist = CC_SAFE_MALLOC (ncount, int); + mlen = CC_SAFE_MALLOC (ncount/2, int); + pi = CC_SAFE_MALLOC (ncount*3/2+1, double); + parent = CC_SAFE_MALLOC (ncount*3/2+1, int); + if (!mlist || !mlen || !pi || !parent) { + fprintf (stderr, "out of memory in test_matching\n"); + CC_IFFREE (mlist, int); + CC_IFFREE (mlen, int); + CC_IFFREE (pi, double); + CC_IFFREE (parent, int); + return 1; + } + + for (i = 0, e = G->edgelist, k = 0; i < G->nedges; i++, e++) { + if (e->x == 1) { + mlist[2*k] = e->orig_nod1; + mlist[2*k + 1] = e->orig_nod2; + if (dat) { + mlen[k] = CCutil_dat_edgelen (e->orig_nod1, e->orig_nod2, dat); + } else { + mlen[k] = elen[i]; + } + k++; + } + } + for (i = 0; i < 3*ncount/2; i++) { + parent[i] = nodelist[i].blossom_parent; + pi[i] = ((double) nodelist[i].pi) / 2.0; + } + + if (matching_check (ncount, pi, parent, mlist, mlen, &csbad)) { + fprintf (stderr, "matching_check failed\n"); + CC_FREE (mlist, int); + CC_FREE (mlen, int); + CC_FREE (pi, double); + CC_FREE (parent, int); + return 1; + } + + if (csbad) { + printf ("matching_check found an error\n"); + fflush (stdout); + *bad = 1; + CC_FREE (mlist, int); + CC_FREE (mlen, int); + CC_FREE (pi, double); + CC_FREE (parent, int); + return 0; + } + + if (matching_price (ncount, dat, pi, parent, &badcount, + &badlist, &badlen, &penalty, (CCtsp_edgegenerator *) NULL, + (char *) NULL)) { + fprintf (stderr, "matching_price failed\n"); + CC_FREE (mlist, int); + CC_FREE (mlen, int); + CC_FREE (pi, double); + CC_FREE (parent, int); + return 1; + } + + if (badcount) { + printf ("pricing on complete graph found %d bad edges\n", badcount); + fflush (stdout); + *bad = 1; + CC_IFFREE (badlist, int); + CC_IFFREE (badlen, int); + CC_FREE (mlist, int); + CC_FREE (mlen, int); + CC_FREE (pi, double); + CC_FREE (parent, int); + return 0; + } + + CC_FREE (mlist, int); + CC_FREE (mlen, int); + CC_FREE (pi, double); + CC_FREE (parent, int); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dual_match_len (graph *G, int fractional, double *val) +#else +static void dual_match_len (G, fractional, val) +graph *G; +int fractional; +double *val; +#endif +{ + int i; + double b = 0.0; + int ncount = G->nnodes; + node *nodelist = G->nodelist; + + if (fractional) { + for (i = 0; i < ncount; i++) { + b += (double) nodelist[i].pi; + } + } else { + for (i = 0; i <= 3*ncount/2; i++) + b += (double) nodelist[i].pi; + } + *val = b / 2.0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int make_match (graph *G) +#else +static int make_match (G) +graph *G; +#endif +{ + int i, i2, j, k, start, counter=0; + int ncount = G->nnodes; + edge *e; + node *nodelist = G->nodelist; + edge *edgelist = G->edgelist; + + for (i = 0; i < ncount; i++) { + if (nodelist[i].status == MATCHED) + counter++; + if (nodelist[i].status == HALVES) { + k = 1; + start = i; + i2 = i; + j = OTHEREND_INT (PEDGE(nodelist[i2].matched_edge), i2); + do { + e = PEDGE(nodelist[j].matched_edge); + if (k % 2) { + nodelist[i2].status = MATCHED; + nodelist[j].status = MATCHED; + edgelist[nodelist[j].matched_edge].x = 0; + nodelist[j].matched_edge = nodelist[i2].matched_edge; + edgelist[nodelist[j].matched_edge].x = 1; + } + i2 = j; + j = OTHEREND_INT (e, i2); + k++; + } while (j!=start); + nodelist[i2].status = UNMATCHED; + edgelist[nodelist[i2].matched_edge].x = 0; + nodelist[i2].matched_edge = -1; + counter++; + } + nodelist[i].label = NIX; + nodelist[i].child = -1; + nodelist[i].sibling = -1; + nodelist[i].parent = -1; + nodelist[i].parent_edge = -1; + nodelist[i].mark = 0; + nodelist[i].tree_root = -1; + } + + counter=0; + for (i = 0; i < ncount; i++) + if (nodelist[i].status == MATCHED) + counter++; + // printf(" %i nodes are matched now !\n",counter); + + /* build list of unmatched nodes */ + + G->unmatched_count = 0; + for (i = 0; i < ncount; i++) { + if (nodelist[i].status == UNMATCHED) { + G->unmatched_count++; + } + } + + j = -1; + for (i = 0; i < ncount; i++) { + if (nodelist[i].status == UNMATCHED) { + if (j != -1) + nodelist[j].mark = i; + j = i; + } + } + if (j != -1) + nodelist[j].mark = -1; + + + if (G->unmatched_count == 0) { + G->unmatched = -1; + } else { + for (i = 0; nodelist[i].status != UNMATCHED; i++); + G->unmatched = i; + } + // printf(" unmatched_count = %i\n", G->unmatched_count); + // fflush (stdout); + + /* hit is used to identify the blossoms that receive a label + during */ + /* the matching run; this will help the pricing code */ + + for (i = 0; i < 3 * ncount / 2; i++) + nodelist[i].hit = 0; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int build_graph (graph *G, int ncount, int ecount, int *elist, int *elen) +#else +static int build_graph (G, ncount, ecount, elist, elen) +graph *G; +int ncount, ecount; +int *elist, *elen; +#endif +{ + int i, j; + edge *e; + + if (ncount % 2 != 0) { + fprintf (stderr, "problem has an odd number of nodes\n"); + return 1; + } + + G->nnodes = ncount; + G->nodelist = CC_SAFE_MALLOC ((3*ncount/2+1), node); + if (!G->nodelist) { + fprintf (stderr, "out of memory in build_graph\n"); + return 1; + } + for (i = 0; i < 3*ncount/2 + 1; i++) { + G->nodelist[i].blossom_parent = -1; + G->nodelist[i].matched_edge = -1; + G->nodelist[i].edg_list = -1; + } + + /* init unused */ + + j = 3*ncount/2; + for (i = ncount; i < j; i++) { + G->nodelist[i].mark = i + 1; + } + G->nodelist[j].mark = -1; + G->unused = ncount; + + G->nedges = ecount; + G->max_nedges = ecount + (1.5 * ncount); + + G->edgelist = CC_SAFE_MALLOC (G->max_nedges, edge); + if (!G->edgelist) { + fprintf (stderr, "out of memory in build_graph\n"); + CC_FREE (G->nodelist, node); + return 1; + } + + for (i = 0; i < ncount; i++) { + G->nodelist[i].mark = 0; + } + + for (i = 0, e = G->edgelist; i < ecount; i++, e++) { + e->nod1 = elist[2*i]; + e->nod2 = elist[2*i+1]; + e->orig_nod1 = e->nod1; + e->orig_nod2 = e->nod2; + e->slack = 2 * elen[i]; /* to work with ints */ + e->mark = 0; + e->ptrs[0] = G->nodelist[e->nod1].edg_list; + G->nodelist[e->nod1].edg_list = 2*i; + e->ptrs[1] = G->nodelist[e->nod2].edg_list; + G->nodelist[e->nod2].edg_list = 2*i + 1; + } + for (; i < G->max_nedges; i++) + G->edgelist[i].mark = 0; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int write_match (graph *G, CCdatagroup *dat, int *elen, char* fname, int *outp) +#else + static int write_match (G, dat, elen, fname, outp) +graph *G; +CCdatagroup *dat; +int *elen; +char *fname; +int *outp; +#endif +{ + int i, c, len = 0; + edge *e; + FILE* fp; + + double szeit; + + szeit = CCutil_zeit(); + // printf(" Writing %s ...", fname); + // fflush(stdout); + + // if ((fp = fopen (fname, "w")) == (FILE *) NULL) { + // fprintf(stderr," Error: Can't open file %s\n",fname); + // return 1; + // } + + c = 0; + for (i = 0; i < G->nnodes; i++) { + if (i == G->edgelist[G->nodelist[i].matched_edge].orig_nod2 || + G->edgelist[G->nodelist[i].matched_edge].x == HALF) { + c++; + } + } + // printf(" %i nodes, %i edges ", G->nnodes, c); + // fprintf (fp, "%i %i\n", G->nnodes, c); + outp[0] = c; + int KOUNT=0; + for (i = 0; i < G->nnodes; i++) { + e = PEDGE(G->nodelist[i].matched_edge); + if (i == e->orig_nod2 || e->x == HALF) { + if (dat) + len = CCutil_dat_edgelen (e->orig_nod1, e->orig_nod2, dat); + else + len = elen[e - G->edgelist]; + outp[1+3*KOUNT] = G->edgelist[G->nodelist[i].matched_edge].orig_nod1; + outp[1+3*KOUNT+1] = G->edgelist[G->nodelist[i].matched_edge].orig_nod2; + outp[1+3*KOUNT+2] = len; + KOUNT++; + // fprintf (fp,"%i %i %i\n", + // G->edgelist[G->nodelist[i].matched_edge].orig_nod1, + // G->edgelist[G->nodelist[i].matched_edge].orig_nod2, len); + } + } + // fclose(fp); + + // printf(" ... in %.2f sec !! \n", CCutil_zeit () - szeit); + // fflush(stdout); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int write_blossom_tree (graph *G, char* blossom_tree_file) +#else +static int write_blossom_tree (G, blossom_tree_file) +graph *G; +char *blossom_tree_file; +#endif +{ + int i,j; + FILE *fp; + double szeit; + double t; + + szeit = CCutil_zeit(); + printf(" Writing %s ...",blossom_tree_file); + fflush(stdout); + + if ((fp = fopen (blossom_tree_file, "w")) == (FILE *) NULL) { + fprintf(stderr," cannot open file %s\n",blossom_tree_file); + return 1; + } + + for (i = 0; i < 3*G->nnodes/2; i++) { + j = G->nodelist[i].blossom_parent; + t = ((double) G->nodelist[i].pi) / 2.0; + fwrite (&j, sizeof(int), 1, fp); + fwrite (&t, sizeof(double), 1, fp); + } + fclose(fp); + + printf(" ... in %.2f sec !! \n", CCutil_zeit () - szeit); + fflush(stdout); + + return 0; +} diff --git a/contrib/blossom/MATCH/match.h b/contrib/blossom/MATCH/match.h new file mode 100644 index 0000000000000000000000000000000000000000..f18f6cf0c4cbd1ec2aa6ab80722af6685cd294ad --- /dev/null +++ b/contrib/blossom/MATCH/match.h @@ -0,0 +1,28 @@ +#ifndef __MATCH_H +#define __MATCH_H + +#include "concorde.h" + +#ifdef CC_PROTOTYPE_ANSI + +int + perfect_match (int ncount, CCdatagroup *dat, int ecount, int **elist, + int **elen, char *blo_filename, char *mat_filename, + int just_fractional, int no_fractional, int use_all_trees, + int partialprice, double *totalzeit), + matching_price (int ncount, CCdatagroup *dat, double *orig_pi, + int *orig_parent, int *badcount, int **badlist, int **badlen, + double *penalty, CCtsp_edgegenerator *starteg, char *hit), + matching_check (int ncount, double *orig_pi, int *orig_parent, + int *matchlist, int *mlen, int *csbad); + +#else + +int + perfect_match (), + matching_price (), + matching_check (); + +#endif + +#endif /* __MATCH_H */ diff --git a/contrib/blossom/MATCH/matprice.c b/contrib/blossom/MATCH/matprice.c new file mode 100644 index 0000000000000000000000000000000000000000..338541933abca768aaf8504af87cc45640aeb61b --- /dev/null +++ b/contrib/blossom/MATCH/matprice.c @@ -0,0 +1,1443 @@ +/************************************************************************/ +/* */ +/* PRICING ROUTINE FOR WEIGHTED PERFECT MATCHING PROBLEMS */ +/* */ +/* Written by: D. Applegate, W. Cook, and A. Rohe */ +/* Date: August 1, 1996 */ +/* */ +/* */ +/* EXPORTED FUNCTION: */ +/* int matching_price (int ncount, CCdatagroup *dat, */ +/* double *orig_pi, int *orig_parent, int *badcount, */ +/* int **badlist, int **badlen, double *penalty, */ +/* edgegenerator *starteg, char *hit) */ +/* RETURNS the edges of negative reduced cost. */ +/* -ncount is the number of nodes in the graph */ +/* -dat is a pointer to the data used to generate edge lengths */ +/* -orig_pi is an array giving the dual variables on the nodes */ +/* and blossoms (the first ncount entries are the nodes) */ +/* -orig_parent is an array giving the parents of the nodes and */ +/* and blossoms in the nesting structure created by the */ +/* matching algorithm (the entry is -1 if there is no parent)*/ +/* -badcount will return the number of edges having negative */ +/* reduced cost */ +/* -badlist will return the negative edges in node node format */ +/* (the space for badlist will be allocated by this routine) */ +/* -badlen will return the lengths of the negative edges */ +/* -penalty will return the sum of the negative reduced costs */ +/* cutcount) */ +/* -starteg is a pointer to an edgegenerator that has been */ +/* initialized (this can be NULL, in which cas the pricing */ +/* is over the complete graph) */ +/* -hit is array (of length 3*ncount/2) that marks the nodes */ +/* that have been hit by a positive dual change during the */ +/* course of the algorithm (it can be NULL) */ +/* int matching_check (int ncount, CCdatagroup *dat, int *matchlist, */ +/* int *mlen, int *orig_parent, int *csbad) */ +/* CHECKS that the complementary slackness conditions hold. */ +/* -variables are as above. */ +/* -matchlist is an array of length ncount giving the edges */ +/* in a perfect matching in end end format */ +/* -mlen is an array of lenght ncount/2 giving the lengths of */ +/* the edges in the matching */ +/* -csbad will return 1 if complementary slackness conditions */ +/* are violated and 0 otherwise) */ +/* */ +/* NOTES: */ +/* */ +/* Returns 0 if it worked and 1 otherwise (for example, when one */ +/* of the mallocs failed). The nodes in the graph should be named */ +/* 0 through #nodes - 1. */ +/* */ +/* The arrays orig_pi and orig_parent are 3/2 ncount long (this */ +/* is the maximum number of nodes + blossoms used in the blossom */ +/* algorithms. Some of the entries will be wasted space. The real */ +/* entries can be determined by following the parent pointers from */ +/* the ncount nodes (the first ncount entries in the arrays). */ +/* */ +/* If matchlist is not NULL, then the complementary slackness */ +/* conditions will be checked for the matching and dual solution. */ +/* */ +/************************************************************************/ + +#include "concorde.h" +#include "match.h" + +#define MAT_GEN_EPSILON 0.000001 +#define MAT_GEN_INFINITY 1000000000000.0 + +typedef struct node { + struct node *parent; + struct node *child; + struct node *sibling; + struct anc *addset; + struct anc *evallist; + double pi; + double sum; + int prenum; + int mark; + char hit; +} node; + +typedef struct anc { + struct anc *parent; + struct anc *next; + struct node *ancestor; + struct node *lca; + int rank; +} anc; + +typedef struct tree { + struct node *nodelist; + struct node *root; + int ncount; + int realncount; +} tree; + +typedef struct junk_param { + struct tree *T; + struct node *nodelist; + CCdatagroup *dat; + int *list; + int *len; + int *badlist; + int *badlen; + int *mark; + double penalty; + int nwant; + int ngot; + int total; + int badcount; + int phase; +} junk_param; + +#ifdef CC_PROTOTYPE_ANSI + +static void + number_tree (node *n, int *prenum, int depth, int *maxdepth), + freetree (tree *T); +static char + get_hit_work (node *n); +static int + cs_matching (tree *T, int *mlist, int *mlen, int *bad), + check_card (node *b, int *not_odd), + match_kdtree_price (tree *T, CCdatagroup *dat, int *badcount, + int **badlist, int **badlen, double *penalty), + merge_edge_lists (int *totalcount, int **totallist, int **totallen, + int ecount, int *elist, int *elen), + buildtree (tree *T, int ncount, double *pi, int *parent, char *hit), + junk_check (int n1, int n2, void *pass_param), + ancestor_price (tree *T, int zero_rc, int ecount, int *elist, + int *elen, int *badcount, int **badlist, int **badlen, double *penalty); +static double + get_sum_work (node *n); +static anc + *ancest_work (node *p), + *find_anc (anc *x), + *union_anc (anc *x, anc *y); + +#else + +static void + number_tree (), + freetree (); +static char + get_hit_work (node *n); +static int + cs_matching (), + check_card (), + match_kdtree_price (), + merge_edge_lists (), + buildtree (), + junk_check (), + ancestor_price (); +static double + get_sum_work (); +static anc + *ancest_work (), + *find_anc (), + *union_anc (); + +#endif + + +#ifdef DEBUG_MATPRICE +#ifdef CC_PROTOTYPE_ANSI + +static void + price_list (tree *T, int ecount, int *elist, int *elen, int *nbad); +static double + price_it (tree *T, int n1, int n2, int len); +static node + *easy_lca (node *n1, node *n2); + +#else + +static void + price_list (); +static double + price_it (); +static node + *easy_lca (); + +#endif +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int matching_price (int ncount, CCdatagroup *dat, double *orig_pi, + int *orig_parent, int *badcount, int **badlist, + int **badlen, double *penalty, CCtsp_edgegenerator *starteg, + char *hit) +#else +int matching_price (ncount, dat, orig_pi, orig_parent, + badcount, badlist, badlen, penalty, starteg, hit) +int ncount; +CCdatagroup *dat; +double *orig_pi; +int *orig_parent; +int *badcount; +int **badlen, **badlist; +double *penalty; +CCtsp_edgegenerator *starteg; +char *hit; +#endif +{ + tree T; + CCtsp_edgegenerator eg; + CCtsp_edgegenerator *myeg = (CCtsp_edgegenerator *) NULL; + double *sums = (double *) NULL; + int i; + int ngot, finished; + int *plist = (int *) NULL; + int *plen = (int *) NULL; + int nwant; + int rval = 0; + int rcount; + int *rlist = (int *) NULL; + int *rlen = (int *) NULL; + double rpenalty = 0.0; + int tcount = 0; + int *tlist = (int *) NULL; + int *tlen = (int *) NULL; + int totalpot = 0; + + + // printf ("matching_price ....\n");fflush (stdout); + *badcount = 0; + *badlist = (int *) NULL; + *badlen = (int *) NULL; + *penalty = 0.0; + + if (buildtree (&T, ncount, orig_pi, orig_parent, hit)) { + // fprintf (stderr, "buildtree failed\n"); + return 1; + } + + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE && !starteg) { + // printf ("Use kd-tree pricing ....\n"); + fflush (stdout); + + if (match_kdtree_price (&T, dat, badcount, badlist, badlen, penalty)) { + // fprintf (stderr, "match_kdtree_price failed\n"); + rval = 1; + goto CLEANUP; + } + } else { + // printf ("Use general pricing ...\n"); + fflush (stdout); + + if (!starteg) { + if (CCtsp_init_edgegenerator (&eg, ncount, dat, (CCtsp_genadj *) NULL, + CCtsp_PRICE_COMPLETE_GRAPH)) { + // fprintf (stderr, "CCtsp_init_edgegenerator failed\n"); + freetree (&T); + return 1; + } + myeg = ⪚ + } else { + myeg = starteg; + } + + sums = CC_SAFE_MALLOC (ncount, double); + if (!sums) { + // fprintf (stderr, "out of memory in matching_price\n"); + rval = 1; + CCtsp_free_edgegenerator (&eg); + goto CLEANUP; + } + + for (i = 0; i < ncount; i++) { + sums[i] = T.nodelist[i].sum; + } + + if (CCtsp_reset_edgegenerator (myeg, sums)) { + // fprintf (stderr, "CCtsp_reset_edgegenerator failed\n"); + rval = 1; + if (!starteg) + CCtsp_free_edgegenerator (&eg); + goto CLEANUP; + } + + nwant = 3 * ncount; + + plist = CC_SAFE_MALLOC (nwant * 2, int); + plen = CC_SAFE_MALLOC (nwant, int); + if (!plist || !plen) { + // fprintf (stderr, "out of memory in matching_price\n"); + rval = 1; + if (!starteg) + CCtsp_free_edgegenerator (&eg); + goto CLEANUP; + } + + do { + ngot = 0; + finished = 0; + if (CCtsp_generate_edges (myeg, nwant, &ngot, plist, plen, &finished)) { + // fprintf (stderr, "generate_edges failed\n"); + rval = 1; + if (!starteg) + CCtsp_free_edgegenerator (&eg); + CC_IFFREE (tlist, int); + CC_IFFREE (tlen, int); + goto CLEANUP; + } + + // printf ("Found %d potential edges\n", ngot); + // printf ("Finished = %d\n", finished); + fflush (stdout); + totalpot += ngot; + + if (ancestor_price (&T, 0, ngot, plist, plen, &rcount, &rlist, + &rlen, &rpenalty)) { + // fprintf (stderr, "ancestor_price failed\n"); + rval = 1; + CC_IFFREE (tlist, int); + CC_IFFREE (tlen, int); + if (!starteg) + CCtsp_free_edgegenerator (&eg); + goto CLEANUP; + } + + if (rcount) { + *badcount += rcount; + *penalty += rpenalty; + + if (merge_edge_lists (&tcount, &tlist, &tlen, + rcount, rlist, rlen)) { + // fprintf (stderr, "merge_edge_lists failed\n"); + rval = 1; + CC_IFFREE (tlist, int); + CC_IFFREE (tlen, int); + if (!starteg) + CCtsp_free_edgegenerator (&eg); + goto CLEANUP; + } + + CC_IFFREE (rlist, int); + CC_IFFREE (rlen, int); + } + } while (!finished); + + // printf ("Total potential edges: %d\n", totalpot); + fflush (stdout); + + if (badcount) { + *badlist = tlist; + *badlen = tlen; + } + + if (!starteg) + CCtsp_free_edgegenerator (&eg); + } + +CLEANUP: + + CC_IFFREE (plist, int); + CC_IFFREE (plen, int); + CC_IFFREE (rlist, int); + CC_IFFREE (rlen, int); + CC_IFFREE (sums, double); + freetree (&T); + + return rval; +} + + +#ifdef CC_PROTOTYPE_ANSI +int matching_check (int ncount, double *orig_pi, int *orig_parent, + int *matchlist, int *mlen, int *csbad) +#else +int matching_check (ncount, orig_pi, orig_parent, matchlist, mlen, csbad) +int ncount; +double *orig_pi; +int *orig_parent; +int *matchlist; +int *mlen; +int *csbad; +#endif +{ + tree T; + double szeit = CCutil_zeit (); + + *csbad = 0; + if (buildtree (&T, ncount, orig_pi, orig_parent, (char *) NULL)) { + fprintf (stderr, "buildtree failed\n"); + return 1; + } + + printf ("Check complementary slackness conditions ....\n"); + fflush (stdout); + if (cs_matching (&T, matchlist, mlen, csbad)) { + fprintf (stderr, "cs_matching failed\n"); + freetree (&T); + return 1; + } + if (*csbad) { + printf ("\nWARNING: complementary slackness NOT satisfied\n\n"); + fflush (stdout); + } else { + printf ("Complementary slackness satisfied (%.2f seconds)\n\n", + CCutil_zeit () - szeit); + fflush (stdout); + } + + freetree (&T); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cs_matching (tree *T, int *mlist, int *mlen, int *bad) +#else +static int cs_matching (T, mlist, mlen, bad) +tree *T; +int *mlist, *mlen; +int *bad; +#endif +{ + int ncount = T->realncount; + node *nodelist = T->nodelist; + int i, k, not_odd = 0; + int bcount = 0; + int *blist = (int *) NULL; + int *blen = (int *) NULL; + char *mark = (char *) NULL; + double t, penalty = 0.0; + node *b, *n, *n1, *n2; + int local_magic = 0; + + *bad = 0; + + mark = CC_SAFE_MALLOC (ncount, char); + if (!mark) { + fprintf (stderr, "out of memory in cs_matching\n"); + return 1; + } + for (i = 0; i < ncount; i++) + mark[i] = 0; + for (i = 0; i < ncount; i++) { + if (mark[mlist[i]]) { + printf ("node %d meets two edges in matching\n", mlist[i]); + fflush (stdout); + *bad = 1; + goto CLEANUP; + } else { + mark[mlist[i]] = 1; + } + } + printf ("All nodes meet exactly one matching edge\n"); + fflush (stdout); + + t = 0.0; + for (i = 0; i < ncount/2; i++) { + t += (double) mlen[i]; + } + printf ("Length of matching: %.2f\n", t); + fflush (stdout); + + if (ancestor_price (T, 1, ncount / 2, mlist, mlen, &bcount, &blist, + &blen, &penalty)) { + fprintf (stderr, "ancestor_price failed\n"); + return 1; + } + CC_IFFREE (blist, int); + CC_IFFREE (blen, int); + + if (bcount > 0) { + printf ("%d matching edges at nonzero reduced cost (%f sum)\n", + bcount, penalty); + fflush (stdout); + *bad = 1; + goto CLEANUP; + } else { + printf ("All matching edges have zero reduced cost\n"); + fflush (stdout); + } + + for (b = T->root->child; b; b = b->sibling) + check_card (b, ¬_odd); + if (not_odd) { + printf ("%d blossoms do not have odd cardinality\n", not_odd); + fflush (stdout); + *bad = 1; + goto CLEANUP; + } else { + printf ("All blossoms have odd cardinality\n"); + fflush (stdout); + } + + for (i = 0; i < T->ncount; i++) { + nodelist[i].mark = 0; + nodelist[i].prenum = 0; + } + for (i = 0; i < ncount/2; i++) { + n1 = nodelist + mlist[2*i]; + n2 = nodelist + mlist[2*i+1]; + local_magic++; + + n = n1; + do { + n->mark = local_magic; + n = n->parent; + } while (n); + + do { + n2->prenum++; + n2 = n2->parent; + } while (n2->mark != local_magic); + + do { + n1->prenum++; + n1 = n1->parent; + } while (n1 != n2); + } + for (i = 0; i < T->ncount; i++) + nodelist[i].mark = 0; + + k = 0; + for (i = T->realncount; i < T->ncount; i++) { + if (nodelist[i].prenum != 1 && nodelist + i != T->root) + k++; + } + if (k) { + printf ("%d blossoms do not contain exactly one matching edge\n", k); + fflush (stdout); + *bad = 1; + goto CLEANUP; + } else { + printf ("All blossoms meet exactly one matching edge\n"); + fflush (stdout); + } + + + +CLEANUP: + + CC_IFFREE (mark, char); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_card (node *b, int *not_odd) +#else +static int check_card (b, not_odd) +node *b; +int *not_odd; +#endif +{ + if (b->child) { + int card = 0; + node *c; + + for (c = b->child; c; c = c->sibling) { + card += check_card (c, not_odd); + } + if (card % 2 == 0) + (*not_odd)++; + return card; + } else { + return 1; + } +} + + +#define PULLIT 20 + +#ifdef CC_PROTOTYPE_ANSI +static int match_kdtree_price (tree *T, CCdatagroup *dat, int *badcount, + int **badlist, int **badlen, double *penalty) +#else +static int match_kdtree_price (T, dat, badcount, badlist, badlen, penalty) +tree *T; +CCdatagroup *dat; +int *badcount; +int **badlist, **badlen; +double *penalty; +#endif +{ + double smax = - MAT_GEN_INFINITY; + int i, j; + node *nodelist = T->nodelist; + int ncount = T->realncount; + double *wcoord = (double *) NULL; + double szeit = CCutil_zeit (); + double dist; + CCkdtree kt; + junk_param p; + int *list = (int *) NULL; + int *len = (int *) NULL; + int *perm = (int *) NULL; + int newtop, newbottom; + int rval = 0; + + { + double mins = nodelist[0].sum; + double maxs = nodelist[0].sum; + double *sum = (double *) NULL; + + sum = CC_SAFE_MALLOC (ncount, double); + perm = CC_SAFE_MALLOC (ncount, int); + if (!sum || !perm) { + fprintf (stderr, "out of memory in match_kdtree_price\n"); + CC_IFFREE (sum, double); + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + sum[i] = nodelist[i].sum; + perm[i] = i; + } + + for (i = 0; i < ncount; i++) { + if (sum[i] > maxs) + maxs = sum[i]; + if (sum[i] < mins) + mins = sum[i]; + } + printf ("Spread: (%f, %f)\n", mins, maxs); + fflush (stdout); + + CCutil_double_perm_quicksort (perm, sum, ncount); + + newtop = ncount - ncount/PULLIT; + newbottom = ncount/PULLIT; + + printf ("Remove %d nodes to get spead of (%f, %f)\n", + 2 * (ncount / PULLIT), sum[perm[newbottom]], sum[perm[newtop - 1]]); + fflush (stdout); + + CC_IFFREE (sum, double); + } + + *badcount = 0; + *badlist = (int *) NULL; + *badlen = (int *) NULL; + *penalty = 0.0; + + p.T = T; + p.dat = dat; + p.nodelist = nodelist; + p.nwant = 3 * ncount; + p.ngot = 0; + p.total = 0; + p.penalty = 0.0; + + list = CC_SAFE_MALLOC (2 * p.nwant, int); + len = CC_SAFE_MALLOC (p.nwant, int); + p.mark = CC_SAFE_MALLOC (ncount, int); + + if (!list || !len || !p.mark) { + fprintf (stderr, "out of memory in match_kdtree_price\n"); + rval = 1; + goto CLEANUP; + } + + p.list = list; + p.len = len; + p.badcount = 0; + p.badlist = (int *) NULL; + p.badlen = (int *) NULL; + + for (i = 0; i < ncount; i++) + p.mark[i] = 0; + + wcoord = CC_SAFE_MALLOC (ncount, double); + if (!wcoord) { + fprintf (stderr, "out of memory in match_kdtree_price\n"); + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < ncount; i++) + wcoord[i] = 0.0; + for (j = newbottom; j < newtop; j++) { + i = perm[j]; + if (nodelist[i].sum > smax) + smax = nodelist[i].sum; + } + for (j = newbottom; j < newtop; j++) { + i = perm[j]; + wcoord[i] = smax - nodelist[i].sum; + } + + dist = 2 * smax - MAT_GEN_EPSILON; + + printf ("Build the kdtree ...\n"); fflush (stdout); + + if (CCkdtree_build (&kt, ncount, dat, wcoord)) { + fprintf (stderr, "CCkdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + + p.phase = 0; + for (i = 0; i < newbottom; i++) + CCkdtree_delete (&kt, perm[i]); + for (i = ncount - 1; i >= newtop; i--) + CCkdtree_delete (&kt, perm[i]); + for (j = newbottom; j < newtop; j++) { + i = perm[j]; + if (nodelist[i].hit) { + if (CCkdtree_fixed_radius_nearest (&kt, dat, wcoord, i, dist, + junk_check, (void *) (&p))) { + fprintf (stderr, "CCkdtree_fixed_radius_nearest failed\n"); + CCkdtree_free (&kt); + CC_IFFREE (p.badlist, int); + CC_IFFREE (p.badlen, int); + rval = 1; + goto CLEANUP; + } + } + if (j % 100000 == 99999) { + printf ("Processed %d nodes\n", j + 1); + fflush (stdout); + } + } + CCkdtree_free (&kt); + + printf ("Processing the deleted nodes ....\n"); + fflush (stdout); + + smax = - MAT_GEN_INFINITY; + for (i = 0; i < ncount; i++) { + if (nodelist[i].sum > smax) + smax = nodelist[i].sum; + } + for (i = 0; i < ncount; i++) { + wcoord[i] = smax - nodelist[i].sum; + } + + dist = 2 * smax - MAT_GEN_EPSILON; + + if (CCkdtree_build (&kt, ncount, dat, wcoord)) { + fprintf (stderr, "CCkdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < newbottom; i++) + p.mark[perm[i]] = 1; + p.phase = 1; + + for (j = 0; j < newbottom; j++) { + i = perm[j]; + if (CCkdtree_fixed_radius_nearest (&kt, dat, wcoord, i, dist, + junk_check, (void *) (&p))) { + fprintf (stderr, "CCkdtree_fixed_radius_nearest failed\n"); + CCkdtree_free (&kt); + CC_IFFREE (p.badlist, int); + CC_IFFREE (p.badlen, int); + rval = 1; + goto CLEANUP; + } + if (j % 1000 == 999) { + printf ("+"); + fflush (stdout); + } + } + + printf ("\nNow the top nodes ....\n"); + fflush (stdout); + + for (i = ncount - 1; i >= newtop; i--) + p.mark[perm[i]] = 2; + p.phase = 2; + + for (j = ncount - 1; j >= newtop; j--) { + i = perm[j]; + if (CCkdtree_fixed_radius_nearest (&kt, dat, wcoord, i, dist, + junk_check, (void *) (&p))) { + fprintf (stderr, "CCkdtree_fixed_radius_nearest failed\n"); + CCkdtree_free (&kt); + CC_IFFREE (p.badlist, int); + CC_IFFREE (p.badlen, int); + rval = 1; + goto CLEANUP; + } + if (j % 1000 == 999) { + printf ("-"); + fflush (stdout); + } + } + CCkdtree_free (&kt); + printf ("\n"); + fflush (stdout); + + if (p.ngot) { + int *rlist = (int *) NULL; + int *rlen = (int *) NULL; + int rcount = 0; + double rpenalty = 0.0; + + if (ancestor_price (p.T, 0, p.ngot, p.list, p.len, &rcount, &rlist, + &rlen, &rpenalty)) { + fprintf (stderr, "ancestor_price failed\n"); + rval = 1; + goto CLEANUP; + } + + if (rcount) { + p.penalty += rpenalty; + if (merge_edge_lists (&(p.badcount), &(p.badlist), &(p.badlen), + rcount, rlist, rlen)) { + fprintf (stderr, "merge_edge_lists failed\n"); + CC_IFFREE (rlist, int); + CC_IFFREE (rlen, int); + CC_IFFREE (p.badlist, int); + CC_IFFREE (p.badlen, int); + rval = 1; + goto CLEANUP; + } + CC_IFFREE (rlist, int); + CC_IFFREE (rlen, int); + } + } + + printf ("Kdtree price time: %.2f seconds\n", CCutil_zeit () - szeit); + printf ("Total number of potential edges: %d\n", p.total); + fflush (stdout); + + *badcount = p.badcount; + *badlist = p.badlist; + *badlen = p.badlen; + *penalty = p.penalty; + +CLEANUP: + + CC_IFFREE (wcoord, double); + CC_IFFREE (list, int); + CC_IFFREE (len, int); + CC_IFFREE (p.mark, int); + CC_IFFREE (perm, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int junk_check (int n1, int n2, void *pass_param) +#else +static int junk_check (n1, n2, pass_param) +int n1, n2; +void *pass_param; +#endif +{ + junk_param *p = (junk_param *) pass_param; + double t; + int l; + + if ((!p->nodelist[n2].hit) || + (p->phase == 0 && n1 < n2) || + (p->phase == 1 && (n1 < n2 || !p->mark[n2])) || + (p->phase == 2 && (!p->mark[n2] || (p->mark[n2] == 2 && n1 < n2)))) { + l = CCutil_dat_edgelen (n1, n2, p->dat); + t = ((double) l) - p->nodelist[n1].sum - p->nodelist[n2].sum; + if (t > -MAT_GEN_EPSILON) { + printf ("What the hey: %f\n", t); + fflush (stdout); + } + p->total++; + p->len[p->ngot] = l; + p->list[2 * p->ngot] = n1; + p->list[2 * p->ngot + 1] = n2; + p->ngot++; + + if (p->ngot == p->nwant) { + int *rlist = (int *) NULL; + int *rlen = (int *) NULL; + int rcount = 0; + double rpenalty = 0.0; + + if (ancestor_price (p->T, 0, p->ngot, p->list, p->len, + &rcount, &rlist, &rlen, &rpenalty)) { + fprintf (stderr, "ancestor_price failed\n"); + return 1; + } + + if (rcount) { + p->penalty += rpenalty; + if (merge_edge_lists (&(p->badcount), &(p->badlist), + &(p->badlen), rcount, rlist, rlen)) { + fprintf (stderr, "merge_edge_lists failed\n"); + CC_IFFREE (rlist, int); + CC_IFFREE (rlen, int); + return 1; + } + CC_IFFREE (rlist, int); + CC_IFFREE (rlen, int); + } + p->ngot = 0; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int merge_edge_lists (int *totalcount, int **totallist, int **totallen, + int ecount, int *elist, int *elen) +#else +static int merge_edge_lists (totalcount, totallist, totallen, ecount, elist, + elen) +int *totalcount; +int **totallist, **totallen; +int ecount; +int *elist, *elen; +#endif +{ + int *nlist = (int *) NULL; + int *nlen = (int *) NULL; + int ncount = *totalcount + ecount; + int i, k; + + if (!ecount) + return 0; + + nlist = CC_SAFE_MALLOC (2 * ncount, int); + nlen = CC_SAFE_MALLOC (ncount, int); + if (!nlist || !nlen) { + fprintf (stderr, "out of memory in merge_edge_lists\n"); + CC_IFFREE (nlist, int); + CC_IFFREE (nlen, int); + return 1; + } + + for (i = 0; i < *totalcount; i++) { + nlist[2 * i] = (*totallist)[2 * i]; + nlist[2 * i + 1] = (*totallist)[2 * i + 1]; + nlen[i] = (*totallen)[i]; + } + for (k = 0; k < ecount; k++, i++) { + nlist[2 * i] = elist[2 * k]; + nlist[2 * i + 1] = elist[2 * k + 1]; + nlen[i] = elen[k]; + } + + if (*totalcount) { + CC_IFFREE (*totallist, int); + CC_IFFREE (*totallen, int); + } + + *totalcount = ncount; + *totallist = nlist; + *totallen = nlen; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int buildtree (tree *T, int ncount, double *pi, int *parent, char *hit) +#else +static int buildtree (T, ncount, pi, parent, hit) +tree *T; +int ncount; +double *pi; +int *parent; +char *hit; +#endif +{ + int bcount = 3 * ncount/2; + int *mark = (int *) NULL; + int *invnames = (int *) NULL; + int i, j, k; + int count = 0; + node *nodelist; + + T->ncount = 0; + T->realncount = 0; + T->nodelist = (node *) NULL; + + mark = CC_SAFE_MALLOC (bcount, int); + if (!mark) { + fprintf (stderr, "out of memory in buildtree\n"); + return 1; + } + + for (i = 0; i < bcount; i++) + mark[i] = 0; + + for (i = 0; i < ncount; i++) { + j = i; + while (j != -1 && mark[j] == 0) { + mark[j] = 1; + j = parent[j]; + } + } + for (i = 0; i < bcount; i++) + if (mark[i]) + count++; + + printf ("%d tree nodes\n", count); + fflush (stdout); + + + T->nodelist = CC_SAFE_MALLOC (count + 1, node); + if (!T->nodelist) { + fprintf (stderr, "out of memory in buildtree\n"); + CC_IFFREE (mark, int); + return 1; + } + T->ncount = count; + T->realncount = ncount; + T->root = T->nodelist + count; + T->root->parent = (node *) NULL; + T->root->child = (node *) NULL; + T->root->sibling = (node *) NULL; + T->root->pi = 0.0; + T->root->hit = 0; + nodelist = T->nodelist; + + invnames = CC_SAFE_MALLOC (bcount, int); + if (!invnames) { + fprintf (stderr, "out of memory in buildtree\n"); + CC_IFFREE (mark, int); + freetree (T); + return 1; + } + + for (k = 0, i = 0; i < bcount; i++) + if (mark[i]) + invnames[i] = k++; + + for (k = 0, i = 0; i < bcount; i++) { + if (mark[i]) { + if (parent[i] == -1) { + nodelist[k].parent = T->root; + } else { + nodelist[k].parent = nodelist + invnames[parent[i]]; + } + nodelist[k].child = (node *) NULL; + nodelist[k].sibling = (node *) NULL; + nodelist[k].pi = pi[i]; + if (hit) { + nodelist[k].hit = hit[i]; + } else { + nodelist[k].hit = 1; + } + k++; + } + } + + for (i = 0; i < count; i++) { + if (nodelist[i].parent->child == (node *) NULL) { + nodelist[i].parent->child = nodelist + i; + } else { + nodelist[i].sibling = nodelist[i].parent->child->sibling; + nodelist[i].parent->child->sibling = nodelist + i; + } + } + + T->root->sum = 0.0; + for (i = 0; i <= count; i++) + nodelist[i].mark = 0; + for (i = 0; i < ncount; i++) + get_sum_work (nodelist + i); + for (i = 0; i <= count; i++) + nodelist[i].mark = 0; + if (hit) { + int hcount = 0; + for (i = 0; i < ncount; i++) { + get_hit_work (nodelist + i); + if (nodelist[i].hit) + hcount++; + } + printf ("%d nodes must be checked\n", hcount); + for (i = 0; i <= count; i++) + nodelist[i].mark = 0; + } else { + for (i = 0; i < ncount; i++) + nodelist[i].hit = 1; + } + + { + double minsum = 1000000000000.0; + double maxsum = -1000000000000.0; + for (i = 0; i < count; i++) { + if (nodelist[i].sum < minsum) + minsum = nodelist[i].sum; + if (nodelist[i].sum > maxsum) + maxsum = nodelist[i].sum; + } + printf ("Range of sums: %f to %f\n", minsum, maxsum); + fflush (stdout); + } + + + + CC_IFFREE (invnames, int); + CC_IFFREE (mark, int); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static double get_sum_work (node *n) +#else +static double get_sum_work (n) +node *n; +#endif +{ + if (!n) + return 0.0; + + if (n->mark) + return n->sum; + else { + n->mark = 1; + n->sum = n->pi + get_sum_work (n->parent); + return n->sum; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static char get_hit_work (node *n) +#else +static char get_hit_work (n) +node *n; +#endif +{ + if (!n) + return 0; + + if (n->mark || n->hit) + return n->hit; + else { + n->mark = 1; + n->hit = get_hit_work (n->parent); + return n->hit; + } +} + + +#ifdef DEBUG_MATPRICE +#ifdef CC_PROTOTYPE_ANSI +static void price_list (tree *T, int ecount, int *elist, int *elen, int *nbad) +#else +static void price_list (T, ecount, elist, elen, nbad) +tree *T; +int ecount; +int *elist, *elen; +int *nbad; +#endif +{ + int i; + double t; + FILE *out = fopen ("dump.edges", "w"); + double szeit = CCutil_zeit (); + + if (!out) { + fprintf (stderr, "couldn't open dump.edges\n"); + exit (1); + } + + *nbad = 0; + + for (i = 0; i < ecount; i++) { + if (i % 10000 == 0) { + printf ("T[%d](%.0f sec) ", i / 10000, CCutil_zeit () - szeit); + fflush (stdout); + } + t = price_it (T, elist[2 * i], elist[2 * i + 1], elen[i]); + if (t < -MAT_GEN_EPSILON) { + (*nbad)++; + fprintf (out, "%d %d %d\n", elist[2 * i], elist[2 * i + 1], + elen[i]); + } + } + printf ("Found %d bad edges [%.2f seconds]\n", *nbad, CCutil_zeit () - szeit); + fflush (stdout); + fclose (out); +} + +#ifdef CC_PROTOTYPE_ANSI +static double price_it (tree *T, int n1, int n2, int len) +#else +static double price_it (T, n1, n2, len) +int n1, n2, len; +tree *T; +#endif +{ + node *lca; + node *m1 = T->nodelist + n1; + node *m2 = T->nodelist + n2; + + lca = easy_lca (m1, m2); + return ((double) len) - m1->sum - m2->sum + (2 * lca->sum); +} + +#ifdef CC_PROTOTYPE_ANSI +static node *easy_lca (node *n1, node *n2) +#else +static node *easy_lca (n1, n2) +#endif +{ + node *n, *a; + for (n = n1; n; n = n->parent) + n->mark = 1; + for (n = n2; n; n = n->parent) + if (n->mark) { + a = n; + break; + } + for (n = n1; n; n = n->parent) + n->mark = 0; + + return a; +} +#endif + +#ifdef CC_PROTOTYPE_ANSI +static void freetree (tree *T) +#else +static void freetree (T) +tree *T; +#endif +{ + CC_IFFREE (T->nodelist, node); + T->ncount = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int ancestor_price (tree *T, int zero_rc, int ecount, int *elist, + int *elen, int *badcount, int **badlist, int **badlen, double *penalty) +#else +static int ancestor_price (T, zero_rc, ecount, elist, elen, badcount, badlist, + badlen, penalty) +tree *T; +int zero_rc; +int ecount; +int *elist, *elen; +int *badcount; +int **badlist, **badlen; +double *penalty; +#endif +{ + int prenum = 0; + int i, nbad; + anc *anclist = (anc *) NULL; + anc *p; + node *n1, *n2, *t; + node *nodelist = T->nodelist; + int maxdepth = 0; + double szeit = CCutil_zeit (); + double w; + + printf ("ancstor_price(%d) ....\n", ecount); + fflush (stdout); + + *badcount = 0; + *badlist = (int *) NULL; + *badlen = (int *) NULL; + *penalty = 0.0; + + number_tree (T->root, &prenum, 0, &maxdepth); +/* + printf ("Maximum Depth of Tree: %d\n", maxdepth); + fflush (stdout); +*/ + if (prenum != T->ncount + 1) { + printf ("Yipes in ancest_init\n"); + fflush (stdout); + } + + anclist = CC_SAFE_MALLOC (ecount, anc); + if (!anclist) { + fprintf (stderr, "out of memory in ancestor_price\n"); + return 1; + } + + for (i = 0; i < ecount; i++) { + n1 = nodelist + elist[2 * i]; + n2 = nodelist + elist[2 * i + 1]; + + if (n1->prenum > n2->prenum) { + CC_SWAP(n1, n2, t); + } + + p = anclist + i; + + p->next = n2->evallist; + n2->evallist = p; + if (n1->addset) { + p->ancestor = (node *) NULL; + n1->addset->rank = 1; + p->rank = 0; + p->parent = n1->addset; + } else { + p->ancestor = n1; + p->rank = 0; + n1->addset = p; + p->parent = p; + } + } + ancest_work (T->root); + + *penalty = 0.0; + nbad = 0; + + if (zero_rc) { + for (i = 0; i < ecount; i++) { + n1 = nodelist + elist[2 * i]; + n2 = nodelist + elist[2 * i + 1]; + + w = ((double) elen[i]) - n1->sum - n2->sum + + (2 * anclist[i].lca->sum); + if (w != 0.0) { + printf ("edge (%d,%d) with rc %f\n", + elist[2 * i], elist[2*i+1], w); + fflush (stdout); + (*penalty) += w; + nbad++; + anclist[i].rank = 1; + } else { + anclist[i].rank = 0; + } + } + } else { + for (i = 0; i < ecount; i++) { + n1 = nodelist + elist[2 * i]; + n2 = nodelist + elist[2 * i + 1]; + + w = ((double) elen[i]) - n1->sum - n2->sum + + (2 * anclist[i].lca->sum); + if (w < -MAT_GEN_EPSILON) { + (*penalty) += w; + nbad++; + anclist[i].rank = 1; + } else { + anclist[i].rank = 0; + } + } + } + + printf ("Number of bad edges: %d (penalty = %f)\n", nbad, *penalty); + fflush (stdout); + + if (nbad > 0) { + *badlist = CC_SAFE_MALLOC (2 * nbad, int); + *badlen = CC_SAFE_MALLOC (nbad, int); + if (!(*badlist) || !(*badlen)) { + fprintf (stderr, "out of memory in ancestor_price\n"); + CC_IFFREE (*badlist, int); + CC_IFFREE (*badlen, int); + CC_IFFREE (anclist, anc); + return 0; + } + nbad = 0; + for (i = 0; i < ecount; i++) { + if (anclist[i].rank) { + (*badlist)[2 * nbad] = elist[2 * i]; + (*badlist)[2 * nbad + 1] = elist[2 * i + 1]; + (*badlen)[nbad] = elen[i]; + nbad++; + } + } + *badcount = nbad; + } + + printf ("Ancestor Time: %.2f seconds\n", CCutil_zeit () - szeit); + fflush (stdout); + + CC_IFFREE (anclist, anc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static anc *ancest_work (node *p) +#else +static anc *ancest_work (p) +node *p; +#endif +{ + node *q; + anc *a; + + for (q = p->child; q; q = q->sibling) { + a = ancest_work (q); + if (a) { + if (p->addset) { + p->addset = union_anc (a, p->addset); + } else { + p->addset = a; + } + p->addset->ancestor = p; + } + } + + for (a = p->evallist; a; a = a->next) { + a->lca = find_anc(a)->ancestor; + } + + return p->addset; +} + +#ifdef CC_PROTOTYPE_ANSI +static void number_tree (node *n, int *prenum, int depth, int *maxdepth) +#else +static void number_tree (n, prenum, depth, maxdepth) +node *n; +int *prenum; +int depth; +int *maxdepth; +#endif +{ + if (depth > *maxdepth) + *maxdepth = depth; + n->prenum = (*prenum)++; + n->addset = (anc *) NULL; + n->evallist = (anc *) NULL; + for (n = n->child; n; n = n->sibling) { + number_tree (n, prenum, depth + 1, maxdepth); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static anc *find_anc (anc *x) +#else +static anc *find_anc (x) +anc *x; +#endif +{ + anc *p = x->parent; + return (x == p) ? x : (x->parent = find_anc (p)); +} + +#ifdef CC_PROTOTYPE_ANSI +static anc *union_anc (anc *x, anc *y) +#else +static anc *union_anc (x, y) +anc *x; +anc *y; +#endif +{ + anc *t; + + if (x->rank > y->rank) { + CC_SWAP (x, y, t); + } else if (x->rank == y->rank) { + y->rank++; + } + x->parent = y; + return y; +} + diff --git a/contrib/blossom/MATCH/matprice.h b/contrib/blossom/MATCH/matprice.h new file mode 100644 index 0000000000000000000000000000000000000000..8b1161d79aee3032b22c68cf8733e4dd37c345dc --- /dev/null +++ b/contrib/blossom/MATCH/matprice.h @@ -0,0 +1,22 @@ +#ifndef __MATPRICE_H +#define __MATPRICE_H + +#ifdef CC_PROTOTYPE_ANSI + +int + matching_price (int ncount, CCdatagroup *dat, double *orig_pi, + int *orig_parent, int *badcount, int **badlist, + int **badlen, double *penalty, CCtsp_edgegenerator *starteg, + char *hit), + matching_check (int ncount, double *orig_pi, int *orig_parent, + int *matchlist, int *mlen, int *csbad); + +#else + +int + matching_price (), + matching_check (); + +#endif + +#endif /* __MATPRICE_H */ diff --git a/contrib/blossom/MATCH/mp_main.c b/contrib/blossom/MATCH/mp_main.c new file mode 100644 index 0000000000000000000000000000000000000000..2d28b1a7f726558eebe16b19d2f29e7876b723a0 --- /dev/null +++ b/contrib/blossom/MATCH/mp_main.c @@ -0,0 +1,428 @@ +/***************************************************************************/ +/* */ +/* TEST PROGRAM FOR PRICING MATCHINGS */ +/* */ +/* Written by: D. Applegate, W. Cook, and A. Rohe */ +/* Date: August 1, 1996 */ +/* */ +/* SEE short decsribtion in usage (). */ +/* */ +/* Link with: */ +/* (see Makefile) */ +/* */ +/* NOTES: */ +/* */ +/* The dual file is a binary file that contains 3/2 ncount records. */ +/* Each record is an int followed by a double. Each record corresponds */ +/* to either a node, or a blossom, or wasted space. The node records */ +/* are the initial ncount entries; the blossom and wasted records are */ +/* mixed in the remaint ncount/2 records. The first entry of a record */ +/* gives the index of the parent of the node or blossom in the nesting */ +/* structure; it is -1 if there is no parent. The second entry is the */ +/* dual value of the node or blossom. To determine which records are */ +/* blossoms and which are wasted, you can trace the parent pointers of */ +/* the node records to find the remaining records that are hit. */ +/* */ +/* If a matching file is given, then the complementary slackness */ +/* conditions will be checked. A matching file has the format of a */ +/* standard edge file. */ +/* */ +/* */ +/***************************************************************************/ + +#include "concorde.h" +#include "matprice.h" + +static int norm = CC_EUCLIDEAN; +static char *dualfilename = (char *) NULL; +static char *datfilename = (char *) NULL; +static char *matfilename = (char *) NULL; +static char *badfilename = (char *) NULL; +static int binary_in = 0; +static int tsplib_in = 0; +static int seed = 0; + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int ac, char **av); + +static void + usage (char *f); + +static int + parseargs (int ac, char **av), + read_matching (char *fname, int ncount, int **matchlist, + CCdatagroup *dat), + read_blossom_tree (char* blossom_tree_file, int ncount, double **pi, + int **parent); + +#else /* CC_PROTOTYPE_ANSI */ + +int + main (); + +static void + usage (); + +static int + parseargs (), + read_matching (), + read_blossom_tree (); + +#endif /* CC_PROTOTYPE_ANSI */ + + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + double szeit; + int ncount; + double *pi = (double *) NULL; + int *parent = (int *) NULL; + CCdatagroup dat; + int csbad = 0; + int badcount = 0; + int *badlist = (int *) NULL; + int *badlen = (int *) NULL; + int *matchlist = (int *) NULL; + double penalty; + int rval = 0; + long l; +#ifdef CC_PROTOTYPE_ANSI + extern long time (long *); +#else + extern long time (); +#endif + + seed = time (&l); + if (parseargs (ac, av)) + return 0; + CCutil_sprand (seed); + + if (datfilename == (char *) NULL || dualfilename == (char *) NULL) { + usage (av[0]); + return 0; + } + ncount = 0; + + szeit = CCutil_zeit (); + if (tsplib_in) { + if (CCutil_gettsplib (datfilename, &ncount, &dat)) { + fprintf (stderr, "could not read the TSPLIB file\n"); + rval = 1; + goto CLEANUP; + } + norm = dat.norm; + } else { + if (CCutil_getdata (datfilename, binary_in, norm, &ncount, &dat)) { + fprintf (stderr, "Could not create data set\n"); + rval = 1; + goto CLEANUP; + } + } + + if (CCutil_init_dat_edgelen (&dat)) { + fprintf (stderr, "init_dat_edgelen failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Number of nodes: %d\n", ncount); + fflush (stdout); + + if (read_blossom_tree (dualfilename, ncount, &pi, &parent)) { + fprintf (stderr, "read_blossom_tree failed\n"); + rval = 1; + goto CLEANUP; + } + + if (matfilename) { + if (read_matching (matfilename, ncount, &matchlist, &dat)) { + fprintf (stderr, "read_matching failed\n"); + rval = 1; + goto CLEANUP; + } + } + + printf ("Hello !\n"); + if (matching_price (ncount, &dat, pi, parent, + &badcount, &badlist, &badlen, &penalty, NULL, NULL)) { + fprintf (stderr, "matching_price failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Found %d bad edges, with total penalty %f\n", badcount, penalty); + fflush (stdout); + + if (badcount) { + if (badfilename) { + if (CCutil_writeedges (ncount, badfilename, badcount, badlist, &dat)) { + fprintf (stderr, "CCutil_writeedges failed\n"); + rval = 1; + goto CLEANUP; + } + } else { + printf ("Writing bad edges to dump.edges\n"); + fflush (stdout); + if (CCutil_writeedges (ncount, "dump.edges", badcount, badlist, &dat)) { + fprintf (stderr, "CCutil_writeedges failed\n"); + rval = 1; + goto CLEANUP; + } + } + } + + if (matfilename) { + int *mlen = CC_SAFE_MALLOC (ncount/2, int); + int i; + + for (i = 0; i < ncount/2; i++ ) + mlen[i] = CCutil_dat_edgelen (matchlist[2*i],matchlist[2*i+1], &dat); + + if ( matching_check (ncount, pi, parent, matchlist, mlen, &csbad)) { + fprintf (stderr, "matching_check failed\n"); + rval = 1; + goto CLEANUP; + } + } + + if (csbad) { + printf ("COMPLEMENTARY SLACKNESS CONDITIONS ARE VIOLATED\n"); + fflush (stdout); + } + + printf ("Total Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (badlist, int); + CC_IFFREE (badlen, int); + CC_IFFREE (pi, double); + CC_IFFREE (parent, int); + CC_IFFREE (matchlist, int); + CCutil_freedatagroup (ncount, &dat); + if (CCutil_bigchunk_free_world ()) { + fprintf (stderr, "ERROR: bigchunk_free_world failed\n"); + return 1; + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "bd:m:n:o:s:T0123456789")) != EOF) + switch (c) { + case 'b': + binary_in = 1; + break; + case 'd': + dualfilename = CCutil_bix_optarg; + break; + case 'm': + matfilename = CCutil_bix_optarg; + break; + case 'n': + datfilename = CCutil_bix_optarg; + break; + case 'o': + badfilename = CCutil_bix_optarg; + break; + case 's': + seed = atoi (CCutil_bix_optarg); + break; + case 'T': + tsplib_in = 1; + break; + case '0': + norm = CC_MAXNORM; + break; + case '1': + norm = CC_EUCLIDEAN_CEIL; + break; + case '2': + norm = CC_EUCLIDEAN; + break; + case '3': + norm = CC_EUCLIDEAN_3D; + break; + case '4': + norm = CC_IBM; + break; + case '5': + norm = CC_ATT; + break; + case '6': + norm = CC_GEOGRAPHIC; + break; + case '7': + norm = CC_MATRIXNORM; + break; + case '8': + norm = CC_DSJRANDNORM; + break; + case '9': + norm = CC_CRYSTAL; + break; + case CC_BIX_GETOPT_UNKNOWN: + case '?': + default: + usage (av[0]); + return 1; + } + if (CCutil_bix_optind != ac) { + usage (av[0]); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "Usage: %s [-see below-]\n", f); + fprintf (stderr, " -b datfile in integer binary format\n"); + fprintf (stderr, " -d f dual file - MUST be specified\n"); + fprintf (stderr, " -m f matching file (to check complementary slackness\n"); + fprintf (stderr, " -n f dat file - MUST be specified\n"); + fprintf (stderr, " -o f output file for bad edges (default: dump.edges)\n"); + fprintf (stderr, " -s # random seed\n"); + fprintf (stderr, " -T the dat file is a TSPLIB file\n"); + fprintf (stderr, " -0 price out using MAX norm\n"); + fprintf (stderr, " -1 price out using JOHNSON norm\n"); + fprintf (stderr, " -2 price out using EUCLIDEAN norm (default)\n"); + fprintf (stderr, " -3 price out using Rounded Euclidean 3D norm\n"); + fprintf (stderr, " -(4 5 6 7 8 9) IBM ATT GEO MATRIX DSJRAND CRYSTAL norm\n"); +} + +#ifdef CC_PROTOTYPE_ANSI +static int read_matching (char *fname, int ncount, int **matchlist, + CCdatagroup *dat) +#else +static int read_matching (fname, ncount, matchlist, dat) +char *fname; +int ncount; +int **matchlist; +CCdatagroup *dat; +#endif +{ + int *matlen = (int *) NULL; + int i, mcount, len; + + if (CCutil_getedgelist (ncount, fname, &mcount, matchlist, &matlen)) { + fprintf (stderr, "getedgelist failed\n"); + return 1; + } + + if (mcount != ncount / 2) { + fprintf (stderr, "matching file %s has wrong format\n", fname); + CC_IFFREE (matlen, int); + return 1; + } + + for (i = 0; i < mcount; i++) { + len = CCutil_dat_edgelen ((*matchlist)[2*i], (*matchlist)[2*i+1], dat); + if (matlen[i] != len) { + fprintf (stderr, "length of (%d,%d) is %d not %d\n", + (*matchlist)[2*i], (*matchlist)[2*i+1], len, matlen[i]); + CC_IFFREE (matlen, int); + return 1; + } + } + + CC_IFFREE (matlen, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int read_blossom_tree (char* blossom_tree_file, int ncount, + double **pi, int **parent) +#else +static int read_blossom_tree (blossom_tree_file, ncount, pi, parent) +char *blossom_tree_file; +int ncount; +double **pi; +int **parent; +#endif +{ + int i,j; + FILE* f; + int *mark = (int *) NULL; + int c1 = 0, c2 = 0; + int bcount = 3 * ncount/2; + double szeit; + + *pi = CC_SAFE_MALLOC (bcount + 1, double); + *parent = CC_SAFE_MALLOC (bcount + 1, int); + mark = CC_SAFE_MALLOC (bcount + 1, int); + if (!(*pi) || !(*parent) || !mark) { + fprintf (stderr, "out of memory in read_blossom_tree\n"); + CC_IFFREE (*pi, double); + CC_IFFREE (*parent, int); + CC_IFFREE (mark, int); + return 1; + } + + printf("Reading %s ...",blossom_tree_file); + fflush(stdout); + szeit = CCutil_zeit(); + if ((f = fopen(blossom_tree_file,"r"))==NULL) { + fprintf(stderr," Error: Can't open file %s\n",blossom_tree_file); + CC_IFFREE (*pi, double); + CC_IFFREE (*parent, int); + CC_IFFREE (mark, int); + return 1; + } + for (i = 0; i < bcount; i++) { + fread ((*parent)+i, sizeof(int), 1, f); + fread ((*pi)+i, sizeof(double), 1, f); + } + fclose (f); + printf(" ... in %.2f sec\n",CCutil_zeit () - szeit); + fflush(stdout); + + for (i = 0; i < bcount; i++) + mark[i]=0; + + for (i = 0; i < ncount; i++) { + j=i; + while (j != -1 && mark[j] == 0) { + mark[j] = 1; + j = (*parent)[j]; + } + } + + for (i = ncount; i < bcount; i++) { + if (mark[i]) { + c1++; + if ((*pi)[i] == 0.0) + c2++; + } + } + + printf ("Number of blossoms: %d (with %d at 0 value)\n", c1, c2); + fflush(stdout); + + CC_IFFREE(mark, int); + return 0; +} diff --git a/contrib/blossom/MATCH/tri_call.c b/contrib/blossom/MATCH/tri_call.c new file mode 100644 index 0000000000000000000000000000000000000000..255c8ae73e68cd25b9b593ed5e6b740bb28c929a --- /dev/null +++ b/contrib/blossom/MATCH/tri_call.c @@ -0,0 +1,185 @@ +/***********************************************************/ +/* */ +/* ROUTINE TO START TRIANGLE CODE */ +/* */ +/* TRIANGLE is a program to calculte Delaunay */ +/* trianglulations, it can be found at */ +/* http://www.cs.cmu.edu/~quake/triangle.html */ +/* */ +/* Written by: A. Rohe */ +/* Date: July 28, 1997 */ +/* */ +/* This program should be compiled with make tri_call */ + +/* This program should be compiled with make tri_call */ +/* */ +/* It can be used the following way: */ +/* */ +/* tri_call <data-file> <edge-file> <triangle> */ +/* */ +/* <data-file> is a normal blossom4 x-y input file */ +/* <edge-file> is a the edgefile-name you would like */ +/* <triangle> is the place of and name of the triangle */ +/* executable */ +/* */ +/* The program will creat a <data-file>.node file and */ +/* a <data-file>.1.edge file and not delete them ! */ +/* */ +/***********************************************************/ +/* */ +/* example: */ +/* */ +/* tri_call 100.dat 100.del ./triangle */ +/* */ +/* this reads the file 100.dat, writes the delaunay */ +/* triangulation to 100.del using the program */ +/* ./triangle. */ +/* The files 100.dat.node and 100.del.1.edge will */ +/* be created. */ +/* */ +/***********************************************************/ +/* */ +/* Then this data can be used the following way: */ +/* */ +/* - To get the minimum weight perfect matching in */ +/* in the complete graph starting with the */ +/* Delaunay triangulation: */ +/* blossom4 -x 100.dat -e 100.del */ +/* */ +/* - To get the minimum weight perfect matching in */ +/* in the Delaunay triangulation: */ +/* blossom4 -e 100.del */ +/* */ +/***********************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +int nodes; +double *x,*y; + + /* +** read_xy, reads the x and y coordinates +*/ +#ifdef PROTOTYPE_ANSI +static void read_write_xy (char* name) +#else +static void read_write_xy (name) +char *name; +#endif +{ + int i; + FILE *fp1,*fp2; + char name2[200]; + + /* OPEN name */ + if ((fp1=fopen(name,"r"))==NULL) { + printf("Can't open file %s \n",name); + exit(1); + } + /* OPEN name2 */ + sprintf(name2,"%s.node",name); + if ((fp2=fopen(name2,"w"))==NULL) { + printf("Can't open file %s \n",name2); + exit(1); + } + + /* get #nodes */ + fscanf(fp1,"%i",&nodes); + fprintf(fp2,"%i 2 0 0\n",nodes); + printf("Number of nodes: %i\n",nodes); + printf("Reading from %s and writing to %s\n",name,name2); + + /* initialize the x[]'s */ + if ((x=(double *)malloc(nodes * sizeof(double))) == NULL) { + printf("Not enough memory to allocate buffer for x\n"); + exit(1); /* terminate program if out of memory */ + } + /* initialize the yy[]'s */ + if ((y=(double *)malloc(nodes * sizeof(double))) == NULL) { + printf("Not enough memory to allocate buffer for y\n"); + exit(1); /* terminate program if out of memory */ + } + + /* read from fp1 and write to fp2 */ + for (i=0;i<nodes;i++) { + fscanf(fp1,"%lf %lf",x+i,y+i); + fprintf(fp2,"%i %lf %lf\n",i,x[i],y[i]); + } + fclose(fp1); + fclose(fp2); +} + + /* +** read_xy, reads the x and y coordinates +*/ +#ifdef PROTOTYPE_ANSI +static void read_write_edges (char* name,char* edgefile) +#else +static void read_write_edges (name,edgefile) +char *name; +char *edgefile; +#endif +{ + int i,a,b; + int edges,dummy; + FILE *fp1,*fp2; + char name2[200]; + + /* OPEN name */ + if ((fp1=fopen(edgefile,"w"))==NULL) { + printf("Can't open file %s \n",edgefile); + exit(1); + } + /* OPEN name2 */ + sprintf(name2,"%s.1.edge",name); + if ((fp2=fopen(name2,"r"))==NULL) { + printf("Can't open file %s \n",name2); + exit(1); + } + + fscanf(fp2,"%i %i",&edges,&dummy); + fprintf(fp1,"%i %i\n",nodes,edges); + printf("Number of edges: %i\n",edges); + printf("Reading from %s and writing to %s\n",name2,edgefile); + + for (i=0;i<edges;i++) { + fscanf(fp2,"%i %i %i",&dummy,&a,&b); + fprintf(fp1,"%i %i %i\n",a,b,(int)(0.5 + sqrt( (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]) ))); + } + fclose(fp1); + fclose(fp2); + free(x); + free(y); +} + +/* +** main program +*/ +#ifdef PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + char triangle_call[200]; + + if (ac<4) { + printf("\nNot enough parameters:\n%s <data-file> <edge-file> <triangle>\n",av[0]); + exit(1); /* terminate program */ + } + + read_write_xy(av[1]); + + sprintf(triangle_call,"%s -e -B -P -N -E -z %s",av[3],av[1]); + printf("I'll do the command '%s' \n",triangle_call); + fflush(stdout); + system(triangle_call); + + read_write_edges(av[1],av[2]); + printf("Ready !\n"); + +} diff --git a/contrib/blossom/README.txt b/contrib/blossom/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..007eab2e1568a4e2870ecd93c19b63ab0ba15b7e --- /dev/null +++ b/contrib/blossom/README.txt @@ -0,0 +1,83 @@ + +This directory contains the source code for concorde97 and MATCH +(which contains the Blossom IV code). + +As a special exception granted by Prof. Bill Cook, the code in this +directory can be used within the Gmsh system for both academic and +non-academic use. Note that this exception to the standard license is +granted only for use within the Gmsh system: see the original email +exchange below: + + +Subject: Re: Concorde non academic use +Date: Thu, 22 Sep 2011 18:01:14 +0200 +Cc: <Jean-Francois.Remacle@uclouvain.be> +To: Bill Cook <bico@isye.gatech.edu> + +Dear Prof. Cook, + +Thanks for your email: it will make many Gmsh users very happy! + +All the best, + +Christophe + +On 22 Sep 2011, at 17:15, Bill Cook wrote: +> +> Dear Professor Remacle, Thanks for your email. That is nice to hear +> that the matching code in useful in your finite-element work. It is +> fine to include Blossom IV and Concorde in your distribution, including +> use for non-academic work. Could you please include wording that the +> Concorde license is granted only for use within the Gmsh system? +> +> Thanks again. +> +> Best regards, +> +> Bill +> +> +> +> Jean-Fran=E7ois Remacle wrote: +>> Dear Dr. Cook, +>> +>> We are the developers of GMSH, the open source mesh generator (see = +www.geuz.org/gmsh <http://www.geuz.org/gmsh> or +>> http://onlinelibrary.wiley.com/doi/10.1002/nme.2579/abstract). We = +provide Gmsh under the GPL license. +>> +>> In a recent research, we have developed a new method for building = +specific kind of meshes (quadrilaterals). This new method requires to = +compute optimal perfect matchings. We have found out that the "Blossom = +IV" implementation was indeed quite effective. This implementation makes = +use of Concorde. +>> +>> In your web page, it is said that "concorde is available for academic = +research use; for other uses, contact William Cook = +<mailto:bico@isye.gatech.edu?subject=3DConcorde> for licensing = +options.". We'd like that Gmsh users can take advantage of our new = +algorithm. Yet, even though most of Gmsh's users are form academia, = +some are from engineering offices. This is indeed incompatible with = +Concorde's license. +>> I therefore contact you for getting more information about the = +licensing options that are available. +>> +>> Best regards, +>> +>> Jean-Fran=E7ois Remacle & Christophe Geuzaine. +>> +>> ------------------------------------------------------------------ +>> Prof. Jean-Francois Remacle +>> Universite catholique de Louvain (UCL) +>> Ecole Polytechnique de Louvain (EPL) - Louvain School of Engineering +>> Institute of Mechanics, Materials and Civil Engineering (iMMC) +>> Center for Systems Engineering and Applied Mechanics (CESAME) +>> Tel : +32-10-472352 -- Mobile : +32-473-909930 +>> +>> +> + +-- +Prof. Christophe Geuzaine +University of Liege, Electrical Engineering and Computer Science +http://www.montefiore.ulg.ac.be/~geuzaine diff --git a/contrib/blossom/concorde97/00_README b/contrib/blossom/concorde97/00_README new file mode 100644 index 0000000000000000000000000000000000000000..dacdaf7b2e3d80202750f25c4f0081f234230a3a --- /dev/null +++ b/contrib/blossom/concorde97/00_README @@ -0,0 +1,42 @@ +INSTRUCTIONS FOR CONFIGURING: (Preliminary Version (27.08.97)) + +1. Edit Makefile.conf to describe your system. If you are fortunate, +your processor, operating system, and compiler already have a prebuilt +entry listed in the comments at the start of the file. If so, +uncomment the "SYS=" line and set it to your system's configuration +name. + +2. Otherwise, edit the lines defining CC, OPTFLAGS, COMFLAGS, +LOADFLAGS, RANLIB, OBJNAME, and CCSYSNAME. Each entry in +Makefile.conf is preceeded by a brief comment describing its meaning. +Try CCSYS_STANDARD if you have an ANSI C compiler, and +CCSYS_STANDARD_KNR if you have an older, K&R C compiler. If you are +fortunate, that will be enough. + +3. Otherwise, you will have to create an entry in INCLUDE/machdefs.h. +Each stanza in machdefs.h contains system-dependent information for +the compiler. Pick a system that you think is "close" to yours, copy +it, and choose a new name (which you will use in Makefile.conf) for +the new description. If you have an ANSI C compiler, include the line +"#define CC_PROTOTYPE_ANSI", otherwise include the line "#undef +CC_PROTOTYPE_ANSI". You may need to adjust the list of system include +files to match your system. Then, select a way to access the amount of +cpu time a process has used on your system. Most systems can access +the cpu time through either get_rusage() or times(). In this case, +just "#define CC_ZEIT_RUSAGE" or "#define CC_ZEIT_TIMES". Otherwise, +use "#define CC_ZEIT_DUMMY", in which case all cpu times reported by +the programs will be 0.0, or define a new CCutil_zeit() function which +returns the accumulated cpu time on your system. + + +INSTRUCTIONS FOR COMPILING: + +Once you have configured your system, compiling is straightforward. +The makefiles included with the code depend upon GNU Make. If you +don't have it, the source code can be downloaded by anonymous ftp from +ftp://prep.ai.mit.edu/pub/gnu/make-3.75.tar.gz. Then, to make +everything, in the top level directory, enter the command "make all". +If you only want to make concorde.a and concorde.h, enter the command +"make". If you only want to make the executable and library in one +subdirectory, cd into that subdirectory and enter "make". + diff --git a/contrib/blossom/concorde97/BIGGUY/Makefile b/contrib/blossom/concorde97/BIGGUY/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6b80298396888bfd4db2fcc5758460608c2a8a7e --- /dev/null +++ b/contrib/blossom/concorde97/BIGGUY/Makefile @@ -0,0 +1,34 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=bigguy.a +LIBSRCS=bigguy.c +ALLSRCS=bg_test.c $(LIBSRCS) +LIBS=$(ROOT)/UTIL/util.a + +all: bg_test $(LIB) + +bg_test: bg_test.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ -lm + +test: bg_test + time bg_test < bigguy.tst > bigguy.ts2 + cmp bigguy.tst bigguy.ts2 + +clean: + -rm -f *.$o $(LIB) bg_test bigguy.ts2 + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +bg_test.$o: bg_test.c $(I)/machdefs.h $(I)/util.h $(I)/bigguy.h +bigguy.$o: bigguy.c $(I)/machdefs.h $(I)/util.h $(I)/bigguy.h diff --git a/contrib/blossom/concorde97/BIGGUY/bg_test.c b/contrib/blossom/concorde97/BIGGUY/bg_test.c new file mode 100644 index 0000000000000000000000000000000000000000..ebd17c49ad8be518bea2ce26c8d592cb4449ce0d --- /dev/null +++ b/contrib/blossom/concorde97/BIGGUY/bg_test.c @@ -0,0 +1,281 @@ +#include "machdefs.h" +#include "util.h" +#include "bigguy.h" + +#define EPSILON ((1.0/(1<<15))*(1.0/(1<<15))) + +#ifdef CC_PROTOTYPE_ANSI + +static CCbigguy + bgrand (double *delta, int maxx); + +static int + bgcheck (CC_SFILE *sfin, CC_SFILE *sfout, CCbigguy x, char *name), + dotest (int maxx, int maxy, int maxs, int ntrial, double *delta, + CCbigguy *sum, CC_SFILE *sfin, CC_SFILE *sfout); + +static void + sum_chk (CCbigguy *sum, CCbigguy x); + +static short + shortrand (short maxs); + +#else + +static CCbigguy + bgrand(); + +static int + bgcheck (), + dotest (); + +static void + sum_chk (); + +static short + shortrand (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + int i; + int x, y, d; + int nerrs = 0; + CC_SFILE *sfin = CCutil_sdopen (0, "r"); + CC_SFILE *sfout = CCutil_sdopen (1, "w"); + double delta; + CCbigguy sum; + + CCutil_sprand (47); + + if (ac > 1) { + fprintf (stderr, "Usage: %s < std_file > new_file\n", av[0]); + return 1; + } + + nerrs += bgcheck (sfin, sfout, CCbigguy_MINBIGGUY, "CCbigguy_MINBIGGUY"); + nerrs += bgcheck (sfin, sfout, CCbigguy_MAXBIGGUY, "CCbigguy_MAXBIGGUY"); + nerrs += bgcheck (sfin, sfout, CCbigguy_ZERO, "CCbigguy_ZERO"); + nerrs += bgcheck (sfin, sfout, CCbigguy_ONE, "CCbigguy_ONE"); + + delta = 0.0; + + sum = CCbigguy_ZERO; + nerrs += bgcheck (sfin, sfout, sum, "sum_init"); + + for (i=6; i<=30; i+=8) { + for (x=(1<<i), y=(1<<i); y >= 1; y /= 16, x += 15*y) { + for (d=(y < 32767 ? y : 32767); d>0; d /= 6) { + nerrs += dotest (x, y/d, d, 100, &delta, &sum, sfin, sfout); + } + for (d=(y < 32767 ? y : 32767); d>0; d /= 6) { + nerrs += dotest (y, x/d, d, 100, &delta, &sum, sfin, sfout); + } + } + } + + CCutil_sclose (sfin); + CCutil_sclose (sfout); + + fprintf (stderr, "%d total errors\n", nerrs); + fprintf (stderr, "Total delta: %.20f\n", delta); + + return nerrs; +} + +#ifdef CC_PROTOTYPE_ANSI +static int dotest (int maxx, int maxy, int maxs, int ntrial, double *delta, + CCbigguy *sum, CC_SFILE *sfin, CC_SFILE *sfout) +#else +static int dotest (maxx, maxy, maxs, ntrial, delta, sum, sfin, sfout) +int maxx; +int maxy; +int maxs; +int ntrial; +double *delta; +CCbigguy *sum; +CC_SFILE *sfin; +CC_SFILE *sfout; +#endif +{ + int i; + int j; + CCbigguy x; + CCbigguy y; + CCbigguy a, b, c, d, e, f, g; + short s; + int nerrs = 0; + + if (maxs > 32767) maxs = 32767; + + for (i=0; i<ntrial; i++) { + x = bgrand (delta, maxx); + y = bgrand (delta, maxy); + s = shortrand (maxs); + + a = x; + CCbigguy_add (&a, y); + + b = x; + CCbigguy_sub (&b, y); + + c = x; + CCbigguy_addmult (&c, y, CCbigguy_cmp (x, y)); + + d = x; + CCbigguy_addmult (&d, y, s); + + e = CCbigguy_ceil (x); + + j = CCutil_lprand(); + + f = CCbigguy_itobigguy (j); + + g = CCbigguy_itobigguy (-j); + + sum_chk (sum, x); + sum_chk (sum, y); + sum_chk (sum, a); + sum_chk (sum, b); + sum_chk (sum, c); + sum_chk (sum, d); + sum_chk (sum, e); + sum_chk (sum, f); + sum_chk (sum, g); + + if (i < 3) { + char nambuf[5]; + sprintf (nambuf, "x%d", i); + nerrs += bgcheck (sfin, sfout, x, nambuf); + nambuf[0] = 'y'; + nerrs += bgcheck (sfin, sfout, y, nambuf); + nambuf[0] = 'a'; + nerrs += bgcheck (sfin, sfout, a, nambuf); + nambuf[0] = 'b'; + nerrs += bgcheck (sfin, sfout, b, nambuf); + nambuf[0] = 'c'; + nerrs += bgcheck (sfin, sfout, c, nambuf); + nambuf[0] = 'd'; + nerrs += bgcheck (sfin, sfout, d, nambuf); + nambuf[0] = 'e'; + nerrs += bgcheck (sfin, sfout, e, nambuf); + nambuf[0] = 'f'; + nerrs += bgcheck (sfin, sfout, f, nambuf); + nambuf[0] = 'g'; + nerrs += bgcheck (sfin, sfout, g, nambuf); + } + } + nerrs += bgcheck (sfin, sfout, *sum, "end sum"); + + return nerrs; +} + +#ifdef CC_PROTOTYPE_ANSI +static void sum_chk (CCbigguy *sum, CCbigguy x) +#else +static void sum_chk (sum, x) +CCbigguy *sum; +CCbigguy x; +#endif +{ + CCbigguy y; + + if (CCbigguy_cmp (x, CCbigguy_ZERO) > 0 && + CCbigguy_cmp (*sum, CCbigguy_ZERO) > 0) { + y = CCbigguy_MAXBIGGUY; + CCbigguy_sub (&y, x); + if (CCbigguy_cmp (*sum, y) >= 0) { + CCbigguy_sub (sum, CCbigguy_MAXBIGGUY); + } + } else if (CCbigguy_cmp (x, CCbigguy_ZERO) < 0 && + CCbigguy_cmp (*sum, CCbigguy_ZERO) < 0) { + y = CCbigguy_MINBIGGUY; + CCbigguy_sub (&y, x); + if (CCbigguy_cmp (*sum, y) <= 0) { + CCbigguy_sub (sum, CCbigguy_MINBIGGUY); + } + } + CCbigguy_add (sum, x); +} + +#ifdef CC_PROTOTYPE_ANSI +static int bgcheck (CC_SFILE *sfin, CC_SFILE *sfout, CCbigguy x, char *name) +#else +static int bgcheck (sfin, sfout, x, name) +CC_SFILE *sfin; +CC_SFILE *sfout; +CCbigguy x; +char *name; +#endif +{ + CCbigguy v; + + CCbigguy_sread (sfin, &v); + CCbigguy_swrite (sfout, x); + if (CCbigguy_cmp(v,x)) { + fprintf (stderr, "%s misread (%.15f != %.15f)\n", name, + CCbigguy_bigguytod(v), CCbigguy_bigguytod(x)); + return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static CCbigguy bgrand (double *delta, int maxv) +#else +static CCbigguy bgrand (delta, maxv) +double *delta; +int maxv; +#endif +{ + CCbigguy x, y; + double d16 = 1.0 / (1 << 16); + double d32 = d16 * d16; + double dx; + + dx = d32 * (CCutil_lprand() & 0xffff); + x = CCbigguy_dtobigguy (dx); + *delta += fabs(dx - CCbigguy_bigguytod(x)); + + dx = d16 * (CCutil_lprand() & 0xffff); + y = CCbigguy_dtobigguy(dx); + *delta += fabs(dx - CCbigguy_bigguytod(y)); + CCbigguy_add (&x, y); + + dx = 1.0 * (CCutil_lprand() % maxv); + y = CCbigguy_dtobigguy(dx); + *delta += fabs(dx - CCbigguy_bigguytod(y)); + CCbigguy_add (&x, y); + + if (CCutil_lprand() & 1) { + return x; + } else { + dx = CCbigguy_bigguytod(x); + y = CCbigguy_ZERO; + CCbigguy_sub (&y, x); + *delta += fabs(dx + CCbigguy_bigguytod(y)); + return y; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static short shortrand (short maxs) +#else +static short shortrand (maxs) +short maxs; +#endif +{ + int s = CCutil_lprand() % maxs; + + if (CCutil_lprand() % 1) s = -s; + + return (short) s; +} diff --git a/contrib/blossom/concorde97/BIGGUY/bigguy.c b/contrib/blossom/concorde97/BIGGUY/bigguy.c new file mode 100644 index 0000000000000000000000000000000000000000..445190746e39289e2801ae2a97f410c2c3cadd32 --- /dev/null +++ b/contrib/blossom/concorde97/BIGGUY/bigguy.c @@ -0,0 +1,375 @@ +/**************************************************************************/ +/* */ +/* BIGGUY OPERATIONS: */ +/* */ +/* x += y CCbigguy_add (CCbigguy *x, CCbigguy y) */ +/* x -= y CCbigguy_sub (CCbigguy *x, CCbigguy y) */ +/* x += y*m CCbigguy_addmult (CCbigguy *x, CCbigguy y, */ +/* short m) */ +/* x<y -1, x==y 0, x>y 1 CCbigguy_cmp (CCbigguy x, CCbigguy y) */ +/* ceil(x) CCbigguy_ceil (CCbigguy x) */ +/* */ +/* (double) x CCbigguy_bigguytod (CCbigguy x) */ +/* (bigguy) i CCbigguy_itobigguy (int i) */ +/* (bigguy) d CCbigguy_dtobigguy (double d) */ +/* */ +/* read(x) CCbigguy_sread (CC_SFILE *f, CCbigguy *x) */ +/* write(x) CCbigguy_swrite (CC_SFILE *f, CCbigguy x) */ +/* */ +/* biggest possible x const CCbigguy CCbigguy_MAXBIGGUY */ +/* smallest possible x const CCbigguy CCbigguy_MINBIGGUY */ +/* 0 const CCbigguy CCbigguy_ZERO */ +/* 1 const CCbigguy CCbigguy_ONE */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int */ +/* CCbigguy_swrite (CC_SFILE *f, CCbigguy x) */ +/* CCbigguy_sread (CC_SFILE *f, CCbigguy *x) */ +/* */ +/* If CC_BIGGUY_LONGLONG is not defined */ +/* */ +/* void */ +/* CCbigguy_addmult (CCbigguy *x, CCbigguy y, short m) */ +/* */ +/* int */ +/* CCbigguy_cmp (CCbigguy x, CCbigguy y) */ +/* */ +/* double */ +/* CCbigguytod (CCbigguy x) */ +/* */ +/* CCbigguy */ +/* CCbigguy_itobigguy (int d) */ +/* CCbigguy_dtobigguy (double d) */ +/* CCbigguy_ceil (CCbigguy x) */ +/* */ +/* If an overflow occurs (in CCbigguy_dtobigguy, CCbigguy_ceil, or */ +/* CCbigguy_addmult), an error message is output and the routines */ +/* abort. */ +/* */ +/* If CC_BIGGUY_LONGLONG is defined, these are implemented by macros, */ +/* and have no overflow checking. */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "bigguy.h" + +#ifdef CC_BIGGUY_LONGLONG + +#ifdef CC_PROTOTYPE_ANSI +int CCbigguy_swrite (CC_SFILE *f, CCbigguy x) +#else +int CCbigguy_swrite(f, x) +CC_SFILE *f; +CCbigguy x; +#endif +{ + if (CCutil_swrite_short (f, (x>>48)&0xffff)) return -1; + if (CCutil_swrite_short (f, (x>>32)&0xffff)) return -1; + if (CCutil_swrite_short (f, (x>>16)&0xffff)) return -1; + if (CCutil_swrite_short (f, x&0xffff)) return -1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCbigguy_sread (CC_SFILE *f, CCbigguy *x) +#else +int CCbigguy_sread (f, x) +CC_SFILE *f; +CCbigguy *x; +#endif +{ + unsigned short y; + + if (CCutil_sread_short (f, &y)) return -1; + *x = ((CCbigguy) y) << 48; + if (CCutil_sread_short (f, &y)) return -1; + *x |= ((CCbigguy) y) << 32; + if (CCutil_sread_short (f, &y)) return -1; + *x |= ((CCbigguy) y) << 16; + if (CCutil_sread_short (f, &y)) return -1; + *x |= ((CCbigguy) y); + return 0; +} + +#else /* CC_BIGGUY_LONGLONG */ + +const CCbigguy CCbigguy_MINBIGGUY = {0x8000,0x0000,0x0000,0x0001}; +const CCbigguy CCbigguy_MAXBIGGUY = {0x7fff,0xffff,0xffff,0xffff}; +const CCbigguy CCbigguy_ZERO = {0,0,0,0}; +const CCbigguy CCbigguy_ONE = {0,1,0,0}; + +#ifdef CC_PROTOTYPE_ANSI + +static void + bigguy_neg (CCbigguy *x); + +#else + +static void + bigguy_neg (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +static void bigguy_neg (CCbigguy *x) +#else +static void bigguy_neg (x) +CCbigguy *x; +#endif +{ + x->ihi = ((unsigned short) 65535) - x->ihi; + x->ilo = ((unsigned short) 65535) - x->ilo; + x->fhi = ((unsigned short) 65535) - x->fhi; + x->flo = ((unsigned short) 65535) - x->flo; + + if (x->flo < 65535) { + x->flo++; + } else { + x->flo = 0; + if (x->fhi < 65535) { + x->fhi++; + } else { + x->fhi = 0; + if (x->ilo < 65535) { + x->ilo++; + } else { + x->ilo = 0; + x->ihi++; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCbigguy_swrite (CC_SFILE *f, CCbigguy x) +#else +int CCbigguy_swrite (f, x) +CC_SFILE *f; +CCbigguy x; +#endif +{ + if (CCutil_swrite_short (f, x.ihi)) return -1; + if (CCutil_swrite_short (f, x.ilo)) return -1; + if (CCutil_swrite_short (f, x.fhi)) return -1; + if (CCutil_swrite_short (f, x.flo)) return -1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCbigguy_sread (CC_SFILE *f, CCbigguy *x) +#else +int CCbigguy_sread (f, x) +CC_SFILE *f; +CCbigguy *x; +#endif +{ + if (CCutil_sread_short (f, &(x->ihi))) return -1; + if (CCutil_sread_short (f, &(x->ilo))) return -1; + if (CCutil_sread_short (f, &(x->fhi))) return -1; + if (CCutil_sread_short (f, &(x->flo))) return -1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +double CCbigguy_bigguytod (CCbigguy x) +#else +double CCbigguy_bigguytod (x) +CCbigguy x; +#endif +{ + int sgn = 1; + + if (x.ihi >= 32768) { + bigguy_neg (&x); + sgn = -1; + } + + return sgn * (((double) x.ihi) * 65536.0 + + ((double) x.ilo) + + ((double) x.fhi) / 65536.0 + + ((double) x.flo) / (65536.0*65536.0)); +} + +#ifdef CC_PROTOTYPE_ANSI +CCbigguy CCbigguy_itobigguy (int d) +#else +CCbigguy CCbigguy_itobigguy (d) +int d; +#endif +{ + CCbigguy x; + int sgn; + + if (d < 0) { + d = -d; + sgn = -1; + } else { + sgn = 1; + } + + x.ihi = ((unsigned short) (d >> 16)); + x.ilo = ((unsigned short) (d & 0xffff)); + x.fhi = 0; + x.flo = 0; + + if (x.ihi >= 32768) { +/* fprintf (stderr, "OVERFLOW in CCbigguy_itobigguy\n"); + fprintf (stderr, "BIGGUY errors are fatal\n"); + abort (); +*/ } + + if (sgn == -1) { + bigguy_neg (&x); + } + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +CCbigguy CCbigguy_dtobigguy (double d) +#else +CCbigguy CCbigguy_dtobigguy (d) +double d; +#endif +{ + CCbigguy x; + int sgn; + + if (d < 0.0) { + d = -d; + sgn = -1; + } else { + sgn = 1; + } + + if (d / 65536.0 >= 32768.0) { +/* fprintf (stderr, "OVERFLOW in CCbigguy_dtobigguy (%.6f)\n", d * sgn); + fprintf (stderr, "BIGGUY errors are fatal\n"); + abort (); +*/ } + + x.ihi = ((unsigned short) (d / 65536.0)); + d -= ((double) x.ihi) * 65536.0; + x.ilo = ((unsigned short) d); + d -= ((double) x.ilo); + x.fhi = ((unsigned short) (d * 65536.0)); + d -= ((double) x.fhi) / 65536.0; + x.flo = ((unsigned short) (d * 65536.0 * 65536.0)); + + if (sgn == -1) { + bigguy_neg (&x); + } + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +CCbigguy CCbigguy_ceil (CCbigguy x) +#else +CCbigguy CCbigguy_ceil (x) +CCbigguy x; +#endif +{ + if (x.fhi || x.flo) { + x.fhi = 0; + x.flo = 0; + x.ilo++; + if (x.ilo == 0) { + if (x.ihi == 32767) { +/* fprintf (stderr, "OVERFLOW in CCbigguy_ceil\n"); + fprintf (stderr, "BIGGUY errors are fatal\n"); + abort (); +*/ } + x.ihi++; + } + } + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCbigguy_cmp (CCbigguy x, CCbigguy y) +#else +int CCbigguy_cmp (x, y) +CCbigguy x; +CCbigguy y; +#endif +{ + if (x.ihi >= 32768 && y.ihi < 32768) return -1; + else if (x.ihi < 32768 && y.ihi >= 32768) return 1; + else if (x.ihi < y.ihi) return -1; + else if (x.ihi > y.ihi) return 1; + else if (x.ilo < y.ilo) return -1; + else if (x.ilo > y.ilo) return 1; + else if (x.fhi < y.fhi) return -1; + else if (x.fhi > y.fhi) return 1; + else if (x.flo < y.flo) return -1; + else if (x.flo > y.flo) return 1; + else return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCbigguy_addmult (CCbigguy *x, CCbigguy y, short m) +#else +void CCbigguy_addmult (x, y, m) +CCbigguy *x; +CCbigguy y; +short m; +#endif +{ + int carry = 0; + int sgn = 1; + + if (m == -32768) { +/* fprintf (stderr, "OVERFLOW in CCbigguy_addmult\n"); + fprintf (stderr, "BIGGUY errors are fatal\n"); + abort (); +*/ } + + if (y.ihi >= 32768) { + bigguy_neg (&y); + m = -m; + } + + if (x->ihi >= 32768) { + bigguy_neg (x); + m = -m; + sgn = -1; + } + + carry = x->flo + m * y.flo; + x->flo = carry & ((unsigned short) 0xffff); + carry -= x->flo; + carry /= 65536; + carry = carry + x->fhi + m * y.fhi; + x->fhi = carry & ((unsigned short) 0xffff); + carry -= x->fhi; + carry /= 65536; + carry = carry + x->ilo + m * y.ilo; + x->ilo = carry & ((unsigned short) 0xffff); + carry -= x->ilo; + carry /= 65536; + carry = carry + x->ihi + m * y.ihi; + x->ihi = carry & ((unsigned short) 0xffff); + carry -= x->ihi; + carry /= 65536; + + if (carry < -1 || carry > 0 || + (carry == -1 && x->ihi < 32768) || + (carry == 0 && x->ihi >= 32768)) { +/* fprintf (stderr, "OVERFLOW in CCbigguy_addmult\n"); + fprintf (stderr, "BIGGUY errors are fatal\n"); + abort (); +*/ } + + if (sgn == -1) { + bigguy_neg (x); + } +} + +#endif /* CC_BIGGUY_LONGLONG */ diff --git a/contrib/blossom/concorde97/BIGGUY/bigguy.tst b/contrib/blossom/concorde97/BIGGUY/bigguy.tst new file mode 100644 index 0000000000000000000000000000000000000000..d0765488bc43591efc21fcc54434c696703c6d61 Binary files /dev/null and b/contrib/blossom/concorde97/BIGGUY/bigguy.tst differ diff --git a/contrib/blossom/concorde97/CUT/Makefile b/contrib/blossom/concorde97/CUT/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b85301465e81862965eac083d090d6838532ddc3 --- /dev/null +++ b/contrib/blossom/concorde97/CUT/Makefile @@ -0,0 +1,34 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=cut.a +LIBSRCS=segments.c connect.c shrink.c mincut.c cut_st.c +ALLSRCS=mc_main.c $(LIBSRCS) +LIBS=$(ROOT)/UTIL/util.a + +all: mincut $(LIB) + +mincut: mc_main.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ -lm + +clean: + -rm -f *.$o $(LIB) mincut + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +connect.$o: connect.c $(I)/machdefs.h $(I)/util.h $(I)/cut.h +cut_st.$o: cut_st.c $(I)/machdefs.h $(I)/util.h $(I)/cut.h +mc_main.$o: mc_main.c $(I)/machdefs.h $(I)/util.h $(I)/cut.h +mincut.$o: mincut.c $(I)/machdefs.h $(I)/util.h $(I)/cut.h +segments.$o: segments.c $(I)/machdefs.h $(I)/util.h $(I)/cut.h +shrink.$o: shrink.c $(I)/machdefs.h $(I)/util.h $(I)/cut.h diff --git a/contrib/blossom/concorde97/CUT/connect.c b/contrib/blossom/concorde97/CUT/connect.c new file mode 100644 index 0000000000000000000000000000000000000000..26f5da432f78321d6160d62c3559d30ce173fdd0 --- /dev/null +++ b/contrib/blossom/concorde97/CUT/connect.c @@ -0,0 +1,278 @@ +/***************************************************************************/ +/* */ +/* Cuts from Connected Components */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 17, 1997 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCcut_connect_components (int ncount, int ecount, int *elist, */ +/* double *x, int *ncomp, int **compscount, int **comps) */ +/* RETURNS the connected components of the graph given by the edgeset */ +/* -ncount is the number of nodes */ +/* -ecount is the number of edges */ +/* -elist is the edge list in node node format */ +/* -x is an vector of length ecount (it can be NULL); is it is not */ +/* NULL, then the connected components will be for the graph */ +/* consisting of the positive edges */ +/* -ncomp will return the number of connected components */ +/* -compscount will return the number of nodes in each of the */ +/* components (it will be an ncomp long array) */ +/* -comps will return the nodes in the components (it will be an */ +/* ncount array, with the first compscount[0] elements making up */ +/* the first component, etc.) */ +/* */ +/* NOTES: */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "cut.h" + +#define CONNECT_ZERO_EPSILON (1e-10) + +typedef struct node { + int *adj; + int degree; + int mark; +} node; + +typedef struct graph { + node *nodelist; + int *adjspace; + int ncount; + int ecount; +} graph; + +#ifdef CC_PROTOTYPE_ANSI + +static int + build_graph (graph *G, int ncount, int ecount, int *elist, + double *x); + +static void + free_graph (graph *G), + connect_search (graph *G, int n, int marker, int *dstack); + +#else + +static int + build_graph (); + +static void + free_graph (), + connect_search (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_connect_components (int ncount, int ecount, int *elist, double *x, + int *ncomp, int **compscount, int **comps) +#else +int CCcut_connect_components (ncount, ecount, elist, x, ncomp, compscount, + comps) +int ncount; +int ecount; +int *elist; +double *x; +int *ncomp; +int **compscount; +int **comps; +#endif +{ + graph G; + int i, k, rval; + int *nmarks = (int *) NULL; + int *dstack = (int *) NULL; + + G.nodelist = (node *) NULL; + G.adjspace = (int *) NULL; + + *ncomp = 0; + *comps = CC_SAFE_MALLOC (ncount, int); + if (!(*comps)) { + fprintf (stderr, "out of memory in CCcut_connect_components\n"); + rval = 1; goto CLEANUP; + } + + rval = build_graph (&G, ncount, ecount, elist, x); + if (rval) { + fprintf (stderr, "build_graph failed\n"); + goto CLEANUP; + } + + dstack = CC_SAFE_MALLOC (ncount, int); + if (!dstack) { + fprintf (stderr, "out of memory in CCcut_connect_components\n"); + CC_FREE (*comps, int); + rval = 1; goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + if (!G.nodelist[i].mark) { + (*ncomp)++; + connect_search (&G, i, *ncomp, dstack); + } + } + + *compscount = CC_SAFE_MALLOC (*ncomp, int); + nmarks = CC_SAFE_MALLOC (*ncomp, int); + if (!(*compscount) || !nmarks) { + fprintf (stderr, "out of memory in CCcut_connect_components\n"); + CC_FREE (*comps, int); + CC_IFFREE (*compscount, int); + CC_IFFREE (nmarks, int); + rval = 1; goto CLEANUP; + } + for (i = 0; i < *ncomp; i++) { + nmarks[i] = 0; + } + for (i = 0; i < ncount; i++) { + nmarks[G.nodelist[i].mark - 1]++; + } + for (i = 0, k = 0; i < *ncomp; i++) { + (*compscount)[i] = nmarks[i]; + nmarks[i] = k; + k += (*compscount)[i]; + } + for (i = 0; i < ncount; i++) { + (*comps)[(nmarks[G.nodelist[i].mark - 1])++] = i; + } + +CLEANUP: + + free_graph (&G); + CC_IFFREE (nmarks, int); + CC_IFFREE (dstack, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int build_graph (graph *G, int ncount, int ecount, int *elist, + double *x) +#else +static int build_graph (G, ncount, ecount, elist, x) +graph *G; +int ncount, ecount; +int *elist; +double *x; +#endif +{ + int rval = 0; + int i; + int *p; + node *nodelist; + + G->nodelist = (node *) NULL; + G->adjspace = (int *) NULL; + G->ncount = ncount; + if (x) { + G->ecount = 0; + for (i = 0; i < ecount; i++) { + if (x[i] > CONNECT_ZERO_EPSILON) + G->ecount++; + } + } else { + G->ecount = ecount; + } + + G->nodelist = CC_SAFE_MALLOC (G->ncount, node); + G->adjspace = CC_SAFE_MALLOC (2*G->ecount, int); + if (!G->nodelist || !G->adjspace) { + fprintf (stderr, "out of memory in build_graph\n"); + rval = 1; goto CLEANUP; + } + nodelist = G->nodelist; + + for (i = 0; i < ncount; i++) { + nodelist[i].degree = 0; + nodelist[i].mark = 0; + } + + if (x) { + for (i = 0; i < ecount; i++) { + if (x[i] > CONNECT_ZERO_EPSILON) { + nodelist[elist[2*i]].degree++; + nodelist[elist[2*i+1]].degree++; + } + } + } else { + for (i = 0; i < ecount; i++) { + nodelist[elist[2*i]].degree++; + nodelist[elist[2*i+1]].degree++; + } + } + + p = G->adjspace; + for (i = 0; i < ncount; i++) { + nodelist[i].adj = p; + p += nodelist[i].degree; + nodelist[i].degree = 0; + } + + if (x) { + for (i = 0; i < ecount; i++) { + if (x[i] > CONNECT_ZERO_EPSILON) { + nodelist[elist[2*i]].adj[nodelist[elist[2*i]].degree++] + = elist[2*i+1]; + nodelist[elist[2*i+1]].adj[nodelist[elist[2*i+1]].degree++] + = elist[2*i]; + } + } + } else { + for (i = 0; i < ecount; i++) { + nodelist[elist[2*i]].adj[nodelist[elist[2*i]].degree++] + = elist[2*i+1]; + nodelist[elist[2*i+1]].adj[nodelist[elist[2*i+1]].degree++] + = elist[2*i]; + } + } + +CLEANUP: + + if (rval) { + CC_IFFREE (G->nodelist, node); + CC_IFFREE (G->adjspace, int); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void free_graph (graph *G) +#else +static void free_graph (G) +graph *G; +#endif +{ + CC_IFFREE (G->nodelist, node); + CC_IFFREE (G->adjspace, int); +} + +#ifdef CC_PROTOTYPE_ANSI +static void connect_search (graph *G, int n, int marker, int *dstack) +#else +static void connect_search (G, n, marker, dstack) +graph *G; +int n, marker; +int *dstack; +#endif +{ + int i, k, head = 0; + node *nodelist = G->nodelist; + + nodelist[n].mark = marker; + dstack[head++] = n; + + while (head > 0) { + n = dstack[--head]; + for (i = 0; i < nodelist[n].degree; i++) { + k = nodelist[n].adj[i]; + if (!nodelist[k].mark) { + nodelist[k].mark = marker; + dstack[head++] = k; + } + } + } +} diff --git a/contrib/blossom/concorde97/CUT/cut_st.c b/contrib/blossom/concorde97/CUT/cut_st.c new file mode 100644 index 0000000000000000000000000000000000000000..4e45ffa0b6bd04e85a070a0f3cbac58199574805 --- /dev/null +++ b/contrib/blossom/concorde97/CUT/cut_st.c @@ -0,0 +1,844 @@ +/***************************************************************************/ +/* */ +/* MINIMUM S-T CUTS IN DIRECTED AND UNDIRECTED GRAPHS */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: July 25, 1996 */ +/* */ +/* An implementation of the Push-Relabel Flow Algorithm described in */ +/* A. Goldberg and R. Tarjan, "A new approach to the maximum-flow */ +/* problem", Journal of the ACM 35 (1988) 921-940. */ +/* */ +/* EXPORTED FUNCTION: */ +/* int mincut_st (int ncount, int ecount, int *elist, double *ecap, */ +/* int s, int t, double *value, int **cut, int *cutcount) */ +/* COMPUTES the min st-cut in a directed or undirected graph. */ +/* -ncount is the number of nodes in the graph. */ +/* -ecount is the number of directed (undirected) edges. */ +/* -elist gives the edges in node node format (interpreted as */ +/* tail head when compiled for directed graphs). */ +/* -ecap gives the capacities of the edges. */ +/* -s is the name of the source node. */ +/* -t is the name of the sink node. */ +/* -value returns the capacity of the minimum cut. */ +/* -cut (if not NULL) returns a list of nodes in a a minimum cut (it */ +/* returns the side that contains t); it will be allocated to an */ +/* array of the appropriate size. */ +/* -cutcount returns the number of nodes in the listed cut, if cut */ +/* is not NULL (if cut is NULL, then cutcount can be NULL). */ +/* */ +/* NOTES: */ +/* Returns 0 if it worked and 1 otherwise (for example, when one */ +/* of the mallocs failed). The nodes in the graph should be named */ +/* 0 through #nodes - 1. */ +/* */ +/* Define UNDIRECTED_GRAPH to compile the code for undirected */ +/* graphs. (This appears to be the way to go for tsp instances.) */ +/* */ +/* Two node selection rules are implemented: queue and highest */ +/* label. One of QUEUE_PRF and HIGHEST_LABEL_PRF must be defined */ +/* (but not both). */ +/* */ +/* The code can carry out global relabelings via a backwards */ +/* breadth-first-search from the sink. The frequency of the */ +/* relabelings is controlled by the defined constant */ +/* GLOBAL_RELABEL_FREQUENCY. A relabling will occur after each */ +/* #nodes * GLOBAL_RELABEL_FREQUENCY nodes have been processed. */ +/* A resonable choice for the constant is 1. */ +/* */ +/* Defining USE_GAP turns on the gap heuristic of Derigs and */ +/* Meyer for determing nodes that can be labeled to ncount. */ +/* This can be used with either the queue or highest label */ +/* variants. */ +/* */ +/* To use this code for maxflows, allow nodes with labels up to */ +/* 2*ncount to become active, or implement an algorithm to */ +/* decompose the preflow to create a flow. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "cut.h" + +#define UNDIRECTED_GRAPH + +#define HIGHEST_LABEL_PRF +#undef QUEUE_PRF + +#define USE_GAP +#define GLOBAL_RELABEL_FREQUENCY 1.0 + +#define INFINITY (1<<30) +#define PRF_EPSILON 0.000000001 +#define GOING_IN 0 +#define GOING_OUT 1 + +#ifdef QUEUE_PRF +#define ADD_TO_ACTIVE(n) { \ + if (!(n)->active) { \ + (n)->qnext = (node *) NULL; \ + if (qtail) { \ + qtail->qnext = (n); \ + } else { \ + qhead = (n); \ + } \ + qtail = (n); \ + (n)->active = 1; \ + } \ +} +#endif + +#ifdef HIGHEST_LABEL_PRF +#define ADD_TO_ACTIVE(n) { \ + if (!(n)->active) { \ + (n)->highnext = high[(n)->flowlabel]; \ + high[(n)->flowlabel] = (n); \ + if (G->highest < (n)->flowlabel) \ + G->highest = (n)->flowlabel; \ + (n)->active = 1; \ + } \ +} +#endif + +#ifdef UNDIRECTED_GRAPH +#define RELABEL_BODY(n) \ + for (rele = (n)->out; rele; rele = rele->outnext) { \ + if (rele->cap - rele->flow > PRF_EPSILON && \ + (relt = rele->ends[1]->flowlabel) < relm) \ + relm = relt; \ + } \ + for (rele = (n)->in; rele; rele = rele->innext) { \ + if (rele->cap + rele->flow > PRF_EPSILON && \ + (relt = rele->ends[0]->flowlabel) < relm) \ + relm = relt; \ + } \ + (n)->flowlabel = ++relm; +#else +#define RELABEL_BODY(n) \ + for (rele = (n)->out; rele; rele = rele->outnext) { \ + if (rele->cap - rele->flow > PRF_EPSILON && \ + (relt = rele->ends[1]->flowlabel) < relm) \ + relm = relt; \ + } \ + for (rele = (n)->in; rele; rele = rele->innext) { \ + if (rele->flow > PRF_EPSILON && \ + (relt = rele->ends[0]->flowlabel) < relm) \ + relm = relt; \ + } \ + (n)->flowlabel = ++relm; +#endif + +#ifdef USE_GAP +#define RELABEL(n) { \ + int relm = INFINITY; \ + edge *rele; \ + int relt, relold = (n)->flowlabel; \ + \ + RELABEL_BODY(n) \ + \ + if ((n)->levelprev) { \ + (n)->levelprev->levelnext = (n)->levelnext; \ + } else { \ + level[relold] = (n)->levelnext; \ + } \ + if ((n)->levelnext) \ + (n)->levelnext->levelprev = (n)->levelprev; \ + \ + if (relm < ncount) { \ + if (level[relm]) { \ + level[relm]->levelprev = (n); \ + (n)->levelnext = level[relm]; \ + (n)->levelprev = (node *) NULL; \ + level[relm] = (n); \ + } else { \ + (n)->levelprev = (node *) NULL; \ + (n)->levelnext = (node *) NULL; \ + level[relm] = (n); \ + } \ + if (!level[relold]) { \ + relold++; \ + while (level[relold]) { \ + node *relno; \ + for (relno = level[relold]; relno; \ + relno = relno->levelnext) { \ + relno->flowlabel = ncount; \ + } \ + level[relold] = (node *) NULL; \ + relold++; \ + } \ + } \ + } \ +} +#else +#define RELABEL(n) { \ + int relm = INFINITY; \ + edge *rele; \ + int relt; \ + \ + RELABEL_BODY(n) \ +} +#endif /* USE_GAP */ + +typedef struct edge { + struct node *ends[2]; + struct edge *innext; + struct edge *outnext; + double cap; + double flow; +} edge; + +typedef struct node { + struct node *qnext; + struct node *tnext; +#ifdef USE_GAP + struct node *levelnext; + struct node *levelprev; +#endif +#ifdef HIGHEST_LABEL_PRF + struct node *highnext; +#endif + struct edge *in; + struct edge *out; + struct edge *incurrent; + struct edge *outcurrent; + double excess; + int magiclabel; + int flowlabel; + char inout; + char active; +} node; + +typedef struct graph { + struct node *nodelist; + struct edge *edgelist; +#ifdef USE_GAP + struct node **level; +#endif +#ifdef HIGHEST_LABEL_PRF + struct node **high; + int highest; +#endif + int nnodes; + int nedges; + int magicnum; +} graph; + + +#ifdef CC_PROTOTYPE_ANSI + +static void + setlabels (graph *G, node *s, node *t), + backwards_bfs (node *s, int K, graph *G), + init_graph (graph *G), + free_graph (graph *G); +static int + grab_the_cut (graph *G, node *n, int **cut, int *cutcount), + buildgraph (graph *G, int ncount, int ecount, int *elist, double *gap); +static double + flow (graph *G, node *s, node *t); + +#else + +static void + setlabels (), + backwards_bfs (), + init_graph (), + free_graph (); +static int + grab_the_cut (), + buildgraph (); +static double + flow (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_mincut_st (int ncount, int ecount, int *elist, double *ecap, + int s, int t, double *value, int **cut, int *cutcount) +#else +int CCcut_mincut_st (ncount, ecount, elist, ecap, s, t, value, cut, cutcount) +int ncount, ecount, *elist; +int s, t; +double *ecap, *value; +int **cut, *cutcount; +#endif +{ + int rval = 0; + graph G; + + init_graph (&G); + + if (cut) { + *cut = (int *) NULL; + if (cutcount) { + *cutcount = 0; + } else { + fprintf (stderr, "cut is specified but not cutcount\n"); + rval = 1; goto CLEANUP; + } + } + + rval = buildgraph (&G, ncount, ecount, elist, ecap); + if (rval) { + fprintf (stderr, "Buildgraph failed\n"); goto CLEANUP; + } + *value = flow (&G, G.nodelist + s, G.nodelist + t); + if (cut) { + rval = grab_the_cut (&G, G.nodelist + t, cut, cutcount); + if (rval) { + fprintf (stderr, "grab_the_cut failed\n"); goto CLEANUP; + } + } + + +CLEANUP: + + free_graph (&G); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static double flow (graph *G, node *s, node *t) +#else +static double flow (G, s, t) +graph *G; +node *s, *t; +#endif +{ +#ifdef QUEUE_PRF + node *qhead = (node *) NULL; + node *qtail = (node *) NULL; +#endif + node *n; + edge *e; + int count, round; + int i; + int ncount = G->nnodes; + edge *edgelist = G->edgelist; + node *nodelist = G->nodelist; +#ifdef USE_GAP + node **level = G->level; +#endif +#ifdef HIGHEST_LABEL_PRF + node **high = G->high; +#endif + +/* + printf ("Find cut separating %d and %d ...\n", s - nodelist, t - nodelist); + fflush (stdout); +*/ + + for (i = 0; i < ncount; i++) { + nodelist[i].excess = 0.0; + nodelist[i].active = 0; +#ifdef HIGHEST_LABEL_PRF + high[i] = (node *) NULL; +#endif + } +#ifdef HIGHEST_LABEL_PRF + G->highest = 0; +#endif + + for (i = G->nedges - 1; i >= 0; i--) + edgelist[i].flow = 0.0; + + t->active = 1; /* a lie, which keeps s and t off the */ + s->active = 1; /* active int */ + + for (e = s->out; e; e = e->outnext) { + if (e->cap > 0.0) { + e->flow = e->cap; + e->ends[1]->excess += e->cap; +#ifdef QUEUE_PRF + ADD_TO_ACTIVE(e->ends[1]); +#endif +#ifdef HIGHEST_LABEL_PRF + e->ends[1]->active = 1; +#endif + } + } +#ifdef UNDIRECTED_GRAPH + for (e = s->in; e; e = e->innext) { + if (e->cap > 0.0) { + e->flow = -e->cap; + e->ends[0]->excess += e->cap; +#ifdef QUEUE_PRF + ADD_TO_ACTIVE(e->ends[0]); +#endif +#ifdef HIGHEST_LABEL_PRF + e->ends[0]->active = 1; +#endif + } + } +#endif + + + setlabels (G, s, t); + count = 0; + round = (int) (GLOBAL_RELABEL_FREQUENCY * ncount); + +#ifdef QUEUE_PRF + while (qhead) { + n = qhead; + qhead = qhead->qnext; + if (!qhead) + qtail = (node *) NULL; + n->active = 0; + if (n->flowlabel >= ncount) + continue; +#endif + +#ifdef HIGHEST_LABEL_PRF + while (G->highest) { + n = high[G->highest]; + n->active = 0; + high[G->highest] = high[G->highest]->highnext; + if (!high[G->highest]) { + G->highest--; + while (G->highest && (high[G->highest] == (node *) NULL)) + G->highest--; + } +#endif + + if (count == round) { + setlabels (G, s, t); + if (n->flowlabel >= ncount) + continue; + count = 0; + } else + count++; + + if (n->inout == GOING_IN) + goto DO_ME_IN; + + if (n->outcurrent) { + while (n->excess > 0.0) { + e = n->outcurrent; + { /* PUSH OUT */ + double rf = e->cap - e->flow; + node *n1 = e->ends[1]; + if (n->flowlabel == n1->flowlabel + 1 && rf > 0.0) { + if (n->excess <= rf) { + e->flow += n->excess; + n1->excess += n->excess; + n->excess = 0.0; + ADD_TO_ACTIVE(n1); + } else { + e->flow += rf; + n1->excess += rf; + n->excess -= rf; + ADD_TO_ACTIVE(n1); + n->outcurrent = e->outnext; + if (!n->outcurrent) { + n->outcurrent = n->out; + n->inout = GOING_IN; + goto DO_ME_IN; + } + } + } else { + n->outcurrent = e->outnext; + if (!n->outcurrent) { + n->outcurrent = n->out; + n->inout = GOING_IN; + goto DO_ME_IN; + } + } + } + } + } +DO_ME_IN: + if (n->incurrent) { + while (n->excess > 0.0) { + e = n->incurrent; + { /* PUSH IN */ +#ifdef UNDIRECTED_GRAPH + double rf = e->cap + e->flow; +#else + double rf = e->flow; +#endif + node *n1 = e->ends[0]; + if (n->flowlabel == n1->flowlabel + 1 && rf > 0.0) { + if (n->excess <= rf) { + e->flow -= n->excess; + n1->excess += n->excess; + n->excess = 0.0; + ADD_TO_ACTIVE(n1); + } else { + e->flow -= rf; + n1->excess += rf; + n->excess -= rf; + ADD_TO_ACTIVE(n1); + n->incurrent = e->innext; + if (!n->incurrent) { + n->incurrent = n->in; + n->inout = GOING_OUT; + RELABEL(n); + break; + } + } + } else { + n->incurrent = e->innext; + if (!n->incurrent) { + n->incurrent = n->in; + n->inout = GOING_OUT; + RELABEL(n); + break; + } + } + } + } + } else { + /* n->in is NULL */ + n->inout = GOING_OUT; + RELABEL(n); + } + if (n->excess > 0.0 && n->flowlabel < ncount) { + ADD_TO_ACTIVE(n); + } + } + + return t->excess; +} + +#ifdef CC_PROTOTYPE_ANSI +static void setlabels (graph *G, node *s, node *t) +#else +static void setlabels (G, s, t) +graph *G; +node *s, *t; +#endif +{ + node *n; + int ncount = G->nnodes; + int num = ++(G->magicnum); + int i; + /* static int duke = 0; */ + + t->flowlabel = 0; + backwards_bfs (t, num, G); + if (s->magiclabel == num) { + printf ("Help - s should not get a label\n"); + s->flowlabel = ncount; + } + + for (i = G->nnodes, n = G->nodelist; i; i--, n++) { + n->outcurrent = n->out; + n->incurrent = n->in; + n->inout = GOING_OUT; + if (n->magiclabel != num) { + n->flowlabel = ncount; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void backwards_bfs (node *s, int K, graph *G) +#else +static void backwards_bfs (s, K, G) +node *s; +int K; +graph *G; +#endif +{ + node *this, *next, *tail; + edge *e; + int dist; +#ifdef USE_GAP + node dummy; + node **level = G->level; +#endif +#ifdef HIGHEST_LABEL_PRF + node **high = G->high; +#endif + + s->magiclabel = K; + next = s; + s->tnext = (node *) NULL; + dist = s->flowlabel; + +#ifdef USE_GAP + { + int i; + for (i = 0; level[i]; i++) + level[i] = (node *) NULL; + level[dist] = s; + s->levelnext = (node *) NULL; + } +#endif +#ifdef HIGHEST_LABEL_PRF + { + int i; + for (i = 0; i <= G->highest; i++) + high[i] = (node *) NULL; + G->highest = 0; + } +#endif + + do { +#ifdef USE_GAP + level[dist]->levelprev = (node *) NULL; + level[dist + 1] = &dummy; + dummy.levelprev = (node *) NULL; +#endif + dist++; + for (this = next, next = (node *) NULL; this; this = this->tnext) { + for (e = this->out; e; e = e->outnext) { + tail = e->ends[1]; +#ifdef UNDIRECTED_GRAPH + if (tail->magiclabel != K && e->cap + e->flow > 0.0) { +#else + if (tail->magiclabel != K && e->flow > 0.0) { +#endif + tail->flowlabel = dist; + tail->tnext = next; + next = tail; + tail->magiclabel = K; +#ifdef USE_GAP + tail->levelnext = level[dist]; + level[dist]->levelprev = tail; + level[dist] = tail; +#endif +#ifdef HIGHEST_LABEL_PRF + if (tail->active) { + tail->highnext = high[dist]; + high[dist] = tail; + } +#endif + } + } + for (e = this->in; e; e = e->innext) { + tail = e->ends[0]; + if (tail->magiclabel != K && e->cap - e->flow > 0.0) { + tail->flowlabel = dist; + tail->tnext = next; + next = tail; + tail->magiclabel = K; +#ifdef USE_GAP + tail->levelnext = level[dist]; + level[dist]->levelprev = tail; + level[dist] = tail; +#endif +#ifdef HIGHEST_LABEL_PRF + if (tail->active) { + tail->highnext = high[dist]; + high[dist] = tail; + } +#endif + } + } + } +#ifdef USE_GAP + if (dummy.levelprev) { + dummy.levelprev->levelnext = (node *) NULL; + level[dist]->levelprev = (node *) NULL; + } else { + level[dist] = (node *) NULL; + } +#endif +#ifdef HIGHEST_LABEL_PRF + if (high[dist]) + G->highest = dist; +#endif + } while (next); +} + +#ifdef CC_PROTOTYPE_ANSI +static int grab_the_cut (graph *G, node *n, int **cut, int *cutcount) +#else +static int grab_the_cut (G, n, cut, cutcount) +graph *G; +node *n; +int **cut; +int *cutcount; +#endif +{ + int rval = 0; + edge *e; + node *q, *top; + int count = 0; + int i, num; + node *nodelist = G->nodelist; + int *tcut = (int *) NULL; + + *cut = (int *) NULL; + *cutcount = 0; + + tcut = CC_SAFE_MALLOC (G->nnodes, int); + if (!tcut) { + fprintf (stderr, "out of memory in grab_the_cut\n"); + rval = 1; goto CLEANUP; + } + + G->magicnum++; + num = G->magicnum; + tcut[count++] = n - nodelist; + q = n; + q->magiclabel = num; + q->tnext = (node *) NULL; + + while (q) { + top = q; + q = q->tnext; + for (e = top->out; e; e = e->outnext) { +#ifdef UNDIRECTED_GRAPH + if (e->cap + e->flow > 0.0 && e->ends[1]->magiclabel != num) { +#else + if (e->flow > 0.0 && e->ends[1]->magiclabel != num) { +#endif + tcut[count++] = e->ends[1] - nodelist; + e->ends[1]->magiclabel = num; + e->ends[1]->tnext = q; + q = e->ends[1]; + } + } + for (e = top->in; e; e = e->innext) { + if (e->cap - e->flow > 0.0 && e->ends[0]->magiclabel != num) { + tcut[count++] = e->ends[0] - nodelist; + e->ends[0]->magiclabel = num; + e->ends[0]->tnext = q; + q = e->ends[0]; + } + } + } + + *cut = CC_SAFE_MALLOC (count, int); + if (!(*cut)) { + fprintf (stderr, "out of memory in grab_the_cut\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < count; i++) { + (*cut)[i] = tcut[i]; + } + *cutcount = count; + +CLEANUP: + + if (rval) { + CC_IFFREE (*cut, int); + } + CC_IFFREE (tcut, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int buildgraph (graph *G, int ncount, int ecount, int *elist, + double *ecap) +#else +static int buildgraph (G, ncount, ecount, elist, ecap) +graph *G; +int ncount, ecount, *elist; +double *ecap; +#endif +{ + int i; + edge *edgelist; + node *nodelist; + + G->nodelist = (node *) NULL; + G->edgelist = (edge *) NULL; +#ifdef USE_GAP + G->level = (node **) NULL; +#endif +#ifdef HIGHEST_LABEL_PRF + G->high = (node **) NULL; +#endif + + G->magicnum = 0; + G->nnodes = ncount; + G->nedges = ecount; + G->nodelist = CC_SAFE_MALLOC (ncount, node); + G->edgelist = CC_SAFE_MALLOC (ecount, edge); + if (!G->nodelist || !G->edgelist) { + fprintf (stderr, "Out of memory in buildgraph\n"); + CC_IFFREE (G->nodelist, node); + CC_IFFREE (G->edgelist, edge); + return 1; + } +#ifdef USE_GAP + G->level = CC_SAFE_MALLOC (ncount + 1, node *); + if (!G->level) { + fprintf (stderr, "Out of memory in buildgraph\n"); + CC_IFFREE (G->nodelist, node); + CC_IFFREE (G->edgelist, edge); + return 1; + } + for (i = 0; i < ncount; i++) + G->level[i] = (node *) NULL; + G->level[ncount] = (node *) NULL; /* A guard dog for a while loop */ +#endif + +#ifdef HIGHEST_LABEL_PRF + G->high = CC_SAFE_MALLOC (ncount, node *); + if (!G->high) { + fprintf (stderr, "Out of memory in buildgraph\n"); + CC_IFFREE (G->nodelist, node); + CC_IFFREE (G->edgelist, edge); + return 1; + } +#endif + + nodelist = G->nodelist; + edgelist = G->edgelist; + + for (i = 0; i < ncount; i++) { + nodelist[i].in = (edge *) NULL; + nodelist[i].out = (edge *) NULL; + nodelist[i].magiclabel = 0; + } + + for (i = 0; i < ecount; i++) { + int tail = elist[2 * i]; + int head = elist[(2 * i) + 1]; + if (tail < 0 || tail >= ncount || + head < 0 || head >= ncount) { + fprintf (stderr, "Edge list in wrong format: Edge %d = [%d, %d]\n", + i, tail, head); + return 1; + } + edgelist[i].ends[0] = nodelist + tail; + edgelist[i].ends[1] = nodelist + head; + edgelist[i].cap = ecap[i]; + edgelist[i].outnext = nodelist[tail].out; + nodelist[tail].out = &(edgelist[i]); + edgelist[i].innext = nodelist[head].in; + nodelist[head].in = &(edgelist[i]); + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void init_graph (graph *G) +#else +static void init_graph (G) +graph *G; +#endif +{ + if (G) { + G->nodelist = (node *) NULL; + G->edgelist = (edge *) NULL; +#ifdef USE_GAP + G->level = (node **) NULL; +#endif +#ifdef HIGHEST_LABEL_PRF + G->high = (node **) NULL; +#endif + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void free_graph (graph *G) +#else +static void free_graph (G) +graph *G; +#endif +{ + CC_IFFREE (G->nodelist, node); + CC_IFFREE (G->edgelist, edge); +#ifdef USE_GAP + CC_IFFREE (G->level, node *); +#endif +#ifdef HIGHEST_LABEL_PRF + CC_IFFREE (G->high, node *); +#endif +} diff --git a/contrib/blossom/concorde97/CUT/mc_main.c b/contrib/blossom/concorde97/CUT/mc_main.c new file mode 100644 index 0000000000000000000000000000000000000000..f9c6f5c342673eb973e1b23fdcb496e8f48770ab --- /dev/null +++ b/contrib/blossom/concorde97/CUT/mc_main.c @@ -0,0 +1,423 @@ +/************************************************************************/ +/* */ +/* Demo of Min-Cutw for Directed and Undirected Graphs */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: September, 1994 (Bonn) */ +/* July 28, 1997 (bico) */ +/* */ +/************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "cut.h" + +#undef USE_DIRECTED_GRAPH + +static int source = -1, sink = -1; +static int showcut = 0; +static int violatedcuts = 0; +static int use_shrink = 1; +static int find_global = 0; +static int binary_in = 0; +static char *fname = (char *) NULL; + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int ac, char **av); + +static void + usage (char *f), + display_cut (int *cut, int count); + +static int + parseargs (int ac, char **av), + shrink_ones (int ncount, int ecount, int *elist, double *dlen, + int *oncount, int *oecount, int **olist, double **olen, + double *minval), + display_all_cuts (double val, int cnt, int *cut, void *pass_param); + +#else + +int + main (); + +static void + usage (), + display_cut (); + +static int + parseargs (), + shrink_ones (), + display_all_cuts (); + +#endif + +#ifdef USE_DIRECTED_GRAPH +#ifdef CC_PROTOTYPE_ANSI +static int + duplicate_edges (int ncount, int ecount, int *elist, double *ecap, + int **tlist, double **tcap); +#else + duplicate_edges (); +#endif +#endif + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + int rval = 0; + double val; + double szeit; + int i, cutcount; + int ncount, ecount; + int *elist = (int *) NULL; + int *cut = (int *) NULL; + int **mycut = (int **) NULL; + double *ecap = (double *) NULL; + + if (parseargs (ac, av)) goto CLEANUP; + + if (find_global && violatedcuts) { + fprintf (stderr, "use at most one of -p and -c arguments\n"); + goto CLEANUP; + } + +#ifdef USE_DIRECTED + if (find_global || violatedcuts) { + fprintf (stderr, "not set up for global cut in directed graphs\n"); + goto CLEANUP; + } +#endif + + + rval = CCutil_getedges_double (&ncount, fname, &ecount, &elist, &ecap, + binary_in); + if (rval) { + fprintf (stderr, "getedges_double failed\n"); goto CLEANUP; + } + + if (showcut) { + mycut = &cut; + } else { + mycut = (int **) NULL; + } + + if (find_global) { + szeit = CCutil_zeit (); + rval = CCcut_mincut (ncount, ecount, elist, ecap, &val, mycut, + &cutcount); + if (rval) { + fprintf (stderr, "CCcut_mincut failed\n"); goto CLEANUP; + } + printf ("Minimum Cut Value: %f (%.2f seconds)\n", val, CCutil_zeit () - szeit); + fflush (stdout); + if (showcut) display_cut (cut, cutcount); + goto CLEANUP; + } else if (violatedcuts) { + szeit = CCutil_zeit (); + rval = CCcut_violated_cuts (ncount, ecount, elist, ecap, + 2.0 - CC_MINCUT_ONE_EPSILON, display_all_cuts, (void *) NULL); + if (rval) { + fprintf (stderr, "CCcut_violated_cuts failed\n"); + goto CLEANUP; + } + printf ("Running time: %.2f seconds\n", CCutil_zeit () - szeit); + goto CLEANUP; + } + + szeit = CCutil_zeit (); + if (use_shrink) { + int tncount, tecount; + int *telist = (int *) NULL; + double *tecap = (double *) NULL; + double minval = CC_MINCUT_BIGDOUBLE; + double sszeit = CCutil_zeit (); + + rval = shrink_ones (ncount, ecount, elist, ecap, &tncount, &tecount, + &telist, &tecap, &minval); + if (rval) { + fprintf (stderr, "shrink_ones failed\n"); goto CLEANUP; + } + printf ("Shrunk graph has %d nodes and %d edges\n", tncount, tecount); + if (minval != CC_MINCUT_BIGDOUBLE) { + printf ("Shrinking found cut of value %f\n", minval); + } + fflush (stdout); + printf ("Time for shrinking: %.2f seconds\n", CCutil_zeit () - sszeit); + fflush (stdout); + CC_IFFREE(elist, int); + CC_IFFREE(ecap, double); + ncount = tncount; + ecount = tecount; + elist = telist; + ecap = tecap; + } + +#ifdef USE_DIRECTED_GRAPH + { + int tncount, tecount; + int *telist = (int *) NULL; + double *tecap = (double *) NULL; + + rval = duplicate_edges (ncount, ecount, elist, ecap, &telist, &tecap); + if (rval) { + fprintf (stderr, "duplicated_edges failed\n"); goto CLEANUP; + } + CC_IFFREE(elist, int); + CC_IFFREE(ecap, double); + ecount *= 2; + elist = telist; + ecap = tecap; + } +#endif + + + if (source == -1) + source = 0; + + if (sink != -1) { + if (source < 0 || sink < 0 || source >= ncount || + sink >= ncount || source == sink) { + printf ("Bad source sink pair\n"); + fflush (stdout); + goto CLEANUP; + } + + szeit = CCutil_zeit (); + rval = CCcut_mincut_st (ncount, ecount, elist, ecap, source, sink, + &val, mycut, &cutcount); + if (rval) { + fprintf (stderr, "mincut_st failed\n"); goto CLEANUP; + } + printf ("Cut value: %f\n", val); + printf ("Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + + if (showcut) display_cut (cut, cutcount); + } else { + double minval = CC_MINCUT_BIGDOUBLE; + double fzeit = CCutil_zeit (); + + printf ("compute all cuts from source node %d\n", source); + fflush (stdout); + for (i = 0; i < ncount; i++) { + if (i != source) { + rval = CCcut_mincut_st (ncount, ecount, elist, ecap, source, i, + &val, (int **) NULL, (int *) NULL); + if (rval) { + fprintf (stderr, "mincut_digraph failed\n"); goto CLEANUP; + } + if (val < minval) + minval = val; + printf ("."); fflush (stdout); + if (i % 75 == 0) + printf ("%d\n", i); + } + } + printf ("\nMinimum Cut Value: %f\n", minval); + printf ("Running Time: %.2f (seconds)\n", CCutil_zeit () - fzeit); + fflush (stdout); + } + + printf ("Total Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (elist, int); + CC_IFFREE (ecap, double); + CC_IFFREE (cut, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "bcCps:St:")) != EOF) + switch (c) { + case 'b': + binary_in = 1; + break; + case 'c': + violatedcuts = 1; + break; + case 'C': + showcut++; + break; + case 'p': + find_global = 1; + break; + case 's': + source = atoi (CCutil_bix_optarg); + break; + case 'S': + use_shrink = 0; + break; + case 't': + sink = atoi (CCutil_bix_optarg); + break; + case '?': + default: + usage (av[0]); + return 1; + } + if (CCutil_bix_optind >= ac) { + usage (av[0]); + return 1; + } + + fname = av[CCutil_bix_optind++]; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "usage: %s [- below -] edge_file\n", f); + fprintf (stderr, " b: binary input file\n"); + fprintf (stderr, " c: display all cuts < 2.0\n"); + fprintf (stderr, " p: use Padberg-Rinaldi style shrinking\n"); + fprintf (stderr, " s #: source\n"); + fprintf (stderr, " t #: sink\n"); + fprintf (stderr, " S: do not use the TSP shrink routines\n"); + fprintf (stderr, " C: display the min cut\n"); +} + +#ifdef CC_PROTOTYPE_ANSI +static void display_cut (int *cut, int count) +#else +static void display_cut (cut, count) +int *cut; +int count; +#endif +{ + int i; + + printf ("MIN CUT:\n"); + for (i = 0; i < count; i++) { + printf ("%3d ", cut[i]); + if (i % 10 == 9) + printf ("\n"); + } + if (i % 10) printf ("\n"); + fflush (stdout); +} + +#ifdef USE_DIRECTED_GRAPH +#ifdef CC_PROTOTYPE_ANSI +static int duplicate_edges (int ncount, int ecount, int *elist, double *ecap, + int **tlist, double **tcap) +#else +static int duplicate_edges (ncount, ecount, elist, ecap, tlist, tcap) +int ncount, ecount; +int *elist; +double *ecap; +int **tlist; +double **tcap; +#endif +{ + int i; + + *tlist = (int *) NULL; + *tcap = (double *) NULL; + + + /* Convert the graph to a digraph */ + + *tlist = CC_SAFE_MALLOC (4 * ecount, int); + *tcap = CC_SAFE_MALLOC (2 * ecount, double); + if (!*tlist || !*tcap) { + fprintf (stderr, "Out of memory in duplicate_edges\n"); + CC_IFFREE (*tlist, int); + CC_IFFREE (*tcap, double); + return 1; + } + + for (i = 0; i < ecount; i++) { + (*tlist)[4 * i] = (*tlist)[4 * i + 3] = elist[2 * i]; + (*tlist)[4 * i + 1] = (*tlist)[4 * i + 2] = elist[2 * i + 1]; + (*tcap)[2 * i] = (*tcap)[2 * i + 1] = ecap[i]; + } + + return 0; +} +#endif + + +#ifdef CC_PROTOTYPE_ANSI +static int shrink_ones (int ncount, int ecount, int *elist, double *dlen, + int *oncount, int *oecount, int **olist, double **olen, double *minval) +#else +static int shrink_ones (ncount, ecount, elist, dlen, oncount, oecount, olist, + olen, minval) +int ncount, ecount; +int *elist; +double *dlen; +int *oncount, *oecount; +int **olist; +double **olen; +double *minval; +#endif +{ + int rval = 0; + CC_SRKgraph G; + + CCcut_SRK_init_graph (&G); + rval = CCcut_SRK_buildgraph (&G, ncount, ecount, elist, dlen); + if (rval) { + fprintf (stderr, "buildgraph failed in shrink_ones\n"); goto CLEANUP; + } + CCcut_SRK_subtour_shrink (&G, minval, CC_MINCUT_ONE_EPSILON, + (CC_SRKcallback *) NULL, (int **) NULL, (int *) NULL); + + rval = CCcut_SRK_grab_edges (&G, oncount, oecount, olist, olen, + (CC_SRKexpinfo *) NULL); + if (rval) { + fprintf (stderr, "grab edges failed in shrink_ones\n"); goto CLEANUP; + } + + +CLEANUP: + + CCcut_SRK_free_graph (&G); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int display_all_cuts (double val, int cnt, int *cut, void *pass_param) +#else +static int display_all_cuts (val, cnt, cut, pass_param) +double val; +int cnt; +int *cut; +void *pass_param; +#endif +{ + if (pass_param) { + fprintf (stderr, "don't know about pass_param in display_all_cuts\n"); + return 1; + } + + if (cut && cnt) { + printf ("Found cut of value %f\n", val); fflush (stdout); + } + return 0; +} diff --git a/contrib/blossom/concorde97/CUT/mincut.c b/contrib/blossom/concorde97/CUT/mincut.c new file mode 100644 index 0000000000000000000000000000000000000000..41b9d6c4ce259d7f78d3235887265a09c716de27 --- /dev/null +++ b/contrib/blossom/concorde97/CUT/mincut.c @@ -0,0 +1,360 @@ +/***************************************************************************/ +/* */ +/* GLOBAL MIN-CUT USING PADBERG-RINALDI SHRINKING */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: July 24, 1997 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int CCcut_mincut (int ncount, int ecount, int *elist, double *dlen, */ +/* double *cutval, int **cut, int *cutcount) */ +/* COMPUTES the global minimum cut in an undirected graph. */ +/* -ncount is the number of nodes in the graph. */ +/* -ecount is the number of edges in the graph. */ +/* -elist is the list of edges in end0 end1 format */ +/* -dlen is a list of the edge capacities */ +/* -cutval returns the capacity of the mincut (it can be NULL). */ +/* -cut will return the indices of the nodes in the minimum cut; */ +/* this variable can be passed in as NULL, otherwise it will be */ +/* an allocated to an array of the appropriate length. */ +/* -cutcount will return the number of nodes in the minimum cut if */ +/* cut is not NULL (if cut is NULL, then cutcount can be NULL). */ +/* NOTE: This function assumes graph is connected. Paths of 1's are */ +/* are shrunk - this is valid for the tsp, but not in general. */ +/* */ +/* int CCcut_violated_cuts (int ncount, int ecount, int *elist, */ +/* double *dlen, double cutoff, int (*doit_fn) (double, int, */ +/* int *, void *), void *pass_param) */ +/* COMPUTES the global minimum cut, but calls the doit_fn function for */ +/* cut the algorithm encounters that has capacity at most cutoff. */ +/* -doit_fn (if not NULL) will be called for each cut having capacity */ +/* less than or equal to the cutoff value; the arguments will be the */ +/* value of the cut, the number of nodes in the cut, the array of */ +/* the members of the cut, and pass_param. */ +/* -pass_param will be passed to doit_fn; it can be NULL or it can be */ +/* used to pass information to the doit_fn function. */ +/* NOTE: This function assumes graph is connected. */ +/* */ +/* NOTES: */ +/* */ +/* This code works with undirected graphs. The shrinking routines */ +/* assume that we are working with the TSP and not interested in cuts */ +/* of weight 2.0 or more. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "cut.h" + +#ifdef CC_PROTOTYPE_ANSI + +static int + mincut_work (int ncount, int ecount, int *elist, double *dlen, + double *cutval, int **cut, int *cutcount, double cutoff, + int (*doit_fn) (double, int, int *, void *), void *pass_param), + flip_the_cut (int ncount, int **cut, int *cutcount); + +#else + +static int + mincut_work (), + flip_the_cut (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_mincut (int ncount, int ecount, int *elist, double *dlen, + double *cutval, int **cut, int *cutcount) +#else +int CCcut_mincut (ncount, ecount, elist, dlen, cutval, cut, cutcount) +int ncount, ecount; +int *elist; +double *dlen; +double *cutval; +int **cut, *cutcount; +#endif +{ + int rval = 0; + + rval = mincut_work (ncount, ecount, elist, dlen, cutval, cut, cutcount, + 0.0, NULL, (void *) NULL); + if (rval) { + fprintf (stderr, "mincut_work failed\n"); goto CLEANUP; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_violated_cuts (int ncount, int ecount, int *elist, double *dlen, + double cutoff, int (*doit_fn) (double, int, int *, void *), + void *pass_param) +#else +int CCcut_violated_cuts (ncount, ecount, elist, dlen, cutoff, doit_fn, + pass_param) +int ncount, ecount; +int *elist; +double *dlen; +double cutoff; +int (*doit_fn) (); +void *pass_param; +#endif +{ + int rval = 0; + + rval = mincut_work (ncount, ecount, elist, dlen, (double *) NULL, + (int **) NULL, (int *) NULL, cutoff, doit_fn, pass_param); + if (rval) { + fprintf (stderr, "mincut_work failed\n"); goto CLEANUP; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int mincut_work (int ncount, int ecount, int *elist, double *dlen, + double *cutval, int **cut, int *cutcount, double cutoff, + int (*doit_fn) (double, int, int *, void *), void *pass_param) +#else +static int mincut_work (ncount, ecount, elist, dlen, cutval, cut, + cutcount, cutoff, doit_fn, pass_param) +int ncount, ecount; +int *elist; +double *dlen; +double *cutval; +int **cut, *cutcount; +double cutoff; +int (*doit_fn) (); +void *pass_param; +#endif +{ + int rval = 0; + CC_SRKgraph G; + CC_SRKexpinfo E; + int i, sncount, secount; + int *slist = (int *) NULL; + double *slen = (double *) NULL; + double minval = CC_MINCUT_BIGDOUBLE; + double val; + CC_SRKnode *squeue = (CC_SRKnode *) NULL; + CC_SRKedge *f; + int *tcut = (int *) NULL; + int **mytcut = (int **) NULL; + int tcount = 0; + CC_SRKcallback *cb = (CC_SRKcallback *) NULL; + + CCcut_SRK_init_graph (&G); + CCcut_SRK_init_expinfo (&E); + if (cut) { + *cut = (int *) NULL; + if (cutcount) { + *cutcount = 0; + } else { + fprintf (stderr, "cut specified, but not cutcount\n"); + rval = 1; goto CLEANUP; + } + } + if (cut || doit_fn) { + mytcut = &tcut; + } else { + mytcut = (int **) NULL; + } + if (cutval) { + *cutval = CC_MINCUT_BIGDOUBLE; + } + if (doit_fn) { + cb = CC_SAFE_MALLOC (1, CC_SRKcallback); + if (!cb) { + fprintf (stderr, "out of memory in mincut_work\n"); + rval = 1; goto CLEANUP; + } + cb->cutoff = cutoff; + cb->pass_param = pass_param; + cb->doit_fn = doit_fn; + } + + rval = CCcut_SRK_buildgraph (&G, ncount, ecount, elist, dlen); + if (rval) { + fprintf (stderr, "buildgraph failed in shrink_ones\n"); goto CLEANUP; + } + rval = CCcut_SRK_subtour_shrink (&G, &minval, CC_MINCUT_ONE_EPSILON, + cb, cut, cutcount); + if (rval) { + fprintf (stderr, "CCcut_SRK_subtour_shrink failed\n"); goto CLEANUP; + } + + if (CCcut_SRK_grab_edges (&G, &sncount, &secount, &slist, &slen, + (CC_SRKexpinfo *) NULL)) { + fprintf (stderr, "grab edges failed in shrink_ones\n"); + rval = 1; goto CLEANUP; + } + + while (sncount > 1) { + if ( G.head->adj == (CC_SRKedge *) NULL || + G.head->next->adj == (CC_SRKedge *) NULL) { + fprintf (stderr, "Disconnected graph\n"); + rval = 1; goto CLEANUP; + } + rval = CCcut_mincut_st (sncount, secount, slist, slen, 0, 1, + &val, mytcut, &tcount); + if (rval) { + fprintf (stderr, "CCcut_mincut_st failed\n"); + goto CLEANUP; + } + if (val < minval) { + minval = val; + if (cut) { + CC_IFFREE (*cut, int); + rval = CCcut_SRK_grab_nodes (&G, &E); + if (rval) { + fprintf (stderr, "CCcut_SRK_grab_nodes failed\n"); + goto CLEANUP; + } + CCcut_SRK_expand (&E, tcut, tcount, cut, cutcount); + CCcut_SRK_free_expinfo (&E); + } + } + if (val < cutoff && doit_fn) { + int *fcut = (int *) NULL; + int fcutcount = 0; + + rval = CCcut_SRK_grab_nodes (&G, &E); + if (rval) { + fprintf (stderr, "CCcut_SRK_grab_nodes failed\n"); + goto CLEANUP; + } + CCcut_SRK_expand (&E, tcut, tcount, &fcut, &fcutcount); + CCcut_SRK_free_expinfo (&E); + rval = doit_fn (val, fcutcount, fcut, pass_param); + if (rval) { + fprintf (stderr, "doit_fn failed\n"); + CC_IFFREE (fcut, int); + goto CLEANUP; + } + CC_IFFREE (fcut, int); + } + + if (cut || doit_fn) { + CC_IFFREE (tcut, int); + } + + CCcut_SRK_identify_nodes (&G, G.head, G.head->next); + + squeue = (CC_SRKnode *) NULL; + for (f = G.head->adj; f; f = f->next) { + f->end->qnext = squeue; + squeue = f->end; + } + G.head->qnext = squeue; + squeue = G.head; + + CCcut_SRK_identify_pr_edges (&G, &minval, &i, squeue, + CC_MINCUT_ONE_EPSILON, cb, cut, cutcount); + + /* if (i) { printf ("[%d]", i); fflush (stdout); } */ + + CC_IFFREE (slist, int); + CC_IFFREE (slen, double); + rval = CCcut_SRK_grab_edges (&G, &sncount, &secount, &slist, &slen, + (CC_SRKexpinfo *) NULL); + if (rval) { + fprintf (stderr, "grab edges failed in shrink_ones\n"); + goto CLEANUP; + } + } + + if (cutval) { + *cutval = minval; + } + + if (cut) { + if (*cutcount > ncount/2) { + rval = flip_the_cut (ncount, cut, cutcount); + if (rval) { + fprintf (stderr, "flip_the_cut failed\n"); goto CLEANUP; + } + } + } + +CLEANUP: + + if (rval) { + if (cut) { + CC_IFFREE (*cut, int); + } + } + CC_IFFREE (slist, int); + CC_IFFREE (slen, double); + CC_IFFREE (tcut, int); + CCcut_SRK_free_graph (&G); + CCcut_SRK_free_expinfo (&E); + CC_IFFREE (cb, CC_SRKcallback); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int flip_the_cut (int ncount, int **cut, int *cutcount) +#else +static int flip_the_cut (ncount, cut, cutcount) +int ncount; +int **cut; +int *cutcount; +#endif +{ + int rval = 0; + int i; + char *marks = (char *) NULL; + int *newcut = (int *) NULL; + int newcutcount = 0; + + if (*cutcount == ncount) { + fprintf (stderr, "cut is the entire graph\n"); + rval = 1; goto CLEANUP; + } + + marks = CC_SAFE_MALLOC (ncount, char); + if (!marks) { + fprintf (stderr, "out of memory in flip_the_cut\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + marks[i] = 0; + } + for (i = 0; i < *cutcount; i++) { + marks[(*cut)[i]] = 1; + } + + newcut = CC_SAFE_MALLOC (ncount - *cutcount, int); + if (!newcut) { + fprintf (stderr, "out of memory in flip_the_cut\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + if (!marks[i]) { + newcut[newcutcount++] = i; + } + } + + CC_IFFREE (*cut, int); + *cut = newcut; + *cutcount = newcutcount; + +CLEANUP: + + if (rval) { + CC_IFFREE (newcut, int); + } + CC_IFFREE (marks, char); + + return rval; +} diff --git a/contrib/blossom/concorde97/CUT/segments.c b/contrib/blossom/concorde97/CUT/segments.c new file mode 100644 index 0000000000000000000000000000000000000000..aa76be3fd85c610949c1adc125d24f575cb8f064 --- /dev/null +++ b/contrib/blossom/concorde97/CUT/segments.c @@ -0,0 +1,352 @@ +/***************************************************************************/ +/* */ +/* LINEAR SUBTOUR SEPARATION ROUTINES */ +/* preliminary */ +/* */ +/* TSP CODE */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: July 25, 1995 */ +/* Thanks: Phil Gibbons, for helpful ideas */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCcut_linsub (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, */ +/* int ecount, int *elist, double *x) */ +/* -cuts will return any new cuts found (they will be added to the */ +/* head of the linked list */ +/* -cutcount will return the number of new cuts added */ +/* -ncount is the number of nodes */ +/* -ecount is the number of edges */ +/* -elist contains the LP edges in node node format */ +/* -x is an LP solution */ +/* */ +/* NOTES: */ +/* linsub runs in time O(m log n). */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "cut.h" + +#define NO_PATHS + +typedef struct psh { + int base; + int size; + double *sum; + double *minpre; +} psh; + +#ifdef CC_PROTOTYPE_ANSI + +static void + psh_free (psh *p), + psh_add (psh *p, int i, double v); + +static int + add_the_cut (int (*doit_fn) (double, int, int, void *), + void *pass_param, double val, int a, int b), + psh_init (psh *p, int k), + psh_minloc (psh *p); + +static double + psh_minval (psh *p); + +#else + +static void + psh_free (), + psh_add (); + +static int + add_the_cut (), + psh_init (), + psh_minloc (); + +static double + psh_minval (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_linsub (int ncount, int ecount, int *elist, double *x, double cutoff, + int (*doit_fn) (double, int, int, void *), void *pass_param) +#else +int CCcut_linsub (ncount, ecount, elist, x, cutoff, doit_fn, pass_param) +int ncount, ecount; +int *elist; +double *x; +double cutoff; +int (*doit_fn) (); +void *pass_param; +#endif +{ + int rval = 0; + psh p; + int i, j; + double v; + int count = 0; + int *perm = (int *) NULL; + int *eperm = (int *) NULL; + int *ends = (int *) NULL; + double *xends = (double *) NULL; +#ifdef NO_PATHS + double sum_next; +#endif + printf ("linsub ... "); fflush (stdout); + + if (psh_init (&p, ncount)) { + return -1; + } + + /* arrange elist into the array ends (with xends being the x values */ + /* so that ends[2*i] is less than ends[2*i+1], and ends is sorted in */ + /* increasing order of ends[2*i] */ + + perm = CC_SAFE_MALLOC (ecount, int); + eperm = CC_SAFE_MALLOC (ecount, int); + if (!perm || !eperm) { + fprintf (stderr, "out of memory in linsub\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < ecount; i++) { + eperm[i] = (elist[2*i] < elist[2*i+1] ? elist[2*i] : elist[2*i+1]); + perm[i] = i; + } + CCutil_int_perm_quicksort (perm, eperm, ecount); + + ends = CC_SAFE_MALLOC (2*ecount, int); + xends = CC_SAFE_MALLOC (ecount, double); + if (!ends || !xends) { + fprintf (stderr, "out of memory in linsub\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < ecount; i++) { + j = perm[i]; + if (elist[2*j] < elist[2*j+1]) { + ends[2*i] = elist[2*j]; + ends[2*i+1] = elist[2*j+1]; + } else { + ends[2*i] = elist[2*j+1]; + ends[2*i+1] = elist[2*j]; + } + xends[i] = x[j]; + } + CC_FREE (perm, int); + CC_FREE (eperm, int); + + for (i = ncount - 1, j = ecount - 1; i > 0; i--) { +#ifdef NO_PATHS + sum_next = 0.0; +#endif + while (j >= 0 && ends[2*j] == i) { + psh_add (&p, ends[2*j+1], -xends[j]); +#ifdef NO_PATHS + if (ends[2*j+1] == i+1) { + sum_next += xends[j]; + } +#endif + j--; + } + v = psh_minval (&p); +#ifdef NO_PATHS + if (sum_next < 0.999999) +#endif + if (2.0 + v < cutoff) { + rval = add_the_cut (doit_fn, pass_param, 2.0 + v, i, + psh_minloc (&p)); + if (rval) { + fprintf (stderr, "add_the_cut failed\n"); goto CLEANUP; + } + count++; + } + psh_add (&p, i, 1.0); + } + +CLEANUP: + + printf ("DONE (found %d cuts)\n", count); + fflush (stdout); + + psh_free (&p); + CC_IFFREE (ends, int); + CC_IFFREE (xends, double); + CC_IFFREE (perm, int); + CC_IFFREE (eperm, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_the_cut (int (*doit_fn) (double, int, int, void *), + void *pass_param, double val, int a, int b) +#else +static int add_the_cut (doit_fn, pass_param, val, a, b) +int (*doit_fn) (); +void *pass_param; +double val; +int a, b; +#endif +{ + int rval = 0; + + rval = doit_fn (val, a, b, pass_param); + if (rval) { + fprintf (stderr, "doit_fn failed\n"); goto CLEANUP; + } + +CLEANUP: + + return rval; +} + +/***************************************************************************/ +/* */ +/* PREFIX SUM HEAP ROUTINES */ +/* */ +/* TSP CODE */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: July 25, 1995 */ +/* Thanks: Phil Gibbons, for the algorithm */ +/* */ +/* These routines implement a heap of prefix sums. The routines are */ +/* self-contained, but unlikely to be useful outside of the linear */ +/* subtour separation code. */ +/* */ +/* PREFIX SUM HEAP FUNCTIONS: */ +/* int psh_init (psh *p, int k) */ +/* -p should point to a psh struct. */ +/* -k is the number of elements in the psh. */ +/* -this initializes the value of all k elements to 0.0. */ +/* -return value 0 means success, 1 means failure. */ +/* void psh_free (psh *p) */ +/* -frees the spaces allocated by psh_init. */ +/* void psh_add (psh *p, int i, double v) */ +/* -adds v to the value of element i. */ +/* double psh_minval (psh *p) */ +/* -returns min_j sum_{i=0}^j value[i]. */ +/* int psh_minloc (psh *p) */ +/* -returns the smallest j which achieves psh_minval(p). */ +/* */ +/* NOTES: */ +/* A k-element heap will malloc 32k bytes of memory. If memory is */ +/* tight, using integer values (instead of doubles) brings it down to */ +/* 16k bytes. */ +/* psh_init takes O(k) time. psh_add and psh_minloc take O(log k) */ +/* time. psh_free and psh_minval take O(1) time. */ +/* */ +/* It is likely that using a ternary tree instead of binary would */ +/* improve performance. Also, psh_add could take advantage of knowing */ +/* which child has changed. */ +/* psh_minloc could be changed to return all elements which achieve */ +/* the min, in time O(log k) per element returned. */ +/* */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static int psh_init (psh *p, int k) +#else +static int psh_init (p, k) +psh *p; +int k; +#endif +{ + int i; + int space; + + p->size = k; + p->base = 1; + while (p->base < k) p->base *= 2; + + space = p->base*2; + + p->sum = CC_SAFE_MALLOC (space, double); + if (!p->sum) + return 1; + p->minpre = CC_SAFE_MALLOC (space, double); + if (!p->minpre) { + CC_FREE (p->sum, double); + return 1; + } + for (i=0; i<space; i++) { + p->sum[i] = 0.0; + p->minpre[i] = 0.0; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void psh_free (psh *p) +#else +static void psh_free (p) +psh *p; +#endif +{ + CC_FREE (p->minpre, double); + CC_FREE (p->sum, double); + p->size = 0; + p->base = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void psh_add (psh *p, int i, double v) +#else +static void psh_add (p, i, v) +psh *p; +int i; +double v; +#endif +{ + double *s = p->sum; + double *m = p->minpre; + + i += p->base; + s[i] += v; + m[i] += v; + i /= 2; + while (i >= 1) { + s[i] += v; + if (m[2*i] < s[2*i] + m[2*i+1]) { + m[i] = m[2*i]; + } else { + m[i] = s[2*i] + m[2*i+1]; + } + i /= 2; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int psh_minloc (psh *p) +#else +static int psh_minloc (p) +psh *p; +#endif +{ + int i = 1; + double *m = p->minpre; + + while (i < p->base) { + if (m[i] == m[2*i]) { + i = 2*i; + } else { + i = 2*i+1; + } + } + if (i - p->base < p->size) { + return i - p->base; + } else { + /* we're lost */ + return p->size - 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static double psh_minval (psh *p) +#else +static double psh_minval (p) +psh *p; +#endif +{ + return p->minpre[1]; +} diff --git a/contrib/blossom/concorde97/CUT/shrink.c b/contrib/blossom/concorde97/CUT/shrink.c new file mode 100644 index 0000000000000000000000000000000000000000..dac0eb0b615524398da2ff4bcc181dc1325a03ad --- /dev/null +++ b/contrib/blossom/concorde97/CUT/shrink.c @@ -0,0 +1,1299 @@ +/***************************************************************************/ +/* */ +/* SHRINK ROUTINES */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook (TSP Code) */ +/* Date: July 19, 1996 */ +/* October 21, 1996 (bico) */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void CCcut_SRK_init_graph (CC_SRKgraph *G) */ +/* INITIALIZES the fields of the CC_SRKgraph. */ +/* */ +/* void CCcut_SRK_free_graph (CC_SRKgraph *G) */ +/* FREES the SRKgraph. */ +/* */ +/* int CCcut_SRK_grab_edges (CC_SRKgraph *G, int *oncount, int *oecount, */ +/* int **olist, double **olen, CC_SRKexpinfo *expand) */ +/* int **omembers) */ +/* RETURNS the edges and member lists for the shrunk graph. */ +/* -G is a pointer to a shrunk graph */ +/* -oncount returns the number of nodes in the shrunk graph */ +/* -oecount returns the number of edges in the shrunk graph */ +/* -olist returns the edges in node node format */ +/* -olen returns the edge lengths */ +/* -expand will be filled in with a memindex and members array; */ +/* memindex returns pointers into the members array, the */ +/* members of node i will be stored in from memindex[i] to */ +/* memindex[i+1] - 1, so memindex is ncount + 1 long; members */ +/* returns the nodes lists corresponding to each node in the */ +/* shrunk graph. (expand can be NULL) */ +/* */ +/* int CCcut_SRK_grab_nodes (CC_SRKgraph *G, SRKexpinfo *expand */ +/* RETURNS the member lists for the shrunk graph (see above) */ +/* */ +/* NOTE: Cyles of 1's will be shrunk into single nodes. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "cut.h" + +#define ADD_TO_PR_QUEUE(n) { \ + if (!(n)->onqueue) { \ + (n)->qnext = (CC_SRKnode *) NULL; \ + if (qtail) \ + qtail->qnext = (n); \ + else \ + qhead = (n); \ + qtail = (n); \ + (n)->onqueue = 1; \ + } \ +} + +#undef PR_USE3 /* PR_USE3 and PR_USE4 cannot be defined in current code */ +#undef PR_USE4 +#undef DEBUG_SHRINK +#define CC_SRK_ZERO_EPSILON (1e-10) + +#ifdef CC_PROTOTYPE_ANSI + +static void +#ifdef DEBUG_SHRINK + printgraph (CC_SRKgraph *G), +#endif + count_ones (CC_SRKgraph *G), + merge_adj (CC_SRKgraph *G, CC_SRKnode *n, CC_SRKnode *m); + +static int + test_node (CC_SRKnode *n, double *minval, CC_SRKcallback *cb, int **cut, + int *cutcount), + expand_the_node (CC_SRKnode *n, int *cutcount, int **cut), + expand_and_pass (CC_SRKnode *n, int (*doit_fn) (double, int, int *, + void *), void *pass_param); + +#else + +static void +#ifdef DEBUG_SHRINK + printgraph (), +#endif + count_ones (), + merge_adj (); + +static int + test_node (), + expand_the_node (), + expand_and_pass (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_SRK_subtour_shrink (CC_SRKgraph *G, double *minval, double epsilon, + CC_SRKcallback *cb, int **cut, int *cutcount) +#else +int CCcut_SRK_subtour_shrink (G, minval, epsilon, cb, cut, cutcount) +CC_SRKgraph *G; +double *minval; +double epsilon; +CC_SRKcallback *cb; +int **cut; +int *cutcount; +#endif +{ + int rval = 0; + int k, cnt = 0; + CC_SRKnode *n; + + for (n = G->head; n; n = n->next) { + cnt++; + } + + /* In the tsp, paths of 1's can be shrunk via a call to the function */ + /* CCcut_SRK_identify_paths. */ + + /* Could call a version of CCcut_SRK_identify_ones */ + + printf ("Identify PR edges ....\n"); + fflush (stdout); + rval = CCcut_SRK_identify_pr_edges (G, minval, &k, (CC_SRKnode *) NULL, + epsilon, cb, cut, cutcount); + if (rval) { + fprintf (stderr, "SRK_identify_pr_edges failed\n"); goto CLEANUP; + } + + cnt -= k; + printf ("Graph shrunk to %d nodes\n", cnt); + fflush (stdout); + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void count_ones (CC_SRKgraph *G) +#else +static void count_ones (G) +CC_SRKgraph *G; +#endif +{ + int k; + CC_SRKnode *n; + CC_SRKedge *e; + + for (n = G->head; n; n = n->next) { + for (k = 0, e = n->adj; e; e = e->next) { + if (e->weight == 1.0) + k++; + } + n->onecnt = k; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_identify_paths (CC_SRKgraph *G, int *newcount, int onecnt_okay) +#else +void CCcut_SRK_identify_paths (G, newcount, onecnt_okay) +CC_SRKgraph *G; +int onecnt_okay; +int *newcount; +#endif +{ + CC_SRKnode *n, *m, *last; + CC_SRKedge *e, *f; + int dropcnt = 0; + double dropweight = 0.0; + int k; + + printf ("Identify paths ...\n"); + fflush (stdout); + + if (!onecnt_okay) + count_ones (G); + for (n = G->head; n; n = n->next) { + if (n->onecnt == 1) { + e = n->adj; + while (e->weight != 1.0) + e = e->next; + last = n; + m = e->end; + while (m->onecnt != 1) { + m->parent = n; + m->members = n->members; + n->members = m; + e = m->adj; + while (e->weight != 1.0 || e->end == last) + e = e->next; + last = m; + m = e->end; + } + m->parent = n; + m->members = n->members; + n->members = m; + m->onecnt = 3; + } + } + + for (n = G->head; n->parent != n; n = n->next); + G->head = n; + G->head->prev = (CC_SRKnode *) NULL; + for (n = G->head->next; n; n = n->next) { + if (n->parent != n) { + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + } + } + for (k = 0, n = G->head; n; n = n->next) { + k++; + if (n->members) { + for (e = n->members->adj; e; e = e->next) { + e->other->end = n; + } + for (m = n->members->members; m; m = m->members) { + for (e = m->adj; e; e = e->next) { + if (e->weight == 1.0) { + e->other->end = n; + } else { + /* drop fluff edge */ + dropcnt++; + dropweight += e->weight; + f = e->other; + if (f->prev) { + f->prev->next = f->next; + } else { + e->end->adj = f->next; + } + if (f->next) { + f->next->prev = f->prev; + } + } + } + } + n->weight = n->weight + n->members->weight; + merge_adj (G, n, n->members); + } + } + + if (dropcnt > 0) { + printf ("dropped %d edges of total weight %f\n", dropcnt, dropweight); + fflush (stdout); + } + + *newcount = k; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_SRK_defluff (CC_SRKgraph *G) +#else +int CCcut_SRK_defluff (G) +CC_SRKgraph *G; +#endif +{ + CC_SRKnode *n; + CC_SRKedge *e, *enext; + int k; + int ndel = 0; + double delweight = 0.0; + + for (n = G->head; n; n = n->next) { + for (k = 0, e = n->adj; e; e = e->next) { + if (e->weight >= 1.0 - CC_SRK_ZERO_EPSILON) { + e->weight = 1.0; + k++; + } + } + n->onecnt = k; + } + + for (n = G->head; n; n = n->next) { + for (e = n->adj, n->adj = (CC_SRKedge *) NULL; e; e = enext) { + enext = e->next; + if (e->weight == 1.0 || + (n->onecnt < 2 && e->end->onecnt < 2 + && e->weight > CC_SRK_ZERO_EPSILON)) { + if (n->adj) n->adj->prev = e; + e->next = n->adj; + n->adj = e; + e->prev = (CC_SRKedge *) NULL; + } else { + delweight += e->weight; + ndel++; + } + } + } + + if (ndel & 1) { + fprintf (stderr, "Whoa, deleted %d (odd) endpoints in SRK_defluff\n", + ndel); + return -1; + } + printf ("SRK_defluff deleted %d endpoints (weight %.6f)\n", ndel, + delweight); + fflush (stdout); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_identify_paths_to_edges (CC_SRKgraph *G, int *newcount, + int onecnt_okay) +#else +void CCcut_SRK_identify_paths_to_edges (G, newcount, onecnt_okay) +CC_SRKgraph *G; +int *newcount; +int onecnt_okay; +#endif +{ + CC_SRKnode *n, *p, *m, *last; + CC_SRKedge *e; + int k; + + printf ("Identify paths to edges ...\n"); + fflush (stdout); + + /* NOTE: We should add in code to drop fluff edges */ + + if (!onecnt_okay) + count_ones (G); + for (n = G->head; n; n = n->next) { + if (n->onecnt == 1) { + e = n->adj; + while (e->weight != 1.0) + e = e->next; + m = e->end; + if (m->onecnt != 1) { + e = m->adj; + while (e->weight != 1.0 || e->end == n) + e = e->next; + last = m; + p = e->end; + while (p->onecnt != 1) { + p->parent = m; + p->members = m->members; + m->members = p; + e = p->adj; + while (e->weight != 1.0 || e->end == last) + e = e->next; + last = p; + p = e->end; + } + p->parent = m; + p->members = m->members; + m->members = p; + p->onecnt = 3; + } + } + } + + + for (n = G->head; n->parent != n; n = n->next); + G->head = n; + G->head->prev = (CC_SRKnode *) NULL; + for (n = G->head->next; n; n = n->next) { + if (n->parent != n) { + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + } + } + for (k = 0, n = G->head; n; n = n->next) { + k++; + if (n->members) { + for (m = n->members; m; m = m->members) { + for (e = m->adj; e; e = e->next) + e->other->end = n; + } + merge_adj (G, n, n->members); + } + } + *newcount = k; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_identify_ones (CC_SRKgraph *G, int *count, double epsilon) +#else +void CCcut_SRK_identify_ones (G, count, epsilon) +CC_SRKgraph *G; +int *count; +double epsilon; +#endif +{ + CC_SRKnode *n; + CC_SRKedge *e; + double tol = 1.0 - epsilon; + + printf ("Identify ones ....\n"); + fflush (stdout); + + *count = 0; + + for (n = G->head; n; n = n->next) { + do { + for (e = n->adj; e; e = e->next) { + if (e->weight >= tol) { + CCcut_SRK_identify_nodes (G, n, e->end); + (*count)++; + break; + } + } + } while (e); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_SRK_identify_pr_edges (CC_SRKgraph *G, double *minval, int *count, + CC_SRKnode *qstart, double epsilon, CC_SRKcallback *cb, int **cut, + int *cutcount) +#else +int CCcut_SRK_identify_pr_edges (G, minval, count, qstart, epsilon, cb, cut, + cutcount) +CC_SRKgraph *G; +double *minval; +int *count; +CC_SRKnode *qstart; +double epsilon; +CC_SRKcallback *cb; +int **cut; +int *cutcount; +#endif +{ + int rval = 0; + CC_SRKnode *n; + CC_SRKedge *e, *f, *h; + double tol, tol1, tol2; + CC_SRKnode *qhead, *qtail; + + /* Trivial PR Test: If w(uv) >= c(u)/2, then we can shrink edge uv. */ + + /* First PR Test: If we have a triangle uv, uw, vw with */ + /* w(uv) + w(vw) >= c(v)/2 and w(uw) + w(vw) >= c(w)/2, then we can */ + /* shrink edge vw. */ + + /* Second PR Test: Compute a lower bound on any cut that separates */ + /* the ends of an edge by summing the minimum values of the edges to */ + /* common neighbors of the ends. If the bound is >= "2", then we can */ + /* shrink the edge. */ + + /* Third PR Test: Edge uv with common neighbors xy. If */ + /* w(ux) + w(uy) + w(uv) >= "1" and w(vx) + w(vy) + w(uv) >= "1" and */ + /* at least one of w(uy) + w(uv) and w(vx) + w(uv) is >= "1" and */ + /* at least one of w(ux) + w(uv) and w(vy) + w(uv) is >= "1" then we */ + /* can shrink the edge uv. */ + + *count = 0; + + if (cut && !cutcount) { + fprintf (stderr, "cut defined, but not cutcount\n"); + rval = 1; goto CLEANUP; + } + + if (qstart) { + qhead = qstart; + for (n = qstart; n->next; n = n->next) + n->onqueue = 1; + qtail = n; + qtail->onqueue = 1; + } else { + for (n = G->head; n->next; n = n->next) { + n->qnext = n->next; + n->onqueue = 1; + } + qhead = G->head; + qtail = n; + qtail->onqueue = 1; + qtail->qnext = (CC_SRKnode *) NULL; + } + + while (qhead) { + n = qhead; + qhead = qhead->qnext; + if (!qhead) + qtail = (CC_SRKnode *) NULL; + if (n->parent != n) + continue; + n->onqueue = 0; + tol = n->weight/2.0 - epsilon; + + for (e = n->adj; e && e->weight < tol; e = e->next); + if (e) { + rval = test_node (n, minval, cb, cut, cutcount); + if (rval) { fprintf (stderr, "test_node failed\n"); goto CLEANUP; } + rval = test_node (e->end, minval, cb, cut, cutcount); + if (rval) { fprintf (stderr, "test_node failed\n"); goto CLEANUP; } + CCcut_SRK_identify_nodes (G, n, e->end); + (*count)++; + ADD_TO_PR_QUEUE(n); + for (h = n->adj; h; h = h->next) { + ADD_TO_PR_QUEUE(h->end); + } + } else { + for (e = n->adj; e; e = e->next) + e->end->prweight = e->weight; + for (e = n->adj; e; e = e->next) { + tol1 = (n->weight/2.0) - e->weight - epsilon; + tol2 = (e->end->weight/2.0) - e->weight - epsilon; + for (f = e->end->adj; f; f = f->next) { + if (f->weight >= tol2 && f->end->prweight >= tol1) { + rval = test_node (n, minval, cb, cut, cutcount); + if (rval) { + fprintf (stderr, "test_node failed\n"); + goto CLEANUP; + } + rval = test_node (e->end, minval, cb, cut, cutcount); + if (rval) { + fprintf (stderr, "test_node failed\n"); + goto CLEANUP; + } + CCcut_SRK_identify_nodes (G, n, e->end); + (*count)++; + ADD_TO_PR_QUEUE(n); + for (h = n->adj; h; h = h->next) { + ADD_TO_PR_QUEUE(h->end); + } + goto GET_OUT; + } + } + } + +#ifdef PR_USE3 + -Must modify to use node current min cut value. + for (e = n->adj; e; e = e->next) { + tol = e->weight; + for (f = e->end->adj; f; f = f->next) { + if (f->end->prweight >= f->weight) + tol += f->weight; + else if (f->end->prweight > -2.0) + tol += f->end->prweight; + } + if (tol >= 1.0 + onetol) { + printf ("X"); fflush (stdout); + CCcut_SRK_identify_nodes (G, n, e->end); + (*count)++; + ADD_TO_PR_QUEUE(n); + for (h = n->adj; h; h = h->next) { + ADD_TO_PR_QUEUE(h->end); + } + goto GET_OUT; + } + } +#endif + +#ifdef PR_USE4 + -Must modify to use node weights. + for (e = n->adj; e; e = e->next) { + tol = onetol - e->weight; + for (f = e->end->adj; f; f = f->next) { + if (f->end->prweight > -2.0) { + for (h = f->next; h; h = h->next) { + if (h->end->prweight > -2.0) { + if (f->weight + h->weight >= tol + && f->end->prweight + h->end->prweight >= tol + && (f->weight >= tol || h->end->prweight >= tol) + && (h->weight >= tol || f->end->prweight >= tol)) { + CCcut_SRK_identify_nodes (G, n, e->end); + (*count)++; + ADD_TO_PR_QUEUE(n); + for (h = n->adj; h; h = h->next) { + ADD_TO_PR_QUEUE(h->end); + } + goto GET_OUT; + } + } + } + } + } + } +#endif + +GET_OUT: + for (e = n->adj; e; e = e->next) + e->end->prweight = -2.0; + } + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int test_node (CC_SRKnode *n, double *minval, CC_SRKcallback *cb, + int **cut, int *cutcount) +#else +static int test_node (n, minval, cb, cut, cutcount) +CC_SRKnode *n; +double *minval; +CC_SRKcallback *cb; +int **cut; +int *cutcount; +#endif +{ + int rval = 0; + + if (n->weight < *minval) { + *minval = n->weight; + /* printf ("New minimum: %f\n", *minval); */ + if (cut) { + CC_IFFREE (*cut, int); + rval = expand_the_node (n, cutcount, cut); + if (rval) { + fprintf (stderr, "expand_the_node failed\n"); goto CLEANUP; + } + } + } + if (cb) { + if (n->weight <= cb->cutoff) { + rval = expand_and_pass (n, cb->doit_fn, cb->pass_param); + if (rval) { + fprintf (stderr,"expand_and_pass failed\n"); goto CLEANUP; + } + } + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int expand_and_pass (CC_SRKnode *n, int (*doit_fn) (double, int, int *, + void *), void *pass_param) +#else +static int expand_and_pass (n, doit_fn, pass_param) +CC_SRKnode *n; +int (*doit_fn) (); +void *pass_param; +#endif +{ + int rval = 0; + int cutcount; + int *cut = (int *) NULL; + + if (!doit_fn) goto CLEANUP; + + rval = expand_the_node (n, &cutcount, &cut); + if (rval) { + fprintf (stderr, "expand_the_node failed\n"); fflush (stdout); + } + + rval = doit_fn (n->weight, cutcount, cut, pass_param); + if (rval) { + fprintf (stderr, "doit_fn failed\n"); goto CLEANUP; + } + +CLEANUP: + + CC_IFFREE (cut, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int expand_the_node (CC_SRKnode *n, int *cutcount, int **cut) +#else +static int expand_the_node (n, cutcount, cut) +CC_SRKnode *n; +int *cutcount; +int **cut; +#endif +{ + int rval = 0; + int cnt; + int *tcut = (int *) NULL; + CC_SRKnode *v; + + *cutcount = 0; + *cut = (int *) NULL; + + cnt = 1; + for (v = n->members; v; v = v->members) { + cnt++; + } + tcut = CC_SAFE_MALLOC (cnt, int); + if (!tcut) { + fprintf (stderr, "out of memory in expand_the_node\n"); + rval = 1; goto CLEANUP; + } + + tcut[0] = n->num; + cnt = 1; + for (v = n->members; v; v = v->members) { + tcut[cnt++] = v->num; + } + + *cutcount = cnt; + *cut = tcut; + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_identify_one_triangles (CC_SRKgraph *G, int *count, + CC_SRKnode *qstart, double epsilon) +#else +void CCcut_SRK_identify_one_triangles (G, count, qstart, epsilon) +CC_SRKgraph *G; +int *count; +CC_SRKnode *qstart; +double epsilon; +#endif +{ + CC_SRKnode *n; + CC_SRKedge *e, *f, *h; + CC_SRKnode *qhead, *qtail; + double tol = 1.0 - epsilon; + + printf ("Identify one edges in tight triangles ....\n"); + fflush (stdout); + + /* Identify any edge of weight one that is contained in a triangle of */ + /* weight two. */ + + *count = 0; + if (qstart) { + qhead = qstart; + for (n = qstart; n->next; n = n->next) + n->onqueue = 1; + qtail = n; + qtail->onqueue = 1; + } else { + for (n = G->head; n->next; n = n->next) { + n->qnext = n->next; + n->onqueue = 1; + } + qhead = G->head; + qtail = n; + qtail->onqueue = 1; + qtail->qnext = (CC_SRKnode *) NULL; + } + + while (qhead) { + n = qhead; + qhead = qhead->qnext; + if (!qhead) + qtail = (CC_SRKnode *) NULL; + if (n->parent != n) + continue; + n->onqueue = 0; + + for (e = n->adj; e && e->weight < tol; e = e->next); + if (e) { + for (f = n->adj; f; f = f->next) + f->end->prweight = f->weight; + for (f = e->end->adj; f; f = f->next) { + if (f->weight + f->end->prweight >= tol || + (f->weight >= tol && f->end != n)) { + CCcut_SRK_identify_nodes (G, n, e->end); + (*count)++; + ADD_TO_PR_QUEUE(n); + for (h = n->adj; h; h = h->next) { + ADD_TO_PR_QUEUE(h->end); + } + goto GET_OUT; + } + } +GET_OUT: + for (e = n->adj; e; e = e->next) + e->end->prweight = -2.0; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_identify_nodes (CC_SRKgraph *G, CC_SRKnode *n, CC_SRKnode *m) +#else +void CCcut_SRK_identify_nodes (G, n, m) +CC_SRKgraph *G; +CC_SRKnode *n, *m; +#endif +{ + CC_SRKedge *e; + + m->parent = n; + n->weight += m->weight; + + if (!n->members) { + n->members = m; + } else if (!m->members) { + m->members = n->members; + n->members = m; + } else { + CC_SRKnode *t; + for (t = n->members; t->members; t = t->members); + t->members = m; + } + + for (e = m->adj; e; e = e->next) { + e->other->end = n; + } + + merge_adj (G, n, m); + + if (m->prev) + m->prev->next = m->next; + else + G->head = m->next; + if (m->next) + m->next->prev = m->prev; +} + +#ifdef CC_PROTOTYPE_ANSI +static void merge_adj (CC_SRKgraph *G, CC_SRKnode *n, CC_SRKnode *m) +#else +static void merge_adj (G, n, m) +CC_SRKgraph *G; +CC_SRKnode *n, *m; +#endif +{ + CC_SRKedge *e, *f, *last, *work; + CC_SRKedge **hit = G->hit; + + /* String together the two lists */ + + if (n->adj) { + for (last = n->adj; last->next; last = last->next); + last->next = m->adj; + if (m->adj) + m->adj->prev = last; + work = n->adj; + } else { + work = m->adj; + } + + /* Remove any edges that become loops */ + + while (work && work->end == n) { + n->weight -= work->weight; + work = work->next; + } + + if (work) { + work->prev = (CC_SRKedge *) NULL; + for (e = work->next; e; e = e->next) { + if (e->end == n) { + n->weight -= e->weight; + e->prev->next = e->next; + if (e->next) + e->next->prev = e->prev; + } + } + } else { + n->adj = (CC_SRKedge *) NULL; + return; + } + + /* Remove the duplicate edges in the work list */ + + hit[work->end->num] = work; + for (e = work->next; e; e = e->next) { + if (hit[e->end->num]) { + /* A duplicate edge */ + + hit[e->end->num]->weight += e->weight; + hit[e->end->num]->other->weight = hit[e->end->num]->weight; + e->prev->next = e->next; + if (e->next) + e->next->prev = e->prev; + + /* Fix the adj of the other end of the duplicate */ + + f = e->other; + if (f->prev) { + f->prev->next = f->next; + } else { + e->end->adj = f->next; + } + if (f->next) { + f->next->prev = f->prev; + } + } else { + hit[e->end->num] = e; + } + } + + for (e = work; e; e = e->next) + hit[e->end->num] = (CC_SRKedge *) NULL; + n->adj = work; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_SRK_buildgraph (CC_SRKgraph *G, int ncount, int ecount, int *elist, + double *dlen) +#else +int CCcut_SRK_buildgraph (G, ncount, ecount, elist, dlen) +CC_SRKgraph *G; +int ncount, ecount; +int *elist; +double *dlen; +#endif +{ + int i; + int *degree = (int *) NULL; + int newecount = 0; + CC_SRKnode *nodespace, *n, *n1, *n2; + CC_SRKedge *e, *adj1, *adj2; + CC_SRKedge **hit; + + G->nodespace = CC_SAFE_MALLOC (ncount, CC_SRKnode); + G->hit = CC_SAFE_MALLOC (ncount, CC_SRKedge *); + if (!G->nodespace || !G->hit) { + fprintf (stderr, "out of memory in SRK_buildgraph\n"); + CC_IFFREE (G->nodespace, CC_SRKnode); + CC_IFFREE (G->hit, CC_SRKedge *); + return 1; + } + nodespace = G->nodespace; + hit = G->hit; + G->head = nodespace; + G->original_ncount = ncount; + G->original_ecount = ecount; + + degree = CC_SAFE_MALLOC (ncount, int); + if (!degree) { + fprintf (stderr, "out of memory in SRK_buildgraph\n"); + CC_IFFREE (G->nodespace, CC_SRKnode); + CC_IFFREE (G->hit, CC_SRKedge *); + return 1; + } + + for (i = 0, n = nodespace; i < ncount; i++, n++) { + n->prev = n - 1; + n->next = n + 1; + n->num = i; + n->members = (CC_SRKnode *) NULL; + n->parent = n; + n->prweight = -2.0; + n->weight = 0.0; + hit[i] = (CC_SRKedge *) NULL; + degree[i] = 0; + n->onecnt = 0; + } + nodespace[0].prev = (CC_SRKnode *) NULL; + nodespace[ncount - 1].next = (CC_SRKnode *) NULL; + + for (i = 0; i < ecount; i++) { + if (dlen[i] > CC_SRK_ZERO_EPSILON) { + newecount++; + degree[elist[2*i]]++; + degree[elist[2*i+1]]++; + } + } + G->edgespace = CC_SAFE_MALLOC (2*newecount, CC_SRKedge); + if (!G->edgespace) { + fprintf (stderr, "out of memory in SRK_buildgraph\n"); + CC_IFFREE (G->nodespace, CC_SRKnode); + CC_IFFREE (G->hit, CC_SRKedge *); + return 1; + } + + for (e = G->edgespace, i = 0; i < ncount; i++) { + nodespace[i].adj = e; + e += degree[i]; + } + for (i = 0; i < ecount; i++) { + if (dlen[i] > CC_SRK_ZERO_EPSILON) { + n1 = nodespace + elist[2 * i]; + n2 = nodespace + elist[2 * i + 1]; + adj1 = n1->adj; + adj2 = n2->adj; + adj1->end = n2; + adj1->weight = dlen[i]; + adj1->next = adj1 + 1; + adj1->prev = adj1 - 1; + adj1->other = adj2; + adj2->end = n1; + adj2->weight = dlen[i]; + adj2->next = adj2 + 1; + adj2->prev = adj2 - 1; + adj2->other = adj1; + n1->adj++; + n2->adj++; + if (dlen[i] == 1.0) { + n1->onecnt++; + n2->onecnt++; + } + } + } + for (e = G->edgespace, i = 0; i < ncount; i++) { + if (degree[i]) { + (nodespace[i].adj - 1)->next = (CC_SRKedge *) NULL; + nodespace[i].adj = e; + nodespace[i].adj->prev = (CC_SRKedge *) NULL; + e += degree[i]; + } else { + nodespace[i].adj = (CC_SRKedge *) NULL; + } + } + + for (i = 0, n = nodespace; i < ncount; i++, n++) { + for (e = n->adj; e; e = e->next) { + n->weight += e->weight; + } + } + + CC_IFFREE(degree, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_SRK_grab_edges (CC_SRKgraph *G, int *oncount, int *oecount, + int **olist, double **olen, CC_SRKexpinfo *expand) +#else +int CCcut_SRK_grab_edges (G, oncount, oecount, olist, olen, expand) +CC_SRKgraph *G; +int *oncount, *oecount; +int **olist; +double **olen; +CC_SRKexpinfo *expand; +#endif +{ + int rval = 0; + int k, num; + int ncount = 0, ecount = 0; + CC_SRKnode *n; + CC_SRKedge *e; + + *oncount = 0; + *oecount = 0; + *olist = (int *) NULL; + *olen = (double *) NULL; + if (expand) { + CCcut_SRK_init_expinfo (expand); + } + + for (n = G->head; n; n = n->next) { + n->newnum = ncount; + for (e = n->adj; e; e = e->next) + ecount++; + ncount++; + } + + if (ecount % 2) { + fprintf (stderr, "Error in grab_edges\n"); + rval = 1; goto CLEANUP; + } else { + ecount /= 2; + } + + if (ecount == 0) { + rval = 0; goto CLEANUP; + } + + *olist = CC_SAFE_MALLOC (ecount * 2, int); + *olen = CC_SAFE_MALLOC (ecount, double); + if (!(*olist) || !(*olen)) { + fprintf (stderr, "out of memory in grab_edges\n"); + rval = 1; goto CLEANUP; + } + + k = 0; + for (n = G->head; n; n = n->next) { + num = n->newnum; + for (e = n->adj; e; e = e->next) { + if (num < e->end->newnum) { + (*olist)[2 * k] = num; + (*olist)[2 * k + 1] = e->end->newnum; + (*olen)[k++] = e->weight; + } + } + } + if (k != ecount) { + fprintf (stderr, "Error in grab_edges\n"); + rval = 1; goto CLEANUP; + } + + *oncount = ncount; + *oecount = ecount; + + if (expand) { + rval = CCcut_SRK_grab_nodes (G, expand); + if (rval) { + fprintf (stderr, "SRK_grab_nodes failed\n"); goto CLEANUP; + } + } + +CLEANUP: + + if (rval) { + CC_IFFREE (*olist, int); + CC_IFFREE (*olen, double); + if (expand) { + CCcut_SRK_free_expinfo (expand); + } + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_SRK_grab_nodes (CC_SRKgraph *G, CC_SRKexpinfo *expand) +#else +int CCcut_SRK_grab_nodes (G, expand) +CC_SRKgraph *G; +CC_SRKexpinfo *expand; +#endif +{ + int rval = 0; + int i; + CC_SRKnode *n, *m; + int total = 0; + int ncount = 0; + + if (!expand) { + fprintf (stderr, "SRK_grab_nodes called without an expand struct\n"); + rval = 1; goto CLEANUP; + } + + for (n = G->head; n; n = n->next) { + ncount++; + } + + CCcut_SRK_init_expinfo (expand); + expand->members = CC_SAFE_MALLOC (G->original_ncount, int); + expand->memindex = CC_SAFE_MALLOC (ncount + 1, int); + if (!(expand->members) || !(expand->memindex)) { + fprintf (stderr, "out of memory in grab_nodes\n"); + rval = 1; goto CLEANUP; + } + for (n = G->head, i = 0; n; n = n->next, i++) { + expand->memindex[i] = total; + expand->members[total++] = n->num; + for (m = n->members; m; m = m->members) + expand->members[total++] = m->num; + } + expand->memindex[i] = total; + +CLEANUP: + + if (rval) CCcut_SRK_free_expinfo (expand); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_init_graph (CC_SRKgraph *G) +#else +void CCcut_SRK_init_graph (G) +CC_SRKgraph *G; +#endif +{ + if (G) { + G->nodespace = (CC_SRKnode *) NULL; + G->edgespace = (CC_SRKedge *) NULL; + G->head = (CC_SRKnode *) NULL; + G->hit = (CC_SRKedge **) NULL; + G->original_ncount = 0; + G->original_ecount = 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_free_graph (CC_SRKgraph *G) +#else +void CCcut_SRK_free_graph (G) +CC_SRKgraph *G; +#endif +{ + if (G) { + CC_IFFREE (G->nodespace, CC_SRKnode); + CC_IFFREE (G->edgespace, CC_SRKedge); + CC_IFFREE (G->hit, CC_SRKedge *); + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_init_callback (CC_SRKcallback *cb) +#else +void CCcut_SRK_init_callback (cb) +CC_SRKcallback *cb; +#endif +{ + if (cb) { + cb->cutoff = 0.0; + cb->pass_param = (void *) NULL; +#ifdef CC_PROTOTYPE_ANSI + cb->doit_fn = (int (*) (double, int, int *, void *)) NULL; +#else + cb->doit_fn = (int (*) ()) NULL; +#endif + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_SRK_trivial (int ncount, CC_SRKexpinfo *expand) +#else +int CCcut_SRK_trivial (ncount, expand) +int ncount; +CC_SRKexpinfo *expand; +#endif +{ + int i; + + expand->memindex = CC_SAFE_MALLOC (ncount+1, int); + if (!expand->memindex) { + fprintf (stderr, "Out of memory in SRK_trivial\n"); + return -1; + } + expand->members = CC_SAFE_MALLOC (ncount, int); + if (!expand->members) { + fprintf (stderr, "Out of memory in SRK_trivial\n"); + CC_FREE (expand->memindex, int); + return -1; + } + for (i=0; i<ncount; i++) { + expand->members[i] = i; + expand->memindex[i] = i; + } + expand->memindex[ncount] = ncount; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_init_expinfo (CC_SRKexpinfo *expand) +#else +void CCcut_SRK_init_expinfo (expand) +CC_SRKexpinfo *expand; +#endif +{ + expand->memindex = (int *) NULL; + expand->members = (int *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCcut_SRK_free_expinfo (CC_SRKexpinfo *expand) +#else +void CCcut_SRK_free_expinfo (expand) +CC_SRKexpinfo *expand; +#endif +{ + CC_IFFREE (expand->memindex, int); + CC_IFFREE (expand->members, int); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCcut_SRK_expand (CC_SRKexpinfo *expand, int *arr, int size, int **pnewarr, + int *pnewsize) +#else +int CCcut_SRK_expand (expand, arr, size, pnewarr, pnewsize) +CC_SRKexpinfo *expand; +int *arr; +int size; +int **pnewarr; +int *pnewsize; +#endif +{ + int newsize = 0; + int *newarr = (int *) NULL; + int i, j, jend; + + *pnewsize = 0; + *pnewarr = (int *) NULL; + for (i=0; i<size; i++) { + newsize += expand->memindex[arr[i]+1] - expand->memindex[arr[i]]; + } + newarr = CC_SAFE_MALLOC (newsize, int); + if (!newarr) { + fprintf (stderr, "Out of memory in SRK_expand\n"); + return -1; + } + newsize = 0; + for (i=0; i<size; i++) { + for (j=expand->memindex[arr[i]], jend = expand->memindex[arr[i]+1]; + j < jend; j++) { + newarr[newsize++] = expand->members[j]; + } + } + *pnewarr = newarr; + *pnewsize = newsize; + return 0; +} + +#ifdef DEBUG_SHRINK +#ifdef CC_PROTOTYPE_ANSI +static void printgraph (CC_SRKgraph *G) +#else +static void printgraph (G) +CC_SRKgraph *G; +#endif +{ + CC_SRKnode *n; + CC_SRKedge *e; + + for (n = G->head; n; n = n->next) { + printf ("Node %d: ", n->num); + fflush (stdout); + for (e = n->adj; e; e = e->next) { + printf ("%d [%.2f] ", e->end->num, e->weight); + fflush (stdout); + if (e->other->end != n || e->other->weight != e->weight) { + printf ("(Whoops) "); + fflush (stdout); + } + } + printf ("\n"); + } +} +#endif diff --git a/contrib/blossom/concorde97/EDGEGEN/Makefile b/contrib/blossom/concorde97/EDGEGEN/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5dfbcc5d47608c63ead4d1734c0243e02d9523b6 --- /dev/null +++ b/contrib/blossom/concorde97/EDGEGEN/Makefile @@ -0,0 +1,34 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=edgegen.a +LIBSRCS=edgegen.c xnear.c +ALLSRCS=eg_main.c $(LIBSRCS) + +LIBS=$(ROOT)/KDTREE/kdtree.a $(ROOT)/FMATCH/fmatch.a \ + $(ROOT)/LINKERN/linkern.a $(ROOT)/UTIL/util.a + +all: edgegen $(LIB) + +edgegen: eg_main.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ -lm + +clean: + -rm -f *.$o $(LIB) edgegen + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +edgegen.$o: edgegen.c $(I)/machdefs.h $(I)/util.h $(I)/edgegen.h \ + $(I)/kdtree.h $(I)/linkern.h $(I)/fmatch.h +eg_main.$o: eg_main.c $(I)/machdefs.h $(I)/util.h $(I)/edgegen.h +xnear.$o: xnear.c $(I)/machdefs.h $(I)/util.h $(I)/edgegen.h diff --git a/contrib/blossom/concorde97/EDGEGEN/edgegen.c b/contrib/blossom/concorde97/EDGEGEN/edgegen.c new file mode 100644 index 0000000000000000000000000000000000000000..085789a70bb4b0240dceb46099d1278db14a08eb --- /dev/null +++ b/contrib/blossom/concorde97/EDGEGEN/edgegen.c @@ -0,0 +1,1952 @@ +/***************************************************************************/ +/* */ +/* COMPUTING INITIAL EDGE SETS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 9, 1995 */ +/* Changes: 6.8.1996 (bico) fixed bug in f2match nearest */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCedgegen_read (char *egname, CCedgegengroup *plan) */ +/* READS an edgegen description from file egname. */ +/* -egname the name of a file */ +/* -plan returns the description of the mix of edges (can be used */ +/* in a call to edgegen () to obtain the edgeset. */ +/* */ +/* int CCedgegen_edges (CCedgegengroup *plan, int ncount, */ +/* CCdatagroup *dat, double *wcoord, int *ecount, int **elist) */ +/* RETURNS the set of edges described in plan. */ +/* -plan describes the mix of edges */ +/* -ncount is the number of nodes */ +/* -dat contains the info to generate edge lengths */ +/* -wcoord are nodeweights for Held-Karp style edge lengths, using */ +/* len[i,j] + wcoord[i] + wcoord[j] (wcoord can be NULL) */ +/* -ecount returns the number of edges */ +/* -elist returns the edges in end1 end2 format */ +/* */ +/* void CCedgegen_init_edgegengroup (CCedgegengroup *plan) */ +/* SETS the fields in plan to 0 (since there are so many fields to */ +/* to deal with) */ +/* */ +/* NOTES: */ +/* To use edgegen, look at the defintion of edgegengroup in */ +/* edgegen.h - you should be able to guess what the parmeters mean. */ +/* Note that wcoord is only used by a limited number of the generating */ +/* routines, for example nearest, but not linkern. */ +/* The functions edgegen and edgegen_read will return nonzero values */ +/* if they fail (for example, if they run out of memory. */ +/* The description file passed to edgegen_read should contain a list */ +/* of some of the following commands: */ +/* EDGEGEN NEAREST # */ +/* -find the nearest # edges */ +/* EDGEGEN QUADNEAREST # */ +/* -find the quadrant-nearest # edges */ +/* EDGEGEN FRAC_TWOMATCH_NEAREST # [PRICED] [BASIC] */ +/* -find the nearest # using the reduced costs of a */ +/* fractional 2-matching as the edgelengths. If either */ +/* of the optional arguments PRICED or BASIC is */ +/* specified then the 2-matching used will be either */ +/* priced against the complete edgeset or converted to */ +/* a basic optimal solution (or both). */ +/* EDGEGEN GREEDY_TOUR */ +/* -find a greedy tour */ +/* EDGEGEN NN_TOUR # */ +/* -find # nearest-neighbor tours */ +/* EDGEGEN RANDOM_TOUR # */ +/* -find # random tours */ +/* EDGEGEN TWOOPT_TOUR # */ +/* -find # 2-opt tours */ +/* EDGEGEN TWOPT5_TOUR # */ +/* -find # 2.5-opt tours */ +/* EDGEGEN THREEOPT_TOUR # */ +/* -find # 3-opt tours */ +/* EDGEGEN LINKERN #1 #2 [QUADNEAREST #3] [NEAREST #4] */ +/* [GREEDY_START | NN_START | RANDOM_START] */ +/* -find #1 Iterated Lin-Kernighan tours using #2 kicks.*/ +/* The good edgeset can be specified by the optional */ +/* arguments QUADNEAREST and NEAREST (the two can be */ +/* used together). The initial tours can be specfied */ +/* by using one of GREEDY_START or NN_START or */ +/* RANDOM_START. */ +/* EDGEGEN NN_TWOMATCH # */ +/* -find # nearest-neighbor 2-matchings */ +/* EDGEGEN TREE */ +/* -find a minimum weight spanning tree. */ +/* EDGEGEN FRAC_TWOMATCH [PRICED] [BASIC] */ +/* -find a minmum weight 2-matching (priced against the */ +/* complete edgeset) (that is a basic optimal solution)*/ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "edgegen.h" +#include "kdtree.h" +#include "linkern.h" +#include "fmatch.h" + +#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) + +typedef struct intptr { + int this; + struct intptr *next; +} intptr; + +static intptr **table = (intptr **) NULL; +static int tabletotal = 0; + +#ifdef CC_PROTOTYPE_ANSI + +static int + call_kdtree_build (CCkdtree *kt, int ncount, CCdatagroup *dat, + double *wcoord, int *built_a_tree), + call_nearest (int ncount, CCdatagroup *dat, double *wcoord, int nearnum, + CCkdtree *kt), + work_nearest (CCkdtree *kt, int ncount, int nearnum, CCdatagroup *dat, + double *wcoord, int *ecount, int **elist), + call_quadnearest (int ncount, CCdatagroup *dat, double *wcoord, int nearnum, + CCkdtree *kt), + work_quadnearest (CCkdtree *kt, int ncount, int nearnum, CCdatagroup *dat, + double *wcoord, int *ecount, int **elist), + call_random_tour (int ncount, CCdatagroup *dat, int number), + call_nearest_tour (int ncount, CCdatagroup *dat, int number, CCkdtree *kt), + work_nearest_tour (CCkdtree *kt, int ncount, int start, CCdatagroup *dat, + int *tour, double *val), + call_greedy_tour (int ncount, CCdatagroup *dat, CCkdtree *kt), + call_twoopt_tour (int ncount, CCdatagroup *dat, CCkdtree *kt, int number, + int two_and_a_half, int use_3opt), + call_linkern (int ncount, CCdatagroup *dat, CCkdtree *kt, + CCedgegengroup *plan), + call_nearest_twomatch (int ncount, CCdatagroup *dat, int number, + CCkdtree *kt), + call_f2match (int ncount, CCdatagroup *dat, CCkdtree *kt, int priceit, + int basic), + call_f2match_nearest (int ncount, CCdatagroup *dat, CCkdtree *kt, + int number, int priceit, int basic), + call_spanning_tree (int ncount, CCdatagroup *dat, double *wcoord, + CCkdtree *kt), + f2match_initial_edgeset (int ncount, CCdatagroup *dat, CCkdtree *kt, + int *ecount, int **elist, int **elen), + put_tour_in_table (int ncount, int *tour), + put_in_table (int i, int j), + general_put_in_table (int i, int j, int *added, intptr **tab); + +static void + randcycle (int ncount, int *cyc, CCdatagroup *dat, double *val); + +#else + +static int + call_kdtree_build (), + call_nearest (), + work_nearest (), + call_quadnearest (), + work_quadnearest (), + call_random_tour (), + call_nearest_tour (), + work_nearest_tour (), + call_greedy_tour (), + call_twoopt_tour (), + call_linkern (), + call_nearest_twomatch (), + call_f2match (), + call_f2match_nearest (), + call_spanning_tree (), + f2match_initial_edgeset (), + put_tour_in_table (), + put_in_table (), + general_put_in_table (); + +static void + randcycle (); + +#endif /* CC_PROTOTYPE_ANSI */ + +CC_PTR_ALLOC_ROUTINE (intptr, intptralloc, intptrchunklist, intptrfreelist) +CC_PTR_FREE_ROUTINE (intptr, intptrfree, intptrfreelist) +CC_PTR_FREE_WORLD_ROUTINE (intptr, intptrfree_world, intptrchunklist, + intptrfreelist) +CC_PTR_LEAKS_ROUTINE (intptr, intptr_check_leaks, intptrchunklist, + intptrfreelist, this, int) + + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_edges (CCedgegengroup *plan, int ncount, CCdatagroup *dat, + double *wcoord, int *ecount, int **elist) +#else +int CCedgegen_edges (plan, ncount, dat, wcoord, ecount, elist) +CCedgegengroup *plan; +int ncount; +CCdatagroup *dat; +double *wcoord; +int *ecount; +int **elist; +#endif +{ + int rval = 0; + int i; + int total, onlist; + CCkdtree kt; + int built_a_tree = 0; + double szeit = CCutil_zeit (); + + *ecount = 0; + *elist = (int *) NULL; + + if (ncount < 3) { + fprintf (stderr, "Cannot run edgegen in an %d node graph\n", ncount); + return 1; + } + + table = CC_SAFE_MALLOC (ncount, intptr *); + if (!table) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) + table[i] = (intptr *) NULL; + tabletotal = 0; + + if (plan->nearest) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_nearest (ncount, dat, wcoord, plan->nearest, &kt)) { + fprintf (stderr, "call_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->quadnearest) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_quadnearest (ncount, dat, wcoord, plan->quadnearest, &kt)) { + fprintf (stderr, "call_quadnearest failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->tour.random_count) { + if (call_random_tour (ncount, dat, plan->tour.random_count)) { + fprintf (stderr, "call_random_tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->tour.nearest_count) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_nearest_tour (ncount, dat, plan->tour.nearest_count, &kt)) { + fprintf (stderr, "call_nearest_tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->tour.greedy) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_greedy_tour (ncount, dat, &kt)) { + fprintf (stderr, "call_greedy_tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->tour.twoopt_count) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_twoopt_tour (ncount, dat, &kt, plan->tour.twoopt_count, + 0, 0)) { + fprintf (stderr, "call_twoopt_tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->tour.twoopt5_count) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_twoopt_tour (ncount, dat, &kt, plan->tour.twoopt5_count, + 1, 0)) { + fprintf (stderr, "call_twoopt_tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->tour.threeopt_count) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_twoopt_tour (ncount, dat, &kt, plan->tour.threeopt_count, + 0, 1)) { + fprintf (stderr, "call_threeopt_tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->linkern.count) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_linkern (ncount, dat, &kt, plan)) { + fprintf (stderr, "call_linkern failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->want_tree) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_spanning_tree (ncount, dat, wcoord, &kt)) { + fprintf (stderr, "call_spanning_tree failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->nearest_twomatch_count) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_nearest_twomatch (ncount, dat, plan->nearest_twomatch_count, + &kt)) { + fprintf (stderr, "call_nearest_twomatch failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->f2match.wantit) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_f2match (ncount, dat, &kt, plan->f2match.priced, + plan->f2match.basic)) { + fprintf (stderr, "call_f2match failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (plan->f2match_nearest.number) { + if (!built_a_tree) { + if (call_kdtree_build (&kt, ncount, dat, wcoord, &built_a_tree)) { + fprintf (stderr, "call_kdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (call_f2match_nearest (ncount, dat, &kt, + plan->f2match_nearest.number, plan->f2match_nearest.priced, + plan->f2match_nearest.basic)) { + fprintf (stderr, "call f2match_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + } + + printf ("Edgegen total edges: %d (%.2f seconds)\n", tabletotal, + CCutil_zeit () - szeit); + fflush (stdout); + + if (tabletotal) { + int j = 0; + intptr *ip, *ipnext; + + *elist = CC_SAFE_MALLOC (2 * tabletotal, int); + if (!(*elist)) { + rval = 1; + goto CLEANUP; + } + *ecount = tabletotal; + for (i = 0; i < ncount; i++) { + for (ip = table[i]; ip; ip = ipnext) { + ipnext = ip->next; + (*elist)[j++] = i; + (*elist)[j++] = ip->this; + intptrfree (ip); + } + table[i] = (intptr *) NULL; + } + } + + if (intptr_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding intptrs in kdnear\n", + total - onlist); + } + + +CLEANUP: + + if (built_a_tree) + CCkdtree_free (&kt); + intptrfree_world (); + CC_IFFREE (table, intptr *); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_kdtree_build (CCkdtree *kt, int ncount, CCdatagroup *dat, + double *wcoord, int *built_a_tree) +#else +static int call_kdtree_build (kt, ncount, dat, wcoord, built_a_tree) +CCkdtree *kt; +int ncount; +CCdatagroup *dat; +double *wcoord; +int *built_a_tree; +#endif +{ + double tzeit; + + *built_a_tree = 0; + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + tzeit = CCutil_zeit (); + if (CCkdtree_build (kt, ncount, dat, wcoord)) { + fprintf (stderr, "CCkdtree_build failed\n"); + return 1; + } + printf ("Built CCkdtree: %.2f (seconds)\n", CCutil_zeit () - tzeit); + *built_a_tree = 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCedgegen_init_edgegengroup (CCedgegengroup *plan) +#else +void CCedgegen_init_edgegengroup (plan) +CCedgegengroup *plan; +#endif +{ + plan->linkern.count = 0; + plan->linkern.quadnearest = 0; + plan->linkern.nearest = 0; + plan->linkern.greedy_start = 0; + plan->linkern.random_start = 0; + plan->linkern.nearest_start = 0; + plan->linkern.nkicks = 0; + + plan->tour.twoopt_count = 0; + plan->tour.twoopt5_count = 0; + plan->tour.threeopt_count = 0; + plan->tour.greedy = 0; + plan->tour.nearest_count = 0; + plan->tour.random_count = 0; + + plan->f2match.wantit = 0; + plan->f2match.basic = 0; + plan->f2match.priced = 0; + + plan->f2match_nearest.number = 0; + plan->f2match_nearest.basic = 0; + plan->f2match_nearest.priced = 0; + + plan->nearest = 0; + plan->quadnearest = 0; + plan->want_tree = 0; + plan->nearest_twomatch_count = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_nearest (int ncount, CCdatagroup *dat, double *wcoord, + int nearnum, CCkdtree *kt) +#else +static int call_nearest (ncount, dat, wcoord, nearnum, kt) +int ncount; +CCdatagroup *dat; +double *wcoord; +int nearnum; +CCkdtree *kt; +#endif +{ + double szeit = CCutil_zeit (); + int current = tabletotal; + int tcount = 0; + int *tlist = (int *) NULL; + int i; + + + if (work_nearest (kt, ncount, nearnum, dat, wcoord, &tcount, &tlist)) { + fprintf (stderr, "work_nearest failed\n"); + return 1; + } + for (i = 0; i < tcount; i++) { + if (put_in_table (tlist[2 * i], tlist[(2 * i) + 1])) { + fprintf (stderr, "put_in_table failed\n"); + CC_IFFREE (tlist, int); + return 1; + } + } + + printf ("Nearest added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + + CC_IFFREE (tlist, int); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int work_nearest (CCkdtree *kt, int ncount, int nearnum, + CCdatagroup *dat, double *wcoord, int *ecount, int **elist) +#else +static int work_nearest (kt, ncount, nearnum, dat, wcoord, ecount, elist) +CCkdtree *kt; +int ncount, nearnum; +CCdatagroup *dat; +double *wcoord; +int *ecount, **elist; +#endif +{ + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + if (CCkdtree_k_nearest (kt, ncount, nearnum, dat, wcoord, + 1, ecount, elist)) { + fprintf (stderr, "CCkdtree_k-nearest failed\n"); + return 1; + } + } else if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + if (CCedgegen_x_k_nearest (ncount, nearnum, dat, wcoord, 1, ecount, + elist)) { + fprintf (stderr, "CCedgegen_x_k_nearest failed\n"); + return 1; + } + } else { + if (CCedgegen_junk_k_nearest (ncount, nearnum, dat, wcoord, 1, ecount, + elist)) { + fprintf (stderr, "CCedgegen_junk_k_nearest failed\n"); + return 1; + } + } + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +static int call_quadnearest (int ncount, CCdatagroup *dat, double *wcoord, + int nearnum, CCkdtree *kt) +#else +static int call_quadnearest (ncount, dat, wcoord, nearnum, kt) +int ncount; +CCdatagroup *dat; +double *wcoord; +int nearnum; +CCkdtree *kt; +#endif +{ + double szeit = CCutil_zeit (); + int current = tabletotal; + int tcount = 0; + int *tlist = (int *) NULL; + int i; + + if (work_quadnearest (kt, ncount, nearnum, dat, wcoord, &tcount, &tlist)) { + fprintf (stderr, "work_nearest failed\n"); + return 1; + } + + for (i = 0; i < tcount; i++) { + if (put_in_table (tlist[2 * i], tlist[(2 * i) + 1])) { + fprintf (stderr, "put_in_table failed\n"); + CC_IFFREE (tlist, int); + return 1; + } + } + + printf ("Quad Nearest added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + + CC_IFFREE (tlist, int); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int work_quadnearest (CCkdtree *kt, int ncount, int nearnum, + CCdatagroup *dat, double *wcoord, int *ecount, int **elist) +#else +static int work_quadnearest (kt, ncount, nearnum, dat, wcoord, ecount, elist) +CCkdtree *kt; +int ncount, nearnum; +CCdatagroup *dat; +double *wcoord; +int *ecount, **elist; +#endif +{ + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + if (CCkdtree_quadrant_k_nearest (kt, ncount, nearnum, dat, wcoord, + 1, ecount, elist)) { + fprintf (stderr, "CCkdtree_k-nearest failed\n"); + return 1; + } + } else if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + if (CCedgegen_x_quadrant_k_nearest (ncount, nearnum, dat, wcoord, 1, + ecount, elist)) { + fprintf (stderr, "CCedgegen_x_k_nearest failed\n"); + return 1; + } + } else { + printf ("Cannot run quadrant nearest with JUNK norms\n"); + printf ("Trying %d-nearest instead\n", 2 * nearnum); + fflush (stdout); + if (CCedgegen_junk_k_nearest (ncount, 2 * nearnum, dat, wcoord, 1, + ecount, elist)) { + fprintf (stderr, "CCedgegen_junk_k_nearest failed\n"); + return 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_random_tour (int ncount, CCdatagroup *dat, int number) +#else +static int call_random_tour (ncount, dat, number) +int ncount; +CCdatagroup *dat; +int number; +#endif +{ + double szeit = CCutil_zeit (); + int current = tabletotal; + int round; + int *tour = (int *) NULL; + double tzeit, val; + int k; + + printf ("Generate %d Random Tours\n", number); + fflush (stdout); + + tour = CC_SAFE_MALLOC (ncount, int); + if (!tour) + return 1; + + for (round = 0; round < number; round++) { + k = tabletotal; + tzeit = CCutil_zeit (); + randcycle (ncount, tour, dat, &val); + if (put_tour_in_table (ncount, tour)) { + fprintf (stderr, "put_tour_in_table failed\n"); + CC_FREE (tour, int); + return 1; + } + printf (" Random tour %d: %.0f, added %d edges (%.2f seconds)\n", + round, val, tabletotal - k, CCutil_zeit () - tzeit); + fflush (stdout); + } + + printf (" TOTAL: Random tours added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + + CC_IFFREE (tour, int); + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +static int call_nearest_tour (int ncount, CCdatagroup *dat, int number, + CCkdtree *kt) +#else +static int call_nearest_tour (ncount, dat, number, kt) +int ncount; +CCdatagroup *dat; +int number; +CCkdtree *kt; +#endif +{ + double szeit = CCutil_zeit (); + int current = tabletotal; + int round; + int *tour = (int *) NULL; + double tzeit, val; + int k; + + printf ("Generate %d Nearest Neighbor Tours\n", number); + fflush (stdout); + + tour = CC_SAFE_MALLOC (ncount, int); + if (!tour) + return 1; + + for (round = 0; round < number; round++) { + k = tabletotal; + tzeit = CCutil_zeit (); + if (work_nearest_tour (kt, ncount, CCutil_lprand () % ncount, + dat, tour, &val)) { + fprintf (stderr, "work_nearest_tour failed\n"); + CC_FREE (tour, int); + return 1; + } + if (put_tour_in_table (ncount, tour)) { + fprintf (stderr, "put_tour_in_table failed\n"); + CC_FREE (tour, int); + return 1; + } + printf (" NN tour %d: %.0f, added %d edges (%.2f seconds)\n", + round, val, tabletotal - k, CCutil_zeit () - tzeit); + fflush (stdout); + } + + printf (" TOTAL: Nearest tours added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + + CC_IFFREE (tour, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int work_nearest_tour (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *tour, double *val) +#else +static int work_nearest_tour (kt, ncount, start, dat, tour, val) +CCkdtree *kt; +int ncount, start; +CCdatagroup *dat; +int *tour; +double *val; +#endif +{ + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + if (CCkdtree_nearest_neighbor_tour (kt, ncount, start, dat, tour, val)) { + fprintf (stderr, "CCkdtree_nearest_neighbor_tour failed\n"); + return 1; + } + } else if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + if (CCedgegen_x_nearest_neighbor_tour (ncount, start, dat, tour, val)) { + fprintf (stderr, "CCedgegen_x_nearest_neighbor_tour failed\n"); + return 1; + } + } else { + if (CCedgegen_junk_nearest_neighbor_tour (ncount, start, dat, tour, + val)) { + fprintf (stderr, "CCedgegen_junk_nearest_neighbor_tour failed\n"); + return 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_greedy_tour (int ncount, CCdatagroup *dat, CCkdtree *kt) +#else +static int call_greedy_tour (ncount, dat, kt) +int ncount; +CCdatagroup *dat; +CCkdtree *kt; +#endif +{ + double szeit = CCutil_zeit (); + int current = tabletotal; + int *tour = (int *) NULL; + double val; + + tour = CC_SAFE_MALLOC (ncount, int); + if (!tour) + return 1; + + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + if (CCkdtree_greedy_tour (kt, ncount, dat, tour, &val)) { + fprintf (stderr, "CCkdtree_greedy_tour failed\n"); + CC_FREE (tour, int); + return 1; + } + if (put_tour_in_table (ncount, tour)) { + fprintf (stderr, "put_tour_in_table failed\n"); + CC_FREE (tour, int); + return 1; + } + printf ("Greedy tour: %.0f, added %d edges (%.2f seconds)\n", + val, tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + } else if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + printf ("No X_NORM greedy tours, using nearest neighbor\n"); + CC_FREE (tour, int); + return call_nearest_tour (ncount, dat, 1, kt); + } else { + printf ("No JUNK_NORM greedy tours, using nearest neighbor\n"); + CC_FREE (tour, int); + return call_nearest_tour (ncount, dat, 1, kt); + } + + CC_IFFREE (tour, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_twoopt_tour (int ncount, CCdatagroup *dat, CCkdtree *kt, + int number, int two_and_a_half, int use_3opt) +#else +static int call_twoopt_tour (ncount, dat, kt, number, two_and_a_half, + use_3opt) +int ncount; +CCdatagroup *dat; +CCkdtree *kt; +int number; +int two_and_a_half; +int use_3opt; +#endif +{ + double szeit = CCutil_zeit (); + double ival, val, tzeit; + int k, round, current = tabletotal; + int *tour1 = (int *) NULL, *tour2 = (int *) NULL; + + if (use_3opt) + printf ("Generate %d 3OPT Tours from Nearest Neighbor\n", number); + else if (two_and_a_half) + printf ("Generate %d 2.5OPT Tours from Nearest Neighbor\n", number); + else + printf ("Generate %d 2OPT Tours from Nearest Neighbor\n", number); + fflush (stdout); + + tour1 = CC_SAFE_MALLOC (ncount, int); + if (!tour1) + return 1; + tour2 = CC_SAFE_MALLOC (ncount, int); + if (!tour2) { + CC_FREE (tour1, int); + return 1; + } + + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + for (round = 0; round < number; round++) { + k = tabletotal; + tzeit = CCutil_zeit (); + if (work_nearest_tour (kt, ncount, CCutil_lprand () % ncount, + dat, tour1, &val)) { + fprintf (stderr, "work_nearest_tour failed\n"); + CC_FREE (tour1, int); + CC_FREE (tour2, int); + return 1; + } + ival = val; + if (use_3opt) { + if (CCkdtree_3opt_tour (kt, ncount, dat, tour1, tour2, &val, + 1)) { + fprintf (stderr, "CCkdtree_3opt_tour failed\n"); + CC_FREE (tour1, int); + CC_FREE (tour2, int); + return 1; + } + + } else { + if (CCkdtree_twoopt_tour (kt, ncount, dat, tour1, tour2, &val, + two_and_a_half, 1)) { + fprintf (stderr, "CCkdtree_twoopt_tour failed\n"); + CC_FREE (tour1, int); + CC_FREE (tour2, int); + return 1; + } + } + if (put_tour_in_table (ncount, tour2)) { + fprintf (stderr, "put_tour_in_table failed\n"); + CC_FREE (tour1, int); + CC_FREE (tour2, int); + return 1; + } + if (use_3opt) + printf (" 3OPT tour %d (from %.0f): %.0f, added %d edges (%.2f sec)\n", + round, ival, val, tabletotal - k, CCutil_zeit () - tzeit); + else if (two_and_a_half) + printf (" 2.5OPT tour %d (from %.0f): %.0f, added %d edges (%.2f sec)\n", + round, ival, val, tabletotal - k, CCutil_zeit () - tzeit); + else + printf (" 2OPT tour %d (from %.0f): %.0f, added %d edges (%.2f sec)\n", + round, ival, val, tabletotal - k, CCutil_zeit () - tzeit); + fflush (stdout); + } + } else if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + if (use_3opt) + printf ("No X_NORM three-opt, using nearest neighbor\n"); + else + printf ("No X_NORM two-opt, using nearest neighbor\n"); + fflush (stdout); + CC_FREE (tour1, int); + CC_FREE (tour2, int); + return call_nearest_tour (ncount, dat, number, kt); + } else { + if (use_3opt) + printf ("No JUNK_NORM three-opt, using nearest neighbor\n"); + else + printf ("No JUNK_NORM two-opt, using nearest neighbor\n"); + fflush (stdout); + CC_FREE (tour1, int); + CC_FREE (tour2, int); + return call_nearest_tour (ncount, dat, number, kt); + } + + if (use_3opt) + printf (" TOTAL: 3-opt tours added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + else if (two_and_a_half) + printf (" TOTAL: 2.5-opt tours added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + else + printf (" TOTAL: 2-opt tours added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + + CC_IFFREE (tour1, int); + CC_IFFREE (tour2, int); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_linkern (int ncount, CCdatagroup *dat, CCkdtree *kt, + CCedgegengroup *plan) +#else +static int call_linkern (ncount, dat, kt, plan) +int ncount; +CCdatagroup *dat; +CCkdtree *kt; +CCedgegengroup *plan; +#endif +{ + int *tour = (int *) NULL, *gtour = (int *) NULL, *itour = (int *) NULL; + double val, gval, ival; + double szeit = CCutil_zeit (); + double tzeit; + int i, k, round; + int current = tabletotal; + int ecount = 0, *elist = (int *) NULL; + int rval = 0; + + printf ("Generate %d Linkern Tours (", plan->linkern.count); + if (plan->linkern.greedy_start) + printf ("Greedy, "); + else if (plan->linkern.random_start) + printf ("Random, "); + else + printf ("Nneigh, "); + printf ("%d kicks, ", plan->linkern.nkicks); + if (plan->linkern.nearest == 0) { + printf ("Quad-%d Edgeset)\n", (plan->linkern.quadnearest ? + plan->linkern.quadnearest : 3)); + } else { + if (plan->linkern.quadnearest == 0) { + printf ("Near-%d Edgeset)\n", plan->linkern.nearest); + } else { + printf ("Quad-%d + Near-%d Edgeset)\n", + plan->linkern.quadnearest, plan->linkern.nearest); + } + } + + /* Build an initial edgeset */ + + if (plan->linkern.nearest == 0 && plan->linkern.quadnearest == 0) { + if (work_quadnearest (kt, ncount, 3, dat, (double *) NULL, + &ecount, &elist)) { + fprintf (stderr, "work_quadnearest failed\n"); + return 1; + } + } else { + if (plan->linkern.nearest == 0) { + if (work_quadnearest (kt, ncount, plan->linkern.quadnearest, + dat, (double *) NULL, &ecount, &elist)) { + fprintf (stderr, "work_quadnearest failed\n"); + return 1; + } + } else if (plan->linkern.quadnearest == 0) { + if (work_nearest (kt, ncount, plan->linkern.nearest, + dat, (double *) NULL, &ecount, &elist)) { + fprintf (stderr, "work_nearest failed\n"); + return 1; + } + } else { + intptr **tab = (intptr **) NULL; + int tcount, *tlist = (int *) NULL; + int j, added; + intptr *ip, *ipnext; + + tab = CC_SAFE_MALLOC (ncount, intptr *); + if (!tab) + return 1; + for (i = 0; i < ncount; i++) + tab[i] = (intptr *) NULL; + ecount = 0; + + if (work_quadnearest (kt, ncount, plan->linkern.quadnearest, + dat, (double *) NULL, &tcount, &tlist)) { + fprintf (stderr, "work_quadnearest failed\n"); + return 1; + } + for (i = 0; i < tcount; i++) { + if (general_put_in_table (tlist[2 * i], tlist[(2 * i) + 1], + &added, tab)) { + fprintf (stderr, "general_put_in_table failed\n"); + CC_FREE (tab, intptr *); + return 1; + } + ecount += added; + } + CC_IFFREE (tlist, int); + + if (work_nearest (kt, ncount, plan->linkern.nearest, + dat, (double *) NULL, &tcount, &tlist)) { + fprintf (stderr, "work_quadnearest failed\n"); + return 1; + } + for (i = 0; i < tcount; i++) { + if (general_put_in_table (tlist[2 * i], tlist[(2 * i) + 1], + &added, tab)) { + fprintf (stderr, "general_put_in_table failed\n"); + CC_FREE (tab, intptr *); + return 1; + } + ecount += added; + } + CC_IFFREE (tlist, int); + + elist = CC_SAFE_MALLOC (2 * ecount, int); + if (!elist) { + CC_FREE (tab, intptr *); + return 1; + } + for (j = 0, i = 0; i < ncount; i++) { + for (ip = tab[i]; ip; ip = ipnext) { + ipnext = ip->next; + elist[j++] = i; + elist[j++] = ip->this; + intptrfree (ip); + } + tab[i] = (intptr *) NULL; + } + CC_FREE (tab, intptr *); + } + } + printf ("Initial Edgeset: %d\n", ecount); + fflush (stdout); + + if (plan->linkern.greedy_start && + ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE)) { + gtour = CC_SAFE_MALLOC (ncount, int); + if (!gtour) { + rval = 1; + goto CLEANUP; + } + tzeit = CCutil_zeit (); + if (CCkdtree_greedy_tour (kt, ncount, dat, gtour, &gval)) { + fprintf (stderr, "CCkdtree_greedy_tour failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Greedy tour: %.0f (%.2f seconds)\n", + gval, CCutil_zeit () - tzeit); + fflush (stdout); + } + + tour = CC_SAFE_MALLOC (ncount, int); + if (!tour) { + rval = 1; + goto CLEANUP; + } + itour = CC_SAFE_MALLOC (ncount, int); + if (!itour) { + rval = 1; + goto CLEANUP; + } + + for (round = 0; round < plan->linkern.count; round++) { + tzeit = CCutil_zeit (); + k = tabletotal; + if (gtour != (int *) NULL) { + for (i = 0; i < ncount; i++) + itour[i] = gtour[i]; + val = gval; + ival = gval; + } else if (plan->linkern.random_start) { + randcycle (ncount, itour, dat, &val); + ival = val; + } else { + if (work_nearest_tour (kt, ncount, CCutil_lprand () % ncount, + dat, itour, &val)) { + fprintf (stderr, "work_nearest_tour failed\n"); + rval = 1; + goto CLEANUP; + } + ival = val; + } + + if (CClinkern_tour (ncount, dat, ecount, elist, 100000000, + plan->linkern.nkicks, itour, tour, &val, 1, -1.0, -1.0, + (char *) NULL)) { + fprintf (stderr, "CClinkern_tour failed\n"); + rval = 1; + goto CLEANUP; + } + + if (put_tour_in_table (ncount, tour)) { + fprintf (stderr, "put_tour_in_table failed\n"); + rval = 1; + goto CLEANUP; + } + printf (" LK tour %d (from %.0f): %.0f, added %d edges (%.2f sec)\n", + round, ival, val, tabletotal - k, CCutil_zeit () - tzeit); + fflush (stdout); + } + + printf (" TOTAL: Linkern tours added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (tour, int); + CC_IFFREE (itour, int); + CC_IFFREE (gtour, int); + CC_IFFREE (elist, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_f2match (int ncount, CCdatagroup *dat, CCkdtree *kt, + int priceit, int basic) +#else +static int call_f2match (ncount, dat, kt, priceit, basic) +int ncount; +CCdatagroup *dat; +CCkdtree *kt; +int priceit, basic; +#endif +{ + int *mat = (int *) NULL; + int ecount; + int *elist = (int *) NULL; + int *elen = (int *) NULL; + int i; + double val; + + if (f2match_initial_edgeset (ncount, dat, kt, &ecount, &elist, &elen)) { + fprintf (stderr, "f2match_initial_edgeset failed\n"); + return 1; + } + + mat = CC_SAFE_MALLOC((6 * ncount) + 1, int); + if (!mat) { + CC_FREE (elist, int); + CC_FREE (elen, int); + return 1; + } + + if (priceit) + i = CCfmatch_fractional_2match (ncount, ecount, elist, elen, dat, &val, + mat, (int *) NULL, (int *) NULL, basic); + else + i = CCfmatch_fractional_2match (ncount, ecount, elist, elen, + (CCdatagroup *) NULL, &val, mat, (int *) NULL, + (int *) NULL, basic); + if (i) { + fprintf (stderr, "CCfmatch_fractional_2match failed\n"); + CC_FREE (mat, int); + CC_FREE (elist, int); + CC_FREE (elen, int); + return 1; + } + + i = 0; + while (mat[i] != -1) { + if (put_in_table (mat[i], mat[i + 1])) { + fprintf (stderr, "put_in_table failed\n"); + CC_FREE (mat, int); + CC_FREE (elist, int); + CC_FREE (elen, int); + return 1; + } + i += 3; + } + + CC_IFFREE (mat, int); + CC_IFFREE (elist, int); + CC_IFFREE (elen, int); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_f2match_nearest (int ncount, CCdatagroup *dat, CCkdtree *kt, + int number, int priceit, int basic) +#else +static int call_f2match_nearest (ncount, dat, kt, number, priceit, basic) +int ncount; +CCdatagroup *dat; +CCkdtree *kt; +int number, priceit, basic; +#endif +{ + int ecount; + int *elist = (int *) NULL; + int *elen = (int *) NULL; + int *dual = (int *) NULL; + int dualmax, i; + double *dcoord = (double *) NULL; + double val; + int rval = 0; + int current = tabletotal; + double szeit = CCutil_zeit (); + + if (f2match_initial_edgeset (ncount, dat, kt, &ecount, &elist, &elen)) { + fprintf (stderr, "f2match_initial_edgeset failed\n"); + return 1; + } + + dual = CC_SAFE_MALLOC (ncount, int); + if (!dual) { + rval = 1; + goto CLEANUP; + } + + if (priceit) + i = CCfmatch_fractional_2match (ncount, ecount, elist, elen, dat, &val, + (int *) NULL, dual, (int *) NULL, basic); + else + i = CCfmatch_fractional_2match (ncount, ecount, elist, elen, + (CCdatagroup *) NULL, &val, (int *) NULL, dual, + (int *) NULL, basic); + if (i) { + fprintf (stderr, "CCfmatch_fractional_2match failed\n"); + rval = 1; + goto CLEANUP; + } + CC_FREE (elist, int); + CC_FREE (elen, int); + ecount = 0; + + dualmax = dual[0]; + for (i = 1; i < ncount; i++) { + if (dual[i] > dualmax) + dualmax = dual[i]; + } + + dcoord = CC_SAFE_MALLOC (ncount, double); + if (!dcoord) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) + dcoord[i] = (dualmax - dual[i]) * 0.5; + CC_FREE (dual, int); + + if (work_nearest (kt, ncount, number, dat, dcoord, &ecount, &elist)) { + fprintf (stderr, "work_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ecount; i++) { + if (put_in_table (elist[2 * i], elist[(2 * i) + 1])) { + fprintf (stderr, "put_in_table failed\n"); + rval = 1; + goto CLEANUP; + } + } + printf ("Fractional 2-match Nearest-%d added %d edges (%.2f seconds)\n", + number, tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + + +CLEANUP: + + CC_IFFREE (elist, int); + CC_IFFREE (elen, int); + CC_IFFREE (dual, int); + CC_IFFREE (dcoord, double); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int f2match_initial_edgeset (int ncount, CCdatagroup *dat, CCkdtree *kt, + int *ecount, int **elist, int **elen) +#else +static int f2match_initial_edgeset (ncount, dat, kt, ecount, elist, elen) +int ncount; +CCdatagroup *dat; +CCkdtree *kt; +int *ecount; +int **elist, **elen; +#endif +{ + intptr **tab = (intptr **) NULL; + int tcount, *tlist = (int *) NULL; + int *ttour = (int *) NULL; + int i, j, added; + intptr *ip, *ipnext; + double tval; + int count; + + *ecount = 0; + *elist = (int *) NULL; + *elen = (int *) NULL; + + tab = CC_SAFE_MALLOC (ncount, intptr *); + if (!tab) + return 1; + for (i = 0; i < ncount; i++) + tab[i] = (intptr *) NULL; + count = 0; + + if (work_quadnearest (kt, ncount, 3, dat, (double *) NULL, &tcount, + &tlist)) { + fprintf (stderr, "work_quadnearest failed\n"); + CC_FREE (tab, intptr *); + return 1; + } + for (i = 0; i < tcount; i++) { + if (general_put_in_table (tlist[2 * i], tlist[(2 * i) + 1], + &added, tab)) { + fprintf (stderr, "general_put_in_table failed\n"); + CC_FREE (tab, intptr *); + return 1; + } + count += added; + } + CC_IFFREE (tlist, int); + + ttour = CC_SAFE_MALLOC (ncount, int); + if (!ttour) { + CC_FREE (tab, intptr *); + return 1; + } + if (work_nearest_tour (kt, ncount, CCutil_lprand () % ncount, dat, ttour, + &tval)) { + fprintf (stderr, "work_nearest_tour failed\n"); + CC_FREE (ttour, int); + return 1; + } + for (i = 1; i < ncount; i++) { + if (general_put_in_table (ttour[i-1], ttour[i], &added, tab)) { + fprintf (stderr, "general_put_in_table failed\n"); + CC_FREE (tab, intptr *); + CC_FREE (ttour, int); + return 1; + } + count += added; + } + if (general_put_in_table (ttour[ncount - 1], ttour[0], &added, tab)) { + fprintf (stderr, "general_put_in_table failed\n"); + CC_FREE (tab, intptr *); + CC_FREE (ttour, int); + return 1; + } + count += added; + CC_FREE (ttour, int); + + *elist = CC_SAFE_MALLOC (2 * count, int); + if (!elist) { + CC_FREE (tab, intptr *); + return 1; + } + *elen = CC_SAFE_MALLOC (count, int); + if (!elen) { + CC_FREE (tab, intptr *); + CC_FREE (*elist, int); + } + *ecount = count; + for (j = 0, i = 0; i < ncount; i++) { + for (ip = tab[i]; ip; ip = ipnext) { + ipnext = ip->next; + (*elist)[2 * j] = i; + (*elist)[(2 * j) + 1] = ip->this; + (*elen)[j++] = CCutil_dat_edgelen (i, ip->this, dat); + intptrfree (ip); + } + tab[i] = (intptr *) NULL; + } + CC_FREE (tab, intptr *); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_spanning_tree (int ncount, CCdatagroup *dat, double *wcoord, + CCkdtree *kt) +#else +static int call_spanning_tree (ncount, dat, wcoord, kt) +int ncount; +CCdatagroup *dat; +double *wcoord; +CCkdtree *kt; +#endif +{ + double szeit = CCutil_zeit (); + int current = tabletotal; + int *tree = (int *) NULL; + int i; + double val; + + tree = CC_SAFE_MALLOC ((2 * ncount) - 2, int); + if (!tree) + return 1; + + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + if (CCkdtree_prim_spanningtree (kt, ncount, dat, wcoord, tree, &val)) { + fprintf (stderr, "CCkdtree_prim_spanningtree failed\n"); + CC_FREE (tree, int); + return 1; + } + } else if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + printf ("No X_NORM spanning tree\n"); + CC_FREE (tree, int); + return 0; + } else { + printf ("No JUNK_NORM spanning tree\n"); + CC_FREE (tree, int); + return 0; + } + + for (i = 0; i < (ncount - 1); i++) { + if (put_in_table (tree[2 * i], tree[(2 * i) + 1])) { + fprintf (stderr, "put_in_table failed\n"); + CC_FREE (tree, int); + return 0; + } + } + printf ("Spanning tree: %.0f, added %d edges (%.2f seconds)\n", + val, tabletotal - current, CCutil_zeit () - szeit); + + CC_IFFREE (tree, int); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_nearest_twomatch (int ncount, CCdatagroup *dat, int number, + CCkdtree *kt) +#else +static int call_nearest_twomatch (ncount, dat, number, kt) +int ncount; +CCdatagroup *dat; +int number; +CCkdtree *kt; +#endif +{ + double szeit = CCutil_zeit (); + int current = tabletotal; + int round; + int *mat = (int *) NULL; + double tzeit, val; + int i, k; + + printf ("Generate %d Nearest Neighbor 2-matchings\n", number); + fflush (stdout); + + mat = CC_SAFE_MALLOC (2 * ncount, int); + if (!mat) + return 1; + + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + for (round = 0; round < number; round++) { + k = tabletotal; + tzeit = CCutil_zeit (); + if (CCkdtree_nearest_neighbor_2match (kt, ncount, + CCutil_lprand () % ncount, dat, mat, &val)) { + fprintf (stderr, "CCkdtree_nearest_neighbor_2match failed\n"); + CC_FREE (mat, int); + return 1; + } + for (i = 0; i < ncount; i++) { + if (put_in_table (mat[2 * i], mat[(2 * i) + 1])) { + fprintf (stderr, "put_in_table failed\n"); + CC_FREE (mat, int); + return 1; + } + } + printf (" NN 2-mat %d: %.0f, added %d edges (%.2f seconds)\n", + round, val, tabletotal - k, CCutil_zeit () - tzeit); + fflush (stdout); + } + } else if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + printf ("No X_NORM NN-2match, using NN-tour instead\n"); + fflush (stdout); + CC_FREE (mat, int); + return call_nearest_tour (ncount, dat, number, kt); + } else { + printf ("No JUNK_NORM NN-2match, using NN-tour instead\n"); + fflush (stdout); + CC_FREE (mat, int); + return call_nearest_tour (ncount, dat, number, kt); + } + + printf (" TOTAL: Nearest 2-matchings added %d edges (%.2f seconds)\n", + tabletotal - current, CCutil_zeit () - szeit); + fflush (stdout); + + CC_IFFREE (mat, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int put_tour_in_table (int ncount, int *tour) +#else +static int put_tour_in_table (ncount, tour) +int ncount; +int *tour; +#endif +{ + int i; + + for (i = 1; i < ncount; i++) { + if (put_in_table (tour[i-1], tour[i])) { + fprintf (stderr, "put_in_table failed\n"); + return 1; + } + } + if (put_in_table (tour[ncount - 1], tour[0])) { + fprintf (stderr, "put_in_table failed\n"); + return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int put_in_table (int i, int j) +#else +static int put_in_table (i, j) +int i, j; +#endif +{ + intptr *ip; + + if (j < i) { + int temp; + SWAP(i, j, temp); + } + + for (ip = table[i]; ip; ip = ip->next) { + if (ip->this == j) { + return 0; + } + } + ip = intptralloc (); + if (!ip) { + return 1; + } + ip->this = j; + ip->next = table[i]; + table[i] = ip; + tabletotal++; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int general_put_in_table (int i, int j, int *added, intptr **tab) +#else +static int general_put_in_table (i, j, added, tab) +int i, j; +int *added; +intptr **tab; +#endif +{ + intptr *ip; + + if (j < i) { + int temp; + SWAP(i, j, temp); + } + + for (ip = tab[i]; ip; ip = ip->next) { + if (ip->this == j) { + *added = 0; + return 0; + } + } + ip = intptralloc (); + if (!ip) { + *added = 0; + return 1; + } + ip->this = j; + ip->next = tab[i]; + tab[i] = ip; + *added = 1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void randcycle (int ncount, int *cyc, CCdatagroup *dat, double *val) +#else +static void randcycle (ncount, cyc, dat, val) +int ncount; +int *cyc; +CCdatagroup *dat; +double *val; +#endif +{ + int i, k, temp; + + for (i = 0; i < ncount; i++) + cyc[i] = i; + + for (i = ncount; i > 1; i--) { + k = CCutil_lprand () % i; + SWAP (cyc[i - 1], cyc[k], temp); + } + + *val = CCutil_dat_edgelen (cyc[ncount - 1], cyc[0], dat); + for (i = 1; i < ncount; i++) + (*val) += CCutil_dat_edgelen (cyc[i - 1], cyc[i], dat); +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_read (char *egname, CCedgegengroup *plan) +#else +int CCedgegen_read (egname, plan) +char *egname; +CCedgegengroup *plan; +#endif +{ + char buf[256]; + char area[256]; + char key[256]; + char field[256]; + char *p; + FILE *in; + + CCedgegen_init_edgegengroup (plan); + + in = fopen (egname, "r"); + if (!in) { + perror (egname); + fprintf (stderr, "can't open %s for input\n", egname); + return 1; + } + + while (fgets (buf, 254, in) != (char *) NULL) { + p = buf; + while (*p != '\0') { + if (*p == ':') + *p = ' '; + p++; + } + p = buf; + if (sscanf (p, "%s", area) != EOF) { + p += strlen (area); + while (*p == ' ') + p++; + if (!strcmp (area, "EDGEGEN")) { + if (sscanf (p, "%s", key) == EOF) { + fprintf (stderr, "ERROR in EDGEGEN LINE - no keyword\n"); + return 1; + } + if (!strcmp (key, "NEAREST")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->nearest = atoi (field); + } else { + printf ("NEAREST count not given, using 1\n"); + plan->nearest = 1; + } + } else if (!strcmp (key, "QUADNEAREST")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->quadnearest = atoi (field); + } else { + printf ("QUADNEAREST count not given, using 1\n"); + plan->quadnearest = 1; + } + } else if (!strcmp (key, "TREE")) { + plan->want_tree = 1; + } else if (!strcmp (key, "NN_TWOMATCH")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->nearest_twomatch_count = atoi (field); + } else { + printf ("NN_TWOMATCH count not given, using 1\n"); + plan->nearest_twomatch_count = 1; + } + } else if (!strcmp (key, "GREEDY_TOUR")) { + plan->tour.greedy = 1; + } else if (!strcmp (key, "NN_TOUR")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->tour.nearest_count = atoi (field); + } else { + printf ("NN_TOUR count not given, using 1\n"); + plan->tour.nearest_count = 1; + } + } else if (!strcmp (key, "RANDOM_TOUR")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->tour.random_count = atoi (field); + } else { + printf ("RANDOM_TOUR count not given, using 1\n"); + plan->tour.random_count = 1; + } + } else if (!strcmp (key, "TWOOPT_TOUR")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->tour.twoopt_count = atoi (field); + } else { + printf ("TWOOPT_TOUR count not given, using 1\n"); + plan->tour.twoopt_count = 1; + } + } else if (!strcmp (key, "TWOOPT5_TOUR")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->tour.twoopt5_count = atoi (field); + } else { + printf ("TWOOPT5_TOUR count not given, using 1\n"); + plan->tour.twoopt5_count = 1; + } + } else if (!strcmp (key, "THREEOPT_TOUR")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->tour.threeopt_count = atoi (field); + } else { + printf ("THREEOPT_TOUR count not given, using 1\n"); + plan->tour.threeopt_count = 1; + } + } else if (!strcmp (key, "FRAC_TWOMATCH")) { + plan->f2match.wantit = 1; + p += strlen (key); + while (*p == ' ') + p++; + while (sscanf (p, "%s", field) != EOF) { + if (!strcmp (field, "BASIC")) + plan->f2match.basic = 1; + else if (!strcmp (field, "PRICED")) + plan->f2match.priced = 1; + else + printf ("Unknown option in FRAC_TWOMATCH\n"); + p += strlen (field); + while (*p == ' ') + p++; + } + } else if (!strcmp (key, "FRAC_TWOMATCH_NEAREST")) { + p += strlen (key); + while (*p == ' ') + p++; + while (sscanf (p, "%s", field) != EOF) { + if (!strcmp (field, "BASIC")) + plan->f2match_nearest.basic = 1; + else if (!strcmp (field, "PRICED")) + plan->f2match_nearest.priced = 1; + else + plan->f2match_nearest.number = atoi (field); + p += strlen (field); + while (*p == ' ') + p++; + } + if (plan->f2match_nearest.number == 0) { + printf ("FRAC_TWOMATCH_NEAREST count not given, using 1\n"); + plan->f2match_nearest.number = 1; + } + } else if (!strcmp (key, "LINKERN")) { + p += strlen (key); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->linkern.count = atoi (field); + p += strlen (field); + while (*p == ' ') + p++; + } else { + printf ("LINKERN count not given, using 1\n"); + plan->linkern.count = 1; + } + if (sscanf (p, "%s", field) != EOF) { + plan->linkern.nkicks = atoi (field); + p += strlen (field); + while (*p == ' ') + p++; + } else { + printf ("LINKERN nkicks not given, using 10\n"); + plan->linkern.nkicks = 10; + } + while (sscanf (p, "%s", field) != EOF) { + if (!strcmp (field, "GREEDY_START")) + plan->linkern.greedy_start = 1; + else if (!strcmp (field, "RANDOM_START")) + plan->linkern.random_start = 1; + else if (!strcmp (field, "NN_START")) + plan->linkern.nearest_start = 1; + else if (!strcmp (field, "NEAREST")) { + p += strlen (field); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->linkern.nearest = atoi (field); + } else { + printf ("LINKERN NEAREST COUNT not given, using 5\n"); + plan->linkern.nearest = 5; + break; + } + } else if (!strcmp (field, "QUADNEAREST")) { + p += strlen (field); + while (*p == ' ') + p++; + if (sscanf (p, "%s", field) != EOF) { + plan->linkern.quadnearest = atoi (field); + } else { + printf ("LINKERN QUADNEAREST COUNT not given, using 3\n"); + plan->linkern.quadnearest = 3; + break; + } + } else { + printf ("Unknown EDGEGEN LINKERN command %s\n", + field); + fflush (stdout); + } + p += strlen (field); + while (*p == ' ') + p++; + } + } else { + printf ("Unknown EDGEGEN command: %s\n", key); + fflush (stdout); + } + } else { + printf ("Cannot parse command line: %s\n", area); + fflush (stdout); + } + } + } + fclose (in); + printf ("\n"); + + if (plan->linkern.count) { + if (!plan->linkern.quadnearest && !plan->linkern.nearest) + plan->linkern.quadnearest = 3; + if (!plan->linkern.greedy_start && !plan->linkern.random_start) + plan->linkern.nearest_start = 1; + if (!plan->linkern.nkicks) + plan->linkern.nkicks = 10; + } + + printf ("Edgegen Request:\n"); + if (plan->nearest) + printf (" Nearest %d\n", plan->nearest); + if (plan->quadnearest) + printf (" Quad-Nearest %d\n", plan->quadnearest); + if (plan->f2match_nearest.number) { + printf (" Frac 2-match Nearest %d (", plan->f2match_nearest.number); + if (plan->f2match_nearest.basic) + printf ("Basic "); + if (plan->f2match_nearest.priced) + printf ("Priced)\n"); + else + printf ("Not Priced)\n"); + } + if (plan->want_tree) + printf (" Minimum Spanning Tree\n"); + if (plan->nearest_twomatch_count) + printf (" NN 2-matchings: %d\n", plan->nearest_twomatch_count); + if (plan->tour.random_count) + printf (" Random Tours: %d\n", plan->tour.random_count); + if (plan->tour.nearest_count) + printf (" NN Tours: %d\n", plan->tour.nearest_count); + if (plan->tour.greedy) + printf (" Greedy Tour\n"); + if (plan->tour.twoopt_count) + printf (" 2OPT Tours: %d\n", plan->tour.twoopt_count); + if (plan->tour.twoopt5_count) + printf (" 2.5OPT Tours: %d\n", plan->tour.twoopt5_count); + if (plan->tour.threeopt_count) + printf (" 3OPT Tours: %d\n", plan->tour.threeopt_count); + if (plan->linkern.count) { + printf (" LK Tours: %d (", plan->linkern.count); + if (plan->linkern.greedy_start) + printf ("Greedy, "); + else if (plan->linkern.random_start) + printf ("Random, "); + else + printf ("NN, "); + if (!plan->linkern.nearest) { + printf ("Quad-%d, ", plan->linkern.quadnearest); + } else { + if (!plan->linkern.quadnearest) { + printf ("Near-%d, ", plan->linkern.nearest); + } else { + printf ("Quad-%d + Near-%d, ", plan->linkern.quadnearest, + plan->linkern.nearest); + } + } + printf ("%d Kicks)\n", plan->linkern.nkicks); + } + if (plan->f2match.wantit) { + printf (" Frac 2-matching ("); + if (plan->f2match.basic) + printf ("Basic "); + if (plan->f2match.priced) + printf ("Priced)\n"); + else + printf ("Not Priced)\n"); + } + printf ("\n"); + fflush (stdout); + + return 0; +} diff --git a/contrib/blossom/concorde97/EDGEGEN/eg_main.c b/contrib/blossom/concorde97/EDGEGEN/eg_main.c new file mode 100644 index 0000000000000000000000000000000000000000..b619011cdf5dcf415b1962212c808b0df524d496 --- /dev/null +++ b/contrib/blossom/concorde97/EDGEGEN/eg_main.c @@ -0,0 +1,405 @@ +/***************************************************************************/ +/* */ +/* CODE FOR TESTING EDGE GENERATION ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 25, 1995 */ +/* */ +/* For a short describtion see usage () */ +/* */ +/* Link with: */ +/* edg_main.o xnear.o */ +/* edgelen.o allocrus.o urandom.o safe_io.o zeit.o bgetopt.o */ +/* edg2cyc.o fastread.o getdata.o */ +/* */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "edgegen.h" + +static int norm = CC_EUCLIDEAN; +static int seed = 0; +static int nnodes_want = 0; +static int nearnum = 0; +static int quadnearnum = 0; +static int f2match_nearnum = 0; +static int usenodeweights = 0; +static int random_weight_limit = 0; +static int random_tour_count = 0; +static int nearest_tour_count = 0; +static int linkern_tour_count = 0; +static int linkern_kicks = 100; +static int use_greedy_in_linkern = 0; +static int use_random_in_linkern = 0; +static int linkern_nearnum = 0; +static int linkern_quadnum = 0; +static int twoopt_tour_count = 0; +static int twoopt5_tour_count = 0; +static int threeopt_tour_count = 0; +static int nearest_twomatch_count = 0; +static int find_greedy_tour = 0; +static int find_fractional_2match = 0; +static int find_spanning_tree = 0; +static int find_delaunay_edges = 0; +static int find_mlinkern_edges = 0; +static int binary_in = 0; +static int tsplib_in = 0; + +static char *nodefile = (char *) NULL; +static char *weightfile = (char *) NULL; +static char *outfile = (char *) NULL; +static char *describefile = (char *) NULL; + + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int ac, char **av); +static void + usage (char *f); +static int + parseargs (int ac, char **av); + +#else + +int + main (); +static void + usage (); +static int + parseargs (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + double szeit; + double *wcoord = (double *) NULL; + int ncount; + int rval = 0; + int ecount = 0; + int *elist = (int *) NULL; + CCdatagroup dat; + CCedgegengroup plan; + + + dat.x = (double *) NULL; + dat.y = (double *) NULL; + dat.z = (double *) NULL; + dat.adj = (int **) NULL; + + seed = (int) CCutil_real_zeit(); + if (parseargs (ac, av)) + return 1; + CCutil_sprand (seed); + + if ((!nnodes_want && !nodefile) || (tsplib_in && !nodefile)) { + usage (av[0]); + return 1; + } + + if (tsplib_in) { + if (CCutil_gettsplib (nodefile, &ncount, &dat)) { + fprintf (stderr, "could not read the TSPLIB file\n"); + rval = 1; + goto CLEANUP; + } + norm = dat.norm; + } else { + ncount = nnodes_want; + if (CCutil_getdata (nodefile, binary_in, norm, &ncount, &dat)) { + rval = 1; + goto CLEANUP; + } + } + + if (CCutil_init_dat_edgelen (&dat)) { + fprintf (stderr, "CCutil_init_dat_edgelen failed\n"); + rval = 1; + goto CLEANUP; + } + + if (usenodeweights) { + if (CCutil_getnodeweights (weightfile, ncount, random_weight_limit, &wcoord)) { + fprintf (stderr, "could not read the nodeweight file\n"); + rval = 1; + goto CLEANUP; + } + } + + if (describefile) { + if (CCedgegen_read (describefile, &plan)) { + fprintf (stderr, "CCedgegen_read failed\n"); + rval = 1; + goto CLEANUP; + } + } else { + CCedgegen_init_edgegengroup (&plan); + + plan.nearest = nearnum; + plan.quadnearest = quadnearnum; + plan.delaunay = find_delaunay_edges; + plan.mlinkern = find_mlinkern_edges; + plan.tour.random_count = random_tour_count; + plan.tour.nearest_count = nearest_tour_count; + plan.tour.greedy = find_greedy_tour; + plan.want_tree = find_spanning_tree; + plan.tour.twoopt_count = twoopt_tour_count; + plan.tour.twoopt5_count = twoopt5_tour_count; + plan.tour.threeopt_count = threeopt_tour_count; + if (linkern_tour_count) { + plan.linkern.count = linkern_tour_count; + if (!linkern_quadnum && !linkern_nearnum) { + linkern_quadnum = 3; + } else { + plan.linkern.quadnearest = linkern_quadnum; + plan.linkern.nearest = linkern_nearnum; + } + if (!use_greedy_in_linkern && !use_random_in_linkern) { + plan.linkern.nearest_start = 1; + } else { + plan.linkern.greedy_start = use_greedy_in_linkern; + plan.linkern.random_start = use_random_in_linkern; + } + plan.linkern.nkicks = linkern_kicks; + } + plan.nearest_twomatch_count = nearest_twomatch_count; + plan.f2match.wantit = find_fractional_2match; + if (f2match_nearnum) { + plan.f2match_nearest.number = f2match_nearnum; + plan.f2match_nearest.basic = 0; + plan.f2match_nearest.priced = 1; + } + } + + szeit = CCutil_zeit (); + + if (CCedgegen_edges (&plan, ncount, &dat, wcoord, &ecount, &elist)) { + fprintf (stderr, "CCedgegen_edges failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Edgegen running time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + + if (outfile && ecount) { + if (CCutil_writeedges (ncount, outfile, ecount, elist, &dat)) { + fprintf (stderr, "Could not write the edge set\n"); + rval = 1; + goto CLEANUP; + } + } + + +CLEANUP: + + CCutil_freedatagroup (ncount, &dat); + CC_IFFREE (wcoord, double); + CC_IFFREE (elist, int); + + if (CCutil_bigchunk_free_world ()) { + fprintf (stderr, "ERROR: CCutil_bigcunk free world failed\n"); + return 1; + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "A:bB:C:dD:f:FGk:L:s:m:M:n:N:o:q:R:STuU:vw:W:x:y:0123456789?")) + != EOF) + switch (c) { + case 'A': + twoopt_tour_count = atoi (CCutil_bix_optarg); + break; + case 'b': + binary_in = 1; + break; + case 'B': + twoopt5_tour_count = atoi (CCutil_bix_optarg); + break; + case 'C': + threeopt_tour_count = atoi (CCutil_bix_optarg); + break; + case 'd': + find_delaunay_edges = 1; + break; + case 'D': + describefile = CCutil_bix_optarg; + break; + case 'f': + f2match_nearnum = atoi (CCutil_bix_optarg); + break; + case 'F': + find_fractional_2match = 1; + break; + case 'G': + find_greedy_tour = 1; + break; + case 'k': + nnodes_want = atoi (CCutil_bix_optarg); + break; + case 'L': + linkern_tour_count = atoi (CCutil_bix_optarg); + break; + case 'm': + find_mlinkern_edges = atoi (CCutil_bix_optarg); + break; + case 'M': + nearest_twomatch_count = atoi (CCutil_bix_optarg); + break; + case 'n': + nearnum = atoi (CCutil_bix_optarg); + break; + case 'N': + nearest_tour_count = atoi (CCutil_bix_optarg); + break; + case 'o': + outfile = CCutil_bix_optarg; + break; + case 'q': + quadnearnum = atoi (CCutil_bix_optarg); + break; + case 'R': + linkern_kicks = atoi (CCutil_bix_optarg); + break; + case 's': + seed = atoi (CCutil_bix_optarg); + break; + case 'S': + find_spanning_tree = 1; + break; + case 'T': + tsplib_in = 1; + break; + case 'u': + use_greedy_in_linkern = 1; + use_random_in_linkern = 0; + break; + case 'U': + random_tour_count = atoi (CCutil_bix_optarg); + break; + case 'v': + use_random_in_linkern = 1; + use_greedy_in_linkern = 0; + break; + case 'w': + usenodeweights = 1; + weightfile = CCutil_bix_optarg; + break; + case 'W': + usenodeweights = 1; + random_weight_limit = atoi (CCutil_bix_optarg); + break; + case 'x': + linkern_quadnum = atoi (CCutil_bix_optarg); + break; + case 'y': + linkern_nearnum = atoi (CCutil_bix_optarg); + break; + case '0': + norm = CC_MAXNORM; + break; + case '1': + norm = CC_EUCLIDEAN_CEIL; + break; + case '2': + norm = CC_EUCLIDEAN; + break; + case '3': + norm = CC_EUCLIDEAN_3D; + break; + case '4': + norm = CC_IBM; + break; + case '5': + norm = CC_ATT; + break; + case '6': + norm = CC_GEOGRAPHIC; + break; + case '7': + norm = CC_MATRIXNORM; + break; + case '8': + norm = CC_DSJRANDNORM; + break; + case '9': + norm = CC_CRYSTAL; + break; + case CC_BIX_GETOPT_UNKNOWN: + case '?': + default: + usage (av[0]); + return 1; + } + if (CCutil_bix_optind < ac) + nodefile = av[CCutil_bix_optind++]; + + if (CCutil_bix_optind > ac) { + usage (av[0]); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "Usage: %s [- see below -] [dat file]\n", f); + fprintf (stderr, " -b dat file in binary-ints\n"); + fprintf (stderr, " -w f node weight file\n"); + fprintf (stderr, " -W # use random node weights, from 0 to # - 1\n"); + fprintf (stderr, " -k # number of nodes for random problem\n"); + fprintf (stderr, " -s # random seed\n"); + fprintf (stderr, " -D f description file\n"); + fprintf (stderr, " -n # find # nearest graph\n"); + fprintf (stderr, " -q # find quadrant # nearest graph\n"); + fprintf (stderr, " -d find Delaunay triangulation\n"); + fprintf (stderr, " -f # find # nearest using f2match reduced costs\n"); + fprintf (stderr, " -U # find # random tours\n"); + fprintf (stderr, " -N # find # nearest neighbor tours\n"); + fprintf (stderr, " -G find greedy tour\n"); + fprintf (stderr, " -(A B C) # find # (2opt, 2.5opt, 3opt) tours\n"); + fprintf (stderr, " -L # find # linkern tours\n"); + fprintf (stderr, " -m # find # linkern matchings\n"); + fprintf (stderr, " -R # use # kicks in linkern (default: 100)\n"); + fprintf (stderr, " -u use greedy starting tour for linkern\n"); + fprintf (stderr, " -v use random starting tours for linkern\n"); + fprintf (stderr, " -x # use # quadnearest in linkern\n"); + fprintf (stderr, " -y # use # nearest in linkern (can use x & y)\n"); + fprintf (stderr, " -M # find # nearest neighbor 2-matchings\n"); + fprintf (stderr, " -S find min spanning tree\n"); + fprintf (stderr, " -F find fractional twomatch (not priced)\n"); + fprintf (stderr, " -o f write the cycle or edge set to f\n"); + fprintf (stderr, " -T the dat file is a TSPLIB file\n"); + fprintf (stderr, " -0 Max norm for edge lengths\n"); + fprintf (stderr, " -1 Ceiling Euclidean norm - from DSJ\n"); + fprintf (stderr, " -2 Rounded Euclidean norm (default)\n"); + fprintf (stderr, " -3 Rounded Euclidean 3D norm\n"); + fprintf (stderr, " -(4 5 6 7 8 9) IBM ATT GEO MATRIX DSJRAND CRYSTAL norm\n"); +} diff --git a/contrib/blossom/concorde97/EDGEGEN/xnear.c b/contrib/blossom/concorde97/EDGEGEN/xnear.c new file mode 100644 index 0000000000000000000000000000000000000000..2ad2284362152766c05cfa77c4c6f369384ea527 --- /dev/null +++ b/contrib/blossom/concorde97/EDGEGEN/xnear.c @@ -0,0 +1,1051 @@ +/***************************************************************************/ +/* */ +/* NEAREST NEIGHBORS FOR X-NORMS AND JUNK-NORMS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 2, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCedgegen_x_k_nearest (int ncount, int k, CCdatagroup *dat, */ +/* double *wcoord, int wantlist, int *ecount, int **elist) */ +/* RETURNS the k_nearest neighbor graph (for X-Norms) */ +/* -ncount is the number of nodes */ +/* -k is the number of nearest neighbors wanted */ +/* -dat contains the info to generate edge lengths */ +/* -wcoord are nodeweights for Held-Karp style edge lengths, using */ +/* len[i,j] + wcoord[i] + wcoord[j] (wcoord can be NULL) */ +/* -wantlist should be set to 0 if you don't want the edges */ +/* -ecount returns the number of edges if wantlist is 1 */ +/* -elist returns the edges in end1 end2 format if wantlist is 1 */ +/* */ +/* int CCedgegen_x_quadrant_k_nearest (int ncount, int k, */ +/* CCdatagroup *dat, double *wcoord, int wantlist, int *ecount, */ +/* int **elist) */ +/* RETURNS the quadrant k_nearest_graph (for X-Norms) */ +/* */ +/* int CCedgegen_x_node_k_nearest (CCxnear *xn, int n, int k, */ +/* int ncount, int *list) */ +/* RETURNS the k nearest neighbors from node n (for X-Norms */ +/* -xn is a structure built by a call to xnear_build () */ +/* -list returns the neighbors of n. The calling routine should */ +/* be sure that list points to an array of length at least num. */ +/* */ +/* int CCedgegen_x_node_quadrant_k_nearest (CCxnear *xn, int n, int k, */ +/* int ncount, int *list) */ +/* RETURNS the quadrant k nearest to node n (for X-Norms) */ +/* -xn is a structure built by a call to xnear_build () */ +/* -list returns the neighbors of n. The calling routine should */ +/* be sure that list points to a sufficiently large array (4*num */ +/* for D2_SIZE norms and 8*num for D3_SIZE norms) */ +/* */ +/* int CCedgegen_x_node_nearest (CCxnear *xn, int ncount, int ni, */ +/* char *marks) */ +/* RETURNS the nearest unmarked node to node n (as the return value) */ +/* -marks is an array. The entries that are nonzero correspond to */ +/* nodes that will not be looked at in the search. */ +/* */ +/* int CCedgegen_x_nearest_neighbor_tour (int ncount, int start, */ +/* CCdatagroup *dat, int *outcycle, double *val) */ +/* RETURNS a nearest neighbor tour, starting at node start. */ +/* -outcycle will contain the tour if it is not NULL (the calling */ +/* routine should be sure it points to an array of length at */ +/* least ncount if it is not set to NULL) */ +/* -val will return the length of the tour. */ +/* */ +/* int CCedgegen_junk_k_nearest (int ncount, int k, CCdatagroup *dat, */ +/* double *wcoord, int wantlist, int *ecount, int **elist) */ +/* RETURNS the k-nearest graph (for JUNK-Norms) */ +/* -see x_k_nearest (above) for the variables */ +/* */ +/* int CCedgegen_junk_node_k_nearest (CCdatagroup *dat, double *wcoord, */ +/* int n, int k, int ncount, int *list) */ +/* RETURNS the k nearest neighbors to node n (for JUNK-Norms) */ +/* -list returns the neighbors of n. The calling routine should */ +/* be sure that list points to an array of length at least num. */ +/* */ +/* int CCedgegen_junk_node_nearest (CCdatagroup *dat, double *wcoord, */ +/* int ncount, int n, char *marks) */ +/* RETURNS the nearest unmarked node to node n (as the return value) */ +/* -marks is an array, the nodes with marks[i] nonzero are ignored. */ +/* */ +/* int CCedgegen_junk_nearest_neighbor_tour (int ncount, int start, */ +/* CCdatagroup *dat, int *outcycle, double *val) */ +/* RETURNS a nearest neighbor tour starting at node start. Note that */ +/* this will be slow for large problems (it is a quadratic routine) */ +/* -see the describtion of x_nearest_neighbor_tour above */ +/* */ +/* int CCedgegen_xnear_build (int ncount, CCdatagroup *dat, */ +/* double *wcoord, CCxnear *xn) */ +/* RETURNS the structure needed for calls to x_node_k_nearest and */ +/* x_quadrant_node_k_nearest (the calling routine should */ +/* be sure that xn points to such a structure). All this */ +/* routine does is permute the data so that the x coordinates */ +/* are in nonincreasing order. */ +/* */ +/* void CCedgegen_xnear_free (int ncount, CCxnear *xn) */ +/* FREES the xnear structure pointed to by xn */ +/* */ +/* NOTES: */ +/* All routines other than CCedgegen_xnear_free and */ +/* CCedgegen_x_node_nearest return 0 on success and 1 on failure */ +/* (normally due to running out of memory). */ +/* The X-Norm functions will also work for KD-Norms, but they are */ +/* much slower than the KD-Norm functions. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "edgegen.h" + +#define BIGDOUBLE (1e30) +#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) +#define NEAR_HEAP_CUTOFF 100 /* When to switch from list to heap */ + +typedef struct shortedge { + double length; + int end; +} shortedge; + +typedef struct intptr { + int this; + struct intptr *next; +} intptr; + +static intptr **table = (intptr **) NULL; + +#ifdef CC_PROTOTYPE_ANSI + +static void + add_to_list_and_reset (int *list, int *lcount, shortedge *nearlist, + int nearnum, int *nodenames), + insert (int n, int m, shortedge *nearlist, CCdatagroup *dat, + double *wcoord), + x_quicksort (int *list, double *x, int l, int u); +static int + run_x_k_nearest (int ncount, int num, CCdatagroup *dat, double *wcoord, + int wantlist, int *ecount, int **elist, int doquad), + put_in_table (int i, int j, int *added); + +#else + +static void + add_to_list_and_reset (), + insert (), + x_quicksort (); +static int + run_x_k_nearest (), + put_in_table (); + +#endif + + +CC_PTR_ALLOC_ROUTINE (intptr, intptralloc, intptrchunklist, intptrfreelist) +CC_PTR_FREE_ROUTINE (intptr, intptrfree, intptrfreelist) +CC_PTR_FREE_WORLD_ROUTINE (intptr, intptrfree_world, intptrchunklist, + intptrfreelist) +CC_PTR_LEAKS_ROUTINE (intptr, intptr_check_leaks, intptrchunklist, + intptrfreelist, this, int) + + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_x_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist) +#else +int CCedgegen_x_k_nearest (ncount, num, dat, wcoord, wantlist, ecount, elist) +int ncount, num; +CCdatagroup *dat; +double *wcoord; +int wantlist, *ecount, **elist; +#endif +{ + return run_x_k_nearest (ncount, num, dat, wcoord, wantlist, ecount, + elist, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_x_quadrant_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist) +#else +int CCedgegen_x_quadrant_k_nearest (ncount, num, dat, wcoord, wantlist, + ecount, elist) +int ncount, num; +CCdatagroup *dat; +double *wcoord; +int wantlist, *ecount, **elist; +#endif +{ + return run_x_k_nearest (ncount, num, dat, wcoord, wantlist, ecount, + elist, 1); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_junk_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist) +#else +int CCedgegen_junk_k_nearest (ncount, num, dat, wcoord, wantlist, ecount, elist) +int ncount, num; +CCdatagroup *dat; +double *wcoord; +int wantlist, *ecount, **elist; +#endif +{ + return run_x_k_nearest (ncount, num, dat, wcoord, wantlist, ecount, + elist, 0); +} + + +#ifdef CC_PROTOTYPE_ANSI +static int run_x_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist, int doquad) +#else +static int run_x_k_nearest (ncount, num, dat, wcoord, wantlist, ecount, elist, + doquad) +int ncount, num; +CCdatagroup *dat; +double *wcoord; +int wantlist, *ecount, **elist; +int doquad; +#endif +{ + int rval = 0; + int i, n; + intptr *ip, *ipnext; + int total, onlist; + int added, ntotal = 0; + int *list = (int *) NULL; + int goal, usex; + CCxnear xn; + + xn.nodenames = (int *) NULL; + xn.invnames = (int *) NULL; + xn.w = (double *) NULL; + xn.dat.x = (double *) NULL; + xn.dat.y = (double *) NULL; + xn.dat.z = (double *) NULL; + xn.dat.adj = (int **) NULL; + + if (wantlist) { + *ecount = 0; + *elist = (int *) NULL; + } + + if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE || + (dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + printf ("Using x-norm nearest code\n"); + usex = 1; + } else { + printf ("Using junk-norm nearest code\n"); + usex = 0; + } + + if (wcoord != (double *) NULL) { + for (i = 0; i < ncount; i++) { + if (wcoord[i] < -0.00000001) { + fprintf (stderr, "Cannot use xnear with negative weights\n"); + return 1; + } + } + } + + if (doquad && dat->z != (double *) NULL) + goal = 8 * num; + else if (doquad) + goal = 4 * num; + else + goal = num; + + if (usex) { + if (CCedgegen_xnear_build (ncount, dat, wcoord, &xn)) { + fprintf (stderr, "build_nodes failed\n"); + rval = 1; + goto CLEANUP; + } + } + + table = CC_SAFE_MALLOC (ncount, intptr *); + if (!table) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) + table[i] = (intptr *) NULL; + list = CC_SAFE_MALLOC (goal, int); + if (!list) { + rval = 1; + goto CLEANUP; + } + + if (!usex && doquad) { + printf ("NOTE: Cannot run quadrant nearest with a JUNK norm.\n"); + printf (" Running nearest instead.\n"); + fflush (stdout); + } + + for (n = 0; n < ncount; n++) { + if (usex) { + if (doquad) { + if (CCedgegen_x_node_quadrant_k_nearest (&xn, n, num, ncount, + list)) { + fprintf (stderr, "x_node_quadrant_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + } else { + if (CCedgegen_x_node_k_nearest (&xn, n, num, ncount, list)) { + fprintf (stderr, "x_node_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + } + } else { + if (CCedgegen_junk_node_k_nearest (dat, wcoord, n, num, ncount, + list)) { + fprintf (stderr, "junk_node_k_nearest_failed\n"); + rval = 1; + goto CLEANUP; + } + } + for (i = 0; i < goal; i++) { + if (list[i] != -1) { + if (put_in_table (n, list[i], &added)) { + fprintf (stderr, "put_in_table failed\n"); + rval = 1; + goto CLEANUP; + } else { + ntotal += added; + } + } + } + if (n % 1000 == 999) { + printf ("."); + fflush (stdout); + } + } + printf (" %d edges\n", ntotal); + fflush (stdout); + + if (wantlist) { + int j = 0; + *elist = CC_SAFE_MALLOC (2 * ntotal, int); + if (!(*elist)) { + rval = 1; + goto CLEANUP; + } + *ecount = ntotal; + for (i = 0; i < ncount; i++) { + for (ip = table[i]; ip; ip = ipnext) { + ipnext = ip->next; + (*elist)[j++] = i; + (*elist)[j++] = ip->this; + intptrfree (ip); + } + table[i] = (intptr *) NULL; + } + } else { + for (i = 0; i < ncount; i++) { + for (ip = table[i]; ip; ip = ipnext) { + ipnext = ip->next; + intptrfree (ip); + } + table[i] = (intptr *) NULL; + } + } + + if (intptr_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding intptrs in kdnear\n", + total - onlist); + } + +CLEANUP: + + intptrfree_world (); + CC_IFFREE (list, int); + CC_IFFREE (table, intptr *); + if (usex) + CCedgegen_xnear_free (ncount, &xn); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_x_node_quadrant_k_nearest (CCxnear *xn, int ni, int nearnum, + int ncount, int *list) +#else +int CCedgegen_x_node_quadrant_k_nearest (xn, ni, nearnum, ncount, list) +CCxnear *xn; +int ni, nearnum, ncount; +int *list; +#endif +{ + int i, j, ntotal = 0; + shortedge *nearlist = (shortedge *) NULL; + double scale; + int goal = (xn->dat.z == (double *) NULL ? 4 * nearnum : 8 * nearnum); + int n = xn->invnames[ni]; + + nearlist = CC_SAFE_MALLOC (nearnum + 1, shortedge); + if (!nearlist) + return 1; + for (i = 0; i < nearnum; i++) + nearlist[i].length = BIGDOUBLE; + nearlist[nearnum].length = -BIGDOUBLE; + + if (xn->dat.norm == CC_GEOGRAPHIC) + scale = CC_GEOGRAPHIC_SCALE; + else if (xn->dat.norm == CC_ATT) + scale = CC_ATT_SCALE; + else + scale = 1.0; + if ((xn->dat.norm & CC_NORM_SIZE_BITS) == CC_D3_NORM_SIZE) { + double ny = xn->dat.y[n]; + double nz = xn->dat.z[n]; + for (j = n - 1; j >= 0 && + (double) ((int)((xn->dat.x[n] - xn->dat.x[j]) * scale)) + < nearlist[0].length; --j) { + if (xn->dat.y[j] <= ny && xn->dat.z[j] <= nz) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n - 1; j >= 0 && + (double) ((int)((xn->dat.x[n] - xn->dat.x[j]) * scale)) + < nearlist[0].length; --j) { + if (xn->dat.y[j] <= ny && xn->dat.z[j] >= nz) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n - 1; j >= 0 && + (double) ((int)((xn->dat.x[n] - xn->dat.x[j]) * scale)) + < nearlist[0].length; --j) { + if (xn->dat.y[j] >= ny && xn->dat.z[j] <= nz) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n - 1; j >= 0 && + (double) ((int)((xn->dat.x[n] - xn->dat.x[j]) * scale)) + < nearlist[0].length; --j) { + if (xn->dat.y[j] >= ny && xn->dat.z[j] >= nz) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n + 1; j < ncount && + (double) ((int)((xn->dat.x[j] - xn->dat.x[n]) * scale)) + < nearlist[0].length; j++) { + if (xn->dat.y[j] <= ny && xn->dat.z[j] <= nz) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n + 1; j < ncount && + (double) ((int)((xn->dat.x[j] - xn->dat.x[n]) * scale)) + < nearlist[0].length; j++) { + if (xn->dat.y[j] <= ny && xn->dat.z[j] >= nz) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n + 1; j < ncount && + (double) ((int)((xn->dat.x[j] - xn->dat.x[n]) * scale)) + < nearlist[0].length; j++) { + if (xn->dat.y[j] >= ny && xn->dat.z[j] <= nz) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n + 1; j < ncount && + (double) ((int)((xn->dat.x[j] - xn->dat.x[n]) * scale)) + < nearlist[0].length; j++) { + if (xn->dat.y[j] >= ny && xn->dat.z[j] >= nz) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + } else { + double ny = xn->dat.y[n]; + for (j = n - 1; j >= 0 && + (double) ((int)((xn->dat.x[n] - xn->dat.x[j]) * scale)) + < nearlist[0].length; --j) { + if (xn->dat.y[j] <= ny) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n - 1; j >= 0 && + (double) ((int)((xn->dat.x[n] - xn->dat.x[j]) * scale)) + < nearlist[0].length; --j) { + if (xn->dat.y[j] >= ny) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n + 1; j < ncount && + (double) ((int)((xn->dat.x[j] - xn->dat.x[n]) * scale)) + < nearlist[0].length; j++) { + if (xn->dat.y[j] <= ny) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + for (j = n + 1; j < ncount && + (double) ((int)((xn->dat.x[j] - xn->dat.x[n]) * scale)) + < nearlist[0].length; j++) { + if (xn->dat.y[j] >= ny) + insert (n, j, nearlist, &(xn->dat), xn->w); + } + add_to_list_and_reset (list, &ntotal, nearlist, nearnum, + xn->nodenames); + } + + if (ntotal < goal) { + for (i = ntotal; i < goal; i++) + list[i] = -1; + } + CC_IFFREE (nearlist, shortedge); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void add_to_list_and_reset (int *list, int *lcount, shortedge *nearlist, + int nearnum, int *nodenames) +#else +static void add_to_list_and_reset (list, lcount, nearlist, nearnum, nodenames) +int *list, *lcount; +shortedge *nearlist; +int nearnum; +int *nodenames; +#endif +{ + int i; + + for (i = 0; i < nearnum; i++) { + if (nearlist[i].length < BIGDOUBLE) { + list[(*lcount)++] = nodenames[nearlist[i].end]; + nearlist[i].length = BIGDOUBLE; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_x_node_k_nearest (CCxnear *xn, int ni, int nearnum, int ncount, + int *list) +#else +int CCedgegen_x_node_k_nearest (xn, ni, nearnum, ncount, list) +CCxnear *xn; +int ni, nearnum, ncount; +int *list; +#endif +{ + int i, j, ntotal; + shortedge *nearlist = (shortedge *) NULL; + double scale; + int n = xn->invnames[ni]; + + nearlist = CC_SAFE_MALLOC (nearnum + 1, shortedge); + if (!nearlist) + return 1; + for (i = 0; i < nearnum; i++) + nearlist[i].length = BIGDOUBLE; + nearlist[nearnum].length = -BIGDOUBLE; + + if (xn->dat.norm == CC_GEOGRAPHIC) + scale = CC_GEOGRAPHIC_SCALE; + else if (xn->dat.norm == CC_ATT) + scale = CC_ATT_SCALE; + else + scale = 1.0; + for (j = n - 1; j >= 0 && + (double) ((int)((xn->dat.x[n] - xn->dat.x[j]) * scale)) + < nearlist[0].length; --j) + insert (n, j, nearlist, &(xn->dat), xn->w); + for (j = n + 1; j < ncount && + (double) ((int)((xn->dat.x[j] - xn->dat.x[n]) * scale)) + < nearlist[0].length; j++) + insert (n, j, nearlist, &(xn->dat), xn->w); + + ntotal = 0; + for (i = 0; i < nearnum; i++) { + if (nearlist[i].length < BIGDOUBLE) + list[ntotal++] = xn->nodenames[nearlist[i].end]; + } + if (ntotal < nearnum) { + fprintf (stderr, "WARNING: There do not exist %d neighbors\n", nearnum); + for (i = ntotal; i < nearnum; i++) + list[i] = -1; + return 1; + } + + CC_IFFREE (nearlist, shortedge); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_x_node_nearest (CCxnear *xn, int ncount, int ni, char *marks) +#else +int CCedgegen_x_node_nearest (xn, ncount, ni, marks) +CCxnear *xn; +int ncount, ni; +char *marks; +#endif +{ + int n = xn->invnames[ni]; + int j, bestnode = 0; + double scale, thisdist, bestdist = BIGDOUBLE; + + if (xn->dat.norm == CC_GEOGRAPHIC) + scale = CC_GEOGRAPHIC_SCALE; + else if (xn->dat.norm == CC_ATT) + scale = CC_ATT_SCALE; + else + scale = 1.0; + for (j = n - 1; j >= 0 && + (double) ((int)((xn->dat.x[n] - xn->dat.x[j]) * scale)) + < bestdist; --j) { + if (!marks[xn->nodenames[j]]) { + thisdist = CCutil_dat_edgelen (n, j, &(xn->dat)); + if (xn->w) + thisdist += (xn->w[n] + xn->w[j]); + if (thisdist < bestdist) { + bestdist = thisdist; + bestnode = j; + } + } + } + for (j = n + 1; j < ncount && + (double) ((int)((xn->dat.x[j] - xn->dat.x[n]) * scale)) + < bestdist; j++) { + if (!marks[xn->nodenames[j]]) { + thisdist = CCutil_dat_edgelen (n, j, &(xn->dat)); + if (xn->w) + thisdist += (xn->w[n] + xn->w[j]); + if (thisdist < bestdist) { + bestdist = thisdist; + bestnode = j; + } + } + } + return xn->nodenames[bestnode]; +} + +#ifdef CC_PROTOTYPE_ANSI +static void insert (int n, int m, shortedge *nearlist, CCdatagroup *dat, + double *wcoord) +#else +static void insert (n, m, nearlist, dat, wcoord) +int n, m; +shortedge *nearlist; +CCdatagroup *dat; +double *wcoord; +#endif +{ + int i; + int thisdist; + + thisdist = CCutil_dat_edgelen (n, m, dat); + + if (wcoord != (double *) NULL) + thisdist += (wcoord[n] + wcoord[m]); + + if (thisdist < nearlist[0].length) { + for (i = 0; nearlist[i+1].length > thisdist; i++) { + nearlist[i].end = nearlist[i + 1].end; + nearlist[i].length = nearlist[i + 1].length; + } + nearlist[i].length = thisdist; + nearlist[i].end = m; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_junk_node_k_nearest (CCdatagroup *dat, double *wcoord, int n, + int nearnum, int ncount, int *list) +#else +int CCedgegen_junk_node_k_nearest (dat, wcoord, n, nearnum, ncount, list) +CCdatagroup *dat; +double *wcoord; +int n, nearnum, ncount; +int *list; +#endif +{ + int i, j, ntotal; + shortedge *nearlist = (shortedge *) NULL; + + nearlist = CC_SAFE_MALLOC (nearnum + 1, shortedge); + if (!nearlist) + return 1; + for (i = 0; i < nearnum; i++) + nearlist[i].length = BIGDOUBLE; + nearlist[nearnum].length = -BIGDOUBLE; + + for (j = n - 1; j >= 0; j--) { + insert (n, j, nearlist, dat, wcoord); + } + for (j = n + 1; j < ncount; j++) { + insert (n, j, nearlist, dat, wcoord); + } + + ntotal = 0; + for (i = 0; i < nearnum; i++) { + if (nearlist[i].length < BIGDOUBLE) + list[ntotal++] = nearlist[i].end; + } + if (ntotal < nearnum) { + fprintf (stderr, "WARNING: There do not exist %d neighbors\n", nearnum); + for (i = ntotal; i < nearnum; i++) + list[i] = -1; + return 1; + } + + CC_IFFREE (nearlist, shortedge); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_junk_node_nearest (CCdatagroup *dat, double *wcoord, int ncount, + int n, char *marks) +#else +int CCedgegen_junk_node_nearest (dat, wcoord, ncount, n, marks) +CCdatagroup *dat; +double *wcoord; +int ncount, n; +char *marks; +#endif +{ + int j, bestnode = 0; + double thisdist, bestdist = BIGDOUBLE; + + + if (wcoord) { + for (j = n - 1; j >= 0; j--) { + if (!marks[j]) { + thisdist = CCutil_dat_edgelen (n, j, dat) + + (wcoord[n] + wcoord[j]); + if (thisdist < bestdist) { + bestdist = thisdist; + bestnode = j; + } + } + } + for (j = n + 1; j < ncount; j++) { + if (!marks[j]) { + thisdist = CCutil_dat_edgelen (n, j, dat) + + (wcoord[n] + wcoord[j]); + if (thisdist < bestdist) { + bestdist = thisdist; + bestnode = j; + } + } + } + } else { + for (j = n - 1; j >= 0; j--) { + if (!marks[j]) { + thisdist = CCutil_dat_edgelen (n, j, dat); + if (thisdist < bestdist) { + bestdist = thisdist; + bestnode = j; + } + } + } + for (j = n + 1; j < ncount; j++) { + if (!marks[j]) { + thisdist = CCutil_dat_edgelen (n, j, dat); + if (thisdist < bestdist) { + bestdist = thisdist; + bestnode = j; + } + } + } + } + + return bestnode; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_x_nearest_neighbor_tour (int ncount, int start, CCdatagroup *dat, + int *outcycle, double *val) +#else +int CCedgegen_x_nearest_neighbor_tour (ncount, start, dat, outcycle, val) +int ncount, start; +CCdatagroup *dat; +int *outcycle; +double *val; +#endif +{ + double len; + int i, current, next; + CCxnear xn; + char *marks; + + /* + printf ("Grow nearest neighbor tour from node %d\n", start); + fflush (stdout); + */ + + if (ncount < 3) { + fprintf (stderr, "Cannot find tour in an %d node graph\n", ncount); + return 1; + } + if ((dat->norm & CC_NORM_BITS) != CC_X_NORM_TYPE && + (dat->norm & CC_NORM_BITS) != CC_KD_NORM_TYPE) { + fprintf (stderr, "Cannot run x_nearest with norm %d\n", dat->norm); + return 1; + } + + if (CCedgegen_xnear_build (ncount, dat, (double *) NULL, &xn)) { + fprintf (stderr, "Unable to build xnear\n"); + return 1; + } + + marks = CC_SAFE_MALLOC (ncount, char ); + if (!marks) { + CCedgegen_xnear_free (ncount, &xn); + return 1; + } + + for (i = 0; i < ncount; i++) + marks[i] = 0; + + + len = 0.0; + current = start; + if (outcycle != (int *) NULL) + outcycle[0] = start; + + for (i = 1; i < ncount; i++) { + marks[current] = 1; + next = CCedgegen_x_node_nearest (&xn, ncount, current, marks); + if (outcycle != (int *) NULL) + outcycle [i] = next; + len += (double) CCutil_dat_edgelen (current, next, dat); + current = next; + } + len += (double) CCutil_dat_edgelen (current, start, dat); + *val = len; + CCedgegen_xnear_free (ncount, &xn); + CC_IFFREE (marks, char); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_junk_nearest_neighbor_tour (int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val) +#else +int CCedgegen_junk_nearest_neighbor_tour (ncount, start, dat, outcycle, val) +int ncount, start; +CCdatagroup *dat; +int *outcycle; +double *val; +#endif +{ + double len; + int i, current, next; + char *marks; + + printf ("Grow nearest neighbor tour from node %d\n", start); + printf ("This is a JUNK norm, so expect a quadratic running time\n"); + fflush (stdout); + + if (ncount < 3) { + fprintf (stderr, "Cannot find tour in an %d node graph\n", ncount); + return 1; + } + + marks = CC_SAFE_MALLOC (ncount, char ); + if (!marks) { + return 1; + } + + for (i = 0; i < ncount; i++) + marks[i] = 0; + + len = 0.0; + current = start; + if (outcycle != (int *) NULL) + outcycle[0] = start; + + for (i = 1; i < ncount; i++) { + marks[current] = 1; + next = CCedgegen_junk_node_nearest (dat, (double *) NULL, ncount, + current, marks); + if (outcycle != (int *) NULL) + outcycle [i] = next; + len += (double) CCutil_dat_edgelen (current, next, dat); + current = next; + } + len += (double) CCutil_dat_edgelen (current, start, dat); + *val = len; + CC_IFFREE (marks, char); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int put_in_table (int i, int j, int *added) +#else +static int put_in_table (i, j, added) +int i, j; +int *added; +#endif +{ + intptr *ip; + + if (j < i) { + int temp; + SWAP(i, j, temp); + } + + for (ip = table[i]; ip; ip = ip->next) + if (ip->this == j) { + *added = 0; + return 0; + } + ip = intptralloc (); + if (!ip) { + *added = 0; + return 1; + } + ip->this = j; + ip->next = table[i]; + table[i] = ip; + *added = 1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCedgegen_xnear_build (int ncount, CCdatagroup *dat, double *wcoord, + CCxnear *xn) +#else +int CCedgegen_xnear_build (ncount, dat, wcoord, xn) +int ncount; +CCdatagroup *dat; +double *wcoord; +CCxnear *xn; +#endif +{ + int i; + + xn->nodenames = (int *) NULL; + xn->invnames = (int *) NULL; + xn->w = (double *) NULL; + xn->dat.x = (double *) NULL; + xn->dat.y = (double *) NULL; + xn->dat.z = (double *) NULL; + xn->dat.adj = (int **) NULL; + + xn->dat.norm = dat->norm; + + xn->nodenames = CC_SAFE_MALLOC (ncount, int); + if (!xn->nodenames) + return 1; + for (i = 0; i < ncount; i++) + xn->nodenames[i] = i; + xn->dat.x = CC_SAFE_MALLOC (ncount, double); + if (!xn->dat.x) { + CC_FREE (xn->nodenames, int); + return 1; + } + for (i = 0; i < ncount; i++) + xn->dat.x[i] = dat->x[i]; + + for (i = 1; i < ncount && dat->x[i] >= dat->x[i - 1]; i++); + if (i < ncount) { + x_quicksort (xn->nodenames, xn->dat.x, 0, ncount - 1); + } + + xn->invnames = CC_SAFE_MALLOC (ncount, int); + if (!xn->invnames) { + CC_FREE (xn->nodenames, int); + CCutil_freedatagroup (ncount, &(xn->dat)); + return 1; + } + for (i = 0; i < ncount; i++) + xn->invnames[xn->nodenames[i]] = i; + + xn->dat.y = CC_SAFE_MALLOC (ncount, double); + if (!xn->dat.y) { + CC_FREE (xn->nodenames, int); + CC_FREE (xn->invnames, int); + CCutil_freedatagroup (ncount, &(xn->dat)); + return 1; + } + for (i = 0; i < ncount; i++) + xn->dat.y[i] = dat->y[xn->nodenames[i]]; + if (dat->z != (double *) NULL) { + xn->dat.z = CC_SAFE_MALLOC (ncount, double); + if (!xn->dat.z) { + CC_FREE (xn->nodenames, int); + CC_FREE (xn->invnames, int); + CCutil_freedatagroup (ncount, &(xn->dat)); + return 1; + } + for (i = 0; i < ncount; i++) + xn->dat.z[i] = dat->z[xn->nodenames[i]]; + } + if (wcoord != (double *) NULL) { + xn->w = CC_SAFE_MALLOC (ncount, double); + if (!xn->w) { + CC_FREE (xn->nodenames, int); + CC_FREE (xn->invnames, int); + CCutil_freedatagroup (ncount, &(xn->dat)); + return 1; + } + for (i = 0; i < ncount; i++) + xn->w[i] = wcoord[xn->nodenames[i]]; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCedgegen_xnear_free (int ncount, CCxnear *xn) +#else +void CCedgegen_xnear_free (ncount, xn) +int ncount; +CCxnear *xn; +#endif +{ + CC_IFFREE (xn->nodenames, int); + CC_IFFREE (xn->invnames, int); + CC_IFFREE (xn->w, double); + CCutil_freedatagroup (ncount, &(xn->dat)); +} + +#ifdef CC_PROTOTYPE_ANSI +static void x_quicksort (int *list, double *x, int l, int u) +#else +static void x_quicksort (list, x, l, u) +int *list; +double *x; +int l, u; +#endif +{ + int i, j, itemp; + double t, dtemp; + + if (l >= u) + return; + + SWAP (x[l], x[(l+u)/2], dtemp); + SWAP (list[l], list[(l+u)/2], itemp); + + i = l; + j = u + 1; + t = x[l]; + + while (1) { + do i++; while (i <= u && x[i] < t); + do j--; while (x[j] > t); + if (j < i) break; + SWAP (x[i], x[j], dtemp); + SWAP (list[i], list[j], itemp); + } + SWAP (x[l], x[j], dtemp); + SWAP (list[l], list[j], itemp); + x_quicksort (list, x, l, j - 1); + x_quicksort (list, x, i, u); +} diff --git a/contrib/blossom/concorde97/FMATCH/Makefile b/contrib/blossom/concorde97/FMATCH/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5279d1ed337adc0edb48f2ee37f524d6501ca218 --- /dev/null +++ b/contrib/blossom/concorde97/FMATCH/Makefile @@ -0,0 +1,33 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=fmatch.a +LIBSRCS=fmatch.c +LIBS=$(ROOT)/EDGEGEN/edgegen.a $(ROOT)/KDTREE/kdtree.a \ + $(ROOT)/LINKERN/linkern.a $(ROOT)/UTIL/util.a +ALLSRCS=fm_main.c $(LIBSRCS) + +all: fmatch $(LIB) + +fmatch: fm_main.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ -lm + +clean: + -rm -f *.$o $(LIB) fmatch + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +fm_main.$o: fm_main.c $(I)/machdefs.h $(I)/util.h $(I)/fmatch.h \ + $(I)/kdtree.h $(I)/edgegen.h +fmatch.$o: fmatch.c $(I)/machdefs.h $(I)/util.h $(I)/fmatch.h \ + $(I)/kdtree.h diff --git a/contrib/blossom/concorde97/FMATCH/fm_main.c b/contrib/blossom/concorde97/FMATCH/fm_main.c new file mode 100644 index 0000000000000000000000000000000000000000..0800e5d11fd9cd7c7eb8b9a7bcca48d5abb43bd0 --- /dev/null +++ b/contrib/blossom/concorde97/FMATCH/fm_main.c @@ -0,0 +1,549 @@ +/***************************************************************************/ +/* */ +/* TEST PROGRAM FOR FRACTIONAL MATCHINGS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 24, 1995 (cofeb24) */ +/* */ +/* SEE short decsribtion in usage (). */ +/* */ +/* Link with: */ +/* SEE fmmake.grs */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "fmatch.h" +#include "kdtree.h" +#include "edgegen.h" + +static int norm = CC_EUCLIDEAN; +static int wantbasic = 0; +static char *edgefilename = (char *) NULL; +static char *datfilename = (char *) NULL; +static char *edgegenfname = (char *) NULL; +static int dumpmatch = 0; +static int dumpdual = 0; +static int dumpbasis = 0; +static int binary_in = 0; +static int tsplib_in = 0; +static int nnodes_want = 0; +static int seed = 0; +static int usenn2match = 0; +static int quadtry = 2; + + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int ac, char **av); + +static void + usage (char *f), + dump_match (int *thematching), + dump_dual (int *thedual, int ncount), + dump_basis (int *thebasis, int ncount); + +static int + parseargs (int ac, char **av), + getgraph (char *edgefile, CCdatagroup *dat, int *ncount, int *ecount, + int **elist, int **elen); + +#else + +int + main (); + +static void + usage (), + dump_match (), + dump_dual (), + dump_basis (); + +static int + parseargs (), + getgraph (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + double v, szeit; + int ncount, ecount; + int *elist = (int *) NULL, *elen = (int *) NULL; + int *thematching = (int *) NULL, *thedual = (int *) NULL; + int *thebasis = (int *) NULL; + CCdatagroup dat, *mydat = (CCdatagroup *) NULL; + int rval = 0; + + seed = (int) CCutil_real_zeit (); + if (parseargs (ac, av)) + return 0; + CCutil_sprand (seed); + + if (edgefilename == (char *) NULL && datfilename == (char *) NULL && + nnodes_want == 0) { + usage (av[0]); + return 0; + } + ncount = nnodes_want; + + szeit = CCutil_zeit (); + if (tsplib_in && datfilename != (char *) NULL) { + if (CCutil_gettsplib (datfilename, &ncount, &dat)) { + fprintf (stderr, "could not read the TSPLIB file\n"); + rval = 1; + goto CLEANUP; + } + norm = dat.norm; + mydat = &dat; + } else if (edgefilename == (char *) NULL || datfilename != (char *) NULL) { + if (CCutil_getdata (datfilename, binary_in, norm, &ncount, &dat)) { + fprintf (stderr, "Could not create data set\n"); + rval = 1; + goto CLEANUP; + } + mydat = &dat; + } else { + mydat = (CCdatagroup *) NULL; + } + + if (mydat) { + if (CCutil_init_dat_edgelen (&dat)) { + fprintf (stderr, "CCutil_init_dat_edgelen failed\n"); + rval = 1; + goto CLEANUP; + } + } + + if (getgraph (edgefilename, &dat, &ncount, &ecount, &elist, &elen)) { + fprintf (stderr, "getgraph failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Initial edgeset: %d edges (%d nodes)\n", ecount, ncount); + printf ("Time to generate graph: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + + if (dumpmatch) { + thematching = CC_SAFE_MALLOC((6 * ncount) + 1, int); + if (!thematching) + goto CLEANUP; + } + if (dumpdual) { + thedual = CC_SAFE_MALLOC(ncount, int); + if (!thedual) + goto CLEANUP; + } + if (dumpbasis) { + thebasis = CC_SAFE_MALLOC(2 * ncount, int); + if (!thebasis) + goto CLEANUP; + } + + + szeit = CCutil_zeit (); + if (CCfmatch_fractional_2match (ncount, ecount, elist, elen, mydat, + &v, thematching, thedual, thebasis, wantbasic)) { + fprintf (stderr, "Fractional matching routine failed\n"); + printf ("Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + goto CLEANUP; + } + + printf ("Total Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + printf ("Final matching weight: %.1f\n", v); + fflush (stdout); + + if (dumpmatch) + dump_match (thematching); + if (dumpdual) + dump_dual (thedual, ncount); + if (dumpbasis) + dump_basis (thebasis, ncount); + + +CLEANUP: + + CC_IFFREE (thematching, int); + CC_IFFREE (thedual, int); + CC_IFFREE (thebasis, int); + CC_IFFREE (elist, int); + CC_IFFREE (elen, int); + + if (mydat != (CCdatagroup *) NULL) { + CCutil_freedatagroup (ncount, mydat); + } + if (CCutil_bigchunk_free_world ()) { + fprintf (stderr, "ERROR: CCutil_bigchunk_free_world failed\n"); + return 1; + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "BbD:e:k:mn:q:s:Txyz0123456789")) != EOF) + switch (c) { + case 'B': + wantbasic = 1; + break; + case 'b': + binary_in = 1; + break; + case 'D': + edgegenfname = CCutil_bix_optarg; + break; + case 'e': + edgefilename = CCutil_bix_optarg; + break; + case 'k': + nnodes_want = atoi (CCutil_bix_optarg); + break; + case 'm': + usenn2match = 1; + break; + case 'n': + datfilename = CCutil_bix_optarg; + break; + case 'q': + quadtry = atoi (CCutil_bix_optarg); + break; + case 's': + seed = atoi (CCutil_bix_optarg); + break; + case 'T': + tsplib_in = 1; + break; + case 'x': + dumpmatch = 1; + break; + case 'y': + dumpdual = 1; + break; + case 'z': + dumpbasis = 1; + wantbasic = 1; + break; + case '0': + norm = CC_MAXNORM; + break; + case '1': + norm = CC_EUCLIDEAN_CEIL; + break; + case '2': + norm = CC_EUCLIDEAN; + break; + case '3': + norm = CC_EUCLIDEAN_3D; + break; + case '4': + norm = CC_IBM; + break; + case '5': + norm = CC_ATT; + break; + case '6': + norm = CC_GEOGRAPHIC; + break; + case '7': + norm = CC_MATRIXNORM; + break; + case '8': + norm = CC_DSJRANDNORM; + break; + case '9': + norm = CC_CRYSTAL; + break; + case CC_BIX_GETOPT_UNKNOWN: + case '?': + default: + usage (av[0]); + return 1; + } + if (CCutil_bix_optind != ac) { + usage (av[0]); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "Usage: %s [-see below-]\n", f); + fprintf (stderr, " -B find basic optimal solution\n"); + fprintf (stderr, " -b datfile in integer binary format\n"); + fprintf (stderr, " -D f edgegen file for initial edge set\n"); + fprintf (stderr, " -e f edge file - initial edge set\n"); + fprintf (stderr, " -k # number of nodes for random problem\n"); + fprintf (stderr, " -m NN 2-matching as initial edge set\n"); + fprintf (stderr, " -n f dat file - for fmatch on complete graph\n"); + fprintf (stderr, " -q # quad-nearest # as initial edge set (default 2)\n"); + fprintf (stderr, " -s # random seed\n"); + fprintf (stderr, " -T the dat file is a TSPLIB file\n"); + fprintf (stderr, " -x dump matching to match.out\n"); + fprintf (stderr, " -y dump dual solution to dual.out\n"); + fprintf (stderr, " -z dump basic edges to basis.out\n"); + fprintf (stderr, " -0 price out using MAX norm\n"); + fprintf (stderr, " -1 price out using JOHNSON norm\n"); + fprintf (stderr, " -2 price out using EUCLIDEAN norm (default)\n"); + fprintf (stderr, " -3 price out using Rounded Euclidean 3D norm\n"); + fprintf (stderr, " -(4 5 6 7 8 9) IBM ATT GEO MATRIX DSJRAND CRYSTAL norm\n"); +} + +#define QUAD_TRY 2 + +#ifdef CC_PROTOTYPE_ANSI +static int getgraph (char *edgefile, CCdatagroup *dat, int *ncount, int *ecount, + int **elist, int **elen) +#else +static int getgraph (edgefile, dat, ncount, ecount, elist, elen) +char *edgefile; +CCdatagroup *dat; +int *ncount, *ecount, **elist, **elen; +#endif +{ + FILE *in; + int i, k; + + + *elist = (int *) NULL; + *elen = (int *) NULL; + + if (edgefile != (char *) NULL) { + if ((in = fopen (edgefile, "r")) == (FILE *) NULL) { + perror (edgefile); + fprintf (stderr, "Unable to open %s for input\n", edgefile); + return 1; + } + + k = CCutil_readint (in); + if (*ncount != 0 && k != *ncount) { + fprintf (stderr, "Edge file does not match dat file\n"); + fclose (in); + return 1; + } + *ncount = k; + *ecount = CCutil_readint (in); + + *elist = CC_SAFE_MALLOC(2 * (*ecount), int); + if (!(*elist)) { + fclose (in); + return 1; + } + *elen = CC_SAFE_MALLOC(*ecount, int); + if (!(*elen)) { + fclose (in); + CC_FREE (*elist, int); + return 1; + } + + for (i = 0, k = 0; i < *ecount; i++) { + (*elist)[k++] = CCutil_readint (in); + (*elist)[k++] = CCutil_readint (in); + (*elen)[i] = CCutil_readint (in); + } + fclose (in); + } else if (edgegenfname) { + CCedgegengroup plan; + if (CCedgegen_read (edgegenfname, &plan)) { + fprintf (stderr, "CCedgegen_read failed\n"); + return 1; + } + if (CCedgegen_edges (&plan, *ncount, dat, (double *) NULL, ecount, + elist)) { + fprintf (stderr, "CCedgegen_edges failed\n"); + return 1; + } + *elen = CC_SAFE_MALLOC(*ecount, int); + if (!(*elen)) { + CC_FREE (*elist, int); + return 1; + } + for (i = 0; i < *ecount; i++) { + (*elen)[i] = CCutil_dat_edgelen ((*elist)[2*i], (*elist)[(2*i) + 1], dat); + } + } else { + if (usenn2match) { + double val; + *ecount = *ncount; + *elist = CC_SAFE_MALLOC(2 * (*ecount), int); + if (!(*elist)) + return 1; + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + printf ("Using nearest neighbor 2-matching graph\n"); + fflush (stdout); + if (CCkdtree_nearest_neighbor_2match ((CCkdtree *) NULL, + *ncount, CCutil_lprand () % (*ncount), dat, + *elist, &val)) { + fprintf (stderr, "nearest 2-matching code failed\n"); + CC_FREE (*elist, int); + return 1; + } + } else { + int *cyc = (int *) NULL; + printf ("Not setup for nearest 2-match with x or junk norms\n"); + printf ("Using nearest neighbour tour graph\n"); + fflush (stdout); + cyc = CC_SAFE_MALLOC (*ncount, int); + if (!cyc) { + CC_FREE (*elist, int); + return 1; + } + if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + if (CCedgegen_x_nearest_neighbor_tour (*ncount, + CCutil_lprand () % (*ncount), dat, cyc, &val)) { + CC_FREE (*elist, int); + CC_FREE (cyc, int); + return 1; + } + } else { + if (CCedgegen_junk_nearest_neighbor_tour (*ncount, + CCutil_lprand () % (*ncount), dat, cyc, &val)) { + CC_FREE (*elist, int); + CC_FREE (cyc, int); + return 1; + } + } + for (i = 0; i < *ncount - 1; i++) { + (*elist)[2 * i] = cyc[i]; + (*elist)[(2 * i) + 1] = cyc[i + 1]; + } + (*elist)[2 * i] = cyc[i]; + (*elist)[(2 * i) + 1] = cyc[0]; + CC_FREE (cyc, int); + } + } else { + if ((dat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + printf ("Using quadrant nearest %d graph\n", quadtry); + fflush (stdout); + if (CCkdtree_quadrant_k_nearest ((CCkdtree *) NULL, *ncount, + quadtry, dat, (double *) NULL, 1, ecount, elist)) { + fprintf (stderr, "CCkdtree-quad nearest code failed\n"); + CC_FREE (*elist, int); + return 1; + } + } else if ((dat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + printf ("Using quadrant nearest %d graph\n", quadtry); + fflush (stdout); + if (CCedgegen_x_quadrant_k_nearest (*ncount, quadtry, dat, + (double *) NULL, 1, ecount, elist)) { + fprintf (stderr, "CCedgegen_x-quad nearest code failed\n"); + CC_FREE (*elist, int); + return 1; + } + } else { + printf ("No junk quad nearest, using %d nearest graph\n", + 4 * quadtry); + fflush (stdout); + if (CCedgegen_junk_k_nearest (*ncount, 4 * quadtry, dat, + (double *) NULL, 1, ecount, elist)) { + fprintf (stderr, "CCedgegen_junk-nearest code failed\n"); + CC_FREE (*elist, int); + return 1; + } + } + } + + *elen = CC_SAFE_MALLOC(*ecount, int); + if (!(*elen)) { + CC_FREE (*elist, int); + return 1; + } + for (i = 0; i < *ecount; i++) { + (*elen)[i] = CCutil_dat_edgelen ((*elist)[2*i], (*elist)[(2*i) + 1], dat); + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_match (int *thematching) +#else +static void dump_match (thematching) +int *thematching; +#endif +{ + FILE *out = fopen ("match.out", "w"); + int k; + + if (out == (FILE *) NULL) { + perror ("match.out"); + fprintf (stderr, "Unable to open match.out for output\n"); + return; + } + + k = 0; + while (thematching[k] != -1) { + fprintf (out, "%d %d %d\n", thematching[k], thematching[k + 1], + thematching[k + 2]); + k += 3; + } +} +#ifdef CC_PROTOTYPE_ANSI +static void dump_dual (int *thedual, int ncount) +#else +static void dump_dual (thedual, ncount) +int *thedual; +int ncount; +#endif +{ + FILE *out = fopen ("dual.out", "w"); + int k; + + if (out == (FILE *) NULL) { + perror ("dual.out"); + fprintf (stderr, "Unable to open dual.out for output\n"); + return; + } + + for (k = 0; k < ncount; k++) + fprintf (out, "%d\n", thedual[k]); +} + + +#ifdef CC_PROTOTYPE_ANSI +static void dump_basis (int *thebasis, int ncount) +#else +static void dump_basis (thebasis, ncount) +int *thebasis; +int ncount; +#endif +{ + FILE *out = fopen ("basis.out", "w"); + int k; + + if (out == (FILE *) NULL) { + perror ("basis.out"); + fprintf (stderr, "Unable to open basis.out for output\n"); + return; + } + + for (k = 0; k < ncount; k++) + fprintf (out, "%d %d\n", thebasis[2 * k], thebasis[(2 * k) + 1]); +} diff --git a/contrib/blossom/concorde97/FMATCH/fmatch.c b/contrib/blossom/concorde97/FMATCH/fmatch.c new file mode 100644 index 0000000000000000000000000000000000000000..dec846c5d8966dfef8a0065472f3781eb779907f --- /dev/null +++ b/contrib/blossom/concorde97/FMATCH/fmatch.c @@ -0,0 +1,2324 @@ +/***************************************************************************/ +/* */ +/* MIN WEIGHT FRACTIONAL 2-MATCHINGS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 24, 1995 - Modified 10/4/95 (Bico) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCfmatch_fractional_2match (int ncount, int ecount, int *elist, */ +/* int *elen, CCdatagroup *dat, double *val, int *thematching, */ +/* int *thedual, int *thebasis, int wantbasic) */ +/* int ncount (the number of nodes in the graph) */ +/* int ecount (the number of edges) */ +/* int *elist (the edgelist in end1 end2 format) */ +/* int *elen (the weights on the edges) */ +/* CCdatagroup *dat (the info to price edges - NULL if no pricing) */ +/* double *xcoord (the x-coordinates for geometric problems - this */ +/* field can be NULL) */ +/* double *ycoord (the y-coordinates) */ +/* int innorm (the NORM for pricing the complete edgeset) */ +/* double *val (returns the optimal weight) */ +/* int *thematching (if non-NULL, then returns the optimal matching */ +/* in end1 end2 value format, where value is 1 if */ +/* edge gets assigned 0.5 and value is 2 if edge */ +/* gets 1.0 - note that the array should be */ +/* allocated by the calling routine, and should */ +/* be 6 * nnodes + 1 long - it is terminated by a */ +/* -1) */ +/* int *thedual (if non-NULL, then returns the optimal dual solution */ +/* with values twice their actual value (so they will */ +/* be integers - the array should be alloced by the */ +/* calling routine, and should be nnodes long) */ +/* int *thebasis (if non-NULL, then returns the edges in the optimal */ +/* basis in end1 end2 format) */ +/* int wantbasis (if nonzero, then the optimal basic solution will */ +/* be found) */ +/* */ +/* */ +/* NOTES: */ +/* Use to find an optimal basis for the initial tsp LP. By changing */ +/* MATCHDEGREE to 1, it should find min-wieght fractional matchings. */ +/* The nodes should be numbered from 0 up to ncount - 1. If dat */ +/* is specified, then the code will use a price-repair loop to solve */ +/* the problem over the complete graph. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "fmatch.h" +#include "kdtree.h" + +#define MATCHDEGREE 2 /* Only set up for 1 or 2? */ +#define MAXWEIGHT 1000000000 + +#define ZERO ((unsigned char) 0) +#define ONE ((unsigned char) 1) +#define TWO ((unsigned char) 2) +#ifdef FALSE +#undef FALSE +#endif +#define FALSE ((unsigned char) 0) +#ifdef TRUE +#undef TRUE +#endif +#define TRUE ((unsigned char) 1) + +#define OTHEREND(e,n) (e->ends[0] == n ? e->ends[1] : e->ends[0]) + +typedef struct edgeptr { + struct edge *this; + struct node *other; + struct edgeptr *next; +} edgeptr; + +typedef struct edge { + struct edge *next; + struct edge *pnext; + struct node *ends[2]; + int weight; + int z; + unsigned char x; + unsigned char basic; +} edge; + +typedef struct shortedge { + struct node *ends[2]; + struct shortedge *next; +} shortedge; + +typedef struct node { + struct node *next; + struct node *pnext; + edgeptr *adj; + edge *parentedge; + int name; + int y; + int label; + struct { + int order; + struct node *next; + struct node **prev; + } sort; + unsigned char flag; + unsigned char matchcnt; +} node; + +static int norm = CC_EUCLIDEAN; + +static node *nodellist = (node *) NULL; +static node **nodenames = (node **) NULL; +static edge *edgellist = (edge *) NULL; +static int nnodes; +static int nedges; +static int PLUS = 1, MINUS = 2; + +static CCdatagroup *gdat = (CCdatagroup *) NULL; + + +#ifdef CC_PROTOTYPE_ANSI + +static void + free_graph (void), + basic_grab_basic (node *n, int parity), + basic_mark_component_as_done (node *n), + basic_expand (node *n, int *hit_odd_circuit), + basic_minalpha (node *n, node **new, int *alpha, int flip_plus_and_minus), + basic_subalpha (node *n, int alpha, int flip_plus_and_minus), + initmat (void), + initlist (node *head, node *tail, node *head2, node *tail2), + expand (node *n, int *found_one), + minalpha (node *n, node **new, int *alpha), + subalpha (node *n, int alpha), + augmentpath (node *n), + augmentpath1 (node *n), + augmentplushalf (node *n, edge *e), + augmentminushalf (node *n, edge *e), + flipcycle (node *n, edge *e, unsigned char v), + augmentpair (node *n, node *n1, edge *e), + setflag (node *n, unsigned char v), + flipseg (node *n, node *n2), + stringup (node *n, node *n1, node *n2, edge *e), + y_quicksort (node **list, int *y, int l, int u), + free_linked_world (void); + +static int + buildgraph (int ncount, int ecount, int *elist, int *elen), + basicrun (void), + basicscan (node *n), + basic_check_scan (node *n), + basicgrow (node *n), + basic_grab_ones (node *n, int parity, edge **odd_circuit), + basic_checkout_basic (node *n, int parity, edge **odd_circuit), + twomatch (void), + chkmat (double *val), + fixmatch (int *radded), + kd_fixmatch (int *radded), + x_fixmatch (int *radded), + junk_fixmatch (int *radded), + checkoutedge (node *n1, node *n2, int *hit), + precheckoutedge (node *n1, node *n2, shortedge **list), + addbadedge (node *n1, node *n2, int w), + augment (node *n); + +static node + *basic_dualchange (node *n), + *dualchange (node *n), + *findflag (node *n), + *findhole (node *n, node *n2); + +static edge + *newedge (node *n1, node *n2), + *findedge (node *n1, node *n2); + + +#else /* CC_PROTOTYPE_ANSI */ + +static void + free_graph (), + basic_grab_basic (), + basic_mark_component_as_done (), + basic_expand (), + basic_minalpha (), + basic_subalpha (), + initmat (), + initlist (), + expand (), + minalpha (), + subalpha (), + augmentpath (), + augmentpath1 (), + augmentplushalf (), + augmentminushalf (), + flipcycle (), + augmentpair (), + setflag (), + flipseg (), + stringup (), + y_quicksort (), + free_linked_world (); + +static int + buildgraph (), + basicrun (), + basicscan (), + basic_check_scan (), + basicgrow (), + basic_grab_ones (), + basic_checkout_basic (), + twomatch (), + chkmat (), + fixmatch (), + kd_fixmatch (), + x_fixmatch (), + junk_fixmatch (), + checkoutedge (), + precheckoutedge (), + addbadedge (), + augment (); + +static node + *basic_dualchange (), + *dualchange (), + *findflag (), + *findhole (); + +static edge + *newedge (), + *findedge (); + + +#endif /* CC_PROTOTYPE_ANSI */ + + +/********** Allocation routines **********/ + + +CC_PTR_ALLOC_ROUTINE (node, nodealloc, node_bigchunklist, node_freelist) +CC_PTR_FREE_ROUTINE (node, nodefree, node_freelist) +CC_PTR_FREE_WORLD_ROUTINE (node, nodefree_world, node_bigchunklist, + node_freelist) +CC_PTR_LEAKS_ROUTINE (node, node_check_leaks, node_bigchunklist, node_freelist, + flag, unsigned char) + +CC_PTR_ALLOC_ROUTINE (edge, edgealloc, edge_bigchunklist, edge_freelist) +CC_PTR_FREE_ROUTINE (edge, edgefree, edge_freelist) +CC_PTR_FREE_WORLD_ROUTINE (edge, edgefree_world, edge_bigchunklist, + edge_freelist) +CC_PTR_LEAKS_ROUTINE (edge, edge_check_leaks, edge_bigchunklist, edge_freelist, + basic, unsigned char) + +CC_PTR_ALLOC_ROUTINE (edgeptr, edgeptralloc, edgeptr_bigchunklist, + edgeptr_freelist) +CC_PTR_FREE_ROUTINE (edgeptr, edgeptrfree, edgeptr_freelist) +CC_PTR_FREE_LIST_ROUTINE (edgeptr, edgeptrfree_list, edgeptrfree) +CC_PTR_FREE_WORLD_ROUTINE (edgeptr, edgeptrfree_world, edgeptr_bigchunklist, + edgeptr_freelist) +CC_PTR_LEAKS_ROUTINE (edgeptr, edgeptr_check_leaks, edgeptr_bigchunklist, + edgeptr_freelist, this, edge *) + +CC_PTR_ALLOC_ROUTINE (shortedge, shortedgealloc, shortedge_bigchunklist, + shortedge_freelist) +CC_PTR_FREE_ROUTINE (shortedge, shortedgefree, shortedge_freelist) +CC_PTR_FREE_WORLD_ROUTINE (shortedge, shortedgefree_world, + shortedge_bigchunklist, shortedge_freelist) +CC_PTR_LEAKS_ROUTINE (shortedge, shortedge_check_leaks, shortedge_bigchunklist, + shortedge_freelist, ends[0], node *) + + +#ifdef CC_PROTOTYPE_ANSI +static void free_linked_world (void) +#else +static void free_linked_world () +#endif +{ + nodefree_world (); + edgefree_world (); + edgeptrfree_world (); + shortedgefree_world (); +} + + +/********** main routines **********/ + + +#ifdef CC_PROTOTYPE_ANSI +static int buildgraph (int ncount, int ecount, int *elist, int *elen) +#else +static int buildgraph (ncount, ecount, elist, elen) +int ncount, ecount, *elist, *elen; +#endif +{ + int i; + node *n; + edge *e; + + nnodes = ncount; + nedges = 0; + + nodenames = CC_SAFE_MALLOC(nnodes, node *); + if (!nodenames) + return 1; + + for (i = 0; i < nnodes; i++) { + n = nodealloc (); + if (!n) + return 1; + n->name = i; + n->adj = (edgeptr *) NULL; + n->next = nodellist; + nodellist = n; + nodenames[i] = n; + } + for (i = 0; i < ecount; i++) { + e = newedge (nodenames[elist[2 * i]], nodenames[elist[(2 * i) + 1]]); + if (!e) + return 1; + e->weight = elen[i] + elen[i]; + } + + if (nedges != ecount) { + fprintf (stderr, "Should have %d edges, not %d\n", ecount, nedges); + free_graph (); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void free_graph (void) +#else +static void free_graph () +#endif +{ + node *n, *nnext; + edge *e, *enext; + + for (n = nodellist; n; n = nnext) { + nnext = n->next; + edgeptrfree_list (n->adj); + nodefree (n); + } + nodellist = (node *) NULL; + for (e = edgellist; e; e = enext) { + enext = e->next; + edgefree (e); + } + edgellist = (edge *) NULL; + CC_IFFREE (nodenames, node *); +} + + +#ifdef CC_PROTOTYPE_ANSI +static edge *newedge (node *n1, node *n2) +#else +static edge *newedge (n1, n2) +node *n1, *n2; +#endif +{ + edge *e; + edgeptr *ep; + + e = edgealloc (); + if (!e) + return (edge *) NULL; + e->ends[0] = n1; + e->ends[1] = n2; + e->next = edgellist; + edgellist = e; + nedges++; + + ep = edgeptralloc (); + if (!ep) { + edgefree (e); + return (edge *) NULL; + } + ep->this = e; + ep->other = n2; + ep->next = n1->adj; + n1->adj = ep; + + ep = edgeptralloc (); + if (!ep) { + edgefree (e); + return (edge *) NULL; + } + ep->this = e; + ep->other = n1; + ep->next = n2->adj; + n2->adj = ep; + + return e; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCfmatch_fractional_2match (int ncount, int ecount, int *elist, int *elen, + CCdatagroup *dat, double *val, int *thematching, int *thedual, + int *thebasis, int wantbasic) +#else +int CCfmatch_fractional_2match (ncount, ecount, elist, elen, dat, val, + thematching, thedual, thebasis, wantbasic) +int ncount, ecount; +int *elist, *elen; +CCdatagroup *dat; +double *val; +int *thematching, *thedual, *thebasis; +int wantbasic; +#endif +{ + int ntotal, nreserve; + double v, vbasic, szeit, tzeit; + int added; + int rval = 0; + + tzeit = CCutil_zeit (); + + if (dat) + norm = dat->norm; + else + norm = 2; + gdat = dat; + if (buildgraph (ncount, ecount, elist, elen)) { + rval = 1; + goto CLEANUP; + } + + initmat (); + if (twomatch ()) { + rval = 1; + goto CLEANUP; + } + if (chkmat (&v)) { + fprintf (stderr, "Chkmat found error in matching\n"); + rval = 1; + goto CLEANUP; + } + printf ("Fractional Matching: %.1f\n", v); + printf ("Initial Running Time: %.2f (seconds)\n", CCutil_zeit () - tzeit); + fflush (stdout); + + if (wantbasic) { + szeit = CCutil_zeit (); + if (basicrun ()) { + fprintf (stderr, "Did not find a basic optimal solution\n"); + rval = 1; + goto CLEANUP; + } + if (chkmat (&vbasic)) { + fprintf (stderr, "Chkmat found error in matching\n"); + rval = 1; + goto CLEANUP; + } + if (vbasic != v) { + fprintf (stderr, "ERROR: Basis routine altered objective\n"); + rval = 1; + goto CLEANUP; + } + printf ("Basis Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + } + + if (dat != (CCdatagroup *) NULL) { + printf ("Price-Repair ...\n"); + fflush (stdout); + szeit = CCutil_zeit (); + if (fixmatch(&added)) { + fprintf (stderr, "fixmatch failed\n"); + rval = 1; + goto CLEANUP; + } + if (chkmat (&v)) { + fprintf (stderr, "Chkmat found error in matching\n"); + rval = 1; + goto CLEANUP; + } + if (wantbasic) { + do { + printf ("Find basis ...\n"); + fflush (stdout); + if (basicrun ()) { + fprintf (stderr, "Did not find a basic solution\n"); + rval = 1; + goto CLEANUP; + } + if (chkmat (&vbasic)) { + fprintf (stderr, "Chkmat found error in matching\n"); + rval = 1; + goto CLEANUP; + } + if (vbasic != v) { + fprintf (stderr, "ERROR: Basis routine altered obj\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Price-repair basic solution ...\n"); + fflush (stdout); + if (fixmatch(&added)) { + fprintf (stderr, "fixmatch failed\n"); + rval = 1; + goto CLEANUP; + } + if (chkmat (&v)) { + fprintf (stderr, "Chkmat found error in matching\n"); + rval = 1; + goto CLEANUP; + } + } while (added); + } + printf ("Running Time for Price-Repair: %.2f\n", + CCutil_zeit () - szeit); + printf ("Fractional Matching on Complete Graph: %.1f\n",v); + fflush (stdout); + } + + *val = v; + + if (thematching != (int *) NULL) { + int k = 0; + edge *e; + for (e = edgellist; e; e = e->next) { + if (e->x != ZERO) { + thematching[k++] = e->ends[0]->name; + thematching[k++] = e->ends[1]->name; + thematching[k++] = (e->x == ONE ? 1 : 2); + } + } + thematching[k] = -1; + } + if (thedual != (int *) NULL) { + int i; + for (i = 0; i < nnodes; i++) + thedual[i] = nodenames[i]->y; + } + if (wantbasic && thebasis != (int *) NULL) { + int k = 0; + edge *e; + for (e = edgellist; e; e = e->next) { + if (e->basic) { + thebasis[k++] = e->ends[0]->name; + thebasis[k++] = e->ends[1]->name; + } + } + } + +CLEANUP: + + free_graph (); + if (node_check_leaks (&ntotal, &nreserve)) { + printf ("Outstanding nodes %d (total %d)\n", + ntotal - nreserve, ntotal); + } + if (edge_check_leaks (&ntotal, &nreserve)) { + printf ("Outstanding edges %d (total %d)\n", + ntotal - nreserve, ntotal); + } + if (edgeptr_check_leaks (&ntotal, &nreserve)) { + printf ("Outstanding edgeptrs %d (total %d)\n", + ntotal - nreserve, ntotal); + } + if (shortedge_check_leaks (&ntotal, &nreserve)) { + printf ("Outstanding shortedges %d (total %d)\n", + ntotal - nreserve, ntotal); + } + free_linked_world (); + + printf ("Total fractional matching time: %.2f (seconds)\n", + CCutil_zeit () - tzeit); + fflush (stdout); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void initmat (void) +#else +static void initmat () +#endif +{ + node *n; + edge *e; + + for (n = nodellist; n; n = n->next) { + n->y = 0; + n->matchcnt = 2 - MATCHDEGREE; + n->parentedge = (edge *) NULL; + n->label = 0; + } + for (e = edgellist; e; e = e->next) { + e->z = 0; + e->x = ZERO; + e->pnext = (edge *) NULL; + } + PLUS = 1; + MINUS = 2; +} + +#ifdef CC_PROTOTYPE_ANSI +static int chkmat (double *val) /* val may be 1/2 integer and big */ +#else +static int chkmat (val) +double *val; +#endif +{ + int k; + double v = 0.0, dualval = 0.0; + node *n; + edge *e; + edgeptr *ep; + + for (n = nodellist; n; n = n->next) { + k = 0; + for (ep = n->adj; ep; ep = ep->next) + k += ep->this->x; + if (k != 2 * MATCHDEGREE) { + fprintf (stderr, "Not a matching, node %d has 2-degree %d\n", + n->name, k); + return 1; + } + dualval += (double) n->y; + } + dualval *= (double) MATCHDEGREE; + for (e = edgellist; e; e = e->next) { + switch (e->x) { + case TWO: + if (e->z < 0 || + e->z != e->ends[0]->y + e->ends[1]->y - e->weight) { + fprintf (stderr, "Error in dual solution - 2\n"); + return 1; + } + v += (double) e->weight; + v += (double) e->weight; + dualval -= (double) e->z; + break; + case ONE: + if (e->z != 0 || + e->ends[0]->y + e->ends[1]->y != e->weight) { + fprintf (stderr, "Error in dual solution - 1\n"); + return 1; + } + v += (double) e->weight; + break; + case ZERO: + if (e->z != 0 || e->ends[0]->y + e->ends[1]->y > e->weight) { + fprintf (stderr, "Error in dual solution - 0\n"); + return 1; + } + break; + default: + fprintf (stderr, "Error in matching values\n"); + return 1; + } + } + v /= 4.0; + dualval /= 2.0; + + if (v != dualval) { + fprintf (stderr, "The primal and dual objective values differ.\n"); + return 1; + } + *val = v; + return 0; +} + + +/********** Core fractional matching routines **********/ + + +#ifdef CC_PROTOTYPE_ANSI +static int twomatch (void) +#else +static int twomatch () +#endif +{ + node *n; + + for (n = nodellist; n; n = n->next) { + while (n->matchcnt != TWO) { + if (augment (n)) { + fprintf (stderr, "augment failed - probably no fmatching\n"); + return 1; + } + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int augment (node *n) +#else +static int augment (n) +node *n; +#endif +{ + node *auglist; + int found_augmenting_path = 0; + + PLUS += 2; + MINUS += 2; + n->label = PLUS; + n->parentedge = (edge *) NULL; + n->matchcnt++; + expand (n, &found_augmenting_path); + if (found_augmenting_path) + return 0; + while ((auglist = dualchange (n)) != (node *) NULL) { + while (auglist) { + expand (auglist, &found_augmenting_path); + if (found_augmenting_path) + return 0; + auglist = auglist->pnext; + } + } + fprintf (stderr, "Error - dual change did not create new edges\n"); + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static void expand (node *n, int *found_one) +#else +static void expand (n, found_one) +node *n; +int *found_one; +#endif +{ + node *n1; + edgeptr *ep; + edge *e; + + if (n->label == PLUS) { + for (ep = n->adj; ep; ep = ep->next) { + if (ep->this->x == ONE) { + augmentplushalf (n, ep->this); + *found_one = 1; + return; + } + } + for (ep = n->adj; ep; ep = ep->next) { + if (ep->this->x == ZERO && + ep->other->y + n->y == ep->this->weight) { + e = ep->this; + n1 = ep->other; + if (n1->label < PLUS) { /* n1 has no label */ + n1->label = MINUS; + n1->parentedge = e; + if (n1->matchcnt != TWO) { + augmentpath (n1); + *found_one = 1; + return; + } + expand (n1, found_one); + if (*found_one) + return; + } else if (n1->label == PLUS) { + augmentpair (n, n1, e); + *found_one = 1; + return; + } + } + } + } else { /* MINUS */ + for (ep = n->adj; ep; ep = ep->next) { + if (ep->this->x == ONE) { + augmentminushalf (n, ep->this); + *found_one = 1; + return; + } + } + for (ep = n->adj; ep; ep = ep->next) { + if (ep->this->x == TWO && ep->this->z == 0) { + e = ep->this; + n1 = ep->other; + if (n1->label < PLUS) { /* n1 has no label */ + n1->label = PLUS; + n1->parentedge = e; + expand (n1, found_one); + if (*found_one) + return; + } else if (n1->label == MINUS) { + augmentpair (n, n1, e); + *found_one = 1; + return; + } + } + } + } + return; +} + +#ifdef CC_PROTOTYPE_ANSI +static node *dualchange (node *n) +#else +static node *dualchange (n) +node *n; +#endif +{ + node *new = (node *) NULL; + int alpha = MAXWEIGHT; + + minalpha (n, &new, &alpha); + if (alpha == MAXWEIGHT) { + fprintf (stderr, "Dual change required, but no candidate edges\n"); + return (node *) NULL; + } + if (alpha & 0x1) { + fprintf (stderr, "Whoops, 2 * alpha = %d, not even\n", alpha); + return (node *) NULL; + } + alpha /= 2; + subalpha (n, alpha); + return new; +} + +#ifdef CC_PROTOTYPE_ANSI +static void minalpha (node *n, node **new, int *alpha) +#else +static void minalpha (n, new, alpha) +node *n; +node **new; +int *alpha; +#endif +{ + int minv = MAXWEIGHT; + int thisv; + node *n1; + edgeptr *ep; + edge *e; + + if (n->label == PLUS) { + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e->x == ZERO) { + n1 = ep->other; + if (n1->label < PLUS) { /* n1 is unlabeled */ + thisv = e->weight - n->y - n1->y; + thisv += thisv; + if (thisv < minv) + minv = thisv; + } else if (n1->label == PLUS) { + thisv = e->weight - n->y - n1->y; + if (thisv < minv) + minv = thisv; + } else { /* n1 has a minus label */ + if (n1->parentedge == e) + minalpha (n1, new, alpha); + } + } + } + } else { /* MINUS case */ + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e->x == TWO) { + n1 = ep->other; + if (n1->label < PLUS) { + thisv = e->z + e->z; + if (thisv < minv) + minv = thisv; + } else if (n1->label == PLUS) { + if (n1->parentedge == e) + minalpha (n1, new, alpha); + } else { /* n1 has a MINUS label */ + thisv = e->z; + if (thisv < minv) + minv = thisv; + } + } + } + } + if (minv < *alpha) { + *new = n; + n->pnext = (node *) NULL; + *alpha = minv; + } else if (minv == *alpha) { + n->pnext = *new; + *new = n; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void subalpha (node *n, int alpha) +#else +static void subalpha (n, alpha) +node *n; +int alpha; +#endif +{ + edgeptr *ep; + edge *e; + node *n1; + + if (n->label == PLUS) { + n->y += alpha; + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e->x == TWO) + e->z += alpha; + else if (e->x == ZERO) { + n1 = ep->other; + if (n1->parentedge == e && n1->label >= PLUS) + subalpha (n1, alpha); + } + } + } else { /* MINUS */ + n->y -= alpha; + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e->x == TWO) { + e->z -= alpha; + n1 = ep->other; + if (n1->parentedge == e && n1->label >= PLUS) + subalpha (n1, alpha); + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void augmentpath (node *n) +#else +static void augmentpath (n) +node *n; +#endif +{ + n->matchcnt++; + augmentpath1 (n); +} + +#ifdef CC_PROTOTYPE_ANSI +static void augmentpath1 (node *n) +#else +static void augmentpath1 (n) +node *n; +#endif +{ + while (n->parentedge != (edge *) NULL) { + n->parentedge->x = TWO - n->parentedge->x; + n = OTHEREND(n->parentedge, n); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void augmentplushalf (node *n, edge *e) +#else +static void augmentplushalf (n, e) +node *n; +edge *e; +#endif +{ + flipcycle (n, e, TWO); + augmentpath1 (n); +} + +#ifdef CC_PROTOTYPE_ANSI +static void augmentminushalf (node *n, edge *e) +#else +static void augmentminushalf (n, e) +node *n; +edge *e; +#endif +{ + flipcycle (n, e, ZERO); + augmentpath1 (n); +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipcycle (node *n, edge *e, unsigned char v) +#else +static void flipcycle (n, e, v) +node *n; +edge *e; +unsigned char v; +#endif +{ + edge *e1; + edge *e2; + + e1 = e->pnext; + if (e1->ends[0] == n || e1->ends[1] == n) + e = e1; + e1 = e; + do { + e1->x = v; + v = TWO - v; + e2 = e1->pnext; + e1->pnext = (edge *) NULL; + e1 = e2; + } while (e1 != e); +} + +#ifdef CC_PROTOTYPE_ANSI +static void augmentpair (node *n, node *n1, edge *e) +#else +static void augmentpair (n, n1, e) +node *n; +node *n1; +edge *e; +#endif +{ + node *n2, *n3; + + setflag (n, FALSE); + setflag (n1, TRUE); + n2 = findflag (n); + if ((n3 = findhole (n, n2)) != (node *) NULL) { + n3->matchcnt++; + flipseg (n, n3); + e->x = TWO - e->x; + augmentpath1 (n1); + return; + } + if ((n3 = findhole (n1, n2)) != (node *) NULL) { + n3->matchcnt++; + flipseg (n1, n3); + e->x = TWO - e->x; + augmentpath1 (n); + return; + } + stringup (n, n1, n2, e); + augmentpath1 (n2); +} + +#ifdef CC_PROTOTYPE_ANSI +static void setflag (node *n, unsigned char v) +#else +static void setflag (n, v) +node *n; +unsigned char v; +#endif +{ + n->flag = v; + while (n->parentedge != (edge *) NULL) { + n = OTHEREND(n->parentedge, n); + n->flag = v; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static node *findflag (node *n) +#else +static node *findflag (n) +node *n; +#endif +{ + while (!n->flag) { + n = OTHEREND(n->parentedge, n); + } + return n; +} + +#ifdef CC_PROTOTYPE_ANSI +static node *findhole (node *n, node *n2) +#else +static node *findhole (n, n2) +node *n; +node *n2; +#endif +{ + while (n != n2) { + if (n->matchcnt != TWO) + return n; + n = OTHEREND(n->parentedge, n); + } + return n2->matchcnt != TWO ? n2 : (node *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipseg (node *n, node *n2) +#else +static void flipseg (n, n2) +node *n; +node *n2; +#endif +{ + while (n != n2) { + n->parentedge->x = TWO - n->parentedge->x; + n = OTHEREND(n->parentedge, n); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void stringup (node *n, node *n1, node *n2, edge *e) +#else +static void stringup (n, n1, n2, e) +node *n; +node *n1; +node *n2; +edge *e; +#endif +{ + edge *preve, *savee; + + preve = e; + while (n != n2) { + n->parentedge->x = ONE; + preve->pnext = n->parentedge; + preve = n->parentedge; + n = OTHEREND(n->parentedge, n); + } + savee = preve; + preve = e; + while (n1 != n2) { + n1->parentedge->x = ONE; + n1->parentedge->pnext = preve; + preve = n1->parentedge; + n1 = OTHEREND(n1->parentedge, n1); + } + savee->pnext = preve; + e->x = ONE; +} + +#ifdef CC_PROTOTYPE_ANSI +static edge *findedge (node *n1, node *n2) +#else +static edge *findedge (n1, n2) +node *n1; +node *n2; +#endif +{ + edgeptr *ep; + + for (ep = n1->adj; ep; ep = ep->next) { + if (ep->other == n2) + return ep->this; + } + return (edge *) NULL; +} + + +/********** Basis finding routines **********/ + + +#ifdef CC_PROTOTYPE_ANSI +static int basicrun (void) +#else +static int basicrun () +#endif +{ + node *n; + edge *e; + + PLUS = 1; + MINUS = 2; + + for (n = nodellist; n; n = n->next) { + n->label = 0; + n->flag = 0; + } + for (e = edgellist; e; e = e->next) + e->basic = 0; + + for (n = nodellist; n; n = n->next) { + if (n->label == 0) { + if (basicscan (n)) + return 1; + } + } + for (n = nodellist; n; n = n->next) { + if (n->flag == 0) { + if (basicgrow (n)) + return 1; + } + } + + for (n = nodellist; n; n = n->next) + n->label = 0; + for (n = nodellist; n; n = n->next) { + if (n->label == 0) { + if (basic_check_scan (n)) + return 1; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int basicscan (node *n) +#else +static int basicscan (n) +node *n; +#endif +{ + edge *odd_circuit = (edge *) NULL; + + PLUS += 2; + MINUS += 2; + n->parentedge = (edge *) NULL; + if (basic_grab_ones (n, 0, &odd_circuit)) + return 1; + if (odd_circuit != (edge *) NULL) { + basic_mark_component_as_done (n); + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int basic_check_scan (node *n) +#else +static int basic_check_scan (n) +node *n; +#endif +{ + edge *odd_circuit = (edge *) NULL; + + PLUS += 2; + MINUS += 2; + n->parentedge = (edge *) NULL; + if (basic_checkout_basic (n, 0, &odd_circuit)) + return 1; + if (odd_circuit == (edge *) NULL) { + printf ("No odd circuit\n"); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int basicgrow (node *n) +#else +static int basicgrow (n) +node *n; +#endif +{ + int hit_odd_circuit = 0; + node *expandlist; + + PLUS += 2; + MINUS += 2; + basic_grab_basic (n, 0); + + n->parentedge = (edge *) NULL; + basic_expand (n, &hit_odd_circuit); + if (hit_odd_circuit) + return 0; + else { + while ((expandlist = basic_dualchange (n)) != (node *) NULL) { + while (expandlist) { + basic_expand (expandlist, &hit_odd_circuit); + if (hit_odd_circuit) + return 0; + expandlist = expandlist->pnext; + } + } + fprintf (stderr, "ERROR: No dual change in basis finding code\n"); + return 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int basic_grab_ones (node *n, int parity, edge **odd_circuit) +#else +static int basic_grab_ones (n, parity, odd_circuit) +node *n; +int parity; +edge **odd_circuit; +#endif +{ + edge *e; + edgeptr *ep; + node *n1; + + n->label = (parity == 0 ? PLUS : MINUS); + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e->x == ONE && e != n->parentedge) { + n1 = ep->other; + if (n1->label == 0) { + n1->parentedge = e; + e->basic = 1; + if (basic_grab_ones (n1, 1 - parity, odd_circuit)) + return 1; + } else if (n1->label == n->label) { + if (*odd_circuit == (edge *) NULL) { + *odd_circuit = e; + e->basic = 1; + } else if (*odd_circuit != e) { + fprintf (stderr, "ERROR: Two odd circuits in 1-graph\n"); + printf ("Circuit forming edges: %d-%d %d-%d\n", + (*odd_circuit)->ends[0]->name, + (*odd_circuit)->ends[1]->name, + e->ends[0]->name, + e->ends[1]->name); + return 1; + } + } else { + fprintf (stderr, "ERROR: Even circuit in 1-graph\n"); + printf ("Circuit forming edge: %d-%d\n", + e->ends[0]->name, + e->ends[1]->name); + return 1; + } + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int basic_checkout_basic (node *n, int parity, edge **odd_circuit) +#else +static int basic_checkout_basic (n, parity, odd_circuit) +node *n; +int parity; +edge **odd_circuit; +#endif +{ + edge *e; + edgeptr *ep; + node *n1; + + n->label = (parity == 0 ? PLUS : MINUS); + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e->basic && e != n->parentedge) { + n1 = ep->other; + if (n1->label == 0) { + n1->parentedge = e; + if (basic_checkout_basic (n1, 1 - parity, odd_circuit)) + return 1; + } else if (n1->label == n->label) { + if (*odd_circuit == (edge *) NULL) { + *odd_circuit = e; + } else if (*odd_circuit != e) { + fprintf (stderr, "ERROR: Two odd circuits in basish\n"); + printf ("Circuit forming edges: %d-%d %d-%d\n", + (*odd_circuit)->ends[0]->name, + (*odd_circuit)->ends[1]->name, + e->ends[0]->name, + e->ends[1]->name); + return 1; + } + } else { + fprintf (stderr, "ERROR: Even circuit in basis\n"); + printf ("Circuit forming edge: %d-%d\n", + e->ends[0]->name, + e->ends[1]->name); + return 1; + } + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void basic_grab_basic (node *n, int parity) +#else +static void basic_grab_basic (n, parity) +node *n; +int parity; +#endif +{ + edgeptr *ep; + + n->label = (parity == 0 ? PLUS : MINUS); + n->flag = 1; + for (ep = n->adj; ep; ep = ep->next) { + if (ep->this->basic) { + if (!ep->other->flag) + basic_grab_basic (ep->other, 1 - parity); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void basic_mark_component_as_done (node *n) +#else +static void basic_mark_component_as_done (n) +node *n; +#endif +{ + edgeptr *ep; + + n->flag = 1; + for (ep = n->adj; ep; ep = ep->next) { + if (ep->this->basic) { + if (!ep->other->flag) + basic_mark_component_as_done (ep->other); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void basic_expand (node *n, int *hit_odd_circuit) +#else +static void basic_expand (n, hit_odd_circuit) +node *n; +int *hit_odd_circuit; +#endif +{ + edge *e; + edgeptr *ep; + node *n1; + + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e != n->parentedge) { + n1 = ep->other; + if (e->basic) { + n1->parentedge = e; + basic_expand (n1, hit_odd_circuit); + if (*hit_odd_circuit) + return; + } else if (n->y + n1->y == e->weight) { + if (n1->label < PLUS) { + e->basic = 1; + if (n1->flag) { + *hit_odd_circuit = 1; + return; + } else { + n1->parentedge = e; + if (n->label == PLUS) + basic_grab_basic (n1, 1); + else + basic_grab_basic (n1, 0); + basic_expand (n1, hit_odd_circuit); + if (*hit_odd_circuit) + return; + } + } else if (n1->label == n->label) { + e->basic = 1; + *hit_odd_circuit = 1; + return; + } + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static node *basic_dualchange (node *n) +#else +static node *basic_dualchange (n) +node *n; +#endif +{ + node *new = (node *) NULL; + int alpha = MAXWEIGHT; + + basic_minalpha (n, &new, &alpha, 0); + if (alpha != MAXWEIGHT) { + alpha /= 2; + basic_subalpha (n, alpha, 0); + } else { + /* reverse sense of PLUS and MINUS */ + basic_minalpha (n, &new, &alpha, 1); + if (alpha == MAXWEIGHT) { + printf ("Basic dual change required, but no candidate edges\n"); + return (node *) NULL; + } + alpha /= 2; + basic_subalpha (n, alpha, 1); + } + return new; +} + +#ifdef CC_PROTOTYPE_ANSI +static void basic_minalpha (node *n, node **new, int *alpha, + int flip_plus_and_minus) +#else +static void basic_minalpha (n, new, alpha, flip_plus_and_minus) +node *n; +node **new; +int *alpha; +int flip_plus_and_minus; +#endif +{ + int minv = MAXWEIGHT; + int thisv; + node *n1; + edge *e; + edgeptr *ep; + + if ((n->label == PLUS && !flip_plus_and_minus) || + (n->label == MINUS && flip_plus_and_minus)) { + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + n1 = ep->other; + if (e->x != TWO) { + if (n1->label < PLUS) { /* n1 is unlabeled */ + thisv = e->weight - n->y - n1->y; + thisv += thisv; + if (thisv < minv) + minv = thisv; + } else if ((n1->label == PLUS && !flip_plus_and_minus) || + (n1->label == MINUS && flip_plus_and_minus)) { + thisv = e->weight - n->y - n1->y; + if (thisv < minv) + minv = thisv; + } else { /* n1 has a minus label */ + if (n1->parentedge == e) + basic_minalpha (n1, new, alpha, flip_plus_and_minus); + } + } else if (e->basic && n1->parentedge == e) { + basic_minalpha (n1, new, alpha, flip_plus_and_minus); + } + } + } else { /* MINUS case */ + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + n1 = ep->other; + if (e->x == TWO) { + if (n1->label < PLUS) { + thisv = e->z + e->z; + if (thisv < minv) + minv = thisv; + } else if ((n1->label == PLUS && !flip_plus_and_minus) || + (n1->label == MINUS && flip_plus_and_minus)) { + if (n1->parentedge == e) + basic_minalpha (n1, new, alpha, flip_plus_and_minus); + } else { /* n1 has a MINUS label */ + thisv = e->z; + if (thisv < minv) + minv = thisv; + } + } else if (e->basic && n1->parentedge == e) { + basic_minalpha (n1, new, alpha, flip_plus_and_minus); + } + } + } + + if (minv < *alpha) { + *new = n; + n->pnext = (node *) NULL; + *alpha = minv; + } else if (minv == *alpha) { + n->pnext = *new; + *new = n; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void basic_subalpha (node *n, int alpha, int flip_plus_and_minus) +#else +static void basic_subalpha (n, alpha, flip_plus_and_minus) +node *n; +int alpha; +int flip_plus_and_minus; +#endif +{ + edge *e; + edgeptr *ep; + + if ((n->label == PLUS && !flip_plus_and_minus) || + (n->label == MINUS && flip_plus_and_minus)) { + n->y += alpha; + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e->x == TWO) + e->z += alpha; + if (e->basic) { + if (ep->other->parentedge == e) + basic_subalpha (ep->other, alpha, flip_plus_and_minus); + } + } + } else { /* MINUS */ + n->y -= alpha; + for (ep = n->adj; ep; ep = ep->next) { + e = ep->this; + if (e->x == TWO) + e->z -= alpha; + if (e->basic) { + if (ep->other->parentedge == e) + basic_subalpha (ep->other, alpha, flip_plus_and_minus); + } + } + } +} + + +/********** Price - Repair routines **********/ + + +#ifdef CC_PROTOTYPE_ANSI +static int checkoutedge (node *n1, node *n2, int *hit) +#else +static int checkoutedge (n1, n2, hit) +node *n1; +node *n2; +int *hit; +#endif +{ + int w, wbar; + edge *e; + + *hit = 0; + w = CCutil_dat_edgelen (n1->name, n2->name, gdat); + w += w; + wbar = w - n1->y - n2->y; + if (wbar < 0) { + if ((e = findedge (n1, n2)) != (edge *) NULL) { + if (e->z != -wbar) { + printf ("Hmmm. edge (%d-%d) has z %d, wbar %d\n", + e->ends[0]->name, e->ends[1]->name, e->z, wbar); + } + } else { + if (addbadedge (n1, n2, w)) { + fprintf (stderr, "addbadedge failed\n"); + return 1; + } + *hit = 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int precheckoutedge (node *n1, node *n2, shortedge **list) +#else +static int precheckoutedge (n1, n2, list) +node *n1; +node *n2; +shortedge **list; +#endif +{ + int w, wbar; + edge *e; + shortedge *s; + + w = CCutil_dat_edgelen (n1->name, n2->name, gdat); + w += w; + wbar = w - n1->y - n2->y; + if (wbar < 0) { + if ((e = findedge (n1, n2)) != (edge *) NULL) { + if (e->z != -wbar) { + printf ("Hmmm. edge (%d-%d) has z %d, wbar %d\n", + e->ends[0]->name, e->ends[1]->name, e->z, wbar); + } + } else { + s = shortedgealloc (); + s->ends[0] = n1; + s->ends[1] = n2; + s->next = *list; + *list = s; + return 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int fixmatch (int *radded) +#else +static int fixmatch (radded) +int *radded; +#endif +{ + if ((gdat->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) + return kd_fixmatch (radded); + else if ((gdat->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) + return x_fixmatch (radded); + else + return junk_fixmatch (radded); +} + +#define NEAR_TRY_NUM 1 /* The number of nearest (wbar) neighbors */ + +#define PULL_DIVISOR 100 /* Do not pull more than nnodes/PULL_DIVISOR. */ +#define PULL_UNIT 100 /* Pull if PULL_UNIT nodes will cut the spread. */ +#define PULL_CUT 2 /* A unit must cut at least spread/PULL_CUT. */ + +#ifdef CC_PROTOTYPE_ANSI +static int kd_fixmatch (int *radded) +#else +static int kd_fixmatch (radded) +int *radded; +#endif +{ + int rval = 0; + int i, j, added, totaladded = 0; + int hit, passcount = 0; + int maxy = -MAXWEIGHT; + int miny = MAXWEIGHT; + double *xcoord = (double *) NULL; + double *ycoord = (double *) NULL; + double *wcoord = (double *) NULL; + CCdatagroup ldat; + node *n; +/* + NEEDED WHEN RADIX SORT IS WORKING + node *ysorted; +*/ + node **heavy, **light, **order = (node **) NULL; + int top, bottom, nlight, nheavy = 0; /* nheavy should be set to 0 */ + int *invnames = (int *) NULL; + double *lbnds = (double *) NULL, *gbnds = (double *) NULL; + + *radded = 0; + + ldat.x = (double *) NULL; + ldat.y = (double *) NULL; + ldat.z = (double *) NULL; + ldat.adj = (int **) NULL; + ldat.norm = gdat->norm; + + + for (n = nodellist; n; n = n->next) { + if (n->y < miny) + miny = n->y; + if (n->y > maxy) + maxy = n->y; + } + printf ("Node weight spread: (%d, %d)\n", miny, maxy); + fflush (stdout); + +/* + THIS CODE CANNOT BE USED UNDER OS2 WITH CURRENT RADIX + for (n = nodellist; n; n = n->next) + n->pnext = n->next; + ysorted = (node *) CCutil_linked_radixsort ((char *) nodellist, + (char *) &(nodellist->pnext), + (char *) &(nodellist->y), sizeof (int)); + + order = CC_SAFE_MALLOC (nnodes, node *); + if (!order) { + rval = 1; + goto CLEANUP; + } + + THIS IS THE CODE WHEN RADIXSORT WORKS WITH NEGATIVES + for (i = 0, n = ysorted; n; i++, n = n->pnext) { + order[i] = n; + } + + INSTEAD, THIS CODE WORKS WITH CURRENT RADIX ON THE RS6000 + for (n = ysorted; n; n = n->pnext) + if (n->y < 0) + break; + for (i = 0; n; n = n->pnext, i++) + order[i] = n; + for (n = ysorted; n && n->y >= 0; n = n->pnext, i++) + order[i] = n; +*/ + + { + /* ONLY HERE UNTIL RADIX WORKS */ + int *y; + + order = CC_SAFE_MALLOC (nnodes, node *); + if (!order) { + rval = 1; + goto CLEANUP; + } + y = CC_SAFE_MALLOC (nnodes, int); + if (!y) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < nnodes; i++) { + order[i] = nodenames[i]; + y[i] = nodenames[i]->y; + } + y_quicksort (order, y, 0, nnodes - 1); + + CC_FREE (y, int); + } + + + { + int new, newspread, newtop, newbottom, spread; + + newtop = top = -1; + newbottom = bottom = nnodes; + nheavy = 0; + spread = maxy - miny; + + do { + new = 0; + while (new < PULL_UNIT && nheavy + new < nnodes/ PULL_DIVISOR) { + if (order[newbottom - 1]->y > -2 * order[newtop + 1]->y) + newbottom--; + else + newtop++; + new++; + } + newspread = order[newbottom - 1]->y - order[newtop + 1]->y; + if (spread - newspread > spread / PULL_CUT) { + spread = newspread; + bottom = newbottom; + top = newtop; + nheavy += new; + } + } while (spread == newspread && nheavy < nnodes / PULL_DIVISOR); + } + + + printf ("Truncated %d nodes to get spread: (%d, %d)\n", + nheavy, order[top + 1]->y, order[bottom - 1]->y); + fflush (stdout); + + + if (nheavy) { + heavy = order; + light = order + nheavy; + nlight = nnodes - nheavy; +/* + THIS IS THE CODE WHEN RADIXSORT WORKS WITH NEGATIVES + for (i = 0, n = ysorted; i <= top; i++, n = n->pnext) { + heavy[i] = n; + } + for (i = 0; i < nlight; i++, n = n->pnext) { + light[i] = n; + } + for (i = top + 1; i < nheavy; i++, n = n->pnext) { + heavy[i] = n; + } +*/ + { + node **temporder = (node **) NULL; + int k; + + temporder = CC_SAFE_MALLOC (nnodes, node *); + if (!temporder) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < nnodes; i++) + temporder[i] = order[i]; + + for (i = 0, k = 0; i <= top; i++) + heavy[i] = temporder[k++]; + for (i = 0; i < nlight; i++) + light[i] = temporder[k++]; + for (i = top + 1; i < nheavy; i++) + heavy[i] = temporder[k++]; + CC_FREE (temporder, node *); + } + + lbnds = CC_SAFE_MALLOC (nheavy, double); + if (!lbnds) { + rval = 1; + goto CLEANUP; + } + gbnds = CC_SAFE_MALLOC (nheavy, double); + if (!gbnds) { + rval = 1; + goto CLEANUP; + } + xcoord = CC_SAFE_MALLOC (nlight, double); + if (!xcoord) { + rval = 1; + goto CLEANUP; + } + ldat.x = xcoord; + ycoord = CC_SAFE_MALLOC (nlight, double); + if (!ycoord) { + rval = 1; + goto CLEANUP; + } + ldat.y = ycoord; + for (i = 0; i < nlight; i++) { + xcoord[i] = gdat->x[light[i]->name]; + ycoord[i] = gdat->y[light[i]->name]; + } + } else { + nlight = nnodes; + light = nodenames; + heavy = (node **) NULL; + xcoord = gdat->x; + ycoord = gdat->y; + ldat.x = xcoord; + ldat.y = ycoord; + CC_FREE (order, node *); + } + + wcoord = CC_SAFE_MALLOC (nlight, double); + if (!wcoord) { + rval = 1; + goto CLEANUP; + } + invnames = CC_SAFE_MALLOC (nnodes, int); + if (!invnames) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < nlight; i++) + invnames[light[i]->name] = i; + for (i = 0; i < nheavy; i++) + invnames[heavy[i]->name] = -i; + + + do { + int nodeschecked = 0; + int saver = 0; + int list[NEAR_TRY_NUM]; + shortedge *s, *snext, *slist = (shortedge *) NULL; + CCkdtree localkt; + added = 0; + maxy = -MAXWEIGHT; + for (i = 0; i < nlight; i++) { + if (light[i]->y > maxy) + maxy = light[i]->y; + } + for (i = 0; i < nlight; i++) + wcoord[i] = ((double) (maxy - light[i]->y)) * 0.5; + if (CCkdtree_build (&localkt, nlight, &ldat, wcoord)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + rval = 1; + goto CLEANUP; + } + for (i = 0; i < nheavy; i++) { /* 1.0 for floats */ + lbnds[i] = gdat->x[heavy[i]->name] - + (((double) (heavy[i]->y)) * 0.5) - 1.0; + gbnds[i] = gdat->x[heavy[i]->name] + + (((double) (heavy[i]->y)) * 0.5) + 1.0; + } + + for (i = 0; i < nlight; i++) { + if (light[i]->label != -1) { + edgeptr *ep; + hit = 0; + for (ep = light[i]->adj; ep; ep = ep->next) { + if (ep->this->x != ZERO && invnames[ep->other->name] >= 0) + CCkdtree_delete (&localkt, invnames[ep->other->name]); + } + nodeschecked++; + if (CCkdtree_node_k_nearest (&localkt, nlight, i, NEAR_TRY_NUM, + &ldat, wcoord, list)) { + fprintf (stderr, "node nearest failed\n"); + CCkdtree_free (&localkt); + rval = 1; + goto CLEANUP; + } + for (j = NEAR_TRY_NUM - 1; j >= 0; j--) { + if (list[j] != -1) + hit += precheckoutedge (light[i], + light[list[j]], &slist); + } + for (j = 0; j < nheavy; j++) { + if (heavy[j]->label == -1) { + if (xcoord[i] + + (((double) light[i]->y) * 0.5) > lbnds[j] && + xcoord[i] - + (((double) light[i]->y) * 0.5) < gbnds[j]) { + hit += precheckoutedge (light[i], heavy[j], &slist); + } else { + saver++; + } + } + } + added += hit; + if (hit == 0) + light[i]->label = -1; + for (ep = light[i]->adj; ep; ep = ep->next) { + if (ep->this->x != ZERO && invnames[ep->other->name] >= 0) + CCkdtree_undelete (&localkt, invnames[ep->other->name]); + } + } + } + for (j = 0; j < nheavy; j++) { + if (heavy[j]->label != -1) { + hit = 0; + nodeschecked++; + for (i = 0; i < nlight; i++) { + if (xcoord[i] + (((double) light[i]->y) * 0.5) > lbnds[j] && + xcoord[i] - (((double) light[i]->y) * 0.5) < gbnds[j]) { + hit += precheckoutedge (light[i], heavy[j], &slist); + } else { + saver++; + } + } + for (i = 0; i < j; i++) { + if (gdat->x[heavy[i]->name] + + (((double) heavy[i]->y) * 0.5) > lbnds[j] && + gdat->x[heavy[i]->name] - + (((double) heavy[i]->y) * 0.5) < gbnds[j]) { + hit += precheckoutedge (heavy[i], heavy[j], &slist); + } + } + for (i = j + 1; i < nheavy; i++) { + if (heavy[i]->label == -1) { + if (gdat->x[heavy[i]->name] + + (((double) heavy[i]->y) * 0.5) > lbnds[j] && + gdat->x[heavy[i]->name] - + (((double) heavy[i]->y) * 0.5) < gbnds[j]) { + hit += precheckoutedge (heavy[i], heavy[j], &slist); + } + } + } + added += hit; + if (hit == 0) + heavy[j]->label = -1; + } + } + + printf ("Need to check %d edges (saved %d checks)\n", added, saver); + fflush (stdout); + CCkdtree_free (&localkt); + + added = 0; + for (s = slist; s; s = snext) { + snext = s->next; + if (checkoutedge (s->ends[0], s->ends[1], &hit)) { + fprintf (stderr, "checkoutedge failed\n"); + rval = 1; + goto CLEANUP; + } + added += hit; + shortedgefree (s); + } + totaladded += added; + printf ("Pass %d: %d edges added (%d total), %d nodes checked\n", + passcount++, added, totaladded, nodeschecked); + fflush (stdout); + } while (added); + *radded = totaladded; + +CLEANUP: + + CC_IFFREE (invnames, int); + CC_IFFREE (wcoord, double); + CC_IFFREE (order, node *); + if (nheavy) { + CC_IFFREE (xcoord, double); + CC_IFFREE (ycoord, double); + CC_IFFREE (lbnds, double); + CC_IFFREE (gbnds, double); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void initlist (node *head, node *tail, node *head2, node *tail2) +#else +static void initlist (head, tail, head2, tail2) +node *head; +node *tail; +node *head2; +node *tail2; +#endif +{ + node *n, *p; + int bound; + double *xcoord = gdat->x; + double scale; + + if (gdat->norm == CC_GEOGRAPHIC) + scale = CC_GEOGRAPHIC_SCALE; + else if (gdat->norm == CC_ATT) + scale = CC_ATT_SCALE; + else + scale = 1.0; + + head->sort.order = -MAXWEIGHT; + tail->sort.order = MAXWEIGHT; + head->sort.next = tail; + head->sort.prev = (node **) NULL; + tail->sort.next = (node *) NULL; + tail->sort.prev = &(head->sort.next); + head2->sort.order = MAXWEIGHT; + tail2->sort.order = -MAXWEIGHT; + head2->sort.next = tail2; + head2->sort.prev = (node **) NULL; + tail2->sort.next = (node *) NULL; + tail2->sort.prev = &(head2->sort.next); + + for (n = nodellist; n; n = n->next) { + bound = (2 * ((int) (scale * xcoord[n->name]))) - n->y; + for (p = head->sort.next; p->sort.order < bound; p = p->sort.next); + n->sort.order = bound; + n->sort.next = p; + n->sort.prev = p->sort.prev; + *(n->sort.prev) = n; + p->sort.prev = &(n->sort.next); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int x_fixmatch (int *radded) +#else +static int x_fixmatch (radded) +int *radded; +#endif +{ + node *n1, *n2; + int i; + int added, hit; + int nodeschecked; + int edgeschecked; + int totaladded = 0; + node high_fakehead, high_faketail, low_fakehead, low_faketail; + int bound; + double *xcoord = gdat->x; + double scale; + + if ((gdat->norm & CC_NORM_BITS) != CC_X_NORM_TYPE && + (gdat->norm & CC_NORM_BITS) != CC_KD_NORM_TYPE) { + fprintf (stderr, "Cannot run x_fixmatch with norm %d\n", gdat->norm); + return 1; + } + + if (gdat->norm == CC_GEOGRAPHIC) + scale = CC_GEOGRAPHIC_SCALE; + else if (gdat->norm == CC_ATT) + scale = CC_ATT_SCALE; + else + scale = 1.0; + + initlist (&high_fakehead, &high_faketail, &low_fakehead, &low_faketail); + + do { + added = 0; + nodeschecked = 0; + edgeschecked = 0; + for (i = 0; i < nnodes; i++) { + n1 = nodenames[i]; + *(n1->sort.prev) = n1->sort.next; + n1->sort.next->sort.prev = n1->sort.prev; + if (n1->label != -1) { + nodeschecked++; + n1->label = -1; + bound = (2 * ((int) (scale * xcoord[n1->name]))) + n1->y + 3; + /* Need the +3 to handle floating point data */ + for (n2 = high_fakehead.sort.next; n2->sort.order < bound; + n2 = n2->sort.next) { + edgeschecked++; + if (checkoutedge (n1, n2, &hit)) { + fprintf (stderr, "checkoutedge failed\n"); + return 1; + } + added += hit; + } + bound = (2 * ((int) (scale * xcoord[n1->name]))) - n1->y - 3; + for (n2 = low_fakehead.sort.next; n2->sort.order > bound; + n2 = n2->sort.next) { + edgeschecked++; + if (checkoutedge (n1, n2, &hit)) { + fprintf (stderr, "checkoutedge failed\n"); + return 1; + } + added += hit; + } + } + bound = (2 * ((int) (scale * xcoord[n1->name]))) + n1->y; + for (n2 = low_fakehead.sort.next; n2->sort.order > bound; + n2 = n2->sort.next); + n1->sort.order = bound; + n1->sort.next = n2; + n1->sort.prev = n2->sort.prev; + *(n1->sort.prev) = n1; + n2->sort.prev = &n1->sort.next; + } + totaladded += added; + printf ("Forward pass completed, %d nodes checked, %d edges checked\n", + nodeschecked, edgeschecked); + printf (" %d edges added, total %d edges added\n", + added, totaladded); + if (added == 0) + break; + added = 0; + nodeschecked = 0; + edgeschecked = 0; + for (i = nnodes - 1; i >= 0; i--) { + n1 = nodenames[i]; + *(n1->sort.prev) = n1->sort.next; + n1->sort.next->sort.prev = n1->sort.prev; + if (n1->label != -1) { + nodeschecked++; + n1->label = -1; + bound = (2 * ((int) (scale * xcoord[n1->name]))) + n1->y + 3; + for (n2 = high_fakehead.sort.next; n2->sort.order < bound; + n2 = n2->sort.next) { + edgeschecked++; + if (checkoutedge (n1, n2, &hit)) { + fprintf (stderr, "checkoutedge failed\n"); + return 1; + } + added += hit; + } + bound = (2 * ((int) (scale * xcoord[n1->name]))) - n1->y - 3; + for (n2 = low_fakehead.sort.next; n2->sort.order > bound; + n2 = n2->sort.next) { + edgeschecked++; + if (checkoutedge (n1, n2, &hit)) { + fprintf (stderr, "checkoutedge failed\n"); + return 1; + } + added += hit; + } + } + bound = (2 * ((int) (scale * xcoord[n1->name]))) - n1->y; + for (n2 = high_fakehead.sort.next; n2->sort.order < bound; + n2 = n2->sort.next); + n1->sort.order = bound; + n1->sort.next = n2; + n1->sort.prev = n2->sort.prev; + *(n1->sort.prev) = n1; + n2->sort.prev = &n1->sort.next; + } + totaladded += added; + printf ("Backward pass completed, %d nodes checked, %d edges checked\n", + nodeschecked, edgeschecked); + printf (" %d edges added, total %d edges added\n", + added, totaladded); + } while (added); + *radded = totaladded; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int junk_fixmatch (int *radded) +#else +static int junk_fixmatch (radded) +int *radded; +#endif +{ + int added, hit, totaladded = 0; + node *n1, *n2; + + *radded = 0; + + do { + added = 0; + for (n1 = nodellist; n1; n1 = n1->next) { + for (n2 = n1->next; n2; n2 = n2->next) { + if (checkoutedge (n1, n2, &hit)) { + fprintf (stderr, "checkoutedge failed\n"); + return 1; + } + added += hit; + } + } + totaladded += added; + printf ("Pass completed: %d edges added, total %d edges added\n", + added, totaladded); + fflush (stdout); + } while (added); + + *radded = totaladded; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int addbadedge (node *n1, node *n2, int w) +#else +static int addbadedge (n1, n2, w) +node *n1; +node *n2; +int w; +#endif +{ + int wbar = -(w - n1->y - n2->y); + edgeptr *ep; + edge *newe; + node *other1 = 0, *other2 = 0; + + for (ep = n1->adj; ep; ep = ep->next) { + switch (ep->this->x) { + case ONE: + flipcycle (n1, ep->this, ZERO); + n1->matchcnt--; + break; + case TWO: + if ((ep->this->z -= wbar) < 0) { + ep->this->z = 0; + ep->this->x = ZERO; + n1->matchcnt--; + ep->other->matchcnt--; + other2 = other1; + other1 = ep->other; + } + break; + } + } + n1->y -= wbar; + newe = newedge (n1, n2); + if (!newe) + return 1; + newe->weight = w; + newe->z = 0; + newe->x = ZERO; + newe->pnext = (edge *) NULL; + while (n1->matchcnt != TWO) + augment (n1); + if (other1) { + while (other1->matchcnt != TWO) + augment (other1); + } + if (other2) { + while (other2->matchcnt != TWO) + augment (other2); + } + return 0; +} + +#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) + +#ifdef CC_PROTOTYPE_ANSI +static void y_quicksort (node **list, int *y, int l, int u) +#else +static void y_quicksort (list, y, l, u) +node **list; +int *y; +int l, u; +#endif +{ + int i, j, t; + int itemp; + node *ntemp; + + if (l >= u) + return; + + SWAP (y[l], y[(l+u)/2], itemp); + SWAP (list[l], list[(l+u)/2], ntemp); + + i = l; + j = u + 1; + t = y[l]; + + while (1) { + do i++; while (i <= u && y[i] < t); + do j--; while (y[j] > t); + if (j < i) break; + SWAP (y[i], y[j], itemp); + SWAP (list[i], list[j], ntemp); + } + SWAP (y[l], y[j], itemp); + SWAP (list[l], list[j], ntemp); + y_quicksort (list, y, l, j - 1); + y_quicksort (list, y, i, u); +} diff --git a/contrib/blossom/concorde97/INCLUDE/Makefile.common b/contrib/blossom/concorde97/INCLUDE/Makefile.common new file mode 100644 index 0000000000000000000000000000000000000000..62562580a63e98c39200dda34589833122bc16aa --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/Makefile.common @@ -0,0 +1,77 @@ +# +# rules common to most of the makefiles +# + +OBJS=$(LIBSRCS:.c=.$o) + +ifneq ($(OBJS),) +$(LIB): $(LIB)($(OBJS)) + $(RANLIB) $(LIB) +endif + +ifneq ($(OBJS),) +$(ROOT)/concorde.a: $(ROOT)/concorde.a($(OBJS)) + $(RANLIB) $(ROOT)/concorde.a +#else +$(ROOT)/concorde.a: +endif + +depend: + mv Makefile Makefile.orig + sed -e '/^# DO NOT DELETE THIS LINE -- make depend depends on it.$$/,$$d' < Makefile.orig > Makefile + echo "# DO NOT DELETE THIS LINE -- make depend depends on it." >> Makefile + echo >> Makefile + echo "I=$$(INCLUDE)" >> Makefile + echo >> Makefile + gcc -DSYSGNUSOLARIS -I$(ROOT)/INCLUDE $(CPLEX_INCFLAG) -MM \ + `echo $(ALLSRCS) | tr ' ' '\012' | sort -u` | \ + sed -e 's,../INCLUDE,$$(I),g' -e 's,\.o,.$$o,g' | \ + awk '{for(i=1;i<=NF;i++){if($$i=="\\"){next;}if(ecnt==0){ \ + printf("%-12s ",$$i);}else if(ecnt==1){printf("%-10s ",$$i);} \ + else{if(ecnt>=5&&ecnt%4==1)printf("\\\n "); \ + if(substr($$i,1,5)=="$$(I)/")printf("%-15s ",$$i);else \ + printf (" %-10s ",$$i);}ecnt++;}printf("\n");ecnt=0;}' >> Makefile + +.PHONY: concorde.a +concorde.a: $(ROOT)/concorde.a + +.PHONY: $(ROOT)/BIGGUY/bigguy.a +$(ROOT)/BIGGUY/bigguy.a: + $(MAKE) -C $(ROOT)/BIGGUY bigguy.a + +.PHONY: $(ROOT)/CUT/cut.a +$(ROOT)/CUT/cut.a: + $(MAKE) -C $(ROOT)/CUT cut.a + +.PHONY: $(ROOT)/EDGEGEN/edgegen.a +$(ROOT)/EDGEGEN/edgegen.a: + $(MAKE) -C $(ROOT)/EDGEGEN edgegen.a + +.PHONY: $(ROOT)/FMATCH/fmatch.a +$(ROOT)/FMATCH/fmatch.a: + $(MAKE) -C $(ROOT)/FMATCH fmatch.a + +.PHONY: $(ROOT)/KDTREE/kdtree.a +$(ROOT)/KDTREE/kdtree.a: + $(MAKE) -C $(ROOT)/KDTREE kdtree.a + +.PHONY: $(ROOT)/LINKERN/linkern.a +$(ROOT)/LINKERN/linkern.a: + $(MAKE) -C $(ROOT)/LINKERN linkern.a + +.PHONY: $(ROOT)/LP/lp.a +$(ROOT)/LP/lp.a: + $(MAKE) -C $(ROOT)/LP lp.a + +.PHONY: $(ROOT)/TSP/tsp.a +$(ROOT)/TSP/tsp.a: + $(MAKE) -C $(ROOT)/TSP tsp.a + +.PHONY: $(ROOT)/UTIL/util.a +$(ROOT)/UTIL/util.a: + $(MAKE) -C $(ROOT)/UTIL util.a + +.PHONY: $(ROOT)/XSTUFF/Xstuff.a +$(ROOT)/XSTUFF/Xstuff.a: + $(MAKE) -C $(ROOT)/XSTUFF Xstuff.a + diff --git a/contrib/blossom/concorde97/INCLUDE/Xstuff.h b/contrib/blossom/concorde97/INCLUDE/Xstuff.h new file mode 100644 index 0000000000000000000000000000000000000000..e8c615030e30ae2db0d65296fd596b98b6aad085 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/Xstuff.h @@ -0,0 +1,35 @@ +#ifndef __XSTUFF_H +#define __XSTUFF_H + +#ifdef CC_PROTOTYPE_ANSI + +int + Xfastcuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xslowcuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xfastsubtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xexactsubtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xcliquetrees (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xconsecutiveones (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x, CCtsp_lpcuts *pool), + Xnecklacecuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x, CCtsp_lpcuts *pool); + +#else + +int + Xfastcuts (), + Xslowcuts (), + Xfastsubtours (), + Xexactsubtours (), + Xcliquetrees (), + Xconsecutiveones (), + Xnecklacecuts (); + +#endif + +#endif /* __XSTUFF_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/bigguy.h b/contrib/blossom/concorde97/INCLUDE/bigguy.h new file mode 100644 index 0000000000000000000000000000000000000000..701acb98a3cd3c8c25778f084a898b5033c790a5 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/bigguy.h @@ -0,0 +1,93 @@ +#ifndef __BIGGUY_H +#define __BIGGUY_H + +#include "util.h" + +#ifdef CC_BIGGUY_LONGLONG + +typedef long long CCbigguy; + +#define CCbigguy_FRACBITS 32 +#define CCbigguy_DUALSCALE (((CCbigguy) 1) << CCbigguy_FRACBITS) +#define CCbigguy_FRACPART(x) ((x) & (CCbigguy_DUALSCALE-1)) +#define CCbigguy_MAXBIGGUY (((((CCbigguy) 1) << 62) - 1) + \ + (((CCbigguy) 1) << 62)) +#define CCbigguy_MINBIGGUY (-CCbigguy_MAXBIGGUY) +#define CCbigguy_bigguytod(x) (((double) (x)) / ((double) CCbigguy_DUALSCALE)) +#define CCbigguy_itobigguy(d) ((CCbigguy) ((d) * (double) CCbigguy_DUALSCALE)) +#define CCbigguy_ceil(x) (CCbigguy_FRACPART(x) ? \ + ((x) + (CCbigguy_DUALSCALE - CCbigguy_FRACPART(x))) : (x)) +#define CCbigguy_cmp(x,y) (((x) < (y)) ? -1 : ((x) > (y)) ? 1 : 0) +#define CCbigguy_ZERO ((CCbigguy) 0) +#define CCbigguy_ONE ((CCbigguy) CCbigguy_DUALSCALE) +#define CCbigguy_addmult(x,y,m) ((*x) += (y)*(m)) +#define CCbigguy_dtobigguy(d) ((CCbigguy) ((d) * (double) CCbigguy_DUALSCALE)) + +#else /* CC_BIGGUY_LONGLONG */ + +typedef struct CCbigguy { + unsigned short ihi; + unsigned short ilo; + unsigned short fhi; + unsigned short flo; +} CCbigguy; + +extern const CCbigguy CCbigguy_MINBIGGUY; +extern const CCbigguy CCbigguy_MAXBIGGUY; +extern const CCbigguy CCbigguy_ZERO; +extern const CCbigguy CCbigguy_ONE; + +#ifdef CC_PROTOTYPE_ANSI + + void + CCbigguy_addmult (CCbigguy *x, CCbigguy y, short m); + + int + CCbigguy_cmp (CCbigguy x, CCbigguy y); + + double + CCbigguy_bigguytod (CCbigguy x); + + CCbigguy + CCbigguy_itobigguy (int d), + CCbigguy_dtobigguy (double d), + CCbigguy_ceil (CCbigguy x); + +#else + + void + CCbigguy_addmult (); + + int + CCbigguy_cmp (); + + double + CCbigguy_bigguytod (); + + CCbigguy + CCbigguy_itobigguy (), + CCbigguy_dtobigguy (), + CCbigguy_ceil (); + +#endif + +#endif /* CC_BIGGUY_LONGLONG */ + +#define CCbigguy_add(x,y) (CCbigguy_addmult(x,y,1)) +#define CCbigguy_sub(x,y) (CCbigguy_addmult(x,y,-1)) + +#ifdef CC_PROTOTYPE_ANSI + +int + CCbigguy_swrite (CC_SFILE *f, CCbigguy x), + CCbigguy_sread (CC_SFILE *f, CCbigguy *x); + +#else + +int + CCbigguy_swrite (), + CCbigguy_sread (); + +#endif + +#endif /* __BIGGUY_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/cut.h b/contrib/blossom/concorde97/INCLUDE/cut.h new file mode 100644 index 0000000000000000000000000000000000000000..1486577b948b1e1c85c26f4779ce83df1bae86bd --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/cut.h @@ -0,0 +1,157 @@ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* PROTOTYPES FOR FILES IN CUT */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + + +#ifndef __CUT_H +#define __CUT_H + + +#define CC_MINCUT_BIGDOUBLE (100000000000.0) +#define CC_MINCUT_ONE_EPSILON (0.000001) + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCcut_mincut (int ncount, int ecount, int *elist, double *dlen, + double *valval, int **cut, int *cutcount), + CCcut_violated_cuts (int ncount, int ecount, int *elist, double *dlen, + double cutoff, int (*doit_fn) (double, int, int *, void *), + void *pass_param), + CCcut_mincut_st (int ncount, int ecount, int *elist, double *ecap, + int s, int t, double *value, int **cut, int *cutcount), + CCcut_linsub (int ncount, int ecount, int *elist, double *x, double cutoff, + int (*doit_fn) (double, int, int, void *), void *pass_param), + CCcut_connect_components (int ncount, int ecount, int *elist, double *x, + int *ncomp, int **compscount, int **comps); + +#else + +int + CCcut_mincut (), + CCcut_violated_cuts (), + CCcut_mincut_st (), + CCcut_linsub (), + CCcut_connect_components (); + +#endif + + + +/***************************************************************************/ +/* */ +/* shrink.c */ +/* */ +/***************************************************************************/ + +typedef struct CC_SRKnode { + struct CC_SRKedge *adj; + struct CC_SRKnode *next; + struct CC_SRKnode *prev; + struct CC_SRKnode *members; + struct CC_SRKnode *parent; + struct CC_SRKnode *qnext; + double prweight; + double weight; + int num; + int newnum; + int onecnt; + int onqueue; +} CC_SRKnode; + +typedef struct CC_SRKedge { + struct CC_SRKnode *end; + struct CC_SRKedge *other; + struct CC_SRKedge *next; + struct CC_SRKedge *prev; + double weight; +} CC_SRKedge; + +typedef struct CC_SRKgraph { + struct CC_SRKnode *nodespace; + struct CC_SRKedge *edgespace; + struct CC_SRKnode *head; + struct CC_SRKedge **hit; + int original_ncount; + int original_ecount; +} CC_SRKgraph; + +typedef struct CC_SRKexpinfo { + int *members; + int *memindex; +} CC_SRKexpinfo; + +typedef struct CC_SRKcallback { + double cutoff; + void *pass_param; +#ifdef CC_PROTOTYPE_ANSI + int (*doit_fn) (double, int, int *, void *); +#else + int (*doit_fn) (); +#endif +} CC_SRKcallback; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCcut_SRK_identify_paths (CC_SRKgraph *G, int *newcount, int onecnt_okay), + CCcut_SRK_identify_paths_to_edges (CC_SRKgraph *G, int *newcount, + int onecnt_okay), + CCcut_SRK_identify_ones (CC_SRKgraph *G, int *count, double epsilon), + CCcut_SRK_identify_one_triangles (CC_SRKgraph *G, int *count, + CC_SRKnode *qstart, double epsilon), + CCcut_SRK_identify_nodes (CC_SRKgraph *G, CC_SRKnode *n, CC_SRKnode *m), + CCcut_SRK_init_graph (CC_SRKgraph *G), + CCcut_SRK_free_graph (CC_SRKgraph *G), + CCcut_SRK_init_expinfo (CC_SRKexpinfo *expand), + CCcut_SRK_free_expinfo (CC_SRKexpinfo *expand), + CCcut_SRK_init_callback (CC_SRKcallback *cb); + +int + CCcut_SRK_buildgraph (CC_SRKgraph *G, int ncount, int ecount, int *elist, + double *dlen), + CCcut_SRK_subtour_shrink (CC_SRKgraph *G, double *minval, double epsilon, + CC_SRKcallback *cb, int **cut, int *cutcount), + CCcut_SRK_identify_pr_edges (CC_SRKgraph *G, double *minval, int *count, + CC_SRKnode *qstart, double epsilon, CC_SRKcallback *cb, int **cut, + int *cutcount), + CCcut_SRK_defluff (CC_SRKgraph *G), + CCcut_SRK_grab_edges (CC_SRKgraph *G, int *oncount, int *oecount, + int **olist, double **olen, CC_SRKexpinfo *expand), + CCcut_SRK_grab_nodes (CC_SRKgraph *G, CC_SRKexpinfo *expand), + CCcut_SRK_trivial (int ncount, CC_SRKexpinfo *expand), + CCcut_SRK_expand (CC_SRKexpinfo *expand, int *arr, int size, int **pnewarr, + int *pnewsize); + +#else + +void + CCcut_SRK_identify_paths (), + CCcut_SRK_identify_paths_to_edges (), + CCcut_SRK_identify_ones (), + CCcut_SRK_identify_one_triangles (), + CCcut_SRK_identify_nodes (), + CCcut_SRK_init_graph (), + CCcut_SRK_free_graph (), + CCcut_SRK_init_expinfo (), + CCcut_SRK_free_expinfo (), + CCcut_SRK_init_callback (); + +int + CCcut_SRK_buildgraph (), + CCcut_SRK_subtour_shrink (), + CCcut_SRK_identify_pr_edges (), + CCcut_SRK_defluff (), + CCcut_SRK_grab_edges (), + CCcut_SRK_grab_nodes (), + CCcut_SRK_trivial (), + CCcut_SRK_expand (); + +#endif + +#endif /* __CUT_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/edgegen.h b/contrib/blossom/concorde97/INCLUDE/edgegen.h new file mode 100644 index 0000000000000000000000000000000000000000..110d25f3f3467356f0b966db55742500b99740f9 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/edgegen.h @@ -0,0 +1,144 @@ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* PROTOTYPES FOR FILES IN EDGEGEN */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + +#ifndef __EDGEGEN_H +#define __EDGEGEN_H + +#include "util.h" + + +/***************************************************************************/ +/* */ +/* edgegen.c */ +/* */ +/***************************************************************************/ + +typedef struct CCedgegengroup { + struct { + int count; + int quadnearest; + int nearest; + int nearest_start; + int greedy_start; + int random_start; + int nkicks; + } linkern; + + struct { + int twoopt_count; + int twoopt5_count; + int threeopt_count; + int greedy; + int nearest_count; + int random_count; + } tour; + + struct { + int wantit; + int basic; + int priced; + } f2match; + + struct { + int number; + int basic; + int priced; + } f2match_nearest; + + int nearest; + int quadnearest; + int want_tree; + int nearest_twomatch_count; + int delaunay; + int mlinkern; +} CCedgegengroup; + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCedgegen_read (char *egname, CCedgegengroup *plan), + CCedgegen_edges (CCedgegengroup *plan, int ncount, CCdatagroup *dat, + double *wcoord, int *ecount, int **elist); +void + CCedgegen_init_edgegengroup (CCedgegengroup *plan); + +#else + +int + CCedgegen_read (), + CCedgegen_edges (); +void + CCedgegen_init_edgegengroup (); + +#endif + + + +/***************************************************************************/ +/* */ +/* xnear.c */ +/* */ +/***************************************************************************/ + +typedef struct CCxnear { + struct CCdatagroup dat; + double *w; + int *nodenames; + int *invnames; +} CCxnear; + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCedgegen_x_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist), + CCedgegen_x_quadrant_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist), + CCedgegen_x_node_k_nearest (CCxnear *xn, int n, int nearnum, int ncount, + int *list), + CCedgegen_x_node_quadrant_k_nearest (CCxnear *xn, int n, int nearnum, + int ncount, int *list), + CCedgegen_x_node_nearest (CCxnear *xn, int ncount, int ni, char *marks), + CCedgegen_x_nearest_neighbor_tour (int ncount, int start, CCdatagroup *dat, + int *outcycle, double *val), + CCedgegen_junk_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist), + CCedgegen_junk_node_k_nearest (CCdatagroup *dat, double *wcoord, int n, + int nearnum, int ncount, int *list), + CCedgegen_junk_node_nearest (CCdatagroup *dat, double *wcoord, int ncount, + int n, char *marks), + CCedgegen_junk_nearest_neighbor_tour (int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val), + CCedgegen_xnear_build (int ncount, CCdatagroup *dat, double *wcoord, + CCxnear *xn); + +void + CCedgegen_xnear_free (int ncount, CCxnear *xn); + +#else + +int + CCedgegen_x_k_nearest (), + CCedgegen_x_quadrant_k_nearest (), + CCedgegen_x_node_k_nearest (), + CCedgegen_x_node_quadrant_k_nearest (), + CCedgegen_x_node_nearest (), + CCedgegen_x_nearest_neighbor_tour (), + CCedgegen_junk_k_nearest (), + CCedgegen_junk_node_k_nearest (), + CCedgegen_junk_node_nearest (), + CCedgegen_junk_nearest_neighbor_tour (), + CCedgegen_xnear_build (); +void + CCedgegen_xnear_free (); + +#endif + +#endif /* __EDGEGEN_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/fmatch.h b/contrib/blossom/concorde97/INCLUDE/fmatch.h new file mode 100644 index 0000000000000000000000000000000000000000..cc708e7d9f79fc6a61e416d4fd446dce4e1e2209 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/fmatch.h @@ -0,0 +1,20 @@ +#ifndef __FMATCH_H +#define __FMATCH_H + +#include "util.h" + +#ifdef CC_PROTOTYPE_ANSI + +int + CCfmatch_fractional_2match (int ncount, int ecount, int *elist, int *elen, + CCdatagroup *dat, double *val, int *thematching, int *thedual, + int *thebasis, int wantbasic); + +#else + +int + CCfmatch_fractional_2match (); + +#endif + +#endif /* __FMATCH_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/kdtree.h b/contrib/blossom/concorde97/INCLUDE/kdtree.h new file mode 100644 index 0000000000000000000000000000000000000000..a940ea5a20fa49c48abe50453c3dae525f99dd09 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/kdtree.h @@ -0,0 +1,104 @@ +#ifndef __KDTREE_H +#define __KDTREE_H + +#include "util.h" + +typedef struct CCkdnode { + double cutval; + struct CCkdnode *loson; + struct CCkdnode *hison; + struct CCkdnode *father; + struct CCkdnode *next; + struct CCkdbnds *bnds; + int lopt; + int hipt; + char bucket; + char empty; + char cutdim; +} CCkdnode; + +typedef struct CCkdtree { + CCkdnode *root; + CCkdnode **bucketptr; + int *perm; +} CCkdtree; + +typedef struct CCkdbnds { + double x[2]; + double y[2]; + struct CCkdbnds *next; +} CCkdbnds; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCkdtree_free (CCkdtree *kt), + CCkdtree_delete (CCkdtree *kt, int k), + CCkdtree_delete_all (CCkdtree *kt, int ncount), + CCkdtree_undelete (CCkdtree *kt, int k), + CCkdtree_undelete_all (CCkdtree *kt, int ncount); +int + CCkdtree_build (CCkdtree *kt, int ncount, CCdatagroup *dat, double *wcoord), + CCkdtree_k_nearest (CCkdtree *kt, int ncount, int k, CCdatagroup *dat, + double *wcoord, int wantlist, int *ocount, int **olist), + CCkdtree_quadrant_k_nearest (CCkdtree *kt, int ncount, int k, + CCdatagroup *dat, double *wcoord, int wantlist, int *ocount, + int **olist), + CCkdtree_node_k_nearest (CCkdtree *kt, int ncount, int n, int k, + CCdatagroup *dat, double *wcoord, int *list), + CCkdtree_node_quadrant_k_nearest (CCkdtree *kt, int ncount, int n, int k, + CCdatagroup *dat, double *wcoord, int *list), + CCkdtree_node_nearest (CCkdtree *kt, int n, CCdatagroup *dat, + double *wcoord), + CCkdtree_fixed_radius_nearest (CCkdtree *kt, CCdatagroup *dat, + double *wcoord, int n, double rad, + int (*doit_fn) (int, int, void *), void *pass_param), + CCkdtree_nearest_neighbor_tour (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val), + CCkdtree_nearest_neighbor_2match (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outmatch, double *val), + CCkdtree_prim_spanningtree (CCkdtree *kt, int ncount, CCdatagroup *dat, + double *wcoord, int *outtree, double *val), + CCkdtree_greedy_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val), + CCkdtree_far_add_tour (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val), + CCkdtree_qboruvka_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val), + CCkdtree_boruvka_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val), + CCkdtree_twoopt_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *incycle, int *outcycle, double *val, + int in_run_two_and_a_half_opt, int run_silently), + CCkdtree_3opt_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *incycle, int *outcycle, double *val, int run_silently); + +#else + +void + CCkdtree_free (), + CCkdtree_delete (), + CCkdtree_delete_all (), + CCkdtree_undelete (), + CCkdtree_undelete_all (); +int + CCkdtree_build (), + CCkdtree_k_nearest (), + CCkdtree_quadrant_k_nearest (), + CCkdtree_node_k_nearest (), + CCkdtree_node_quadrant_k_nearest (), + CCkdtree_node_nearest (), + CCkdtree_fixed_radius_nearest (), + CCkdtree_nearest_neighbor_tour (), + CCkdtree_nearest_neighbor_2match (), + CCkdtree_prim_spanningtree (), + CCkdtree_greedy_tour (), + CCkdtree_far_add_tour (), + CCkdtree_qboruvka_tour (), + CCkdtree_boruvka_tour (), + CCkdtree_twoopt_tour (), + CCkdtree_3opt_tour (); +#endif + +#endif /* __KDTREE_H */ + diff --git a/contrib/blossom/concorde97/INCLUDE/linkern.h b/contrib/blossom/concorde97/INCLUDE/linkern.h new file mode 100644 index 0000000000000000000000000000000000000000..fc3b6c2d33f5d13e10a20fe7f7918b36ed1d1864 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/linkern.h @@ -0,0 +1,124 @@ +#ifndef __LINKERN_H +#define __LINKERN_H + +#include "util.h" + +#ifdef CC_PROTOTYPE_ANSI + +int + CClinkern_tour (int ncount, CCdatagroup *dat, int ecount, + int *elist, int stallcount, int repeatcount, int *incycle, + int *outcycle, double *val, int run_silently, double time_bound, + double length_bound, char *saveit_name); + +#else + +int + CClinkern_tour (); + +#endif + + + +/***************************************************************************/ +/* */ +/* Must define exactly one of: */ +/* */ +/* CC_LINKED_LIST_FLIPPER (flip_llX) */ +/* CC_ARRAY_FLIPPER (flip_ary) */ +/* CC_TWO_LEVEL_FLIPPER (flip_two) */ +/* CC_SEGMENTS_FLIPPER (flip_sg1) */ +/* CC_NO_UNDO_SEGMENTS_FLIPPER (flip_sg2) */ +/* CC_FULL_SEGMENTS_FLIPPER (flip_sg3) */ +/* CC_SPLAY_FLIPPER (flip_sp2) */ +/* CC_BTREE_FLIPPER (flip_btr) */ +/* */ +/* NOTE: If MARK_NEIGHBORS is not defined in linkern.c, then */ +/* NO_UNDO_SEGMENTS may follow a different improving sequence then */ +/* the other flippers, since the next and prevs in turn () will be */ +/* with respect to an out-of-date-tour. */ +/* */ +/***************************************************************************/ + + +#define CC_TWO_LEVEL_FLIPPER +/* #define BTREE_FLIPPER */ + +#ifdef CC_LINKED_LIST_FLIPPER +#define CC_EXTRA_INFO_FLIP +#endif + +#ifdef CC_ARRAY_FLIPPER +#define CC_USE_FLIP_CLEANING +#endif + +#ifdef CC_TWO_LEVEL_FLIPPER +#define CC_USE_FLIP_CLEANING +#endif + +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER +#define CC_USE_FLIP_CLEANING +#define CC_USE_QUICK_FLIPS +#endif + +#ifdef CC_FULL_SEGMENTS_FLIPPER +#define CC_USE_FLIP_CLEANING +#endif + +#ifdef CC_SPLAY_FLIPPER +#define CC_USE_FLIP_CLEANING +#define CC_EXTRA_INFO_FLIP +#endif + +#ifdef CC_BTREE_FLIPPER +#define CC_USE_FLIP_CLEANING +#define CC_EXTRA_INFO_FLIP +#endif + +#ifdef CC_PROTOTYPE_ANSI + +int + CClinkern_flipper_init (int ncount, int *cyc), + CClinkern_flipper_reset_perm (int ncount), + CClinkern_flipper_reset_temp (int ncount), + CClinkern_flipper_next (int x), + CClinkern_flipper_prev (int x), + CClinkern_flipper_cycle (int *x), + CClinkern_flipper_sequence_burst (int x, int y, int z), + CClinkern_flipper_sequence (int x, int y, int z); + +void +#ifdef CC_EXTRA_INFO_FLIP + CClinkern_flipper_flip (int xprev, int x, int y, int ynext), +#else + CClinkern_flipper_flip (int x, int y), +#endif + CClinkern_flipper_flip_quick (int x, int y), + CClinkern_flipper_flip_perm (int x, int y), + CClinkern_flipper_sequence_burst_init (int x, int z), + CClinkern_flipper_finish (void), + CClinkern_flipper_free_world (void); + +#else + +int + CClinkern_flipper_init (), + CClinkern_flipper_reset_perm (), + CClinkern_flipper_reset_temp (), + CClinkern_flipper_next (), + CClinkern_flipper_prev (), + CClinkern_flipper_cycle (), + CClinkern_flipper_sequence_burst (), + CClinkern_flipper_sequence (); + +void + CClinkern_flipper_flip (), + CClinkern_flipper_flip_quick (), + CClinkern_flipper_flip_perm (), + CClinkern_flipper_sequence_burst_init (), + CClinkern_flipper_finish (), + CClinkern_flipper_free_world (); + +#endif + +#endif /* __LINKERN_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/lp.h b/contrib/blossom/concorde97/INCLUDE/lp.h new file mode 100644 index 0000000000000000000000000000000000000000..988d9f059263dba5df5f996382b2c133c010428c --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/lp.h @@ -0,0 +1,121 @@ +#ifndef __LP_H +#define __LP_H + +#define CClp_METHOD_DUAL 1 +#define CClp_METHOD_BARRIER 2 + +#define CClp_SUCCESS 0 +#define CClp_FAILURE 1 +#define CClp_UNBOUNDED 2 +#define CClp_INFEASIBLE 3 +#define CClp_UNKNOWN 4 + +typedef struct CClp { + struct cpxenv *cplex_env; + struct cpxlp *cplex_lp; + int lp_allocated; +} CClp; + +typedef struct CClpbasis { + int *rstat; + int *cstat; + double *dnorm; +} CClpbasis; + +#ifdef CC_PROTOTYPE_ANSI + +int + CClp_init (CClp *lp), + CClp_loadlp (CClp *lp, char *name, int ncols, int nrows, int objsense, + double *obj, double *rhs, char *sense, int *matbeg, int *matcnt, + int *matind, double *matval, double *lb, double *ub), + CClp_opt (CClp *lp, int method), + CClp_dualopt (CClp *lp), + CClp_limited_dualopt (CClp *lp, int lim, int *status, double *upperbound), + CClp_primalopt (CClp *lp), + CClp_addrows (CClp *lp, int newrows, int newnz, double *rhs, char *sense, + int *rmatbeg, int *rmatind, double *rmatval), + CClp_addcols (CClp *lp, int newcols, int newnz, double *obj, + int *cmatbeg, int *cmatind, double *cmatval, double *lb, + double *ub), + CClp_delete_row (CClp *lp, int i), + CClp_delete_set_of_rows (CClp *lp, int *delstat), + CClp_delete_column (CClp *lp, int i), + CClp_delete_set_of_columns (CClp *lp, int *delstat), + CClp_setbnd (CClp *lp, int col, char lower_or_upper, double bnd), + CClp_get_basis_and_norms (CClp *lp, CClpbasis *b), + CClp_load_basis_and_norms (CClp *lp, CClpbasis *b), + CClp_basis (CClp *lp, int *cstat, int *rstat), + CClp_loadbasis (CClp *lp, int *cstat, int *rstat), + CClp_getbasis_and_norms (CClp *lp, int *cstat, int *rstat, + double *dnorm), + CClp_loadbasis_and_norms (CClp *lp, int *cstat, int *rstat, + double *dnorm), + CClp_x (CClp *lp, double *x), + CClp_rc (CClp *lp, double *rc), + CClp_pi_range (CClp *lp, double *pi, int from, int to), + CClp_objval (CClp *lp, double *obj), + CClp_nonzeros (CClp *lp), + CClp_status (CClp *lp, int *status), + CClp_getweight (CClp *lp, int nrows, int *rmatbeg, int *rmatind, + double *rmatval, double *weight), + CClp_dump_lp (CClp *lp, char *fname), + CClp_getgoodlist (CClp *lp, int *goodlist, int *goodlen_p, + double *downpen, double *uppen), + CClp_strongbranch (CClp *lp, int *candidatelist, int ncand, + double *downpen, double *uppen, int iterations, + double *upperbound), + CClp_getfarkasmultipliers (CClp *lp, double *y); + +void + CClp_init_struct (CClp *lp), + CClp_free (CClp *lp), + CClp_init_basis (CClpbasis *b), + CClp_free_basis (CClpbasis *b), + CClp_pivotin (CClp *lp, int i); + +#else + +int + CClp_init (), + CClp_loadlp (), + CClp_opt (), + CClp_dualopt (), + CClp_limited_dualopt (), + CClp_primalopt (), + CClp_addrows (), + CClp_addcols (), + CClp_delete_row (), + CClp_delete_set_of_rows (), + CClp_delete_column (), + CClp_delete_set_of_columns (), + CClp_setbnd (), + CClp_get_basis_and_norms (), + CClp_load_basis_and_norms (), + CClp_basis (), + CClp_loadbasis (), + CClp_getbasis_and_norms (), + CClp_loadbasis_and_norms (), + CClp_x (), + CClp_rc (), + CClp_pi_range (), + CClp_objval (), + CClp_nonzeros (), + CClp_status (), + CClp_getweight (), + CClp_dump_lp (), + CClp_getgoodlist (), + CClp_strongbranch (), + CClp_getfarkasmultipliers (); + +void + CClp_init_struct (), + CClp_free (), + CClp_init_basis (), + CClp_free_basis (), + CClp_pivotin (); + +#endif + + +#endif /* __LP_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/machdefs.h b/contrib/blossom/concorde97/INCLUDE/machdefs.h new file mode 100644 index 0000000000000000000000000000000000000000..7612cb3ce47aac1c1ca0a30c4a1e121d4fb7b84e --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/machdefs.h @@ -0,0 +1,94 @@ +#ifndef __MACHDEFS_H +#define __MACHDEFS_H + +#define NDEBUG +#define CCSYS_STANDARD + +#ifdef CCSYS_STANDARD +#define CC_PROTOTYPE_ANSI +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#include <time.h> +#define CC_ZEIT_TIMES +#endif + +#ifdef CCSYS_STANDARD_KNR +#undef CC_PROTOTYPE_ANSI +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#include <time.h> +#define CC_ZEIT_TIMES +#define const +#define void int +#endif + +#ifdef CCSYS_ALTERNATE +#define CC_PROTOTYPE_ANSI +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#include <time.h> +#define CC_ZEIT_RUSAGE +#endif + +#ifdef CCSYS_SUNOS_GCC +#define CC_PROTOTYPE_ANSI +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#include <time.h> + +extern int + printf (const char *, ...), + fprintf (FILE *, const char *, ...), + fflush (FILE *), + scanf (const char *, ...), + sscanf (const char *, const char *, ...), + fscanf (FILE *, const char *, ...), + fclose (FILE *), + _filbuf (FILE *), + rename (const char *, const char *), + time (int *); + +extern void + perror (const char *); + +#define CC_ZEIT_TIMES +#endif + + +#ifndef NULL +#define NULL (0) +#endif + +#endif /* __MACHDEFS_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/macrorus.h b/contrib/blossom/concorde97/INCLUDE/macrorus.h new file mode 100644 index 0000000000000000000000000000000000000000..35db43624b2d72296bfae9ce5646b01176fa6781 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/macrorus.h @@ -0,0 +1,8 @@ +#ifndef __MACRORUS_H +#define __MACRORUS_H + +#define CC_SWAP(a,b,t) (((t)=(a)),((a)=(b)),((b)=(t))) + +#define CC_OURABS(a) (((a) >= 0) ? (a) : -(a)) + +#endif /* __MACRORUS_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/prefix.h b/contrib/blossom/concorde97/INCLUDE/prefix.h new file mode 100644 index 0000000000000000000000000000000000000000..eebaf8d76c83cb76461f4077e3666cd304049e7c --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/prefix.h @@ -0,0 +1,9 @@ +#ifndef __PREFIX_H +#define __PREFIX_H + +#define CC_PROTOTYPE_ANSI + +#include <stdio.h> +#include <stdlib.h> + +#endif /* __PREFIX_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/tsp.h b/contrib/blossom/concorde97/INCLUDE/tsp.h new file mode 100644 index 0000000000000000000000000000000000000000..2915941442030e7cb365431f18747e826d9cea39 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/tsp.h @@ -0,0 +1,996 @@ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* PROTOTYPES FOR FILES IN CUT */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + + +#ifndef __TSP_H +#define __TSP_H + +#include "util.h" +#include "edgegen.h" +#include "bigguy.h" +#include "lp.h" +#include "cut.h" +#include "kdtree.h" + +/*************** Tolerances for the LP and Cutting routines ***************/ + +#define CCtsp_MIN_VIOL (0.00001) /* min violation for cut to be added to lp */ +#define CCtsp_CUTS_NEXT_TOL (0.0001) /* to try next level */ +#define CCtsp_CUTS_NEXT_ROUND (0.00000001) /* if improve is less, stop round */ +#define CCtsp_PRICE_RCTHRESH (-0.00001) /* to add a bad edge */ +#define CCtsp_PRICE_MAXPENALTY (0.49) /* penalty permitted in addbad */ +#define CCtsp_PHASE1_RCTHRESH (-0.000000001) +#define CCtsp_PHASE1_MAXPENALTY (0.00000001) +#define CCtsp_EDGE_LIFE (1000000) /* 200 */ /* Large for subtour runs */ +#define CCtsp_CUT_LIFE (50) +#define CCtsp_CUT_BATCH (250) /* number of new cuts before lp optimize */ +#define CCtsp_STORE_BATCH (50) /* number of new cuts before lp addrows */ +#define CCtsp_INTTOL (0.0001) /* used to check if lp soln is integral */ + +/************************** Branching Strategies ************************/ + +#define CCtsp_BRANCH_MIDDLE 1 +#define CCtsp_BRANCH_STRONG 2 + +/*************************************************************************/ + +#define CCtsp_LP_MAXDOUBLE 1e30 + +#define CCtsp_CUTRHS(c) (3*(c)->cliquecount - (c)->handlecount - 1) + +typedef struct CCtsp_lpnode { + int deg; + int mark; + struct CCtsp_lpadj *adj; +} CCtsp_lpnode; + +typedef struct CCtsp_lpedge { + int ends[2]; /* ends[0] should always be < ends[1] */ + int fixed; + int branch; /* < 0 means set to 0 and > 0 means set to 1 */ + int len; + int age; + int coef; /* should be maintained at zero */ + int coefnext; /* should be maintained at -2 */ +} CCtsp_lpedge; + +typedef struct CCtsp_lpadj { + int to; + int edge; +} CCtsp_lpadj; + +typedef struct CCtsp_lpgraph { + int ncount; + int espace; + int ecount; + int nodemarker; + CCtsp_lpnode *nodes; + CCtsp_lpedge *edges; + CCtsp_lpadj *adjspace; + int adjstart; + int adjend; +} CCtsp_lpgraph; + +typedef struct CCtsp_predge { + int ends[2]; + int len; + double rc; +} CCtsp_predge; + +typedef struct CCtsp_pricegroup { + int ncount; + int espace; + int ecount; + CCtsp_lpnode *nodes; + CCtsp_predge *edges; + int cliquecount; + struct CCtsp_lpclique *cliques; /* just a copy of the pointer */ + CCtsp_lpgraph *graph; /* pointer to the copy in a CCtsp_lp */ + CCtsp_lpadj *adjspace; + double *node_pi; + double *clique_pi; + double penalty; +} CCtsp_pricegroup; + +typedef struct CCtsp_extraedge { + int ends[2]; +} CCtsp_extraedge; + +typedef struct CCtsp_sparser { + unsigned int node : 24; + unsigned int mult : 8; +} CCtsp_sparser; + +typedef struct CCtsp_segment { + int lo; + int hi; +} CCtsp_segment; + +typedef struct CCtsp_lpclique { + int segcount; + struct CCtsp_segment *nodes; + int hashnext; + int refcount; +} CCtsp_lpclique; + +#define CC_FOREACH_NODE_IN_CLIQUE(i,c,tmp) \ + for(tmp=0;tmp<(c).segcount;tmp++) \ + for(i=(c).nodes[tmp].lo;i<=(c).nodes[tmp].hi;i++) + +#define CCtsp_NEWCUT_AGE (-1) + +typedef struct CCtsp_lpcut { + int handlecount; + int cliquecount; + int modcount; + int age; + int rhs; + char sense; + char branch; + int *cliques; + struct CCtsp_sparser *mods; +} CCtsp_lpcut; + +typedef struct CCtsp_lpcut_in { + int handlecount; + int cliquecount; + int rhs; + char sense; + char branch; + CCtsp_lpclique *cliques; + struct CCtsp_lpcut_in *next; + struct CCtsp_lpcut_in *prev; +} CCtsp_lpcut_in; + +typedef struct CCtsp_lp_result { + double ub; + double lb; + int ecount; + int *elist; + double *x; + double *rc; +} CCtsp_lp_result; + +typedef struct CCtsp_lpcuts { + int cutcount; + int cliqueend; + int cutspace; + int cliquespace; + int cliquehashsize; + int cliquefree; + int *cliquehash; + CCtsp_lpcut *cuts; + CCtsp_lpclique *cliques; + CCgenhash *cuthash; + char *tempcuthash; + int tempcuthashsize; +} CCtsp_lpcuts; + +typedef struct CCtsp_bigdual { + int cutcount; + CCbigguy *node_pi; + CCbigguy *cut_pi; +} CCtsp_bigdual; + +typedef struct CCtsp_tighten_info { + int ncall; + int nfail; + int nadd; + int nadd_tied; + int ndel; + int ndel_tied; + double add_delta; + double del_delta; + double time; +} CCtsp_tighten_info; + +typedef struct CCtsp_branchobj { + int depth; + int rhs; + int ends[2]; + char sense; + CCtsp_lpclique *clique; +} CCtsp_branchobj; + +typedef struct CCtsp_cutselect { + int cutpool; + int connect; + int segments; + int exactsubtour; + int tighten_lp; + int decker_lp; + int teething_lp; + int tighten_pool; + int decker_pool; + int teething_pool; + int maxchunksize; + int Xfastcuts; + int Xexactsubtours; + int Xslowcuts; + int consecutiveones; + int necklace; + int usetighten; /* set to 1 to tighten before cuts are added */ + int extra_connect; /* set to 1 to force a connected solution */ + double nexttol; + double roundtol; +} CCtsp_cutselect; + +/* nodes are reordered to match compression tour */ + +typedef struct CCtsp_genadj { + int deg; + struct CCtsp_genadjobj *list; +} CCtsp_genadj; + +typedef struct CCtsp_genadjobj { + int end; + int len; +} CCtsp_genadjobj; + +typedef struct CCtsp_edgegenerator { + double *node_piest; + struct CCdatagroup *dg; + int *supply; + CCkdtree *kdtree; + CCxnear *xnear; + struct CCtsp_xnorm_pricer *xprice; + CCtsp_genadjobj *adjobjspace; + CCtsp_genadj *adj; + int ncount; + int nneighbors; + int start; + int current; + int supplyhead; + int supplycount; +} CCtsp_edgegenerator; + +typedef struct CCtsp_xnorm_pricer_val { + double val; + struct CCtsp_xnorm_pricer_val *next; + struct CCtsp_xnorm_pricer_val *prev; + int index; +} CCtsp_xnorm_pricer_val; + +typedef struct CCtsp_xnorm_pricer { + CCdatagroup *dat; + double *pi; + int *order; + CCtsp_xnorm_pricer_val *xminuspi_space; + CCtsp_xnorm_pricer_val *xminuspi; + int *invxminuspi; + int ncount; +} CCtsp_xnorm_pricer; + +typedef struct CCtsp_lp { + CCtsp_lpgraph graph; + CCtsp_lpcuts cuts; + CCtsp_lpcuts *pool; + CClp lp; + int *perm; + CCdatagroup *dat; + int fullcount; + struct CCtsp_genadj *fulladj; + struct CCtsp_genadjobj *fulladjspace; + int nfixededges; + int *fixededges; + struct CCtsp_qsparsegroup *sparsifier; + int edge_life; + int cut_life; + char *name; + int id; + int parent_id; + int root; + double upperbound; + double lowerbound; + CCbigguy exact_lowerbound; + CCtsp_bigdual *exact_dual; + int infeasible; + int full_edges_valid; + CClpbasis *basis; + CCtsp_lpcut_in cutqueue; /* dummy entry for doubly-linked + list */ + CCtsp_lp_result result; + CCtsp_tighten_info tighten_stats; + int branchdepth; + CCtsp_branchobj *branchhistory; +} CCtsp_lp; + +typedef struct CCtsp_lprow { + int rowcnt; + int nzcnt; + char *sense; + double *rhs; + int *begin; /* offset into the array for start of row */ + int indexspace; + int *indices; /* the column indices of the row entries */ + int entryspace; + double *entries; /* the matrix entries */ +} CCtsp_lprow; + + + +/***************************************************************************/ +/* */ +/* tsp_lp.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCtsp_cutting_loop (CCtsp_lp *lp, CCtsp_cutselect *sel, int savelp), + CCtsp_subtour_loop (CCtsp_lp *lp), + CCtsp_pricing_loop (CCtsp_lp *lp, double *bnd), + CCtsp_init_cutselect (CCtsp_lp *lp, CCtsp_cutselect *s), + CCtsp_call_x_heuristic (CCtsp_lp *lp, double *val, int *outcyc), + CCtsp_bb_cutting (char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double *upbound, CCtsp_lpcuts *pool, + CCtsp_cutselect *sel, double *val, int *prune, int *foundtour, + int *besttour), + CCtsp_init_lp (CCtsp_lp **lp, char *probname, int probnum, + char *probfilename, int ncount, CCdatagroup *dat, int ecount, + int *elist, int *elen, int excount, int *exlist, int *exlen, + int exvalid, int *ptour, double initial_ub, CCtsp_lpcuts *pool), + CCtsp_bb_init_lp (CCtsp_lp **lp, char *probname, int probnum, + int ncount, CCdatagroup *dat, int *ptour, double initial_ub, + CCtsp_lpcuts *pool), + CCtsp_get_lp_result (CCtsp_lp *lp, double *lb, double *ub, int *ecount, + int **elist, double **x, double **rc, double **node_pi, + double **cut_pi), + CCtsp_process_cuts (CCtsp_lp *lp, int *pnadded, int tighten), + CCtsp_add_cut_to_cutlist (CCtsp_lpcuts *cuts, CCtsp_lpcut *c), + CCtsp_add_cut (CCtsp_lp *lp, CCtsp_lpcut_in *d, CCtsp_lprow *cr), + CCtsp_lpcut_in_nzlist (CCtsp_lpgraph *g, CCtsp_lpcut_in *c), + CCtsp_add_nzlist_to_lp (CCtsp_lp *lp, int nzlist, int rhs, char sense, + CCtsp_lprow *cr), + CCtsp_add_vars_to_lp (CCtsp_lp *lp, CCtsp_predge *prlist, int n), + CCtsp_update_result (CCtsp_lp *lp), + CCtsp_infeas_recover (CCtsp_lp *lp), + CCtsp_test_cut_branch (CCtsp_lp *lp, CCtsp_lpclique *c, double *down, + double *up), + CCtsp_register_cliques (CCtsp_lpcuts *cuts, CCtsp_lpcut_in *c, + CCtsp_lpcut *new), + CCtsp_addbad_variables (CCtsp_lp *lp, struct CCtsp_edgegenerator *eg, + double *ppenalty, int *pnadded, double rcthresh, + double maxpenalty, int phase1, int *feasible), + CCtsp_eliminate_variables (CCtsp_lp *lp), + CCtsp_build_lpgraph (CCtsp_lpgraph *g, int ncount, int ecount, + int *elist, int *elen), + CCtsp_build_lpadj (CCtsp_lpgraph *g, int estart, int eend), + CCtsp_add_multiple_rows (CCtsp_lp *lp, CCtsp_lprow *cr), + CCtsp_delete_cut (CCtsp_lp *lp, int i), + CCtsp_find_edge (CCtsp_lpgraph *g, int from, int to), + CCtsp_find_branch (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_branchobj **bobj, double *val, int **cyc, int usecliques), + CCtsp_bb_find_branch (char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double *upperbound, + CCtsp_lpcuts *pool, CCtsp_branchobj **b, int usecliques, + int *foundtour, int *besttour), + CCtsp_check_integral (CCtsp_lp *lp, double *val, int **cyc, int *yesno), + CCtsp_find_branch_edge (CCtsp_lp *lp, int *n0, int *n1, double *val, + int **cyc, int branchtype), + CCtsp_find_branch_cliques (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_lpclique **bcliques, double **bval), + CCtsp_execute_branch (CCtsp_lp *lp, CCtsp_branchobj *b), + CCtsp_execute_unbranch (CCtsp_lp *lp, CClpbasis *basis), + CCtsp_splitprob (CCtsp_lp *lp, CCtsp_branchobj *b, int child0, int child1), + CCtsp_bb_splitprob (char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double initial_ub, CCtsp_lpcuts *pool, + CCtsp_branchobj *b, int child0, int child1, double *val0, + double *val1, int *prune0, int *prune1), + CCtsp_dumptour (int ncount, CCdatagroup *dat, int *perm, char *probname, + int *tour), + CCtsp_add_branchhistory_to_lp (CCtsp_lp *lp), + CCtsp_easy_dfs_brancher (CCtsp_lp *lp, CCtsp_cutselect *sel, int depth, + double *upbound, int *bbcount, int usecliques, int *besttour), + CCtsp_bfs_brancher (char *probname, int id, double lowerbound, + CCtsp_cutselect *sel, double *upbound, int *bbcount, int usecliques, + CCdatagroup *mydat, int *ptour, CCtsp_lpcuts *pool, int ncount, + int *besttour), + CCtsp_do_interactive_branch (CCtsp_lp *lp), + CCtsp_inspect_full_edges (CCtsp_lp *lp), + CCtsp_read_probfile (CCtsp_lp *lp, char *fname, int ncount), + CCtsp_read_probfile_id (CCtsp_lp *lp, char *fname, int id, int ncount), + CCtsp_write_probfile_sav (CCtsp_lp *lp), + CCtsp_write_probfile_id (CCtsp_lp *lp), + CCtsp_dump_x (CCtsp_lp *lp, char *fname), + CCtsp_exact_price (CCtsp_lp *lp, CCbigguy *bound, int phase1), + CCtsp_edge_elimination (CCtsp_lp *lp), + CCtsp_exact_dual (CCtsp_lp *lp), + CCtsp_verify_infeasible_lp (CCtsp_lp *lp, int *yesno), + CCtsp_verify_lp_prune (CCtsp_lp *lp, int *yesno), + CCtsp_tighten_lpcut_in (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, + double *x, CCtsp_lpcut_in *d, CCtsp_tighten_info *stats, + double *pimprove), + CCtsp_tighten_lpcut (CCtsp_lpgraph *g, CCtsp_lpclique *cliques, + CCtsp_lpcut *c, double *x, CCtsp_lpcut_in *d, + CCtsp_tighten_info *stats, double *pimprove), + CCtsp_test_pure_comb (int ncount, CCtsp_lpcut_in *c, int *yes_no, + int *handle), + CCtsp_test_pseudocomb (int ncount, CCtsp_lpcut_in *c, int handle, + int *yes_no), + CCtsp_test_teeth_disjoint (int ncount, CCtsp_lpcut_in *c, int handle, + int *yes_no), + CCtsp_find_pure_handle (int ncount, CCtsp_lpcut_in *c, int *handle), + CCtsp_comb_to_double_decker (CCtsp_lpgraph *g, double *x, + CCtsp_lpcut_in *c, CCtsp_lpcut_in **d), + CCtsp_teething (CCtsp_lpgraph *g, double *x, CCtsp_lpcut_in *cut, + CCtsp_lpcut_in **newcut), + CCtsp_init_cutpool (int ncount, char *poolfilename, CCtsp_lpcuts **pool), + CCtsp_write_cutpool (int ncount, char *poolfilename, CCtsp_lpcuts *pool), + CCtsp_search_cutpool (CCtsp_lpcuts *pool, CCtsp_lpcut_in **cuts, + int *cutcount, int ncount, int ecount, int *elist, double *x), + CCtsp_search_cutpool_cliques (CCtsp_lpcuts *pool, CCtsp_lpclique **cliques, + int *cliquecount, int ncount, int ecount, int *elist, double *x, + double maxdelta, int maxcliques, double **cliquevals), + CCtsp_branch_cutpool_cliques (CCtsp_lpcuts *pool, CCtsp_lpclique **cliques, + int *cliquecount, int ncount, int ecount, int *elist, double *x, + int nwant, double **cliquevals), + CCtsp_add_to_cutpool (CCtsp_lpcuts *pool, CCtsp_lpcuts *cuts, + CCtsp_lpcut *c), + CCtsp_add_to_cutpool_lpcut_in (CCtsp_lpcuts *pool, CCtsp_lpcut_in *cut), + CCtsp_display_cutpool (CCtsp_lpcuts *pool), + CCtsp_price_cuts (CCtsp_lpcuts *pool, int ncount, int ecount, int *elist, + double *x, double *cutval), + CCtsp_clique_to_array (CCtsp_lpclique *c, int **ar, int *count), + CCtsp_clique_delta (CCtsp_lpgraph *g, double *x, CCtsp_lpclique *c, + double *delta), + CCtsp_x_greedy_tour (CCdatagroup *dat, int ncount, int ecount, int *elist, + double *x, int *cyc, double *val), + CCtsp_x_greedy_tour_lk (CCdatagroup *dat, int ncount, int ecount, + int *elist, double *x, int *cyc, double *val); + +void + CCtsp_init_tsp_lp_struct (CCtsp_lp *lp), + CCtsp_free_tsp_lp_struct (CCtsp_lp **lp), + CCtsp_add_cuts_to_queue (CCtsp_lp *lp, CCtsp_lpcut_in **c), + CCtsp_delete_cut_from_cutlist (CCtsp_lpcuts *cuts, int ind), + CCtsp_init_lprow (CCtsp_lprow *cr), + CCtsp_free_lprow (CCtsp_lprow *cr), + CCtsp_unregister_cliques (CCtsp_lpcuts *cuts, CCtsp_lpcut *c), + CCtsp_free_cutpool (CCtsp_lpcuts **pool), + CCtsp_init_lpgraph_struct (CCtsp_lpgraph *g), + CCtsp_free_lpgraph (CCtsp_lpgraph *g), + CCtsp_free_lpcut_in (CCtsp_lpcut_in *c), + CCtsp_free_lpclique (CCtsp_lpclique *c), + CCtsp_free_bigdual (CCtsp_bigdual **d), + CCtsp_init_branchobj (CCtsp_branchobj *b), + CCtsp_free_branchobj (CCtsp_branchobj *b), + CCtsp_print_branchhistory (CCtsp_lp *lp), + CCtsp_init_tighten_info (CCtsp_tighten_info *stats), + CCtsp_print_tighten_info (CCtsp_tighten_info *stats), + CCtsp_mark_clique (CCtsp_lpclique *c, int *marks, int marker), + CCtsp_mark_clique_and_neighbors (CCtsp_lpgraph *g, CCtsp_lpclique *c, + int *marks, int marker), + CCtsp_mark_cut (CCtsp_lpcut_in *c, int *marks, int marker), + CCtsp_mark_cut_and_neighbors (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, + int *marks, int marker), + CCtsp_mark_clique_and_neighbors_double (CCtsp_lpgraph *g, CCtsp_lpclique *c, + double *marks, double marker), + CCtsp_is_clique_marked (CCtsp_lpclique *c, int *marks, int marker, + int *yes_no), + CCtsp_clique_count (CCtsp_lpclique *c, int *count); + + +double + CCtsp_cutprice (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, double *x); + +#else + +int + CCtsp_cutting_loop (), + CCtsp_subtour_loop (), + CCtsp_pricing_loop (), + CCtsp_init_cutselect (), + CCtsp_call_x_heuristic (), + CCtsp_bb_cutting (), + CCtsp_init_lp (), + CCtsp_bb_init_lp (), + CCtsp_get_lp_result (), + CCtsp_process_cuts (), + CCtsp_add_cut_to_cutlist (), + CCtsp_add_cut (), + CCtsp_lpcut_in_nzlist (), + CCtsp_add_nzlist_to_lp (), + CCtsp_add_vars_to_lp (), + CCtsp_update_result (), + CCtsp_infeas_recover (), + CCtsp_test_cut_branch (), + CCtsp_register_cliques (), + CCtsp_addbad_variables (), + CCtsp_eliminate_variables (), + CCtsp_build_lpgraph (), + CCtsp_build_lpadj (), + CCtsp_add_multiple_rows (), + CCtsp_delete_cut (), + CCtsp_find_edge (), + CCtsp_find_branch (), + CCtsp_bb_find_branch (), + CCtsp_check_integral (), + CCtsp_find_branch_edge (), + CCtsp_find_branch_cliques (), + CCtsp_execute_branch (), + CCtsp_execute_unbranch (), + CCtsp_splitprob (), + CCtsp_bb_splitprob (), + CCtsp_dumptour (), + CCtsp_add_branchhistory_to_lp (), + CCtsp_easy_dfs_brancher (), + CCtsp_bfs_brancher (), + CCtsp_do_interactive_branch (), + CCtsp_inspect_full_edges (), + CCtsp_read_probfile (), + CCtsp_read_probfile_id (), + CCtsp_write_probfile_sav (), + CCtsp_write_probfile_id (), + CCtsp_dump_x (), + CCtsp_exact_price (), + CCtsp_edge_elimination (), + CCtsp_exact_dual (), + CCtsp_verify_infeasible_lp (), + CCtsp_verify_lp_prune (), + CCtsp_tighten_lpcut_in (), + CCtsp_tighten_lpcut (), + CCtsp_test_pure_comb (), + CCtsp_test_pseudocomb (), + CCtsp_test_teeth_disjoint (), + CCtsp_find_pure_handle (), + CCtsp_comb_to_double_decker (), + CCtsp_teething (), + CCtsp_init_cutpool (), + CCtsp_write_cutpool (), + CCtsp_search_cutpool (), + CCtsp_search_cutpool_cliques (), + CCtsp_branch_cutpool_cliques (), + CCtsp_add_to_cutpool (), + CCtsp_add_to_cutpool_lpcut_in (), + CCtsp_display_cutpool (), + CCtsp_price_cuts (), + CCtsp_clique_to_array (), + CCtsp_clique_delta (), + CCtsp_x_greedy_tour (), + CCtsp_x_greedy_tour_lk (); + +void + CCtsp_init_tsp_lp_struct (), + CCtsp_free_tsp_lp_struct (), + CCtsp_add_cuts_to_queue (), + CCtsp_delete_cut_from_cutlist (), + CCtsp_init_lprow (), + CCtsp_free_lprow (), + CCtsp_unregister_cliques (), + CCtsp_free_cutpool (), + CCtsp_init_lpgraph_struct (), + CCtsp_free_lpgraph (), + CCtsp_free_lpcut_in (), + CCtsp_free_lpclique (), + CCtsp_free_bigdual (), + CCtsp_init_branchobj (), + CCtsp_free_branchobj (), + CCtsp_print_branchhistory (), + CCtsp_init_tighten_info (), + CCtsp_print_tighten_info (), + CCtsp_mark_clique (), + CCtsp_mark_clique_and_neighbors (), + CCtsp_mark_cut (), + CCtsp_mark_cut_and_neighbors (), + CCtsp_mark_clique_and_neighbors_double (), + CCtsp_is_clique_marked (), + CCtsp_clique_count (); + + +double + CCtsp_cutprice (); + +#endif + +/***************************************************************************/ +/* */ +/* cliqhash.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCtsp_init_cliquehash (CCtsp_lpcuts *cuts, int size), + CCtsp_register_clique (CCtsp_lpcuts *cuts, CCtsp_lpclique *c); + +void + CCtsp_free_cliquehash (CCtsp_lpcuts *cuts), + CCtsp_unregister_clique (CCtsp_lpcuts *cuts, int c); + +#else + +int + CCtsp_init_cliquehash (), + CCtsp_register_clique (); + +void + CCtsp_free_cliquehash (), + CCtsp_unregister_clique (); + +#endif + + + +/***************************************************************************/ +/* */ +/* cutcall.c */ +/* */ +/***************************************************************************/ + +typedef struct cutinfo { + CC_SRKexpinfo expand; + CCtsp_lpcut_in **clist; + CCtsp_lpcut_in *current; + int *cutcount; +} cutinfo; + +#ifdef CC_PROTOTYPE_ANSI + +int + CCtsp_connect_cuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x), + CCtsp_segment_cuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x), + CCtsp_exact_subtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x), + CCtsp_tighten_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts), + CCtsp_double_decker_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts), + CCtsp_teething_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts), + CCtsp_copy_lpcut_in (CCtsp_lpcut_in *c, CCtsp_lpcut_in *new), + CCtsp_segment_to_subtour (CCtsp_lpcut_in **cut, int a, int b), + CCtsp_array_to_subtour (CCtsp_lpcut_in **cut, int *ar, int acount), + CCtsp_array_to_lpclique (int *ar, int acount, CCtsp_lpclique *cliq), + CCtsp_seglist_to_lpclique (int nseg, int *list, CCtsp_lpclique *cliq), + CCtsp_add_node_to_lpclique (CCtsp_lpclique *cin, CCtsp_lpclique *cout, + int n), + CCtsp_delete_node_from_lpclique (CCtsp_lpclique *cin, + CCtsp_lpclique *cout, int n), + CCtsp_lpcut_to_lpcut_in (CCtsp_lpcuts *cuts, CCtsp_lpcut *c, + CCtsp_lpcut_in *new), + CCtsp_copy_lpclique (CCtsp_lpclique *c, CCtsp_lpclique *new), + CCtsp_file_cuts (char *cutfile, CCtsp_lpcut_in **cuts, int *cutcount, + int ncount, int *tour), + CCtsp_file_cuts_write (char *cutfile, CCtsp_lpcuts *cuts, int *tour), + CCtsp_buildcut_begin (cutinfo *cuts, int init_cliquecount), + CCtsp_buildcut_addclique (cutinfo *cuts, int *arr, int size, int handle); + +void + CCtsp_init_lpcut_in (CCtsp_lpcut_in *c), + CCtsp_init_lpclique (CCtsp_lpclique *c), + CCtsp_print_lpcut_in (CCtsp_lpcut_in *c), + CCtsp_print_lpclique (CCtsp_lpclique *c), + CCtsp_lpclique_compare (CCtsp_lpclique *a, CCtsp_lpclique *b, int *diff), + CCtsp_buildcut_abort (cutinfo *cuts), + CCtsp_buildcut_finish (cutinfo *cuts, int rhs); + +#else + +int + CCtsp_connect_cuts (), + CCtsp_segment_cuts (), + CCtsp_exact_subtours (), + CCtsp_tighten_lp (), + CCtsp_double_decker_lp (), + CCtsp_teething_lp (), + CCtsp_copy_lpcut_in (), + CCtsp_segment_to_subtour (), + CCtsp_array_to_subtour (), + CCtsp_array_to_lpclique (), + CCtsp_seglist_to_lpclique (), + CCtsp_add_node_to_lpclique (), + CCtsp_delete_node_from_lpclique (), + CCtsp_lpcut_to_lpcut_in (), + CCtsp_copy_lpclique (), + CCtsp_file_cuts (), + CCtsp_file_cuts_write (), + CCtsp_buildcut_begin (), + CCtsp_buildcut_addclique (); + +void + CCtsp_init_lpcut_in (), + CCtsp_init_lpclique (), + CCtsp_print_lpcut_in (), + CCtsp_print_lpclique (), + CCtsp_lpclique_compare (), + CCtsp_buildcut_abort (), + CCtsp_buildcut_finish (); + +#endif + + + +/***************************************************************************/ +/* */ +/* edgemap.c */ +/* */ +/***************************************************************************/ + +typedef struct CCtsp_edgeinf { + int ends[2]; + int val; + struct CCtsp_edgeinf *next; +} CCtsp_edgeinf; + +typedef struct CCtsp_edgehash { + struct CCtsp_edgeinf **table; + unsigned int size; + unsigned int mult; +} CCtsp_edgehash; + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCtsp_edgehash_init (CCtsp_edgehash *h, int size), + CCtsp_edgehash_add (CCtsp_edgehash *h, int end1, int end2, int val), + CCtsp_edgehash_del (CCtsp_edgehash *h, int end1, int end2), + CCtsp_edgehash_find (CCtsp_edgehash *h, int end1, int end2); + +void + CCtsp_edgehash_delall (CCtsp_edgehash *h), + CCtsp_edgehash_free (CCtsp_edgehash *h); + +#else + +int + CCtsp_edgehash_init (), + CCtsp_edgehash_add (), + CCtsp_edgehash_del (), + CCtsp_edgehash_find (); + +void + CCtsp_edgehash_delall (), + CCtsp_edgehash_free (); + +#endif + + +/***************************************************************************/ +/* */ +/* generate.c */ +/* */ +/***************************************************************************/ + +#define CCtsp_PRICE_COMPLETE_GRAPH -1 +#define CCtsp_GEN_PRICE_EPSILON 0.0001 /* 0.0000001 */ +#define CCtsp_GEN_USE_ADJ 50 /* Cutoff for using explicit adj list */ + +#ifdef CC_PROTOTYPE_ANSI + +void + CCtsp_free_edgegenerator (CCtsp_edgegenerator *eg); + +int + CCtsp_init_edgegenerator (CCtsp_edgegenerator *eg, int ncount, + CCdatagroup *dg, CCtsp_genadj *adj, int nneighbors), + CCtsp_reset_edgegenerator (CCtsp_edgegenerator *eg, double *node_piest), + CCtsp_generate_edges (CCtsp_edgegenerator *eg, int nwant, int *pngot, + int *elist, int *elen, int *finished), + CCtsp_edgelist_to_genadj (int ncount, int ecount, int *elist, int *elen, + CCtsp_genadj **adj, CCtsp_genadjobj **adjobjspace); + +#else + +void + CCtsp_free_edgegenerator (); + +int + CCtsp_init_edgegenerator (), + CCtsp_reset_edgegenerator (), + CCtsp_generate_edges (), + CCtsp_edgelist_to_genadj (); + +#endif + + + +/***************************************************************************/ +/* */ +/* prob_io.c */ +/* */ +/***************************************************************************/ + +#define CCtsp_PROB_IO_VERSION 1 +#define CCtsp_PROB_FILE_NAME_LEN 128 + +#define CCtsp_PROB_IO_CUTS_VERSION_BASE -1000 +#define CCtsp_PROB_IO_CUTS_VERSION -1001 /* Should be <= BASE (-1000) */ + +typedef struct CCtsp_PROB_FILE { + CC_SFILE *f; + char name[CCtsp_PROB_FILE_NAME_LEN]; + int id; + int parent; + double ub; + double lb; + CCbigguy exactlb; + int nnodes; + int child0; + int child1; + int real; /* Set to 1 when we know this is a real child */ + int processed; + int infeasible; + struct { + int dat; + int edge; + int fulladj; + int cut; + int tour; + int basis; + int norms; + int fix; + int exactdual; + int history; + } offsets; +} CCtsp_PROB_FILE; + + +#ifdef CC_PROTOTYPE_ANSI + +CCtsp_PROB_FILE + *CCtsp_prob_read (char *f, int n), + *CCtsp_prob_read_name (char *f), + *CCtsp_prob_write (char *f, int n), + *CCtsp_prob_write_name (char *fname, char *pname); + +int + CCtsp_prob_file_delete (char *f, int n), + CCtsp_prob_getname (CCtsp_PROB_FILE *p, char *name), + CCtsp_prob_getid (CCtsp_PROB_FILE *p, int *id), + CCtsp_prob_getparent (CCtsp_PROB_FILE *p, int *parent), + CCtsp_prob_getub (CCtsp_PROB_FILE *p, double *ub), + CCtsp_prob_getlb (CCtsp_PROB_FILE *p, double *lb), + CCtsp_prob_getexactlb (CCtsp_PROB_FILE *p, CCbigguy *lb), + CCtsp_prob_getnnodes (CCtsp_PROB_FILE *p, int *nnodes), + CCtsp_prob_getchildren (CCtsp_PROB_FILE *p, int *child0, int *child1), + CCtsp_prob_getreal (CCtsp_PROB_FILE *p, int *real), + CCtsp_prob_getprocessed (CCtsp_PROB_FILE *p, int *processed), + CCtsp_prob_getinfeasible (CCtsp_PROB_FILE *p, int *infeasible), + CCtsp_prob_gettour (CCtsp_PROB_FILE *p, int **tour), + CCtsp_prob_getedges (CCtsp_PROB_FILE *p, int *nedges, int **elist, + int **elen), + CCtsp_prob_getcuts (CCtsp_PROB_FILE *p, CC_SFILE *s, CCtsp_lpcuts *cuts), + CCtsp_prob_getbasis (CCtsp_PROB_FILE *p, int *ccount, int *rcount, + int **cstat, int **rstat), + CCtsp_prob_getnorms (CCtsp_PROB_FILE *p, int *rcount, double **dnorm), + CCtsp_prob_getfulladj (CCtsp_PROB_FILE *p, int ncount, int *fullcount, + CCtsp_genadj **adj, CCtsp_genadjobj **adjspace), + CCtsp_prob_getfixed (CCtsp_PROB_FILE *p, int *ecount, int **elist), + CCtsp_prob_getexactdual (CCtsp_PROB_FILE *p, int ncount, + CCtsp_bigdual **d), + CCtsp_prob_gethistory (CCtsp_PROB_FILE *p, int *depth, + CCtsp_branchobj **history), + CCtsp_prob_rclose (CCtsp_PROB_FILE *p), + + CCtsp_prob_putname (CCtsp_PROB_FILE *p, char *name), + CCtsp_prob_putid (CCtsp_PROB_FILE *p, int id), + CCtsp_prob_putparent (CCtsp_PROB_FILE *p, int parent), + CCtsp_prob_putub (CCtsp_PROB_FILE *p, double ub), + CCtsp_prob_putlb (CCtsp_PROB_FILE *p, double lb), + CCtsp_prob_putexactlb (CCtsp_PROB_FILE *p, CCbigguy lb), + CCtsp_prob_putnnodes (CCtsp_PROB_FILE *p, int nnodes), + CCtsp_prob_putchildren (CCtsp_PROB_FILE *p, int child0, int child1), + CCtsp_prob_putreal (CCtsp_PROB_FILE *p, int real), + CCtsp_prob_putprocessed (CCtsp_PROB_FILE *p, int processed), + CCtsp_prob_putinfeasible (CCtsp_PROB_FILE *p, int infeasible), + CCtsp_prob_puttour (CCtsp_PROB_FILE *p, int *tour), + CCtsp_prob_putedges (CCtsp_PROB_FILE *p, int nedges, int *elist, int *elen), + CCtsp_prob_putcuts (CCtsp_PROB_FILE *p, CC_SFILE *s, CCtsp_lpcuts *cuts), + CCtsp_prob_putbasis (CCtsp_PROB_FILE *p, int ccount, int rcount, int *cstat, + int *rstat), + CCtsp_prob_putnorms (CCtsp_PROB_FILE *p, int rcount, double *dnorm), + CCtsp_prob_putfulladj (CCtsp_PROB_FILE *p, int ncount, int fullcount, + CCtsp_genadj *adj), + CCtsp_prob_putfixed (CCtsp_PROB_FILE *p, int ecount, int *elist), + CCtsp_prob_putexactdual (CCtsp_PROB_FILE *p, CCtsp_bigdual *d, int ncount), + CCtsp_prob_puthistory (CCtsp_PROB_FILE *p, int depth, + CCtsp_branchobj *history), + CCtsp_prob_wclose (CCtsp_PROB_FILE *p); + +#else + +CCtsp_PROB_FILE + *CCtsp_prob_read (), + *CCtsp_prob_read_name (), + *CCtsp_prob_write (), + *CCtsp_prob_write_name (); + +int + CCtsp_prob_file_delete (), + CCtsp_prob_getname (), + CCtsp_prob_getid (), + CCtsp_prob_getparent (), + CCtsp_prob_getub (), + CCtsp_prob_getlb (), + CCtsp_prob_getexactlb (), + CCtsp_prob_getnnodes (), + CCtsp_prob_getchildren (), + CCtsp_prob_getreal (), + CCtsp_prob_getprocessed (), + CCtsp_prob_getinfeasible (), + CCtsp_prob_gettour (), + CCtsp_prob_getedges (), + CCtsp_prob_getcuts (), + CCtsp_prob_getbasis (), + CCtsp_prob_getnorms (), + CCtsp_prob_getfulladj (), + CCtsp_prob_getfixed (), + CCtsp_prob_getexactdual (), + CCtsp_prob_gethistory (), + CCtsp_prob_rclose (), + + CCtsp_prob_putname (), + CCtsp_prob_putid (), + CCtsp_prob_putparent (), + CCtsp_prob_putub (), + CCtsp_prob_putlb (), + CCtsp_prob_putexactlb (), + CCtsp_prob_putnnodes (), + CCtsp_prob_putchildren (), + CCtsp_prob_putreal (), + CCtsp_prob_putprocessed (), + CCtsp_prob_putinfeasible (), + CCtsp_prob_puttour (), + CCtsp_prob_putedges (), + CCtsp_prob_putcuts (), + CCtsp_prob_putbasis (), + CCtsp_prob_putnorms (), + CCtsp_prob_putfulladj (), + CCtsp_prob_putfixed (), + CCtsp_prob_putexactdual (), + CCtsp_prob_puthistory (), + CCtsp_prob_wclose (); + +#endif + + + +/***************************************************************************/ +/* */ +/* qsparse.c */ +/* */ +/***************************************************************************/ + +typedef struct CCtsp_qsparsegroup { + CCdheap *add_queue; /* An empty heap will be maintained */ + CCdheap *sub_queue; /* An empty heap will be maintained */ + int *count_m1; /* The array will be maintained at 0 */ + int *count_non0; /* The array will be maintained at 0 */ + int *count_1; /* The array will be maintained at 0 */ + int *on_add_queue; /* The array will be maintained at 0 */ + int *on_sub_queue; /* The array will be maintained at 0 */ + int *mults; /* The array will be maintained at 0 */ +} CCtsp_qsparsegroup; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCtsp_free_qsparsify (CCtsp_qsparsegroup **pqs); +int + CCtsp_qsparsify (CCtsp_qsparsegroup **pqs, struct CCtsp_lpgraph *g, + int *pnzlist, int *scount, struct CCtsp_sparser **slist, + int *savedcount); +#else + +void + CCtsp_free_qsparsify (); +int + CCtsp_qsparsify (); + +#endif + +#endif /* __TSP_H */ diff --git a/contrib/blossom/concorde97/INCLUDE/util.h b/contrib/blossom/concorde97/INCLUDE/util.h new file mode 100644 index 0000000000000000000000000000000000000000..1421f5e776da9da62a6fb54d9f17f5a2a0c44bc9 --- /dev/null +++ b/contrib/blossom/concorde97/INCLUDE/util.h @@ -0,0 +1,935 @@ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* PROTOTYPES FOR FILES IN UTIL */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + + +#ifndef __UTIL_H +#define __UTIL_H + + + +/***************************************************************************/ +/* */ +/* allocrus.c */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* */ +/* MEMORY ALLOCATION MACROS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 24, 1995 (cofeb24) */ +/* */ +/* */ +/* EXPORTED MACROS: */ +/* CC_SAFE_MALLOC (nnum,type) */ +/* int nnum (the number of objects to be malloced) */ +/* data type (the sort of objects to be malloced) */ +/* RETURNS a pointer to the allocated space. If out of memory, */ +/* it prints an error message and returns NULL. */ +/* */ +/* CC_FREE (object,type) */ +/* type *object (pointer to previously allocated space) */ +/* data type (the sort of object) */ +/* ACTION: frees the memory and sets the object to NULL. */ +/* */ +/* CC_IFFREE (object,type) */ +/* type *object (pointer to previously allocated space) */ +/* data type (the sort of object) */ +/* ACTION: if *object is not NULL, frees the memory and sets */ +/* the object to NULL. */ +/* */ +/* CC_PTR_ALLOC_ROUTINE (type, functionname, chunklist, freelist) */ +/* data type (the sort of objects) */ +/* string functionname (the generated function) */ +/* CCbigchunkptr *chunklist (used to accumulate bigchunks) */ +/* type *freelist (used for the linked list of objects) */ +/* ACTION: Generates a function ("functionname") that returns */ +/* (type *) objects, keeping the free ones on freelist */ +/* and getting its space from calls to bigchunkalloc. */ +/* */ +/* CC_PTR_FREE_ROUTINE (type, functionname, freelist) */ +/* Parameters as above. */ +/* ACTION: Generates a function that adds an object to the */ +/* freelist. */ +/* */ +/* CC_PTR_FREE_LIST_ROUTINE (type, functionname, freefunction) */ +/* Parameters defined as above, with freefunction the function */ +/* generated by PTR_FREE_ROUTINE. */ +/* ACTION: Generates a function to free a linked list of */ +/* objects using calls to freefunction. */ +/* */ +/* CC_PTR_FREE_WORLD_ROUTINE( type, functionname, chunklist, freelist) */ +/* Parameters defined as above. */ +/* ACTION: Generates a function that returns all of the */ +/* memory used in the PTR_ALLOC_ROUTINE allocations */ +/* back to the global supply of CCbigchunkptrs. */ +/* */ +/* CC_PTR_LEAKS_ROUTINE (type, name, chunklist, freelist, field, */ +/* fieldtype) */ +/* As above, with "field" the name of a "fieldtype" field in the */ +/* object type that can be set to 0 or to 1. */ +/* ACTION: Generates a function that checks to see that we have */ +/* not leaked any of the objects. */ +/* */ +/* CC_PTR_STATUS_ROUTINE (type, name, chunklist, freelist) */ +/* ACTION: Like LEAKS, but does not check for duplicates (and so */ +/* does not corrupt the objects). */ +/* */ +/* NOTES: */ +/* These routines use the functions in allocrus.c. The PTR macros */ +/* The PTR macros generate the functions for allocating objects for */ +/* linked lists. They get their raw memory from the bigchunk supply, so */ +/* so foo_free_world (geneated by PTR_FREE_WORLD_ROUTINE) should be */ +/* called for each type of linked object "foo" when closing down the */ +/* local memory. */ +/* To use these functions, put the macros near the top of the file */ +/* before any calls to the functions (since the macros also write the */ +/* function prototypes). If you use PTR_FREE_LIST_ROUTINE for foo, you */ +/* must also use PTR_FREE_ROUTINE, and PTR_FREE_LIST_ROUTINE must be */ +/* listed after CC_PTR_FREE_ROUTINE (to get the prototype). */ +/* */ +/***************************************************************************/ + + +#define CC_SAFE_MALLOC(nnum,type) \ + (type *) CCutil_allocrus (((unsigned int) (nnum)) * sizeof (type)) + +#define CC_FREE(object,type) { \ + CCutil_freerus ((void *) (object)); \ + object = (type *) NULL; \ +} + +#define CC_IFFREE(object,type) { \ + if ((object)) CC_FREE ((object),type); \ +} + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_ALLOC_ROUTINE(type, functionname) \ +static type * functionname (void); \ +static type * functionname (void) +#else +#define CC_HEADER_PTR_ALLOC_ROUTINE(type, functionname) \ +static type * functionname (); \ +static type * functionname () +#endif + +#define CC_PTR_ALLOC_ROUTINE(type, functionname, chunklist, freelist) \ +static type * freelist = ( type * ) NULL; \ +static CCbigchunkptr * chunklist = ( CCbigchunkptr * ) NULL; \ + CC_HEADER_PTR_ALLOC_ROUTINE (type, functionname) \ +{ \ + type *p; \ + \ + if (! freelist ) { \ + int count = CC_BIGCHUNK / sizeof ( type ); \ + CCbigchunkptr *bp; \ + \ + bp = CCutil_bigchunkalloc (); \ + if (!bp) { \ + fprintf (stderr, "ptr alloc failed\n"); \ + return ( type * ) NULL; \ + } \ + freelist = ( type * ) bp->this; \ + bp->next = chunklist ; \ + chunklist = bp; \ + \ + for (p = freelist + count - 2; p >= freelist ; p--) \ + p->next = p + 1; \ + freelist [count - 1].next = ( type * ) NULL; \ + } \ + p = freelist ; \ + freelist = p->next; \ + \ + return p; \ +} + + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_FREE_ROUTINE(type, functionname) \ +static void functionname ( type *p ); \ +static void functionname ( type *p ) +#else +#define CC_HEADER_PTR_FREE_ROUTINE(type, functionname) \ +static void functionname (); \ +static void functionname ( p ) \ +type *p; +#endif + +#define CC_PTR_FREE_ROUTINE(type, functionname, freelist) \ + CC_HEADER_PTR_FREE_ROUTINE(type, functionname) \ +{ \ + p->next = freelist ; \ + freelist = p; \ +} + + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_FREE_LIST_ROUTINE(type, functionname) \ +static void functionname ( type *p ); \ +static void functionname ( type *p ) +#else +#define CC_HEADER_PTR_FREE_LIST_ROUTINE(type, functionname) \ +static void functionname (); \ +static void functionname ( p ) \ +type *p; +#endif + +#define CC_PTR_FREE_LIST_ROUTINE(type, functionname, freefunction) \ + CC_HEADER_PTR_FREE_LIST_ROUTINE (type, functionname) \ +{ \ + type *next; \ + \ + while (p) { \ + next = p->next; \ + freefunction (p); \ + p = next; \ + } \ +} + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_FREE_WORLD_ROUTINE(functionname) \ +static void functionname (void); \ +static void functionname (void) +#else +#define CC_HEADER_PTR_FREE_WORLD_ROUTINE(functionname) \ +static void functionname (); \ +static void functionname () +#endif + +#define CC_PTR_FREE_WORLD_ROUTINE(type, functionname, chunklist, freelist) \ + CC_HEADER_PTR_FREE_WORLD_ROUTINE(functionname) \ +{ \ + CCbigchunkptr *bp, *bpnext; \ + \ + for (bp = chunklist ; bp; bp = bpnext) { \ + bpnext = bp->next; \ + CCutil_bigchunkfree (bp); \ + } \ + chunklist = (CCbigchunkptr *) NULL; \ + freelist = (type *) NULL; \ +} + + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_LEAKS_ROUTINE(functionname) \ +static int functionname (int *total, int *onlist); \ +static int functionname (int *total, int *onlist) +#else +#define CC_HEADER_PTR_LEAKS_ROUTINE(functionname) \ +static int functionname (); \ +static int functionname (total, onlist) \ +int *total, *onlist; +#endif + +#define CC_PTR_LEAKS_ROUTINE(type,name,chunklist,freelist,field,fieldtype) \ + CC_HEADER_PTR_LEAKS_ROUTINE(name) \ +{ \ + int count = CC_BIGCHUNK / sizeof ( type ); \ + int duplicates = 0; \ + type * p; \ + CCbigchunkptr *bp; \ + \ + *total = 0; \ + *onlist = 0; \ + \ + for (bp = chunklist ; bp; bp = bp->next) \ + (*total) += count; \ + \ + for (p = freelist ; p; p = p->next) { \ + (*onlist)++; \ + p-> field = ( fieldtype ) 0; \ + } \ + for (p = freelist ; p; p = p->next) { \ + if (p-> field == ( fieldtype ) 1) \ + duplicates++; \ + else \ + p-> field = ( fieldtype ) 1; \ + } \ + if (duplicates) { \ + fprintf (stderr, "WARNING: %d duplicates on ptr free list \n", \ + duplicates); \ + } \ + return *total - *onlist; \ +} + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_STATUS_ROUTINE(functionname) \ +static int functionname (int *total, int *onlist); \ +static int functionname (int *total, int *onlist) +#else +#define CC_HEADER_PTR_STATUS_ROUTINE(functionname) \ +static int functionname (); \ +static int functionname (total, onlist) \ +int *total, *onlist; +#endif + +#define CC_PTR_STATUS_ROUTINE(type, name, chunklist, freelist) \ + CC_HEADER_PTR_STATUS_ROUTINE(name) \ +{ \ + int count = CC_BIGCHUNK / sizeof ( type ); \ + type * p; \ + CCbigchunkptr *bp; \ + \ + *total = 0; \ + *onlist = 0; \ + \ + for (bp = chunklist ; bp; bp = bp->next) \ + (*total) += count; \ + \ + for (p = freelist ; p; p = p->next) \ + (*onlist)++; \ + return *total - *onlist; \ +} + + +#define CC_BIGCHUNK ((int) ((1<<16)-16)) + +typedef struct CCbigchunkptr { + void *this; + struct CCbigchunkptr *next; +} CCbigchunkptr; + + +#ifdef CC_PROTOTYPE_ANSI + +void + *CCutil_allocrus (unsigned int size), + *CCutil_reallocrus (void *ptr, unsigned int size), + CCutil_freerus (void *p), + CCutil_bigchunkquery (int *total, int *reserve), + CCutil_bigchunkfree (CCbigchunkptr *bp); + +int + CCutil_reallocrus_scale (void **pptr, int *pnnum, int count, double scale, + unsigned int size), + CCutil_reallocrus_count (void **pptr, int count, unsigned int size), + CCutil_bigchunk_free_world (void); + +CCbigchunkptr + *CCutil_bigchunkalloc (void); + +#else + +void + *CCutil_allocrus (), + *CCutil_reallocrus (), + CCutil_freerus (), + CCutil_bigchunkquery (), + CCutil_bigchunkfree (); + +int + CCutil_reallocrus_scale (), + CCutil_reallocrus_count (), + CCutil_bigchunk_free_world (); + +CCbigchunkptr + *CCutil_bigchunkalloc (); + +#endif + + +/***************************************************************************/ +/* */ +/* bgetopt.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_bix_getopt (int, char **, char *); + +#else + +int + CCutil_bix_getopt (); + +#endif + +#define CC_BIX_GETOPT_UNKNOWN -3038 + +extern int CCutil_bix_optind; +extern char *CCutil_bix_optarg; + + + +/***************************************************************************/ +/* */ +/* dheaps_i.c */ +/* */ +/***************************************************************************/ + +typedef struct CCdheap { + double *key; + int *entry; + int *loc; + int total_space; + int size; +} CCdheap; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCutil_dheap_free (CCdheap *h), + CCutil_dheap_insert (CCdheap *h, int i), + CCutil_dheap_delete (CCdheap *h, int i), + CCutil_dheap_changekey (CCdheap *h, int i, double newkey); +int + CCutil_dheap_init (CCdheap *h, int k), + CCutil_dheap_resize (CCdheap *h, int newsize), + CCutil_dheap_findmin (CCdheap *h), + CCutil_dheap_deletemin (CCdheap *h); + +#else + +void + CCutil_dheap_free (), + CCutil_dheap_insert (), + CCutil_dheap_delete (), + CCutil_dheap_changekey (); +int + CCutil_dheap_init (), + CCutil_dheap_resize (), + CCutil_dheap_findmin (), + CCutil_dheap_deletemin (); + +#endif + + +/***************************************************************************/ +/* */ +/* edg2cyc.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_edge_to_cycle (int ncount, int *elist, int *cyc); + +#else + +int + CCutil_edge_to_cycle (); + +#endif + + + +/***************************************************************************/ +/* */ +/* edgelen.c */ +/* */ +/***************************************************************************/ + +typedef struct CCdatagroup { + double *x; + double *y; + double *z; + int **adj; + int norm; +} CCdatagroup; + + +#ifdef CC_PROTOTYPE_ANSI + +extern int + (*CCutil_dat_edgelen) (int i, int j, CCdatagroup *dat); +int + CCutil_init_dat_edgelen (CCdatagroup *dat), + CCutil_max_edgelen (int i, int j, CCdatagroup *dat), + CCutil_euclid_edgelen (int i, int j, CCdatagroup *dat), + CCutil_ibm_edgelen (int i, int j, CCdatagroup *dat), + CCutil_euclid_ceiling_edgelen (int i, int j, CCdatagroup *dat), + CCutil_euclid3d_edgelen (int i, int j, CCdatagroup *dat), + CCutil_geographic_edgelen (int i, int j, CCdatagroup *dat), + CCutil_att_edgelen (int i, int j, CCdatagroup *dat), + CCutil_dsjrand_edgelen (int i, int j, CCdatagroup *dat), + CCutil_crystal_edgelen (int i, int j, CCdatagroup *dat), + CCutil_matrix_edgelen (int i, int j, CCdatagroup *dat); +void + CCutil_dsjrand_init (int maxdist, int seed), + CCutil_freedatagroup (int ncount, CCdatagroup *dat); + +#else + +extern int + (*CCutil_dat_edgelen) (); +int + CCutil_init_dat_edgelen (), + CCutil_max_edgelen (), + CCutil_euclid_edgelen (), + CCutil_ibm_edgelen (), + CCutil_euclid_ceiling_edgelen (), + CCutil_euclid3d_edgelen (), + CCutil_geographic_edgelen (), + CCutil_att_edgelen (), + CCutil_dsjrand_edgelen (), + CCutil_crystal_edgelen (), + CCutil_matrix_edgelen (); +void + CCutil_dsjrand_init (), + CCutil_freedatagroup (); + +#endif + + +#define CC_KD_NORM_TYPE 128 /* Kdtrees work */ +#define CC_X_NORM_TYPE 256 /* Old nearest works */ +#define CC_JUNK_NORM_TYPE 512 /* Nothing works */ + +#define CC_D2_NORM_SIZE 1024 /* x,y coordinates */ +#define CC_D3_NORM_SIZE 2048 /* x,y,z coordinates */ +#define CC_MATRIX_NORM_SIZE 4096 /* adj matrix */ + +#define CC_NORM_BITS (CC_KD_NORM_TYPE | CC_X_NORM_TYPE | CC_JUNK_NORM_TYPE) +#define CC_NORM_SIZE_BITS (CC_D2_NORM_SIZE | CC_D3_NORM_SIZE | CC_MATRIX_NORM_SIZE) + +#define CC_MAXNORM (0 | CC_KD_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_EUCLIDEAN_CEIL (1 | CC_KD_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_EUCLIDEAN (2 | CC_KD_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_EUCLIDEAN_3D (3 | CC_X_NORM_TYPE | CC_D3_NORM_SIZE) +#define CC_IBM (4 | CC_JUNK_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_ATT (5 | CC_X_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_GEOGRAPHIC (6 | CC_X_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_MATRIXNORM (7 | CC_JUNK_NORM_TYPE | CC_MATRIX_NORM_SIZE) +#define CC_DSJRANDNORM (8 | CC_JUNK_NORM_TYPE) +#define CC_CRYSTAL (9 | CC_X_NORM_TYPE | CC_D3_NORM_SIZE) + +#define CC_GEOGRAPHIC_SCALE (6378.388 * 3.14 / 180.0) /* see edgelen.c */ +#define CC_ATT_SCALE (.31622) /* sqrt(1/10) */ + +/* For X-NORMS, scales are such that |x[i] - x[j]| * scale <= edgelen(i,j). */ +/* Ggeographic is slightly off, since the fractional part of x[i] is really */ +/* really minutes, not fractional degrees. */ + + + +/***************************************************************************/ +/* */ +/* fastread.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_readint (FILE *); + +#else + +int + CCutil_readint (); + +#endif + + + +/***************************************************************************/ +/* */ +/* genhash.c */ +/* */ +/***************************************************************************/ + +typedef struct CCgenhash { + int nelem; + int maxelem; + int size; +#ifdef CC_PROTOTYPE_ANSI + int (*hcmp) (void *key1, void *key2, void *u_data); + unsigned int (*hfunc) (void *key, void *u_data); +#else + int (*hcmp) (); + unsigned int (*hfunc) (); +#endif + void *u_data; + double maxdensity; + double lowdensity; + struct CCgenhash_elem **table; +} CCgenhash; + +typedef struct CCgenhash_iter { + int i; + struct CCgenhash_elem *next; +} CCgenhash_iter; + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_genhash_init (CCgenhash *h, int size, + int (*hcmp) (void *key1, void *key2, void *u_data), + unsigned int (*hfunc) (void *key, void *u_data), + void *u_data, double maxdensity, double lowdensity), + CCutil_genhash_insert (CCgenhash *h, void *key, void *data), + CCutil_genhash_insert_h (CCgenhash *h, unsigned int hashval, void *key, + void *data), + CCutil_genhash_replace (CCgenhash *h, void *key, void *data), + CCutil_genhash_replace_h (CCgenhash *h, unsigned int hashval, void *key, + void *data), + CCutil_genhash_delete (CCgenhash *h, void *key), + CCutil_genhash_delete_h (CCgenhash *h, unsigned int hashval, void *key); + +unsigned int + CCutil_genhash_hash (CCgenhash *h, void *key); + +void + *CCutil_genhash_lookup (CCgenhash *h, void *key), + *CCutil_genhash_lookup_h (CCgenhash *h, unsigned int hashval, void *key), + *CCutil_genhash_next (CCgenhash *h, CCgenhash_iter *iter, void **key, + int *keysize); + +void + CCutil_genhash_u_data (CCgenhash *h, void *u_data), + CCutil_genhash_free (CCgenhash *h, void (*freefunc)(void *key, void *data, + void *u_data)), + CCutil_genhash_start (CCgenhash *h, CCgenhash_iter *iter); + +#else + +int + CCutil_genhash_init (), + CCutil_genhash_insert (), + CCutil_genhash_insert_h (), + CCutil_genhash_replace (), + CCutil_genhash_replace_h (), + CCutil_genhash_delete (), + CCutil_genhash_delete_h (); + +unsigned int + CCutil_genhash_hash (); + +void + *CCutil_genhash_lookup (), + *CCutil_genhash_lookup_h (), + *CCutil_genhash_next (); + +void + CCutil_genhash_u_data (), + CCutil_genhash_free (), + CCutil_genhash_start (); + +#endif + + + +/***************************************************************************/ +/* */ +/* getdata.c */ +/* */ +/***************************************************************************/ + +#define CC_MASTER_NO_DAT 100 +#define CC_MASTER_DAT 101 + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_getdata (char *datname, int binary_in, int innorm, int *ncount, + CCdatagroup *dat), + CCutil_writemaster (char *mastername, int ncount, CCdatagroup *dat, + int *perm), + CCutil_getmaster (char *mastername, int *ncount, CCdatagroup *dat, + int **perm), + CCutil_getnodeweights (char *weightname, int ncount, int weight_limit, + double **wcoord), + CCutil_gettsplib (char *datname, int *ncount, CCdatagroup *dat), + CCutil_datagroup_perm (int ncount, CCdatagroup *dat, int *perm), + CCutil_getedgelist (int ncount, char *fname, int *ecount, int **elist, + int **elen), + CCutil_getedgelist_n (int *ncount, char *fname, int *ecount, int **elist, + int **elen), + CCutil_getcycle_edgelist (int ncount, char *cyclename, int *outcycle), + CCutil_getcycle (int ncount, char *cyclename, int *outcycle), + CCutil_getedges_double (int *ncount, char *fname, int *ecount, int **elist, + double **elen, int binary_in), + CCutil_writeedges (int ncount, char *outedgename, int ecount, int *elist, + CCdatagroup *dat), + CCutil_writecycle_edgelist (int ncount, char *outedgename, int *cycle, + CCdatagroup *dat), + CCutil_writecycle (int ncount, char *outcyclename, int *cycle), + CCutil_writeedges_double (int ncount, char *outedgename, int ecount, + int *elist, double *elen, int binary_out); + +#else + +int + CCutil_getdata (), + CCutil_writemaster (), + CCutil_getmaster (), + CCutil_getnodeweights (), + CCutil_gettsplib (), + CCutil_datagroup_perm (), + CCutil_getedgelist (), + CCutil_getedgelist_n (), + CCutil_getcycle_edgelist (), + CCutil_getcycle (), + CCutil_getedges_double (), + CCutil_writeedges (), + CCutil_writecycle_edgelist (), + CCutil_writecycle (), + CCutil_writeedges_double (); + +#endif + + + +/***************************************************************************/ +/* */ +/* priority.c */ +/* */ +/***************************************************************************/ + +typedef struct CCpriority { + CCdheap heap; + union pri_data { + void *data; + int next; + } *pri_info; + int space; + int freelist; +} CCpriority; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCutil_priority_free (CCpriority *pri), + CCutil_priority_delete (CCpriority *pri, int handle), + CCutil_priority_changekey (CCpriority *pri, int handle, double newkey), + *CCutil_priority_findmin (CCpriority *pri, double *keyval), + *CCutil_priority_deletemin (CCpriority *pri, double *keyval); + +int + CCutil_priority_init (CCpriority *pri, int k), + CCutil_priority_insert (CCpriority *pri, void *data, double keyval); + +#else + +void + CCutil_priority_free (), + CCutil_priority_delete (), + CCutil_priority_changekey (), + *CCutil_priority_findmin (), + *CCutil_priority_deletemin (); + +int + CCutil_priority_init (), + CCutil_priority_insert (); + +#endif + + +/***************************************************************************/ +/* */ +/* safe_io.c */ +/* */ +/***************************************************************************/ + +#define CC_SBUFFER_SIZE (4000) +#define CC_SFNAME_SIZE (32) + +typedef struct CC_SFILE { + int status; + int desc; + int chars_in_buffer; + int current_buffer_char; /* only used for reading */ + int bits_in_last_char; /* writing: number of empty bits in + * buffer[chars_in_buffer]; + * reading: number of full bits in + * buffer[?] */ + int pos; + char fname[CC_SFNAME_SIZE]; + unsigned char buffer[CC_SBUFFER_SIZE]; +} CC_SFILE; + +#ifdef CC_PROTOTYPE_ANSI + +CC_SFILE + *CCutil_sopen (char *f, char *s), + *CCutil_sdopen (int d, char *s); + +int + CCutil_swrite (CC_SFILE *f, unsigned char *buf, int size), + CCutil_swrite_bits (CC_SFILE *f, unsigned int x, int xbits), + CCutil_swrite_char (CC_SFILE *f, unsigned char x), + CCutil_swrite_string (CC_SFILE *f, unsigned char *x), + CCutil_swrite_short (CC_SFILE *f, unsigned short x), + CCutil_swrite_int (CC_SFILE *f, unsigned int x), + CCutil_swrite_double (CC_SFILE *f, double x), + CCutil_sread (CC_SFILE *f, unsigned char *buf, int size), + CCutil_sread_bits (CC_SFILE *f, unsigned int *x, int xbits), + CCutil_sread_char (CC_SFILE *f, unsigned char *x), + CCutil_sread_string (CC_SFILE *f, unsigned char *x, int maxlen), + CCutil_sread_short (CC_SFILE *f, unsigned short *x), + CCutil_sread_short_r (CC_SFILE *f, unsigned short *x), + CCutil_sread_int (CC_SFILE *f, unsigned int *x), + CCutil_sread_int_r (CC_SFILE *f, unsigned int *x), + CCutil_sread_double (CC_SFILE *f, double *x), + CCutil_sread_double_r (CC_SFILE *f, double *x), + CCutil_sflush (CC_SFILE *f), + CCutil_stell (CC_SFILE *f), + CCutil_sseek (CC_SFILE *f, int offset), + CCutil_srewind (CC_SFILE *f), + CCutil_sclose (CC_SFILE *f), + CCutil_sbits (unsigned int x), + CCutil_sdelete_file (char *fname), + CCutil_sdelete_file_backup (char *fname); + +#else + +CC_SFILE + *CCutil_sopen (), + *CCutil_sdopen (); + +int + CCutil_swrite (), + CCutil_swrite_bits (), + CCutil_swrite_char (), + CCutil_swrite_string (), + CCutil_swrite_short (), + CCutil_swrite_int (), + CCutil_swrite_double (), + CCutil_sread (), + CCutil_sread_bits (), + CCutil_sread_char (), + CCutil_sread_string (), + CCutil_sread_short (), + CCutil_sread_short_r (), + CCutil_sread_int (), + CCutil_sread_int_r (), + CCutil_sread_double (), + CCutil_sread_double_r (), + CCutil_sflush (), + CCutil_stell (), + CCutil_sseek (), + CCutil_srewind (), + CCutil_sclose (), + CCutil_sbits (), + CCutil_sdelete_file (), + CCutil_sdelete_file_backup (); + +#endif + + + +/***************************************************************************/ +/* */ +/* sortrus.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +void + CCutil_int_array_quicksort (int *len, int n), + CCutil_int_perm_quicksort (int *perm, int *len, int n), + CCutil_double_perm_quicksort (int *perm, double *len, int n), + CCutil_rselect (int *arr, int l, int r, int m, double *coord); + +char + *CCutil_linked_radixsort (char *data, char *datanext, char *dataval, + int valsize); + +#else + +void + CCutil_int_array_quicksort (), + CCutil_int_perm_quicksort (), + CCutil_double_perm_quicksort (), + CCutil_rselect (); + +char + *CCutil_linked_radixsort (); + +#endif + + + +/***************************************************************************/ +/* */ +/* urandom.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +void + CCutil_sprand (int); +int + CCutil_lprand (void); + +#else + +void + CCutil_sprand (); +int + CCutil_lprand (); + +#endif + + + +/***************************************************************************/ +/* */ +/* util.c */ +/* */ +/***************************************************************************/ + + +#ifdef CC_PROTOTYPE_ANSI + +char + *CCutil_strrchr (char *s, int c); + +unsigned int + CCutil_nextprime (unsigned int x); + +int + CCutil_our_gcd (int a, int b); + +#else + +char + *CCutil_strrchr (); + +unsigned int + CCutil_nextprime (); + +int + CCutil_our_gcd (); + +#endif + + + +/***************************************************************************/ +/* */ +/* zeit.c */ +/* */ +/***************************************************************************/ + + +#ifdef CC_PROTOTYPE_ANSI + +double + CCutil_zeit (void), + CCutil_real_zeit (void); + +#else + +double + CCutil_zeit (), + CCutil_real_zeit (); + +#endif + + +#endif /* __UTIL_H */ diff --git a/contrib/blossom/concorde97/KDTREE/Makefile b/contrib/blossom/concorde97/KDTREE/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0a5d597ba21e8f3bef8548f5f78c3bb32d7968d6 --- /dev/null +++ b/contrib/blossom/concorde97/KDTREE/Makefile @@ -0,0 +1,33 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=kdtree.a +LIBSRCS=kdbuild.c kdnear.c kdspan.c kdtwoopt.c +LIBS=$(ROOT)/UTIL/util.a +ALLSRCS=kd_main.c $(LIBSRCS) + +all: kdtree $(LIB) + +kdtree: kd_main.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ -lm + +clean: + -rm -f *.$o $(LIB) kdtree + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +kd_main.$o: kd_main.c $(I)/machdefs.h $(I)/util.h $(I)/kdtree.h +kdbuild.$o: kdbuild.c $(I)/machdefs.h $(I)/util.h $(I)/kdtree.h +kdnear.$o: kdnear.c $(I)/machdefs.h $(I)/util.h $(I)/kdtree.h +kdspan.$o: kdspan.c $(I)/machdefs.h $(I)/util.h $(I)/kdtree.h +kdtwoopt.$o: kdtwoopt.c $(I)/machdefs.h $(I)/util.h $(I)/kdtree.h diff --git a/contrib/blossom/concorde97/KDTREE/kd_main.c b/contrib/blossom/concorde97/KDTREE/kd_main.c new file mode 100644 index 0000000000000000000000000000000000000000..013f940b288b025939cf08d6a01f12212bf32dad --- /dev/null +++ b/contrib/blossom/concorde97/KDTREE/kd_main.c @@ -0,0 +1,544 @@ +/***************************************************************************/ +/* */ +/* CODE FOR TESTING KD-TREE ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 24, 1995 (cofeb24) */ +/* */ +/* For a short describtion see usage () */ +/* */ +/***************************************************************************/ + + +#include "machdefs.h" +#include "util.h" +#include "kdtree.h" + +static int norm = CC_EUCLIDEAN; +static int usenodeweights = 0; +static int random_weight_limit = 0; +static int seed = 0; +static int nnodes_want = 0; +static int nearnum = 0; +static int quadnearnum = 0; +static int find_nearest_tour = 0; +static int find_nearest_2match = 0; +static int find_greedy_tour = 0; +static int find_fa_tour = 0; +static int find_qboruvka_tour = 0; +static int find_boruvka_tour = 0; +static int find_twoopt_tour = 0; +static int find_3opt_tour = 0; +static int find_spanning_tree = 0; +static int run_two_and_a_half_opt = 0; +static int binary_in = 0; +static int tsplib_in = 0; + +static char *nodefile = (char *) NULL; +static char *weightfile = (char *) NULL; +static char *cycle_for_twoopt = (char *) NULL; +static char *outfile = (char *) NULL; + + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int ac, char **av); +static void + usage (char *f); +static int + parseargs (int ac, char **av); + +#else + +int + main (); +static void + usage (); +static int + parseargs (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + double val, szeit; + CCkdtree kt; + CCdatagroup dat; + double *wcoord = (double *) NULL; + int ncount; + int *ttour = (int *) NULL, *tour2 = (int *) NULL; + int rval = 0; + int ecount; + int *elist = (int *) NULL; + + seed = (int) CCutil_real_zeit (); + if (parseargs (ac, av)) + return 1; + CCutil_sprand (seed); + + if ((!nnodes_want && !nodefile) || (tsplib_in && !nodefile)) { + usage (av[0]); + return 1; + } + + if (tsplib_in) { + if (CCutil_gettsplib (nodefile, &ncount, &dat)) { + fprintf (stderr, "could not read the TSPLIB file\n"); + rval = 1; + goto CLEANUP; + } + norm = dat.norm; + } else { + ncount = nnodes_want; + if (CCutil_getdata (nodefile, binary_in, norm, &ncount, &dat)) { + rval = 1; + goto CLEANUP; + } + } + if ((norm & CC_NORM_BITS) != CC_KD_NORM_TYPE) { + fprintf (stderr, "Cannot run CCkdtree with norm %d\n", norm); + rval = 1; + goto CLEANUP; + } + + if (CCutil_init_dat_edgelen (&dat)) { + fprintf (stderr, "init_dat_edgelen failed\n"); + rval = 1; + goto CLEANUP; + } + + if (usenodeweights) { + if (CCutil_getnodeweights (weightfile, ncount, random_weight_limit, + &wcoord)) { + fprintf (stderr, "could not read the nodeweight file\n"); + rval = 1; + goto CLEANUP; + } + } + + if (find_nearest_tour || find_greedy_tour || find_twoopt_tour || + find_fa_tour || find_qboruvka_tour || find_boruvka_tour || + find_3opt_tour) { + ttour = CC_SAFE_MALLOC (ncount, int); + if (!ttour) { + rval = 1; + goto CLEANUP; + } + } + if (find_twoopt_tour || find_3opt_tour) { + tour2 = CC_SAFE_MALLOC (ncount, int); + if (!tour2) { + rval = 1; + goto CLEANUP; + } + } + + if (cycle_for_twoopt) { + if (CCutil_getcycle (ncount, cycle_for_twoopt, ttour)) { + fprintf (stderr, "Getcycle failed\n"); + rval = 1; + goto CLEANUP; + } + } else if (find_nearest_tour) { + szeit = CCutil_zeit (); + if (CCkdtree_nearest_neighbor_tour ((CCkdtree *) NULL, ncount, + CCutil_lprand () % ncount, &dat, ttour, &val)) { + fprintf (stderr, "Nearest neighbor failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("NN tour: %.2f (%.2f seconds)\n", val, CCutil_zeit () - szeit); + fflush (stdout); + } else if (find_fa_tour) { + szeit = CCutil_zeit (); + if (CCkdtree_far_add_tour ((CCkdtree *) NULL, ncount, + CCutil_lprand () % ncount, &dat, ttour, &val)) { + fprintf (stderr, "Farthest Addition Tour failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("FA tour: %.2f (%.2f seconds)\n", val, CCutil_zeit () - szeit); + fflush (stdout); + { + char *marks; + int i; + + marks = CC_SAFE_MALLOC (ncount, char); + if (!marks) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) + marks[i] = 0; + for (i = 0; i < ncount; i++) { + if (ttour[i] < 0 || ttour[i] >= ncount) { + fprintf (stderr, "MADE NODE IN FA TOUR: %d\n", ttour[i]); + rval = 1; + goto CLEANUP; + } + if (marks[ttour[i]]) { + fprintf (stderr, "REPEAT NODE IN FA-TOUR: %d\n", ttour[i]); + fprintf (stderr, "BAD INDEX: %d\n", i); + rval = 1; + goto CLEANUP; + } else { + marks[ttour[i]] = 1; + } + } + CC_FREE (marks, char); + } + } else if (find_boruvka_tour) { + szeit = CCutil_zeit (); + if (CCkdtree_boruvka_tour ((CCkdtree *) NULL, ncount, &dat, ttour, + &val)) { + fprintf (stderr, "Boruvka tour failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Boruvka tour: %.2f (%.2f seconds)\n", + val, CCutil_zeit () - szeit); + fflush (stdout); + } else if (find_qboruvka_tour) { + szeit = CCutil_zeit (); + if (CCkdtree_qboruvka_tour ((CCkdtree *) NULL, ncount, &dat, ttour, + &val)) { + fprintf (stderr, "Quick-Boruvka tour failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Quick-Boruvka tour: %.2f (%.2f seconds)\n", + val, CCutil_zeit () - szeit); + fflush (stdout); + } else if (find_greedy_tour) { + szeit = CCutil_zeit (); + if (CCkdtree_greedy_tour ((CCkdtree *) NULL, ncount, &dat, ttour, + &val)) { + fprintf (stderr, "Greedy tour failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Greedy tour: %.2f (%.2f seconds)\n", + val, CCutil_zeit () - szeit); + fflush (stdout); + } + + if (find_twoopt_tour) { + szeit = CCutil_zeit (); + if (CCkdtree_twoopt_tour ((CCkdtree *) NULL, ncount, &dat, ttour, + tour2, &val, run_two_and_a_half_opt, 0)) { + fprintf (stderr, "Two-opt failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("2-opt tour: %.2f (%.2f seconds))\n", + val, CCutil_zeit () - szeit); + fflush (stdout); + } else if (find_3opt_tour) { + szeit = CCutil_zeit (); + if (CCkdtree_3opt_tour ((CCkdtree *) NULL, ncount, &dat, ttour, tour2, + &val, 0)) { + fprintf (stderr, "3-opt failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("3-opt tour: %.2f (%.2f seconds))\n", + val, CCutil_zeit () - szeit); + fflush (stdout); + { + char *marks; + int i; + + marks = CC_SAFE_MALLOC (ncount, char); + if (!marks) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) + marks[i] = 0; + for (i = 0; i < ncount; i++) { + if (tour2[i] < 0 || tour2[i] >= ncount) { + fprintf (stderr, "MADE NODE IN TOUR2: %d\n", tour2[i]); + rval = 1; + goto CLEANUP; + } + if (marks[tour2[i]]) { + fprintf (stderr, "REPEATED NODE IN TOUR2: %d\n", + tour2[i]); + rval = 1; + goto CLEANUP; + } else { + marks[tour2[i]] = 1; + } + } + CC_FREE (marks, char); + } + } + + if (find_spanning_tree) { + if (outfile) { + ecount = ncount - 1; + elist = CC_SAFE_MALLOC (2 * ecount, int); + if (!elist) { + rval = 1; + goto CLEANUP; + } + } + szeit = CCutil_zeit (); + if (CCkdtree_prim_spanningtree ((CCkdtree *) NULL, ncount, &dat, wcoord, + elist, &val)) { + fprintf (stderr, "Prim_spanningtree failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Min spanning tree: %.2f (%.2f seconds)\n", val, + CCutil_zeit () - szeit); + fflush (stdout); + } else if (nearnum) { + int wantlist = (outfile ? 1 : 0); + szeit = CCutil_zeit (); + if (CCkdtree_k_nearest ((CCkdtree *) NULL, ncount, nearnum, &dat, + wcoord, wantlist, &ecount, &elist)) { + fprintf (stderr, "k-nearest failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Nearest %d: %.2f (seconds)\n", + nearnum, CCutil_zeit () - szeit); + fflush (stdout); + } else if (quadnearnum) { + int wantlist = (outfile ? 1 : 0); + szeit = CCutil_zeit (); + if (CCkdtree_quadrant_k_nearest ((CCkdtree *) NULL, ncount, quadnearnum, + &dat, wcoord, wantlist, &ecount, &elist)) { + fprintf (stderr, "k-nearest failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Quadrant-Nearest %d: %.2f (seconds)\n", quadnearnum, + CCutil_zeit () - szeit); + fflush (stdout); + } else if (find_nearest_2match) { + if (outfile) { + ecount = ncount; + elist = CC_SAFE_MALLOC (2 * ecount, int); + if (!elist) { + rval = 1; + goto CLEANUP; + } + } + szeit = CCutil_zeit (); + if (CCkdtree_nearest_neighbor_2match ((CCkdtree *) NULL, ncount, + CCutil_lprand () % ncount, &dat, elist, &val)) { + fprintf (stderr, "Nearest neighbor 2-matching failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Nearest 2-matching: %.2f (%.2f seconds)\n", val, + CCutil_zeit () - szeit); + fflush (stdout); + } else if (!find_nearest_tour && !find_greedy_tour && !find_twoopt_tour && + !find_qboruvka_tour && !find_boruvka_tour && !find_fa_tour && + !find_3opt_tour) { + szeit = CCutil_zeit (); + if (CCkdtree_build (&kt, ncount, &dat, wcoord)) { + fprintf (stderr, "CCkdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Built CCkdtree: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + CCkdtree_free (&kt); + } + + if (outfile) { + if (find_twoopt_tour || find_3opt_tour) { + if (CCutil_writecycle (ncount, outfile, tour2)) { + fprintf (stderr, "Could not write tour\n"); + rval = 1; + goto CLEANUP; + } + } else if (find_nearest_tour || find_greedy_tour || find_fa_tour || + find_qboruvka_tour || find_boruvka_tour) { + if (CCutil_writecycle (ncount, outfile, ttour)) { + fprintf (stderr, "Could not write tour\n"); + rval = 1; + goto CLEANUP; + } + } else if (find_spanning_tree || find_nearest_2match || nearnum || + quadnearnum) { + if (CCutil_writeedges (ncount, outfile, ecount, elist, &dat)) { + fprintf (stderr, "Could not write the edge set\n"); + rval = 1; + goto CLEANUP; + } + } + } + + +CLEANUP: + + CCutil_freedatagroup (ncount, &dat); + if (wcoord) + CC_FREE (wcoord, double); + if (ttour) + CC_FREE (ttour, int); + if (tour2) + CC_FREE (tour2, int); + if (elist) + CC_FREE (elist, int); + if (CCutil_bigchunk_free_world ()) { + fprintf (stderr, "ERROR: CCutil_bigcunk free world failed\n"); + return 1; + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "bfghjk:mn:o:pq:s:tTvw:W:x:Xz:Z012?")) != EOF) + switch (c) { + case 'b': + binary_in = 1; + break; + case 'f': + find_fa_tour = 1; + break; + case 'j': + find_qboruvka_tour = 1; + break; + case 'w': + usenodeweights = 1; + weightfile = CCutil_bix_optarg; + break; + case 'W': + usenodeweights = 1; + random_weight_limit = atoi (CCutil_bix_optarg); + break; + case 'k': + nnodes_want = atoi (CCutil_bix_optarg); + break; + case 's': + seed = atoi (CCutil_bix_optarg); + break; + case 'n': + nearnum = atoi (CCutil_bix_optarg); + break; + case 'm': + find_nearest_2match++; + break; + case 'q': + quadnearnum = atoi (CCutil_bix_optarg); + break; + case 't': + find_nearest_tour++; + break; + case 'g': + find_greedy_tour++; + break; + case 'v': + find_boruvka_tour++; + break; + case 'Z': + find_twoopt_tour++; + find_greedy_tour++; + break; + case 'z': + cycle_for_twoopt = CCutil_bix_optarg; + find_twoopt_tour++; + break; + case 'X': + find_3opt_tour++; + find_greedy_tour++; + break; + case 'x': + cycle_for_twoopt = CCutil_bix_optarg; + find_3opt_tour++; + break; + case 'h': + run_two_and_a_half_opt++; + break; + case 'o': + outfile = CCutil_bix_optarg; + break; + case 'p': + find_spanning_tree++; + break; + case 'T': + tsplib_in = 1; + break; + case '0': + norm = CC_MAXNORM; + break; + case '1': + norm = CC_EUCLIDEAN_CEIL; + break; + case '2': + norm = CC_EUCLIDEAN; + break; + case CC_BIX_GETOPT_UNKNOWN: + case '?': + default: + usage (av[0]); + return 1; + } + if (CCutil_bix_optind < ac) + nodefile = av[CCutil_bix_optind++]; + + if (CCutil_bix_optind > ac) { + usage (av[0]); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "Usage: %s [- see below -] [node_file]\n", f); + fprintf (stderr, " -b: dat file in binary-ints\n"); + fprintf (stderr, " -w f use node weights from file\n"); + fprintf (stderr, " -W # use random node weights (0, #)\n"); + fprintf (stderr, " -k # number of nodes for random problem\n"); + fprintf (stderr, " -s # random seed\n"); + fprintf (stderr, " -n # find # nearest graph\n"); + fprintf (stderr, " -q # find quadrant # nearest graph\n"); + fprintf (stderr, " -t nearest neighbor tour\n"); + fprintf (stderr, " -g greedy tour\n"); + fprintf (stderr, " -j quick-boruvka tour\n"); + fprintf (stderr, " -v boruvka tour\n"); + fprintf (stderr, " -f farthest addition tour\n"); + fprintf (stderr, " -z f two_opt the given cycle\n"); + fprintf (stderr, " -Z run two_opt (default: on greedy)\n"); + fprintf (stderr, " -x f 3_opt the given cycle\n"); + fprintf (stderr, " -X run 3_opt (default: on greedy)\n"); + fprintf (stderr, " -h use limited 3-swaps in two_opt\n"); + fprintf (stderr, " -m nearest neighbor 2-matcing\n"); + fprintf (stderr, " -p min spanning tree (prim)\n"); + fprintf (stderr, " -o f write the cycle or edge set to f\n"); + fprintf (stderr, " -T node file is a TSPLIB file\n"); + fprintf (stderr, " -0 Max norm for edge lengths\n"); + fprintf (stderr, " -1 Euclidean Ceiling norm\n"); + fprintf (stderr, " -2 Rounded Euclidean norm (default)\n"); +} diff --git a/contrib/blossom/concorde97/KDTREE/kdbuild.c b/contrib/blossom/concorde97/KDTREE/kdbuild.c new file mode 100644 index 0000000000000000000000000000000000000000..3efcf0091044c730fc0e17dc45104ad7ef910909 --- /dev/null +++ b/contrib/blossom/concorde97/KDTREE/kdbuild.c @@ -0,0 +1,474 @@ +/***************************************************************************/ +/* */ +/* ROUTINE FOR BUILDING KDTREES */ +/* */ +/* (Based on Jon Bentley's paper "K-d trees for semidynamic point sets") */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 24, 1995 (cofeb24) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCkdtree_build (CCkdtree *intree, int ncount, CCdatagroup *dat, */ +/* double *wcoord) */ +/* -When called, intree should point to a CCkdtree struct that the */ +/* funtion will load with the tree it builds. The wcoord array */ +/* is used for node weights (like in Held-Karp), it can be NULL. */ +/* The node weights must be nonegative (for cutoffs). */ +/* void CCkdtree_free (CCkdtree *kt) */ +/* -Frees the space (including the ptrs) used by kt. */ +/* void CCkdtree_delete (CCkdtree *kt, int k) */ +/* -Deletes the point k from the CCkdtree kt. */ +/* void CCkdtree_undelete (CCkdtree *kt, int k) */ +/* -Puts the previously deleted point k back into kt. */ +/* void CCkdtree_delete_all (CCkdtree *kt, int ncount) */ +/* -Deletes all points in kt. */ +/* void CCkdtree_undelete_all (CCkdtree *kt, int ncount) */ +/* -Puts all deleted points back in kt. Used to cleanup trees. */ +/* */ +/* NOTES: */ +/* On a 32 bit machine, a CCkdtree on n nodes needs about 52n bytes */ +/* of memory. CCkdtree_build will return 1 if an error occurs (most */ +/* likely running out of memory). */ +/* CCutil_sprand () should be called before calling */ +/* CCkdtree_build (). */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "kdtree.h" + +#define CUTOFF 5 +#define BNDS_DEPTH 5 /* When bnds info is recorded */ +#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) +#define BIGDOUBLE 100000000.0 + +#ifdef CC_PROTOTYPE_ANSI + +static void + kdtree_free_work (CCkdnode *p), + kdtree_free_world (void); +static unsigned char + findmaxspread (int l, int u, CCkdtree *thetree, double *datx, + double *daty, double *datw); +static CCkdnode + *build (int l, int u, int *depth, double *current_bnds_x, + double *current_bnds_y, CCkdtree *thetree, double *datx, + double *daty, double *datw); + +#else + +static void + kdtree_free_work (), + kdtree_free_world (); +static unsigned char + findmaxspread (); +static CCkdnode + *build (); + +#endif + +CC_PTR_ALLOC_ROUTINE (CCkdnode, CCkdnodealloc, CCkdnodechunklist, + CCkdnodefreelist) +CC_PTR_FREE_ROUTINE (CCkdnode, CCkdnodefree, CCkdnodefreelist) +CC_PTR_FREE_WORLD_ROUTINE (CCkdnode, CCkdnodefree_world, CCkdnodechunklist, + CCkdnodefreelist) +CC_PTR_LEAKS_ROUTINE (CCkdnode, CCkdnode_check_leaks, CCkdnodechunklist, + CCkdnodefreelist, empty, char) +CC_PTR_STATUS_ROUTINE (CCkdnode, CCkdnode_status, CCkdnodechunklist, + CCkdnodefreelist) + +CC_PTR_ALLOC_ROUTINE (CCkdbnds, CCkdbndsalloc, CCkdbndschunklist, + CCkdbndsfreelist) +CC_PTR_FREE_ROUTINE (CCkdbnds, CCkdbndsfree, CCkdbndsfreelist) +CC_PTR_FREE_WORLD_ROUTINE (CCkdbnds, CCkdbndsfree_world, CCkdbndschunklist, + CCkdbndsfreelist) +CC_PTR_LEAKS_ROUTINE (CCkdbnds, CCkdbnds_check_leaks, CCkdbndschunklist, + CCkdbndsfreelist, x[0], double) + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_build (CCkdtree *intree, int ncount, CCdatagroup *dat, + double *wcoord) +#else +int CCkdtree_build (intree, ncount, dat, wcoord) +CCkdtree *intree; +int ncount; +CCdatagroup *dat; +double *wcoord; +#endif +{ + int i; + int depth; + double current_bnds_x[2]; + double current_bnds_y[2]; + CCkdtree *thetree; + + if (wcoord != (double *) NULL) { + for (i = 0; i < ncount; i++) { + if (wcoord[i] < -0.00000001) { + fprintf (stderr, "Cannot build with negative node weights\n"); + return 1; + } + } + } + + thetree = intree; + thetree->perm = CC_SAFE_MALLOC (ncount, int); + if (!thetree->perm) + return 1; + for (i = 0; i < ncount; i++) + thetree->perm[i] = i; + + thetree->bucketptr = CC_SAFE_MALLOC (ncount, CCkdnode *); + if (!thetree->bucketptr) { + CC_FREE (thetree->perm, int); + return 1; + } + + depth = 0; + current_bnds_x[0] = -BIGDOUBLE; + current_bnds_x[1] = BIGDOUBLE; + current_bnds_y[0] = -BIGDOUBLE; + current_bnds_y[1] = BIGDOUBLE; + + thetree->root = build (0, ncount - 1, &depth, current_bnds_x, + current_bnds_y, thetree, dat->x, dat->y, wcoord); + if (!(thetree->root)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + CC_FREE (thetree->perm, int); + CC_FREE (thetree->bucketptr, CCkdnode *); + return 1; + } else { + thetree->root->father = (CCkdnode *) NULL; + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCkdtree_free (CCkdtree *kt) +#else +void CCkdtree_free (kt) +CCkdtree *kt; +#endif +{ + int total, onlist; + + if (kt->perm) + CC_FREE (kt->perm, int); + if (kt->bucketptr) + CC_FREE (kt->bucketptr, CCkdnode *); + kdtree_free_work (kt->root); + kt->root = (CCkdnode *) NULL; + if (CCkdnode_status (&total, &onlist)) { + printf ("Active Kdtree Nodes: %d\n", total - onlist); + fflush (stdout); + } else { + kdtree_free_world (); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void kdtree_free_world (void) +#else +static void kdtree_free_world () +#endif +{ + int total, onlist; + + if (CCkdnode_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding CCkdnodes\n", total - onlist); + } + if (CCkdbnds_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding CCkdbnds\n", total - onlist); + } + CCkdnodefree_world (); + CCkdbndsfree_world (); +} + +#ifdef CC_PROTOTYPE_ANSI +static void kdtree_free_work (CCkdnode *p) +#else +static void kdtree_free_work (p) +CCkdnode *p; +#endif +{ + if (p->bucket) { + if (p->bnds) + CCkdbndsfree (p->bnds); + CCkdnodefree (p); + } else { + kdtree_free_work (p->loson); + kdtree_free_work (p->hison); + if (p->bnds) + CCkdbndsfree (p->bnds); + CCkdnodefree (p); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static CCkdnode *build (int l, int u, int *depth, double *current_bnds_x, + double *current_bnds_y, CCkdtree *thetree, + double *datx, double *daty, double *datw) +#else +static CCkdnode *build (l, u, depth, current_bnds_x, current_bnds_y, thetree, + datx, daty, datw) +int l, u; +int *depth; +double *current_bnds_x, *current_bnds_y; +CCkdtree *thetree; +double *datx, *daty, *datw; +#endif +{ + CCkdnode *p; + int i, m; + double savebnd; + + (*depth)++; + p = CCkdnodealloc (); + if (!p) { + (*depth)--; + return (CCkdnode *) NULL; + } + p->empty = 0; + + if (u - l + 1 < CUTOFF) { + p->bucket = 1; + p->lopt = l; + p->hipt = u; + for (i = l; i <= u; i++) + thetree->bucketptr[thetree->perm[i]] = p; + p->bnds = (CCkdbnds *) NULL; + } else { + p->bucket = 0; + if (!((*depth) % BNDS_DEPTH)) { + p->bnds = CCkdbndsalloc (); + if (!p->bnds) { + (*depth)--; + CCkdnodefree (p); + return (CCkdnode *) NULL; + } + p->bnds->x[0] = current_bnds_x[0]; + p->bnds->x[1] = current_bnds_x[1]; + p->bnds->y[0] = current_bnds_y[0]; + p->bnds->y[1] = current_bnds_y[1]; + } else { + p->bnds = (CCkdbnds *) NULL; + } + + p->cutdim = findmaxspread (l, u, thetree, datx, daty, datw); + m = (l + u) / 2; + switch (p->cutdim) { + case 0: + CCutil_rselect (thetree->perm, l, u, m, datx); + p->cutval = datx[thetree->perm[m]]; + + savebnd = current_bnds_x[1]; + current_bnds_x[1] = p->cutval; + p->loson = build (l, m, depth, current_bnds_x, current_bnds_y, + thetree, datx, daty, datw); + if (!p->loson) + { (*depth)--; CCkdnodefree (p); return (CCkdnode *) NULL; } + current_bnds_x[1] = savebnd; + + savebnd = current_bnds_x[0]; + current_bnds_x[0] = p->cutval; + p->hison = build (m + 1, u, depth, current_bnds_x, current_bnds_y, + thetree, datx, daty, datw); + if (!p->hison) + { (*depth)--; CCkdnodefree (p); return (CCkdnode *) NULL; } + current_bnds_x[0] = savebnd; + + break; + case 1: + CCutil_rselect (thetree->perm, l, u, m, daty); + p->cutval = daty[thetree->perm[m]]; + + savebnd = current_bnds_y[1]; + current_bnds_y[1] = p->cutval; + p->loson = build (l, m, depth, current_bnds_x, current_bnds_y, + thetree, datx, daty, datw); + if (!p->loson) + { (*depth)--; CCkdnodefree (p); return (CCkdnode *) NULL; } + current_bnds_y[1] = savebnd; + + savebnd = current_bnds_y[0]; + current_bnds_y[0] = p->cutval; + p->hison = build (m + 1, u, depth, current_bnds_x, current_bnds_y, + thetree, datx, daty, datw); + if (!p->hison) + { (*depth)--; CCkdnodefree (p); return (CCkdnode *) NULL; } + current_bnds_y[0] = savebnd; + + break; + case 2: + CCutil_rselect (thetree->perm, l, u, m, datw); + p->cutval = datw[thetree->perm[m]]; + + p->loson = build (l, m, depth, current_bnds_x, current_bnds_y, + thetree, datx, daty, datw); + if (!p->loson) + { (*depth)--; CCkdnodefree (p); return (CCkdnode *) NULL; } + + p->hison = build (m + 1, u, depth, current_bnds_x, current_bnds_y, + thetree, datx, daty, datw); + if (!p->hison) + { (*depth)--; CCkdnodefree (p); return (CCkdnode *) NULL; } + + break; + } + p->loson->father = p; + p->hison->father = p; + } + (*depth)--; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static unsigned char findmaxspread (int l, int u, CCkdtree *thetree, + double *datx, double *daty, double *datw) +#else +static unsigned char findmaxspread (l, u, thetree, datx, daty, datw) +int l, u; +CCkdtree *thetree; +double *datx, *daty, *datw; +#endif +{ + int i; + double xmax, xmin, xval, xspread; + double ymax, ymin, yval, yspread; + double wmax, wmin, wval, wspread; + + wmax = (double) 0.0; + wmin = (double) 0.0; + + if (datw != (double *) NULL) { + wmin = datw[thetree->perm[l]]; + wmax = wmin; + } + xmin = datx[thetree->perm[l]]; + xmax = xmin; + ymin = daty[thetree->perm[l]]; + ymax = ymin; + for (i = l + 1; i <= u; i++) { + xval = datx[thetree->perm[i]]; + if (xval < xmin) + xmin = xval; + else if (xval > xmax) + xmax = xval; + yval = daty[thetree->perm[i]]; + if (yval < ymin) + ymin = yval; + else if (yval > ymax) + ymax = yval; + if (datw != (double *) NULL) { + wval = datw[thetree->perm[i]]; + if (wval < wmin) + wmin = wval; + else if (wval > wmax) + wmax = wval; + } + } + + xspread = xmax - xmin; + yspread = ymax - ymin; + + if (datw != (double *) NULL) { + wspread = (wmax - wmin); + if (xspread >= yspread && xspread >= wspread) + return (unsigned char) 0; + else if (yspread >= xspread && yspread >= wspread) + return (unsigned char) 1; + else { + return (unsigned char) 2; + } + } else { + if (xspread >= yspread) + return (unsigned char) 0; + else + return (unsigned char) 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCkdtree_delete (CCkdtree *kt, int k) +#else +void CCkdtree_delete (kt, k) +CCkdtree *kt; +int k; +#endif +{ + int j, temp; + CCkdnode *p; + + p = kt->bucketptr[k]; + j = p->lopt; + while (kt->perm[j] != k) + j++; + SWAP (kt->perm[j], kt->perm[p->hipt], temp); + (p->hipt)--; + if (p->lopt > p->hipt) { + p->empty = 1; + while ((p = p->father) != (CCkdnode *) NULL && + p->loson->empty && p->hison->empty) + p->empty = 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCkdtree_delete_all (CCkdtree *kt, int ncount) +#else +void CCkdtree_delete_all (kt, ncount) +CCkdtree *kt; +int ncount; +#endif +{ + int k; + + for (k = 0; k < ncount; k++) + CCkdtree_delete (kt, k); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CCkdtree_undelete (CCkdtree *kt, int k) +#else +void CCkdtree_undelete (kt, k) +CCkdtree *kt; +int k; +#endif +{ + int j, temp; + CCkdnode *p; + + p = kt->bucketptr[k]; + j = p->lopt; + while (kt->perm[j] != k) + j++; + if (j > p->hipt) { + (p->hipt)++; + SWAP (kt->perm[j], kt->perm[p->hipt], temp); + if (p->empty) { + p->empty = 0; + while ((p = p->father) != (CCkdnode *) NULL && p->empty) + p->empty = 0; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCkdtree_undelete_all (CCkdtree *kt, int ncount) +#else +void CCkdtree_undelete_all (kt, ncount) +CCkdtree *kt; +int ncount; +#endif +{ + int k; + + for (k = 0; k < ncount; k++) + CCkdtree_undelete (kt, k); +} diff --git a/contrib/blossom/concorde97/KDTREE/kdnear.c b/contrib/blossom/concorde97/KDTREE/kdnear.c new file mode 100644 index 0000000000000000000000000000000000000000..1c2e24efec0849a51148eb9538c22654ca81a2e2 --- /dev/null +++ b/contrib/blossom/concorde97/KDTREE/kdnear.c @@ -0,0 +1,1438 @@ +/***************************************************************************/ +/* */ +/* ROUTINES FOR FINDING NEAREST NEIGHBORS */ +/* */ +/* (Based on Jon Bentley's paper "K-d trees for semidynamic point sets") */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 24, 1995 (cofeb24) */ +/* Changes: August 6 (bico) - added wcoord to fixed radius search */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCkdtree_k_nearest (CCkdtree *kt, int ncount, int k, */ +/* CCdatagroup *dat, double *wcoord, int wantlist, int *ocount, */ +/* int **olist) */ +/* RETURNS the k-nearest neighbor graph. */ +/* -kt can be NULL, otherwise it should point to a CCkdtree buildt */ +/* by a call to kdbuild () */ +/* -ncount is the number of points. */ +/* -k is the number of nearest neighbors wanted. */ +/* -wcoord is an array of node weights (like Held-Karp), it can */ +/* be NULL. The weights should be nonnegative. */ +/* -wantlist is 1 if you want the function to return the edges. */ +/* -ocount returns the number of edges (if wantlist is 1) and */ +/* olist returns the edgelist is end1 end2 format. */ +/* int CCkdtree_quadrant_k_nearest (CCkdtree *kt, int ncount, int k, */ +/* CCdatagroup *dat, double *wcoord, */ +/* int wantlist, int *ocount, int **olist) */ +/* RETURNS the quadrant k-nearest neighbor graph. */ +/* -see CCkdtree_k_nearest. */ +/* int CCkdtree_node_k_nearest (CCkdtree *kt, int ncount, int n, int k, */ +/* CCdatagroup *dat, double *wcoord, int *list) */ +/* RETURNS the k nearest points to point n. */ +/* -The k points are return in list (and list must be allocated by */ +/* calling routine. */ +/* -kt is a pointer to a CCkdtree previously built by */ +/* CCkdtree_build. */ +/* int CCkdtree_node_quadrant_k_nearest (CCkdtree *kt, int ncount, */ +/* int n, int k, CCdatagroup *dat, double *wcoord, int *list) */ +/* RETURNS the quadrant k nearest point to point n. */ +/* -see CCkdtree_node_k_nearest. */ +/* int CCkdtree_node_nearest (ktree *kt, int n, CCdatagroup *dat, */ +/* double *wcoord) */ +/* RETURNS the nearest point to point n. */ +/* -kt CANNOT be NULL. */ +/* -The point is returned as the function value. kt is a pointer */ +/* to a CCkdtree (previously buildt by a call to CCkdtree_build) */ +/* int CCkdtree_fixed_radius_nearest (CCkdtree *kt, CCdatagroup *dat, */ +/* double *wcoord, int n, double rad, */ +/* int (*doit_fn) (int, int, void *), void *pass_param) */ +/* ACTION: Calls the function doit_fn (n, a, void *), where a ranges */ +/* over all points within distance rad of the point n. The */ +/* void * field can be used to bundle a group of parmeters */ +/* into pass_param that will be passed to doit_fn. */ +/* -kt CANNOT be NULL. */ +/* -doit_fn can also call CCkdtree_fixed_radius_nearest (no globals */ +/* are set by the function calls) */ +/* -pass_param can be NULL or used to point to a structure with */ +/* with parameters for doit_fn. */ +/* int CCkdtree_nearest_neighbor_tour (CCkdtree *kt, int ncount, */ +/* int start, CCdatagroup *dat, int *outcycle, double *val) */ +/* -kt can be NULL. */ +/* -Node weights are not used. */ +/* -start is the starting node for the tour. */ +/* -if outcycle is not NULL, then it should point to a array of */ +/* length at least ncount (allocated by the calling routine). The */ +/* cycle will be returned in the array in node node node format. */ +/* -the length of the tour is return in val. */ +/* int CCkdtree_nearest_neighbor_2match (CCkdtree *kt, int ncount, */ +/* int start, CCdatagroup *dat, int *outmatch, double *val) */ +/* -Like CCkdtree_nearest_neighbor_tour. If outmatch is not NULL */ +/* then it should point to an array of length at leaast 2*ncount. */ +/* */ +/* NOTES: */ +/* If memory is tight, use CCkdtree_node_k_nearest to get the edges */ +/* one node at a time. (CCkdtree_k_nearest () builds a hash table to */ +/* avoid duplicate edges, and it will use 8 * nedges bytes.) */ +/* CCkdtree_node_nearest returns the nearest point as the function */ +/* value; CCkdtree_fixed_radius_nearest returns 1 if doit_fn returns a */ +/* a nonzero value, otherwise it returns 0; all other routines return 0 */ +/* if successful and 1 otherwise. */ +/* */ +/***************************************************************************/ + + +#include "machdefs.h" +#include "util.h" +#include "kdtree.h" + +#define BIGDOUBLE 100000000.0 +#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) +#define NEAR_HEAP_CUTOFF 100 /* When to switch from list to heap */ + /* On an RS6000, the heap started winning */ + /* at 100 (by 200 it was 3 times faster) */ + +typedef struct shortedge { + int end; + double length; +} shortedge; + +typedef struct intptr { + int this; + struct intptr *next; +} intptr; + +#define Fedgelen(n1, n2) \ + (datw != (double *) NULL ? \ + CCutil_dat_edgelen ((n1), (n2), dat) \ + + datw[(n1)] + datw[(n2)] : \ + CCutil_dat_edgelen ((n1), (n2), dat)) + +#ifdef CC_PROTOTYPE_ANSI + +static void + node_k_nearest_work (CCkdtree *thetree, CCdatagroup *dat, double *datw, + CCkdnode *p, CCdheap *near_heap, int *heap_names, int *heap_count, + int target, int num, shortedge *nearlist, double *worst_on_list, + CCkdbnds *box), + node_nearest_work (CCkdtree *thetree, CCdatagroup *dat, double *datw, + CCkdnode *p, int target, double *ndist, int *nnode); +static int + run_kdtree_k_nearest (CCkdtree *kt, int ncount, int k, CCdatagroup *dat, + double *wcoord, int wantlist, int *ocount, int **olist, int doquad), + put_in_table (int i, int j, int *added, intptr **table), + q_run_it (CCkdtree *thetree, CCdatagroup *dat, double *datw, int *llist, + int *lcount, int *list, int target, int num, CCkdbnds *box), + run_kdtree_node_k_nearest (CCkdtree *thetree, CCdatagroup *dat, + double *datw, + int *list, int target, int num, CCkdbnds *box), + ball_in_bounds (CCdatagroup *dat, CCkdbnds *bnds, int n, double dist), + fixed_radius_nearest_work (CCkdtree *thetree, CCkdnode *p, + int (*doit_fn) (int, int, void *), + int target, double dist, CCdatagroup *dat, double *wcoord, + double xtarget, double ytarget, void *pass_param); + +#else + +static void + node_k_nearest_work (), + node_nearest_work (); +static int + run_kdtree_k_nearest (), + put_in_table (), + q_run_it (), + run_kdtree_node_k_nearest (), + ball_in_bounds (), + fixed_radius_nearest_work (); + +#endif + +CC_PTR_ALLOC_ROUTINE (intptr, intptralloc, intptrchunklist, intptrfreelist) +CC_PTR_FREE_ROUTINE (intptr, intptrfree, intptrfreelist) +CC_PTR_FREE_WORLD_ROUTINE (intptr, intptrfree_world, intptrchunklist, + intptrfreelist) +CC_PTR_LEAKS_ROUTINE (intptr, intptr_check_leaks, intptrchunklist, + intptrfreelist, this, int) + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_k_nearest (CCkdtree *kt, int ncount, int k, CCdatagroup *dat, + double *wcoord, int wantlist, int *ocount, int **olist) +#else +int CCkdtree_k_nearest (kt, ncount, k, dat, wcoord, wantlist, ocount, olist) +CCkdtree *kt; +int ncount, k; +CCdatagroup *dat; +double *wcoord; +int wantlist, *ocount, **olist; +#endif +{ + return run_kdtree_k_nearest (kt, ncount, k, dat, wcoord, + wantlist, ocount, olist, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_quadrant_k_nearest (CCkdtree *kt, int ncount, int k, + CCdatagroup *dat, double *wcoord, int wantlist, int *ocount, + int **olist) +#else +int CCkdtree_quadrant_k_nearest (kt, ncount, k, dat, wcoord, wantlist, ocount, + olist) +CCkdtree *kt; +int ncount, k; +CCdatagroup *dat; +double *wcoord; +int wantlist, *ocount, **olist; +#endif +{ + return run_kdtree_k_nearest (kt, ncount, k, dat, wcoord, + wantlist, ocount, olist, 1); +} + + +#ifdef CC_PROTOTYPE_ANSI +static int run_kdtree_k_nearest (CCkdtree *kt, int ncount, int k, + CCdatagroup *dat, double *wcoord, int wantlist, int *ocount, + int **olist, int doquad) +#else +static int run_kdtree_k_nearest (kt, ncount, k, dat, wcoord, wantlist, ocount, + olist, doquad) +CCkdtree *kt; +int ncount, k; +CCdatagroup *dat; +double *wcoord; +int wantlist, *ocount, **olist; +int doquad; +#endif +{ + int i, n; + intptr *ip, *ipnext; + int total, onlist; + CCkdtree localkt, *mykt; + int added, ntotal = 0; + int rval = 0; + int *list = (int *) NULL; + int goal = (doquad ? (4 * k) : k); + int newtree = 0; + intptr **table = (intptr **) NULL; + + if (wcoord != (double *) NULL) { + for (i = 0; i < ncount; i++) { + if (wcoord[i] < -0.00000001) { + fprintf (stderr, "Cannot CCkdtree with negative node weights\n"); + return 1; + } + } + } + + if (wantlist) { + *ocount = 0; + *olist = (int *) NULL; + } + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, wcoord)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + mykt = &localkt; + newtree = 1; + } else { + mykt = kt; + } + + + table = CC_SAFE_MALLOC (ncount, intptr *); + if (!table) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) + table[i] = (intptr *) NULL; + list = CC_SAFE_MALLOC (goal, int); + if (!list) { + rval = 1; + goto CLEANUP; + } + + for (n = 0; n < ncount; n++) { + if (doquad) { + if (CCkdtree_node_quadrant_k_nearest (mykt, ncount, n, k, dat, + wcoord, list)) { + rval = 1; + goto CLEANUP; + } + } else { + if (CCkdtree_node_k_nearest (mykt, ncount, n, k, dat, wcoord, + list)) { + rval = 1; + goto CLEANUP; + } + } + for (i = 0; i < goal; i++) { + if (list[i] != -1) { + if (put_in_table (n, list[i], &added, table)) { + rval = 1; + goto CLEANUP; + } else { + ntotal += added; + } + } + } +/* + if (n == 0) { + printf ("Neighbors of Node %d (%d, %d) :\n", n, + (int) dat->x[n], (int) dat->y[n]); + for (i = 0; i < goal; i++) { + if (list[i] != -1) { + printf ("%d %d (%d, %d)\n", list[i], + CCutil_dat_edgelen (n, list[i], dat), + (int) dat->x[list[i]], (int) dat->y[list[i]]); + } + } + } +*/ + if (n % 1000 == 999) { + printf ("."); + fflush (stdout); + } + } + printf (" %d edges\n", ntotal); + fflush (stdout); + + if (wantlist) { + int j = 0; + *olist = CC_SAFE_MALLOC (2 * ntotal, int); + if (!(*olist)) { + rval = 1; + goto CLEANUP; + } + *ocount = ntotal; + for (i = 0; i < ncount; i++) { + for (ip = table[i]; ip; ip = ipnext) { + ipnext = ip->next; + (*olist)[j++] = i; + (*olist)[j++] = ip->this; + intptrfree (ip); + } + table[i] = (intptr *) NULL; + } + } else { + for (i = 0; i < ncount; i++) { + for (ip = table[i]; ip; ip = ipnext) { + ipnext = ip->next; + intptrfree (ip); + } + table[i] = (intptr *) NULL; + } + } + if (intptr_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding intptrs in kdnear\n", + total - onlist); + } + +CLEANUP: + + intptrfree_world (); + if (table) + CC_FREE (table, intptr *); + if (list) + CC_FREE (list, int); + if (newtree) + CCkdtree_free (&localkt); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int put_in_table (int i, int j, int *added, intptr **table) +#else +static int put_in_table (i, j, added, table) +int i, j; +int *added; +intptr **table; +#endif +{ + intptr *ip; + + if (j < i) { + int temp; + SWAP(i, j, temp); + } + + for (ip = table[i]; ip; ip = ip->next) + if (ip->this == j) { + *added = 0; + return 0; + } + ip = intptralloc (); + if (!ip) { + *added = 0; + return 1; + } + ip->this = j; + ip->next = table[i]; + table[i] = ip; + *added = 1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_node_quadrant_k_nearest (CCkdtree *kt, int ncount, int n, int k, + CCdatagroup *dat, double *wcoord, int *list) +#else +int CCkdtree_node_quadrant_k_nearest (kt, ncount, n, k, dat, wcoord, list) +CCkdtree *kt; +int ncount, n, k; +CCdatagroup *dat; +double *wcoord; +int *list; +#endif +{ + CCkdbnds localbnds; + int i, lcount = 0; + int *llist = (int *) NULL; + int rval = 0; + CCkdtree localkt; + CCkdtree *thetree; + int newtree = 0; + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, wcoord)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + llist = CC_SAFE_MALLOC (k, int); + if (!llist) { + rval = 1; + goto CLEANUP; + } + + localbnds.x[0] = dat->x[n]; + localbnds.x[1] = BIGDOUBLE; + localbnds.y[0] = dat->y[n]; + localbnds.y[1] = BIGDOUBLE; + if (q_run_it (thetree, dat, wcoord, llist, &lcount, list, n, k, + &localbnds)) { + fprintf (stderr, "run_kdtree_node_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + + localbnds.x[0] = dat->x[n]; + localbnds.x[1] = BIGDOUBLE; + localbnds.y[0] = -BIGDOUBLE; + localbnds.y[1] = dat->y[n]; + if (q_run_it (thetree, dat, wcoord, llist, &lcount, list, n, k, + &localbnds)) { + fprintf (stderr, "run_kdtree_node_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + + localbnds.x[0] = -BIGDOUBLE; + localbnds.x[1] = dat->x[n]; + localbnds.y[0] = -BIGDOUBLE; + localbnds.y[1] = dat->y[n]; + if (q_run_it (thetree, dat, wcoord, llist, &lcount, list, n, k, + &localbnds)) { + fprintf (stderr, "run_kdtree_node_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + + localbnds.x[0] = -BIGDOUBLE; + localbnds.x[1] = dat->x[n]; + localbnds.y[0] = dat->y[n]; + localbnds.y[1] = BIGDOUBLE; + if (q_run_it (thetree, dat, wcoord, llist, &lcount, list, n, k, + &localbnds)) { + fprintf (stderr, "run_kdtree_node_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + + for (i = lcount; i < (4 * k); i++) + list[i] = -1; + +CLEANUP: + + CC_FREE (llist, int); + if (newtree) + CCkdtree_free (&localkt); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int q_run_it (CCkdtree *thetree, CCdatagroup *dat, double *datw, + int *llist, int *lcount, int *list, int target, int num, CCkdbnds *box) +#else +static int q_run_it (thetree, dat, datw, llist, lcount, list, target, num, box) +CCkdtree *thetree; +CCdatagroup *dat; +double *datw; +int *llist; +int *lcount; +int *list; +int target; +int num; +CCkdbnds *box; +#endif +{ + int i, j; + + if (run_kdtree_node_k_nearest (thetree, dat, datw, llist, target, num, + box)) + return 1; + for (i = 0; i < num; i++) { + if (llist[i] != -1) { + for (j = 0; j < *lcount; j++) + if (list[j] == llist[i]) + break; + if (j == *lcount) + list[(*lcount)++] = llist[i]; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_node_k_nearest (CCkdtree *kt, int ncount, int n, int k, + CCdatagroup *dat, double *wcoord, int *list) +#else +int CCkdtree_node_k_nearest (kt, ncount, n, k, dat, wcoord, list) +CCkdtree *kt; +int ncount, n, k; +CCdatagroup *dat; +double *wcoord; +int *list; +#endif +{ + CCkdtree localkt; + CCkdtree *thetree; + int newtree = 0; + int rval = 0; + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, wcoord)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + rval = run_kdtree_node_k_nearest (thetree, dat, wcoord, list, n, k, + (CCkdbnds *) NULL); + if (newtree) + CCkdtree_free (&localkt); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int run_kdtree_node_k_nearest (CCkdtree *thetree, CCdatagroup *dat, + double *datw, int *list, int target, int num, CCkdbnds *box) +#else +static int run_kdtree_node_k_nearest (thetree, dat, datw, list, target, num, + box) +CCkdtree *thetree; +CCdatagroup *dat; +double *datw; +int *list; +int target; +int num; +CCkdbnds *box; +#endif +{ + int i; + CCkdnode *p, *lastp; + double diff; + CCdheap near_heap; + int *heap_names = (int *) NULL; + int heap_count = 0; + shortedge *nearlist = (shortedge *) NULL; + double worst_on_list = BIGDOUBLE; + + if (num >= NEAR_HEAP_CUTOFF) { + if (CCutil_dheap_init (&near_heap, num)) + return 1; + heap_names = CC_SAFE_MALLOC (num, int); + if (!heap_names) { + CCutil_dheap_free (&near_heap); + return 1; + } + heap_count = 0; + } else { + nearlist = CC_SAFE_MALLOC (num + 1, shortedge); + if (!nearlist) { + CCutil_dheap_free (&near_heap); + CC_FREE (heap_names, int); + return 1; + } + for (i = 0; i < num; i++) + nearlist[i].length = BIGDOUBLE; + nearlist[num].length = -BIGDOUBLE; + } + +/* + To do top down search just use: + + node_k_nearest_work (thetree->root); +*/ + + p = thetree->bucketptr[target]; + node_k_nearest_work (thetree, dat, datw, p, &near_heap, heap_names, + &heap_count, target, num, nearlist, &worst_on_list, + box); + while (1) { + lastp = p; + p = p->father; + if (p == (CCkdnode *) NULL) + break; + switch (p->cutdim) { + case 0: + diff = p->cutval - dat->x[target]; + if (lastp == p->loson) { /* So target is on low side */ + if (worst_on_list > (double) ((int) diff)) + if (box == (CCkdbnds *) NULL || p->cutval <= box->x[1]) + node_k_nearest_work (thetree, dat, datw, p->hison, + &near_heap, heap_names, &heap_count, target, + num, nearlist, &worst_on_list, box); + } else { + if (worst_on_list > (double) ((int) -diff)) + if (box == (CCkdbnds *) NULL || p->cutval >= box->x[0]) + node_k_nearest_work (thetree, dat, datw, p->loson, + &near_heap, heap_names, &heap_count, target, + num, nearlist, &worst_on_list, box); + } + break; + case 1: + diff = p->cutval - dat->y[target]; + if (lastp == p->loson) { + if (worst_on_list > (double) ((int) diff)) + if (box == (CCkdbnds *) NULL || p->cutval <= box->y[1]) + node_k_nearest_work (thetree, dat, datw, p->hison, + &near_heap, heap_names, &heap_count, target, + num, nearlist, &worst_on_list, box); + } else { + if (worst_on_list > (double) ((int) -diff)) + if (box == (CCkdbnds *) NULL || p->cutval >= box->y[0]) + node_k_nearest_work (thetree, dat, datw, p->loson, + &near_heap, heap_names, &heap_count, target, + num, nearlist, &worst_on_list, box); + } + break; + case 2: + if (lastp == p->loson) { + if (worst_on_list > p->cutval + datw[target]) + node_k_nearest_work (thetree, dat, datw, p->hison, + &near_heap, heap_names, &heap_count, target, + num, nearlist, &worst_on_list, box); + } else { + node_k_nearest_work (thetree, dat, datw, p->loson, &near_heap, + heap_names, &heap_count, target, num, nearlist, + &worst_on_list, box); + } + break; + } + if (datw == (double *) NULL && p->bnds && + ball_in_bounds (dat, p->bnds, target, worst_on_list)) + /* Doing extra check for box with quad-nearest appears to slow */ + /* things down. */ + break; + } + + if (num >= NEAR_HEAP_CUTOFF) { + if (heap_count < num) { + if (box == (CCkdbnds *) NULL) { + fprintf (stderr, "WARNING: There do not exist %d neighbors\n", + num); + } + for (i = 0; i < heap_count; i++) { + list[i] = heap_names[i]; + } + for (; i < num; i++) + list[i] = -1; + } else { + for (i = 0; i < num; i++) + list[i] = heap_names[i]; + } + } else { + int ntot = 0; + for (i = 0; i < num; i++) { + if (nearlist[i].length < BIGDOUBLE) + list[ntot++] = nearlist[i].end; + } + if (ntot < num) { + if (box == (CCkdbnds *) NULL) { + fprintf (stderr, "WARNING: There do not exist %d neighbors\n", + num); + } + for (i = ntot; i < num; i++) + list[i] = -1; + } + } + + if (num >= NEAR_HEAP_CUTOFF) { + CC_FREE (heap_names, int); + CCutil_dheap_free (&near_heap); + } else { + CC_FREE (nearlist, shortedge); + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void node_k_nearest_work (CCkdtree *thetree, CCdatagroup *dat, + double *datw, CCkdnode *p, CCdheap *near_heap, int *heap_names, + int *heap_count, int target, int num, shortedge *nearlist, + double *worst_on_list, CCkdbnds *box) +#else +static void node_k_nearest_work (thetree, dat, datw, p, near_heap, heap_names, + heap_count, target, num, nearlist, worst_on_list, box) +CCkdtree *thetree; +CCdatagroup *dat; +double *datw; +CCkdnode *p; +CCdheap *near_heap; +int *heap_names; +int *heap_count; +int target, num; +shortedge *nearlist; +double *worst_on_list; +CCkdbnds *box; +#endif +{ + int i, h, k; + double val, thisx, thisdist; + + if (p->bucket) { + if (num >= NEAR_HEAP_CUTOFF) { + for (i = p->lopt; i <= p->hipt; i++) { + if (thetree->perm[i] != target) { + if (box == (CCkdbnds *) NULL || + (dat->x[thetree->perm[i]] >= box->x[0] && + dat->x[thetree->perm[i]] <= box->x[1] && + dat->y[thetree->perm[i]] >= box->y[0] && + dat->y[thetree->perm[i]] <= box->y[1])) { + thisdist = Fedgelen (thetree->perm[i], target); + if (*heap_count < num) { + near_heap->key[*heap_count] = -thisdist; + heap_names[*heap_count] = thetree->perm[i]; + CCutil_dheap_insert (near_heap, *heap_count); + (*heap_count)++; + } else if (*worst_on_list > thisdist) { + h = CCutil_dheap_deletemin (near_heap); + heap_names[h] = thetree->perm[i]; + near_heap->key[h] = -thisdist; + CCutil_dheap_insert (near_heap, h); + h = CCutil_dheap_findmin (near_heap); + *worst_on_list = -near_heap->key[h]; + } + } + } + } + } else { + for (i = p->lopt; i <= p->hipt; i++) { + if (thetree->perm[i] != target) { + if (box == (CCkdbnds *) NULL || + (dat->x[thetree->perm[i]] >= box->x[0] && + dat->x[thetree->perm[i]] <= box->x[1] && + dat->y[thetree->perm[i]] >= box->y[0] && + dat->y[thetree->perm[i]] <= box->y[1])) { + thisdist = Fedgelen (thetree->perm[i], target); + if (*worst_on_list > thisdist) { + for (k = 0; nearlist[k+1].length > thisdist; k++) { + nearlist[k].end = nearlist[k + 1].end; + nearlist[k].length = nearlist[k + 1].length; + } + nearlist[k].length = thisdist; + nearlist[k].end = thetree->perm[i]; + *worst_on_list = nearlist[0].length; + } + } + } + } + } + } else { + val = p->cutval; + switch (p->cutdim) { + case 0: + thisx = dat->x[target]; + if (thisx < val) { + node_k_nearest_work (thetree, dat, datw, p->loson, near_heap, + heap_names, heap_count, target, num, nearlist, + worst_on_list, box); + /* Truncation for floating point coords */ + if (*worst_on_list > (double) ((int) (val - thisx))) + if (box == (CCkdbnds *) NULL || val >= box->x[0]) + node_k_nearest_work (thetree, dat, datw, p->hison, + near_heap, heap_names, heap_count, target, + num, nearlist, worst_on_list, box); + } else { + node_k_nearest_work (thetree, dat, datw, p->hison, near_heap, + heap_names, heap_count, target, num, nearlist, + worst_on_list, box); + if (*worst_on_list > (double) ((int) (thisx - val))) + if (box == (CCkdbnds *) NULL || val <= box->x[1]) + node_k_nearest_work (thetree, dat, datw, p->loson, + near_heap, heap_names, heap_count, target, + num, nearlist, worst_on_list, box); + } + break; + case 1: + thisx = dat->y[target]; + if (thisx < val) { + node_k_nearest_work (thetree, dat, datw, p->loson, near_heap, + heap_names, heap_count, target, num, nearlist, + worst_on_list, box); + if (*worst_on_list > (double) ((int) (val - thisx))) + if (box == (CCkdbnds *) NULL || val >= box->y[0]) + node_k_nearest_work (thetree, dat, datw, p->hison, + near_heap, heap_names, heap_count, target, + num, nearlist, worst_on_list, box); + } else { + node_k_nearest_work (thetree, dat, datw, p->hison, near_heap, + heap_names, heap_count, target, num, nearlist, + worst_on_list, box); + if (*worst_on_list > (double) ((int) (thisx - val))) + if (box == (CCkdbnds *) NULL || val <= box->y[1]) + node_k_nearest_work (thetree, dat, datw, p->loson, + near_heap, heap_names, heap_count, target, + num, nearlist, worst_on_list, box); + } + break; + case 2: + thisx = datw[target]; + node_k_nearest_work (thetree, dat, datw, p->loson, near_heap, + heap_names, heap_count, target, num, nearlist, + worst_on_list, box); + if (*worst_on_list > val + thisx) + node_k_nearest_work (thetree, dat, datw, p->hison, near_heap, + heap_names, heap_count, target, num, nearlist, + worst_on_list, box); + break; + } + } +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_node_nearest (CCkdtree *kt, int n, CCdatagroup *dat, + double *wcoord) +#else +int CCkdtree_node_nearest (kt, n, dat, wcoord) +CCkdtree *kt; +int n; +CCdatagroup *dat; +double *wcoord; +#endif +{ + CCkdnode *p, *lastp; + double diff; + double ndist = BIGDOUBLE; + int nnode; + CCkdtree *thetree = (CCkdtree *) NULL; + + if (kt == (CCkdtree *) NULL) { + fprintf (stderr, "ERROR: kt cannot be NULL in CCkdtree_node_nearest)\n"); + return n; + } + + thetree = kt; + + ndist = BIGDOUBLE; + nnode = n; + +/* + To do top down search just use: + + node_nearest_work (kt->root); + return nnode; +*/ + + p = kt->bucketptr[n]; + node_nearest_work (thetree, dat, wcoord, p, n, &ndist, &nnode); + while (1) { + lastp = p; + p = p->father; + if (p == (CCkdnode *) NULL) + break; + switch (p->cutdim) { + case 0: + diff = p->cutval - dat->x[n]; + if (lastp == p->loson) { + if (ndist > (double) ((int) diff)) + node_nearest_work (thetree, dat, wcoord, p->hison, n, + &ndist, &nnode); + } else { + if (ndist > (double) ((int) (-diff))) + node_nearest_work (thetree, dat, wcoord, p->loson, n, + &ndist, &nnode); + } + break; + case 1: + diff = p->cutval - dat->y[n]; + if (lastp == p->loson) { + if (ndist > (double) ((int) diff)) + node_nearest_work (thetree, dat, wcoord, p->hison, n, + &ndist, &nnode); + } else { + if (ndist > (double) ((int) (-diff))) + node_nearest_work (thetree, dat, wcoord, p->loson, n, + &ndist, &nnode); + } + break; + case 2: + if (lastp == p->loson) { + if (ndist > p->cutval + wcoord[n]) + node_nearest_work (thetree, dat, wcoord, p->hison, n, + &ndist, &nnode); + } else { + node_nearest_work (thetree, dat, wcoord, p->loson, n, + &ndist, &nnode); + } + break; + } + if (wcoord == (double *) NULL && p->bnds && + ball_in_bounds (dat, p->bnds, n, ndist)) + break; + } + return nnode; +} + +#ifdef CC_PROTOTYPE_ANSI +static int ball_in_bounds (CCdatagroup *dat, CCkdbnds *bnds, int n, double dist) +#else +static int ball_in_bounds (dat, bnds, n, dist) +CCdatagroup *dat; +CCkdbnds *bnds; +int n; +double dist; +#endif +{ + if ((double) ((int) (dat->x[n] - bnds->x[0])) < dist || + (double) ((int) (bnds->x[1] - dat->x[n])) < dist || + (double) ((int) (dat->y[n] - bnds->y[0])) < dist || + (double) ((int) (bnds->y[1] - dat->y[n])) < dist) + return 0; + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static void node_nearest_work (CCkdtree *thetree, CCdatagroup *dat, + double *datw, CCkdnode *p, int target, double *ndist, int *nnode) +#else +static void node_nearest_work (thetree, dat, datw, p, target, ndist, nnode) +CCkdtree *thetree; +CCdatagroup *dat; +double *datw; +CCkdnode *p; +int target; +double *ndist; +int *nnode; +#endif +{ + int i; + double val, thisx, thisdist; + + if (!p->empty) { + if (p->bucket) { + for (i = p->lopt; i <= p->hipt; i++) { + if (thetree->perm[i] != target) { + thisdist = Fedgelen (thetree->perm[i], target); + if (*ndist > thisdist) { + *ndist = thisdist; + *nnode = thetree->perm[i]; + } + } + } + } else { + val = p->cutval; + switch (p->cutdim) { + case 0: + thisx = dat->x[target]; + if (thisx < val) { + node_nearest_work (thetree, dat, datw, p->loson, target, + ndist, nnode); + if (*ndist > (double) ((int) (val - thisx))) + node_nearest_work (thetree, dat, datw, p->hison, + target, ndist, nnode); + } else { + node_nearest_work (thetree, dat, datw, p->hison, target, + ndist, nnode); + if (*ndist > (double) ((int) (thisx - val))) + node_nearest_work (thetree, dat, datw, p->loson, + target, ndist, nnode); + } + break; + case 1: + thisx = dat->y[target]; + if (thisx < val) { + node_nearest_work (thetree, dat, datw, p->loson, target, + ndist, nnode); + if (*ndist > (double) ((int) (val - thisx))) + node_nearest_work (thetree, dat, datw, p->hison, + target, ndist, nnode); + } else { + node_nearest_work (thetree, dat, datw, p->hison, target, + ndist, nnode); + if (*ndist > (double) ((int) (thisx - val))) + node_nearest_work (thetree, dat, datw, p->loson, + target, ndist, nnode); + } + break; + case 2: + thisx = datw[target]; + node_nearest_work (thetree, dat, datw, p->loson, target, ndist, + nnode); + if (*ndist > val + thisx) + node_nearest_work (thetree, dat, datw, p->hison, target, + ndist, nnode); + break; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_fixed_radius_nearest (CCkdtree *kt, CCdatagroup *dat, + double *datw, int n, double rad, int (*doit_fn) (int, int, void *), + void *pass_param) +#else +int CCkdtree_fixed_radius_nearest (kt, dat, datw, n, rad, doit_fn, pass_param) +CCkdtree *kt; +CCdatagroup *dat; +double *datw; +int n; +double rad; +int (*doit_fn)(); +void *pass_param; +#endif +{ + CCkdnode *p, *lastp; + double dist, diff, xtarget, ytarget; + int target; + + if (kt == (CCkdtree *) NULL) { + fprintf (stderr, "ERROR: fixed_radius_nearest needs a CCkdtree\n"); + return 0; + } + + dist = (double) rad; + target = n; + xtarget = dat->x[target]; + ytarget = dat->y[target]; + + p = kt->bucketptr[target]; + if (fixed_radius_nearest_work (kt, p, doit_fn, target, dist, dat, datw, + xtarget, ytarget, pass_param)) + return 1; + + if (datw) { + double wdist = dist - datw[target]; + while (1) { + lastp = p; + p = p->father; + if (p == (CCkdnode *) NULL) + return 0; + if (p->cutdim == 0) + diff = p->cutval - xtarget; + else if (p->cutdim == 1) + diff = p->cutval - ytarget; + else + diff = p->cutval; + if (lastp == p->loson) { + if (wdist > (double) ((int) diff)) { + if (fixed_radius_nearest_work (kt, p->hison, doit_fn, + target, dist, dat, datw, xtarget, ytarget, + pass_param)) + return 1; + } + } else { + if (wdist > (double) ((int) -diff)) { + if (fixed_radius_nearest_work (kt, p->loson, doit_fn, + target, dist, dat, datw, xtarget, ytarget, + pass_param)) + return 1; + } + } + if (p->bnds && /* ball_in_bounds */ + !((double) ((int) (xtarget - p->bnds->x[0])) < wdist || + (double) ((int) (p->bnds->x[1] - xtarget)) < wdist || + (double) ((int) (ytarget - p->bnds->y[0])) < wdist || + (double) ((int) (p->bnds->y[1] - ytarget)) < wdist)) + return 0; + } + } else { + while (1) { + lastp = p; + p = p->father; + if (p == (CCkdnode *) NULL) + return 0; + if (p->cutdim == 0) + diff = p->cutval - xtarget; + else + diff = p->cutval - ytarget; + + if (lastp == p->loson) { + if (dist > (double) ((int) diff)) { + if (fixed_radius_nearest_work (kt, p->hison, doit_fn, + target, dist, dat, datw, xtarget, ytarget, + pass_param)) + return 1; + } + } else { + if (dist > (double) ((int) -diff) || p->cutdim == 2) { + if (fixed_radius_nearest_work (kt, p->loson, doit_fn, + target, dist, dat, datw, xtarget, ytarget, + pass_param)) + return 1; + } + } + if (p->bnds && /* ball_in_bounds */ + !((double) ((int) (xtarget - p->bnds->x[0])) < dist || + (double) ((int) (p->bnds->x[1] - xtarget)) < dist || + (double) ((int) (ytarget - p->bnds->y[0])) < dist || + (double) ((int) (p->bnds->y[1] - ytarget)) < dist)) + return 0; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int fixed_radius_nearest_work (CCkdtree *thetree, CCkdnode *p, + int (*doit_fn) (int, int, void *), int target, double dist, + CCdatagroup *dat, double *datw, double xtarget, double ytarget, + void *pass_param) +#else +static int fixed_radius_nearest_work (thetree, p, doit_fn, target, dist, dat, + datw, xtarget, ytarget, pass_param) +CCkdtree *thetree; +CCkdnode *p; +int (*doit_fn)(); +int target; +double dist; +CCdatagroup *dat; +double *datw; +double xtarget, ytarget; +void *pass_param; +#endif +{ + int i, c; + double val, thisx, thisdist; + + if (p->empty) + return 0; + + if (p->bucket) { + for (i = p->lopt; i <= p->hipt; i++) { + c = thetree->perm[i]; + if (c != target) { + thisdist = Fedgelen (c, target); + if (thisdist < dist) { + if (doit_fn (target, c, pass_param)) { + return 1; + } + } + } + } + return 0; + } else { + if (datw) { + double wdist = dist - datw[target]; + + val = p->cutval; + switch (p->cutdim) { + case 0: + thisx = xtarget; + break; + case 1: + thisx = ytarget; + break; + case 2: + if (fixed_radius_nearest_work (thetree, p->loson, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + if (p->cutval <= wdist) { + if (fixed_radius_nearest_work (thetree, p->hison, doit_fn, + target, dist, dat, datw, xtarget, ytarget, + pass_param)) { + return 1; + } + } + return 0; + default: + return 0; + } + if (thisx < val) { + if (fixed_radius_nearest_work (thetree, p->loson, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + if (wdist > (double) ((int) (val - thisx))) { + if (fixed_radius_nearest_work (thetree, p->hison, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + } + } else { + if (fixed_radius_nearest_work (thetree, p->hison, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + if (wdist > (double) ((int) (thisx - val))) { + if (fixed_radius_nearest_work (thetree, p->loson, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + } + } + } else { + val = p->cutval; + switch (p->cutdim) { + case 0: + thisx = xtarget; + break; + case 1: + thisx = ytarget; + break; + case 2: + default: + fprintf (stderr, "ERROR: split on w without node weights\n"); + return 0; + } + if (thisx < val) { + if (fixed_radius_nearest_work (thetree, p->loson, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + if (dist > (double) ((int) (val - thisx))) { + if (fixed_radius_nearest_work (thetree, p->hison, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + } + } else { + if (fixed_radius_nearest_work (thetree, p->hison, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + if (dist > (double) ((int) (thisx - val))) { + if (fixed_radius_nearest_work (thetree, p->loson, doit_fn, + target, dist, dat, datw, xtarget, ytarget, pass_param)) { + return 1; + } + } + } + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_nearest_neighbor_tour (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val) +#else +int CCkdtree_nearest_neighbor_tour (kt, ncount, start, dat, outcycle, val) +CCkdtree *kt; +int ncount, start; +CCdatagroup *dat; +int *outcycle; +double *val; +#endif +{ + double len; + int i, current, next; + CCkdtree localkt, *mykt; + int newtree = 0; + + if (ncount < 3) { + fprintf (stderr, "Cannot find tour in an %d node graph\n", ncount); + return 1; + } + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, (double *) NULL)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + mykt = &localkt; + newtree = 1; + } else { + mykt = kt; + } + + /* + printf ("Grow nearest neighbor tour from node %d\n", start); + fflush (stdout); + */ + + len = 0.0; + current = start; + if (outcycle != (int *) NULL) + outcycle[0] = start; + for (i = 1; i < ncount; i++) { + CCkdtree_delete (mykt, current); + next = CCkdtree_node_nearest (mykt, current, dat, (double *) NULL); + if (outcycle != (int *) NULL) + outcycle [i] = next; + len += (double) CCutil_dat_edgelen (current, next, dat); + current = next; + } + len += (double) CCutil_dat_edgelen (current, start, dat); + *val = len; + if (newtree) + CCkdtree_free (&localkt); + else + CCkdtree_undelete_all (kt, ncount); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_nearest_neighbor_2match (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outmatch, double *val) +#else +int CCkdtree_nearest_neighbor_2match (kt, ncount, start, dat, outmatch, val) +CCkdtree *kt; +int ncount, start; +CCdatagroup *dat; +int *outmatch; +double *val; +#endif +{ + double len; + int i, j, cur, next; + CCkdtree localkt, *mykt; + double szeit; + int count = 0, cyccount = 0; + char *mark = (char *) NULL; + int newtree = 0; + int rval = 0; + + if (ncount < 3) { + fprintf (stderr, "Cannot find 2-matching in an %d node graph\n", + ncount); + return 1; + } + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, (double *) NULL)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + mykt = &localkt; + newtree = 1; + } else { + mykt = kt; + } + + mark = CC_SAFE_MALLOC (ncount, char); + if (!mark) { + rval = 1; + goto CLEANUP; + } + for (i = 0 ; i < ncount; i++) + mark[i] = 0; + + printf ("Grow nearest neighbor 2-matching from node %d\n", start); + fflush (stdout); + szeit = CCutil_zeit (); + len = 0.0; + + while (count < ncount) { + for (j = start; j < ncount && mark[j]; j++); + if (j == ncount) { + for (j = 0; j < start && mark[j]; j++); + if (j == start) { + fprintf (stderr, "ERROR in near-2match\n"); + rval = 1; + goto CLEANUP; + } + } + start = j; + mark[start] = 1; + CCkdtree_delete (mykt, start); + next = CCkdtree_node_nearest (mykt, start, dat, (double *) NULL); + mark[next] = 1; + len += (double) CCutil_dat_edgelen (start, next, dat); + if (outmatch != (int *) NULL) { + outmatch[2 * count] = start; + outmatch[(2 * count) + 1] = next; + } + count++; + CCkdtree_delete (mykt, next); + cur = CCkdtree_node_nearest (mykt, next, dat, (double *) NULL); + len += (double) CCutil_dat_edgelen (next, cur, dat); + if (outmatch != (int *) NULL) { + outmatch[2 * count] = next; + outmatch[(2 * count) + 1] = cur; + } + count++; + CCkdtree_undelete (mykt, start); + while (cur != start && count < ncount - 3) { + mark[cur] = 1; + CCkdtree_delete (mykt, cur); + next = CCkdtree_node_nearest (mykt, cur, dat, (double *) NULL); + len += (double) (*CCutil_dat_edgelen) (cur, next, dat); + if (outmatch != (int *) NULL) { + outmatch[2 * count] = cur; + outmatch[(2 * count) + 1] = next; + } + count++; + cur = next; + } + CCkdtree_delete (mykt, start); + + if (cur != start) { /* Not enough nodes for another circuit */ + while (count < ncount - 1) { + mark[cur] = 1; + CCkdtree_delete (mykt, cur); + next = CCkdtree_node_nearest (mykt, cur, dat, (double *) NULL); + len += (double) CCutil_dat_edgelen (cur, next, dat); + if (outmatch != (int *) NULL) { + outmatch[2 * count] = cur; + outmatch[(2 * count) + 1] = next; + } + count++; + cur = next; + } + len += (double) CCutil_dat_edgelen (cur, start, dat); + if (outmatch != (int *) NULL) { + outmatch[2 * count] = cur; + outmatch[(2 * count) + 1] = start; + } + count++; + } + cyccount++; + } + + *val = len; + printf ("%d cycles in 2-matching\n", cyccount); + printf ("Running time for Nearest Neighbor 2-match: %.2f\n", + CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + if (newtree) + CCkdtree_free (&localkt); + else + CCkdtree_undelete_all (kt, ncount); + if (mark) + CC_FREE (mark, char); + return rval; +} diff --git a/contrib/blossom/concorde97/KDTREE/kdspan.c b/contrib/blossom/concorde97/KDTREE/kdspan.c new file mode 100644 index 0000000000000000000000000000000000000000..6b9256fc058b323e6ee1136697913aa5e0dceebd --- /dev/null +++ b/contrib/blossom/concorde97/KDTREE/kdspan.c @@ -0,0 +1,1052 @@ +/***************************************************************************/ +/* */ +/* KD-TREE BASED MIN SPANNING TREE AND GREEDY TOUR */ +/* */ +/* (Based on Jon Bentley's paper "Fast algorithms for geometric */ +/* traveling salesman problems", ORSA Journal on Computing.) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook (mainly from Jon */ +/* Bentley's paper) */ +/* Date: February 16, 1995 (cofeb16) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCkdtree_prim_spanningtree (CCkdtree *kt, int ncount, */ +/* CCdatagroup *dat, double *wcoord, int *outtree, double *val) */ +/* RETURNS a min weight spanning tree. */ +/* -kt is a pointer to a CCkdtree built by a call to CCkdtree_build.*/ +/* If kt is NULL, then CCkdtree_build will be called. */ +/* -If wcoord is not NULL, then the array should have nonnegative */ +/* values. The code will use Held-Karp style distances. */ +/* -If outtree is non NULL, it should point to an array of length */ +/* at least 2*ncount - 2. The edges in the min spanning tree will */ +/* be returned in the array in end end format. */ +/* -The length of the min tree is returned in val. */ +/* int CCkdtree_greedy_tour (CCkdtree *kt, int ncount, CCdatagroup *dat,*/ +/* int *outcycle, double *val) */ +/* RETURNS a greedy tour. (No randomization (expect in building the */ +/* CCkdtree) so there is no point in calling this more than once) */ +/* -kt can be NULL. */ +/* -Does not use node weights. */ +/* -If outcycle is non NUL, it should point to an array of length */ +/* at least ncount. The cycle will be returned in node node node */ +/* format. */ +/* int CCkdtree_far_add_tour (CCkdtree *kt, int ncount, */ +/* CCdatagroup *dat, int *outcycle, double *val, int start) */ +/* RETURNS a farthest addition tour, beginning with node start. */ +/* -like CCkdtree_greedy_tour. */ +/* */ +/* NOTES: */ +/* Uses around 20n bytes of memory for an n node problem (plus the */ +/* memory for a CCkdtree), for a spanning tree, and 33n for a greedy */ +/* tour. Both functions return 0 if successful, and nonzero if they */ +/* failed (usually due to running out of memory. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "kdtree.h" + +typedef struct faobj { + struct faobj *next; + struct faobj *prev; + int name; +} faobj; + +#define Fedgelen(n1, n2) \ + (datw != (double *) NULL ? \ + CCutil_dat_edgelen ((n1), (n2), dat) \ + + datw[(n1)] + datw[(n2)] : \ + CCutil_dat_edgelen ((n1), (n2), dat)) + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +#ifdef CC_PROTOTYPE_ANSI + +static void + add_primheap (CCdheap *prim_heap, CCkdtree *kt, int n, int *neighbor, + CCdatagroup *dat, double *datw), + greedy_add_primheap (CCdheap *prim_heap, CCkdtree *kt, int n, int *neighbor, + CCdatagroup *dat), + fa_add_primheap (CCdheap *prim_heap, int n, int len); + +#ifdef USE_SPACEFILL +static int + space_fill_curve (int ncount, CCdatagroup *dat, int *outcyc, double *len); +#endif + +#else + +static void + add_primheap (), + greedy_add_primheap (), + fa_add_primheap (); + +#ifdef USE_SPACEFILL +static int + space_fill_curve (ncount, dat, outcyc, len); +#endif + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_prim_spanningtree (CCkdtree *kt, int ncount, CCdatagroup *dat, + double *wcoord, int *outtree, double *val) +#else +int CCkdtree_prim_spanningtree (kt, ncount, dat, wcoord, outtree, val) +CCkdtree *kt; +int ncount; +CCdatagroup *dat; +double *wcoord; +int *outtree; +double *val; +#endif +{ + CCkdtree localkt, *thetree; + double len; + int i, n; + int klist = 0; + int newtree = 0; + int *neighbor = (int *) NULL; + CCdheap prim_heap; + + if (wcoord != (double *) NULL) { + for (i = 0; i < ncount; i++) { + if (wcoord[i] < -0.00000001) { + fprintf (stderr, "Cannot kdtree with negative node weights\n"); + return 1; + } + } + } + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, wcoord)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + neighbor = CC_SAFE_MALLOC (ncount, int); + if (!neighbor) + return 1; + + printf ("Find minimum weight spanning tree\n"); + fflush (stdout); + + CCutil_dheap_init (&prim_heap, ncount); + for (i = 0; i < ncount; i++) + neighbor[i] = -1; + + CCkdtree_delete (thetree, 0); + add_primheap (&prim_heap, thetree, 0, neighbor, dat, wcoord); + + len = 0.0; + for (i = 1; i < ncount; i++) { + if (i % 10000 == 1) { + printf ("."); + fflush (stdout); + } + while (1) { + n = CCutil_dheap_deletemin (&prim_heap); + if (neighbor[neighbor[n]] == -1) + break; + else + add_primheap (&prim_heap, thetree, n, neighbor, dat, wcoord); + } + if (outtree) { + outtree[klist++] = n; + outtree[klist++] = neighbor[n]; + } + len += prim_heap.key[n]; + CCkdtree_delete (thetree, neighbor[n]); + add_primheap (&prim_heap, thetree, neighbor[n], neighbor, dat, wcoord); + add_primheap (&prim_heap, thetree, n, neighbor, dat, wcoord); + } + *val = len; + printf ("\nLength of Spanning Tree: %.2f\n", len); + if (wcoord != (double *) NULL) { + double tval = 0.0; + for (i = 0; i < ncount; i++) + tval += wcoord[i]; + tval *= 2.0; + printf ("TSP BOUND: %.2f\n", len - tval); + } + + if (newtree) + CCkdtree_free (&localkt); + else + CCkdtree_undelete_all (kt, ncount); + CCutil_dheap_free (&prim_heap); + if (neighbor) { + CC_FREE (neighbor, int); + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void add_primheap (CCdheap *prim_heap, CCkdtree *kt, int n, + int *neighbor, CCdatagroup *dat, double *datw) +#else +static void add_primheap (prim_heap, kt, n, neighbor, dat, datw) +CCdheap *prim_heap; +CCkdtree *kt; +int n; +int *neighbor; +CCdatagroup *dat; +double *datw; +#endif +{ + neighbor[n] = CCkdtree_node_nearest (kt, n, dat, datw); + prim_heap->key[n] = (double) Fedgelen (n, neighbor[n]); + CCutil_dheap_insert (prim_heap, n); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_greedy_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val) +#else +int CCkdtree_greedy_tour (kt, ncount, dat, outcycle, val) +CCkdtree *kt; +int ncount; +CCdatagroup *dat; +int *outcycle; +double *val; +#endif +{ + CCkdtree localkt, *thetree; + double len; + int i, x, y; + char *degree = (char *) NULL; + int *tail = (int *) NULL; + int *tcyc = (int *) NULL; + int tcount = 0; + int rval = 0; + int newtree = 0; + int *neighbor = (int *) NULL; + CCdheap prim_heap; + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, (double *) NULL)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + printf ("Grow a greedy tour \n"); + fflush (stdout); + + if (outcycle) { + tcyc = CC_SAFE_MALLOC (2 * ncount, int); + if (!tcyc) { + rval = 1; + goto CLEANUP; + } + } + + neighbor = CC_SAFE_MALLOC (ncount, int); + if (!neighbor) { + rval = 1; + goto CLEANUP; + } + degree = CC_SAFE_MALLOC (ncount, char); + if (!degree) { + rval = 1; + goto CLEANUP; + } + tail = CC_SAFE_MALLOC (ncount, int); + if (!tail) { + rval = 1; + goto CLEANUP; + } + if (CCutil_dheap_init (&prim_heap, ncount)) { + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < ncount; i++) { + degree[i] = 0; + tail[i] = -1; + greedy_add_primheap (&prim_heap, thetree, i, neighbor, dat); + } + + len = 0.0; + for (i = 1; i < ncount; i++) { + while (1) { + x = CCutil_dheap_deletemin (&prim_heap); + if (degree[x] == 2) + continue; + y = neighbor[x]; + if (degree[y] < 2 && y != tail[x]) + break; /* add (x, y) to the tour */ + if (tail[x] != -1) { + CCkdtree_delete (thetree, tail[x]); + greedy_add_primheap (&prim_heap, thetree, x, neighbor, dat); + CCkdtree_undelete (thetree, tail[x]); + } else { + greedy_add_primheap (&prim_heap, thetree, x, neighbor, dat); + } + } + if (tcyc) { + tcyc[tcount++] = x; + tcyc[tcount++] = y; + } + len += prim_heap.key[x]; + (degree[x])++; + if (degree[x] == 2) + CCkdtree_delete (thetree, x); + (degree[y])++; + if (degree[y] == 2) + CCkdtree_delete (thetree, y); + if (tail[x] == -1) { + if (tail[y] == -1) { + tail[x] = y; + tail[y] = x; + } else { + tail[x] = tail[y]; + tail[tail[y]] = x; + } + } else if (tail[y] == -1) { + tail[tail[x]] = y; + tail[y] = tail[x]; + } else { + tail[tail[x]] = tail[y]; + tail[tail[y]] = tail[x]; + } + if (degree[x] == 1) { + CCkdtree_delete (thetree, tail[x]); + greedy_add_primheap (&prim_heap, thetree, x, neighbor, dat); + CCkdtree_undelete (thetree, tail[x]); + } + if (i % 10000 == 9999) { + printf ("."); + fflush (stdout); + } + } + for (x = 0; degree[x] != 1; x++); + for (y = x + 1; degree[y] != 1; y++); + if (tcyc) { + tcyc[tcount++] = x; + tcyc[tcount++] = y; + } + len += (double) CCutil_dat_edgelen (x, y, dat); + *val = len; + if (ncount >= 10000) + printf ("\n"); + printf ("Length of Greedy Tour: %.2f\n", len); + CCutil_dheap_free (&prim_heap); + + if (tcyc) { + if (CCutil_edge_to_cycle (ncount, tcyc, outcycle)) { + fprintf (stderr, "ERROR: greedy tour is not a tour\n"); + rval = 1; + goto CLEANUP; + } + } + +CLEANUP: + + if (newtree) + CCkdtree_free (&localkt); + else + CCkdtree_undelete_all (kt, ncount); + if (tcyc) + CC_FREE (tcyc, int); + if (neighbor) + CC_FREE (neighbor, int); + if (degree) + CC_FREE (degree, char); + if (tail) + CC_FREE (tail, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void greedy_add_primheap (CCdheap *prim_heap, CCkdtree *kt, int n, + int *neighbor, CCdatagroup *dat) +#else +static void greedy_add_primheap (prim_heap, kt, n, neighbor, dat) +CCdheap *prim_heap; +CCkdtree *kt; +int n; +int *neighbor; +CCdatagroup *dat; +#endif +{ + CCkdtree_delete (kt, n); + neighbor[n] = CCkdtree_node_nearest (kt, n, dat, (double *) NULL); + CCkdtree_undelete (kt, n); + prim_heap->key[n] = (double) CCutil_dat_edgelen (n, neighbor[n], dat); + CCutil_dheap_insert (prim_heap, n); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_far_add_tour (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val) +#else +int CCkdtree_far_add_tour (kt, ncount, start, dat, outcycle, val) +CCkdtree *kt; +int ncount; +int start; +CCdatagroup *dat; +int *outcycle; +double *val; +#endif +{ + CCkdtree localkt, *thetree; + double len = 0.0; + int i, x, y, oldx; + int rval = 0; + int newtree = 0; + faobj *supply = (faobj *) NULL; + faobj *fa, *fx; + int *neighbor = (int *) NULL; + CCdheap prim_heap; + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, (double *) NULL)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + printf ("Grow a farthest addition tour from node %d \n", start); + fflush (stdout); + + neighbor = CC_SAFE_MALLOC (ncount, int); + if (!neighbor) { + rval = 1; + goto CLEANUP; + } + supply = CC_SAFE_MALLOC (ncount, faobj); + if (!supply) { + rval = 1; + goto CLEANUP; + } + if (CCutil_dheap_init (&prim_heap, ncount)) { + rval = 1; + goto CLEANUP; + } + + CCkdtree_delete_all (thetree, ncount); + CCkdtree_undelete (thetree, start); + + for (i = 0; i < ncount; i++) { + if (i != start) { + neighbor[i] = start; + fa_add_primheap (&prim_heap, i, CCutil_dat_edgelen (i, start, dat)); + } + } + + fa = &(supply[start]); + fa->prev = fa; + fa->next = fa; + fa->name = start; + + y = CCutil_dheap_deletemin (&prim_heap); + CCkdtree_undelete (thetree, y); + fa = &(supply[y]); + fa->name = y; + fa->prev = &(supply[start]); + fa->next = &(supply[start]); + supply[start].next = fa; + supply[start].prev = fa; + + for (i = 2; i < ncount; i++) { + while (1) { + y = CCutil_dheap_deletemin (&prim_heap); + oldx = neighbor[y]; + x = CCkdtree_node_nearest (thetree, y, dat, (double *) NULL); + if (x == oldx) + break; + fa_add_primheap (&prim_heap, y, CCutil_dat_edgelen (x, y, dat)); + neighbor[y] = x; + } + CCkdtree_undelete (thetree, y); + + fa = &(supply[y]); + fa->name = y; + fx = &(supply[x]); + if (CCutil_dat_edgelen (y, fx->next->name, dat) - + CCutil_dat_edgelen (x, fx->next->name, dat) <= + CCutil_dat_edgelen (y, fx->prev->name, dat) - + CCutil_dat_edgelen (x, fx->prev->name, dat)) { + fa->prev = fx; + fa->next = fx->next; + fa->next->prev = fa; + fx->next = fa; + } else { + fa->next = fx; + fa->prev = fx->prev; + fa->prev->next = fa; + fx->prev = fa; + } + if (i % 10000 == 9999) { + printf ("."); + fflush (stdout); + } + } + + fx = fa = &(supply[start]); + if (outcycle) { + i = 0; + do { + outcycle[i++] = fa->name; + len += (double) CCutil_dat_edgelen (fa->name, fa->next->name, dat); + fa = fa->next; + } while (fa != fx); + + } else { + do { + len += (double) CCutil_dat_edgelen (fa->name, fa->next->name, dat); + fa = fa->next; + } while (fa != fx); + } + + *val = len; + if (ncount >= 10000) + printf ("\n"); + printf ("Length of Farthest Addition Tour: %.2f\n", len); + CCutil_dheap_free (&prim_heap); + +CLEANUP: + + if (newtree) + CCkdtree_free (&localkt); + else + CCkdtree_undelete_all (kt, ncount); + if (neighbor) + CC_FREE (neighbor, int); + if (supply) + CC_FREE (supply, faobj); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void fa_add_primheap (CCdheap *prim_heap, int n, int len) +#else +static void fa_add_primheap (prim_heap, n, len) +CCdheap *prim_heap; +int n; +int len; +#endif +{ + prim_heap->key[n] = (double) -len; + CCutil_dheap_insert (prim_heap, n); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_qboruvka_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val) +#else +int CCkdtree_qboruvka_tour (kt, ncount, dat, outcycle, val) +CCkdtree *kt; +int ncount; +CCdatagroup *dat; +int *outcycle; +double *val; +#endif +{ + CCkdtree localkt, *thetree; + double len; + int i, x, y; + char *degree = (char *) NULL; + int *tail = (int *) NULL; + int *tcyc = (int *) NULL; + int tcount = 0, count; + int rval = 0; + int newtree = 0; + int *perm = (int *) NULL; + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, (double *) NULL)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + printf ("Grow a Quick-Boruvka tour \n"); + fflush (stdout); + + if (outcycle) { + tcyc = CC_SAFE_MALLOC (2 * ncount, int); + if (!tcyc) { + rval = 1; + goto CLEANUP; + } + } + + degree = CC_SAFE_MALLOC (ncount, char); + if (!degree) { + rval = 1; + goto CLEANUP; + } + tail = CC_SAFE_MALLOC (ncount, int); + if (!tail) { + rval = 1; + goto CLEANUP; + } + perm = CC_SAFE_MALLOC (ncount, int); + if (!perm) { + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < ncount; i++) { +#ifndef USE_SPACEFILL + perm[i] = i; +#endif + degree[i] = 0; + tail[i] = -1; + + } +#ifndef USE_SPACEFILL + CCutil_double_perm_quicksort (perm, dat->x, ncount); +#endif + +#ifdef USE_SPACEFILL + if ((dat->norm & CC_NORM_SIZE_BITS) == CC_D2_NORM_SIZE) { + double sflen; + if (space_fill_curve (ncount, dat, perm, &sflen)) { + fprintf (stderr, "space_fill_curve failed\n"); + rval = 1; + goto CLEANUP; + } + } else { + for (i = 0; i < ncount; i++) + perm[i] = i; + CCutil_double_perm_quicksort (perm, dat->x, ncount); + } +#endif + + len = 0.0; + count = 1; + while (count < ncount) { + for (i = 0; i < ncount && count < ncount; i++) { + x = perm[i]; + if (degree[x] != 2) { + if (tail[x] != -1) { + CCkdtree_delete (thetree, tail[x]); + y = CCkdtree_node_nearest (thetree, x, dat, + (double *) NULL); + CCkdtree_undelete (thetree, tail[x]); + } else + y = CCkdtree_node_nearest (thetree, x, dat, + (double *) NULL); + + /* add (x, y) to the tour */ + if (degree[x] != 0) + CCkdtree_delete (thetree, x); + if (degree[y] != 0) + CCkdtree_delete (thetree, y); + len += (double) CCutil_dat_edgelen (x, y, dat); + degree[x]++; + degree[y]++; + if (tcyc) { + tcyc[tcount++] = x; + tcyc[tcount++] = y; + } + if (tail[x] == -1) { + if (tail[y] == -1) { + tail[x] = y; + tail[y] = x; + } else { + tail[x] = tail[y]; + tail[tail[y]] = x; + } + } else if (tail[y] == -1) { + tail[tail[x]] = y; + tail[y] = tail[x]; + } else { + tail[tail[x]] = tail[y]; + tail[tail[y]] = tail[x]; + } + if (count % 10000 == 9999) { + printf ("."); + fflush (stdout); + } + count++; + } + } + } + for (x = 0; degree[x] != 1; x++); + for (y = x + 1; degree[y] != 1; y++); + if (tcyc) { + tcyc[tcount++] = x; + tcyc[tcount++] = y; + } + len += (double) CCutil_dat_edgelen (x, y, dat); + *val = len; + if (ncount >= 10000) + printf ("\n"); + printf ("Length of Quick-Boruvka Tour: %.2f\n", len); + + if (tcyc) { + if (CCutil_edge_to_cycle (ncount, tcyc, outcycle)) { + fprintf (stderr, "ERROR: greedy tour is not a tour\n"); + rval = 1; + goto CLEANUP; + } + } + +CLEANUP: + + if (newtree) + CCkdtree_free (&localkt); + else + CCkdtree_undelete_all (kt, ncount); + CC_IFFREE (tcyc, int); + CC_IFFREE (degree, char); + CC_IFFREE (tail, int); + CC_IFFREE (perm, int); + return rval; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_boruvka_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val) +#else +int CCkdtree_boruvka_tour (kt, ncount, dat, outcycle, val) +CCkdtree *kt; +int ncount; +CCdatagroup *dat; +int *outcycle; +double *val; +#endif +{ + CCkdtree localkt, *thetree; + double len; + int i, x, y; + char *degree = (char *) NULL; + int *tail = (int *) NULL; + int *tcyc = (int *) NULL; + int tcount = 0, count; + int rval = 0; + int newtree = 0; + int *getem = (int *) NULL; + int *getemlen = (int *) NULL; + int *perm = (int *) NULL; + int getemcount, newgetemcount; + int round = 0; + int *neighbor = (int *) NULL; + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, (double *) NULL)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + printf ("Grow a Boruvka tour \n"); + fflush (stdout); + + if (outcycle) { + tcyc = CC_SAFE_MALLOC (2 * ncount, int); + if (!tcyc) { + rval = 1; + goto CLEANUP; + } + } + + degree = CC_SAFE_MALLOC (ncount, char); + if (!degree) { + rval = 1; + goto CLEANUP; + } + tail = CC_SAFE_MALLOC (ncount, int); + if (!tail) { + rval = 1; + goto CLEANUP; + } + neighbor = CC_SAFE_MALLOC (ncount, int); + if (!neighbor) { + rval = 1; + goto CLEANUP; + } + getem = CC_SAFE_MALLOC (ncount, int); + if (!getem) { + rval = 1; + goto CLEANUP; + } + getemlen = CC_SAFE_MALLOC (ncount, int); + if (!getemlen) { + rval = 1; + goto CLEANUP; + } + perm = CC_SAFE_MALLOC (ncount, int); + if (!perm) { + rval = 1; + goto CLEANUP; + } + getemcount = ncount; + + for (i = 0; i < ncount; i++) { + degree[i] = 0; + tail[i] = -1; + getem[i] = i; + } + + len = 0.0; + count = 1; + while (count < ncount) { + round++; + i = 0; + while (i < getemcount) { + x = getem[i]; + if (degree[x] != 2) { + if (tail[x] != -1) { + CCkdtree_delete (thetree, tail[x]); + neighbor[i] = CCkdtree_node_nearest (thetree, x, dat, + (double *) NULL); + CCkdtree_undelete (thetree, tail[x]); + } else { + neighbor[i] = CCkdtree_node_nearest (thetree, x, dat, + (double *) NULL); + } + getemlen[i] = CCutil_dat_edgelen (x, neighbor[i], dat); + perm[i] = i; + i++; + } else { + getem[i] = getem[--getemcount]; + } + } + CCutil_int_perm_quicksort (perm, getemlen, getemcount); + newgetemcount = 0; + for (i = 0; i < getemcount && count < ncount; i++) { + x = getem[perm[i]]; + if (degree[x] != 2) { + y = neighbor[perm[i]]; + if (degree[y] != 2 && tail[x] != y) { + /* add (x, y) to the tour */ + if (degree[x] != 0) + CCkdtree_delete (thetree, x); + else + perm[newgetemcount++] = x; + if (degree[y] != 0) + CCkdtree_delete (thetree, y); + len += (double) CCutil_dat_edgelen (x, y, dat); + degree[x]++; + degree[y]++; + if (tcyc) { + tcyc[tcount++] = x; + tcyc[tcount++] = y; + } + if (tail[x] == -1) { + if (tail[y] == -1) { + tail[x] = y; + tail[y] = x; + } else { + tail[x] = tail[y]; + tail[tail[y]] = x; + } + } else if (tail[y] == -1) { + tail[tail[x]] = y; + tail[y] = tail[x]; + } else { + tail[tail[x]] = tail[y]; + tail[tail[y]] = tail[x]; + } + if (count % 10000 == 9999) { + printf ("."); + fflush (stdout); + } + count++; + } else { + perm[newgetemcount++] = x; + } + } + } + getemcount = newgetemcount; + { + int *temp; + SWAP (getem, perm, temp); + } + } + for (x = 0; degree[x] != 1; x++); + for (y = x + 1; degree[y] != 1; y++); + if (tcyc) { + tcyc[tcount++] = x; + tcyc[tcount++] = y; + } + len += (double) CCutil_dat_edgelen (x, y, dat); + *val = len; + if (ncount >= 10000) + printf ("\n"); + printf ("Length of Boruvka Tour: %.0f (%d Rounds)\n", len, round); + + if (tcyc) { + if (CCutil_edge_to_cycle (ncount, tcyc, outcycle)) { + fprintf (stderr, "ERROR: greedy tour is not a tour\n"); + rval = 1; + goto CLEANUP; + } + } + +CLEANUP: + + if (newtree) + CCkdtree_free (&localkt); + else + CCkdtree_undelete_all (kt, ncount); + if (tcyc) + CC_FREE (tcyc, int); + if (degree) + CC_FREE (degree, char); + if (tail) + CC_FREE (tail, int); + if (neighbor) + CC_FREE (neighbor, int); + if (getem) + CC_FREE (getem, int); + if (getemlen) + CC_FREE (getemlen, int); + if (perm) + CC_FREE (perm, int); + return rval; +} + +#ifdef USE_SPACEFILL +#ifdef CC_PROTOTYPE_ANSI +static int space_fill_curve (int ncount, CCdatagroup *dat, int *outcyc, + double *len) +#else +static int space_fill_curve (ncount, dat, outcyc, len) +int ncount; +CCdatagroup *dat; +int *outcyc; +double *len; +#endif +{ + int i, h, M; + int x, y, z; + int k, nbits; + int *th = (int *) NULL; + int *cyc = (int *) NULL; + double tx, ty, tM; + + /* From Platzman and Bartholdi, JACM 36 (1989) 719-737. */ + + if ((dat->norm & CC_NORM_SIZE_BITS) != CC_D2_NORM_SIZE) { + printf ("Need a 2-coordinate norm to use space filling curve\n"); + fflush (stdout); + return 1; + } + + th = CC_SAFE_MALLOC (ncount, int); + if (!th) + return 1; + + if (outcyc != (int *) NULL) { + cyc = outcyc; + } else { + cyc = CC_SAFE_MALLOC (ncount, int); + if (!cyc) { + CC_FREE (th, int); + return 1; + } + } + + tM = 0.0; + tx = 0.0; + ty = 0.0; + + for (i = 0; i < ncount; i++) { + cyc[i] = i; + if (dat->x[i] < tx) + tx = dat->x[i]; + else if (dat->x[i] > tM) + tM = dat->x[i]; + + if (dat->y[i] < ty) + ty = dat->y[i]; + else if (dat->y[i] > tM) + tM = dat->y[i]; + } + + M = (int) (tM - tx - ty + 1.0); + + nbits = 0; + while ((1 << nbits) < ncount) + nbits++; + nbits += 2; + + for (i = 0; i < ncount; i++) { + x = (int) (dat->x[i] - tx); /* To make coords nonnegative ints */ + y = (int) (dat->y[i] - ty); + + h = 0; + k = 1; + if (x > y) { + h = 1; + x = M - x; + y = M - y; + } + + while (k < nbits) { + h <<= 1; + k++; + + if (x + y > M) { + h++; + z = M - y; + y = x; + x = z; + } + + if (k < nbits) { + h <<= 1; + k++; + + x <<= 1; + y <<= 1; + + if (y > M) { + h++; + z = y - M; + y = M - x; + x = z; + } + } + } + th[i] = h; + } + + CCutil_int_perm_quicksort (cyc, th, ncount); + *len = (double) CCutil_dat_edgelen (cyc[ncount - 1], cyc[0], dat); + for (i = 1; i < ncount; i++) + (*len) += CCutil_dat_edgelen (cyc[i - 1], cyc[i], dat); + printf ("Spacefilling Curve Tour: %.2f\n", *len); + fflush (stdout); + + if (th) + CC_FREE (th, int); + if (!outcyc && cyc) + CC_FREE (cyc, int); + + return 0; +} +#endif diff --git a/contrib/blossom/concorde97/KDTREE/kdtwoopt.c b/contrib/blossom/concorde97/KDTREE/kdtwoopt.c new file mode 100644 index 0000000000000000000000000000000000000000..5cf49e3392fff299912ba08099db1961599388dc --- /dev/null +++ b/contrib/blossom/concorde97/KDTREE/kdtwoopt.c @@ -0,0 +1,1057 @@ +/***************************************************************************/ +/* */ +/* KD-TREE BASED GEOMETRIC 2-OPT ROUTINE */ +/* */ +/* (Based on Jon Bentley's paper "Fast algorithms for geometric */ +/* traveling salesman problems", ORSA Journal on Computing.) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook (mainly from Jon */ +/* Bentley's paper) */ +/* Date: February 16, 1995 (cofeb16) */ +/* Modified: October 11, 1995 (Bico) - removed globals. */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCkdtree_twoopt_tour (CCkdtree *kt, int ncount, CCdatagroup *dat,*/ +/* int *incycle, int *outcycle, double *val, */ +/* int run_two_and_a_half_opt, int run_silently) */ +/* RETURNS a 2-opted cycle (well, approximately 2-opted) */ +/* -kt can be NULL. */ +/* -Does not use node weights. */ +/* -incycle is the starting cycle. */ +/* -If outcycle is not NULL, then it should point to an array of */ +/* length at least ncount (allocated by the calling routine). The */ +/* final tour will be placed in this array. */ +/* -The length of the tour is returned in val. */ +/* -If in_run_two_and_a_half_opt is nonzero, then some limited */ +/* 3-swapping is performded. */ +/* -run_silently (if nonzero then very little info will be printed) */ +/* int CCkdtree_3opt_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, */ +/* int *incycle, int *outcycle, double *val, run_silently) */ +/* RETURNS an approximately 3-opted tour. */ +/* -kt can be NULL. */ +/* */ +/* NOTES: */ +/* Uses around 13n bytes of memory for an n node problem (plus the */ +/* the memory for the CCkdtree). Returns 0 if successful, and nonzero if */ +/* it failed (usually due to running out of memory. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "kdtree.h" + +#define Edgelen(a, b) CCutil_dat_edgelen ((a), (b), dat) +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define ADD_TO_ACTIVE_QUEUE(n, ip, q) { \ + if (!(q)->active[(n)]) { \ + (q)->active[(n)] = 1; \ + (ip) = intptralloc (); \ + (ip)->this = (n); \ + (ip)->next = (intptr *) NULL; \ + if ((q)->bottom) \ + (q)->bottom->next = (ip); \ + else \ + (q)->queue = (ip); \ + (q)->bottom = (ip); \ + } \ +} + +typedef struct intptr { + int this; + struct intptr *next; +} intptr; + +typedef struct optqueue { + char *active; + intptr *queue; + intptr *bottom; +} optqueue; + +typedef struct flipper { + int reversed; + int cycle_size; + int short_size; + int *cyc; + int *cyc_inv; +} flipper; + +typedef struct twoopt_param { + CCdatagroup *dat; + optqueue *activequeue; + flipper *flipstuff; + int node_b; +} twoopt_param; + +typedef struct twoopt_and_a_half_param { + CCdatagroup *dat; + optqueue *activequeue; + flipper *flipstuff; + int node_b; +} twoopt_and_a_half_param; + +typedef struct threeopt_param { + CCdatagroup *dat; + optqueue *activequeue; + flipper *flipstuff; + int node_a; + int node_b; + int node_c; + int ab_dist; + int ac_dist; + int cd_dist; + CCkdtree *thetree; +} threeopt_param; + +CC_PTR_ALLOC_ROUTINE (intptr, intptralloc, intptrchunklist, intptrfreelist) +CC_PTR_FREE_ROUTINE (intptr, intptrfree, intptrfreelist) +CC_PTR_FREE_WORLD_ROUTINE (intptr, intptrfree_world, intptrchunklist, + intptrfreelist) +CC_PTR_LEAKS_ROUTINE (intptr, intptr_check_leaks, intptrchunklist, + intptrfreelist, this, int) + + +#ifdef CC_PROTOTYPE_ANSI + +static void + flipper_cycle (flipper *f, int *x), + flipper_finish (flipper *f), + flipper_flip (flipper *f, int x, int y), + randcycle (int ncount, int *cyc), + twoopt_free_world (void); +static int + run_two_opt (int ncount, int run_silently, int *tour, + int run_two_and_a_half_swap, int *neighbor, CCkdtree *thetree, + CCdatagroup *dat, optqueue *activequeue), + run_3_opt (int ncount, int run_silently, int *tour, int *neighbor, + CCkdtree *thetree, CCdatagroup *dat, optqueue *activequeue), + swap_from_node (int a, int run_two_an_a_half_swap, int *neighbor, + CCkdtree *thetree, CCdatagroup *dat, optqueue *activequeue, + flipper *f), + try_two_swap (int a, int c, void *pass_param), + try_two_and_a_half_swap (int a, int c, void *pass_param), + three_swap_from_node (int a, int *neighbor, CCkdtree *thetree, + CCdatagroup *dat, optqueue *activequeue, flipper *f), + try_three_swap (int a, int c, void *pass_param), + try_three_swap_2 (int a, int c, void *pass_param), + flipper_init (flipper *f, int *incyc, int n), + flipper_next (flipper *f, int x), + flipper_prev (flipper *f, int x), + flipper_sequence (flipper *f, int x, int y, int z); +static double + cycle_length (int *cyc, int ncount, CCdatagroup *dat); + +#else + +static void + flipper_cycle (), + flipper_finish (), + flipper_flip (), + randcycle (), + twoopt_free_world (); +static int + run_two_opt (), + run_3_opt (), + swap_from_node (), + try_two_swap (), + try_two_and_a_half_swap (), + three_swap_from_node (), + try_three_swap (), + try_three_swap_2 (), + flipper_init (), + flipper_next (), + flipper_prev (), + flipper_sequence (); +static double + cycle_length (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_twoopt_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *incycle, int *outcycle, double *val, + int run_two_and_a_half_opt, int run_silently) +#else +int CCkdtree_twoopt_tour (kt, ncount, dat, incycle, outcycle, val, + run_two_and_a_half_opt, run_silently) +CCkdtree *kt; +int ncount; +CCdatagroup *dat; +int *incycle, *outcycle; +double *val; +int run_two_and_a_half_opt; +int run_silently; +#endif +{ + CCkdtree localkt; + int i; + int rval = 0; + double szeit; + int newtree = 0; + intptr *ip; + int *tour = (int *) NULL; + int *neighbor = (int *) NULL; + CCkdtree *thetree = (CCkdtree *) NULL; + optqueue activequeue; + + *val = 0.0; + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, (double *) NULL)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + activequeue.active = (char *) NULL; + activequeue.queue = (intptr *) NULL; + activequeue.bottom = (intptr *) NULL; + + if (!run_silently) { + printf ("Find 2-opt Tour starting with tour of length %.2f\n", + cycle_length (incycle, ncount, dat)); + fflush (stdout); + } + + szeit = CCutil_zeit (); + tour = CC_SAFE_MALLOC (ncount, int); + if (!tour) { + rval = 1; + goto CLEANUP; + } + neighbor = CC_SAFE_MALLOC (ncount, int); + if (!neighbor) { + rval = 1; + goto CLEANUP; + } + activequeue.active = CC_SAFE_MALLOC (ncount, char); + if (!activequeue.active) { + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < ncount; i++) + activequeue.active[i] = 0; + + randcycle (ncount, tour); /* init active_queue with random order */ + for (i = 0; i < ncount; i++) { + ADD_TO_ACTIVE_QUEUE (tour[i], ip, &activequeue); + } + + for (i = 0; i < ncount; i++) { + tour[i] = incycle[i]; + } + run_two_opt (ncount, run_silently, tour, run_two_and_a_half_opt, + neighbor, thetree, dat, &activequeue); + + *val = cycle_length (tour, ncount, dat); + if (!run_silently) { + printf ("Length of Two-opt Cycle: %.2f\n", *val); + fflush (stdout); + } + if (outcycle != (int *) NULL) { + for (i = 0; i < ncount; i++) + outcycle[i] = tour[i]; + } + if (!run_silently) { + printf ("Running time for Two Opt: %.2f\n", CCutil_zeit () - szeit); + fflush (stdout); + } + +CLEANUP: + + if (newtree) + CCkdtree_free (&localkt); + if (tour) + CC_FREE (tour, int); + if (neighbor) + CC_FREE (neighbor, int); + if (activequeue.active) + CC_FREE (activequeue.active, char); + twoopt_free_world (); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int run_two_opt (int ncount, int run_silently, int *tour, + int run_two_and_a_half_opt, int *neighbor, + CCkdtree *thetree, CCdatagroup *dat, optqueue *activequeue) +#else +static int run_two_opt (ncount, run_silently, tour, run_two_and_a_half_opt, + neighbor, thetree, dat, activequeue) +int ncount; +int run_silently; +int *tour; +int run_two_and_a_half_opt; +int *neighbor; +CCkdtree *thetree; +CCdatagroup *dat; +optqueue *activequeue; +#endif +{ + int i, hit; + int start; + intptr *ip; + flipper f; + + for (i = 0; i < ncount; i++) { + CCkdtree_delete (thetree, i); + neighbor[i] = CCkdtree_node_nearest (thetree, i, dat, (double *) NULL); + CCkdtree_undelete (thetree, i); + } + + flipper_init (&f, tour, ncount); + hit = 0; + while (activequeue->queue) { + ip = activequeue->queue; + start = ip->this; + activequeue->queue = ip->next; + if (ip == activequeue->bottom) + activequeue->bottom = (intptr *) NULL; + intptrfree (ip); + activequeue->active[start] = 0; + if (swap_from_node (start, run_two_and_a_half_opt, neighbor, + thetree, dat, activequeue, &f)) { + hit++; + if (!run_silently && hit % 1000 == 0) { + printf ("."); + fflush (stdout); + if (hit % 50000 == 0) { + flipper_cycle (&f, tour); + printf ("\nCurrent length: %.2f\n", + cycle_length (tour, ncount, dat)); + fflush (stdout); + } + } + } + } + + if (!run_silently) { + printf ("\nMade %d swaps\n", hit); + fflush (stdout); + } + + flipper_cycle (&f, tour); + flipper_finish (&f); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void twoopt_free_world (void) +#else +static void twoopt_free_world () +#endif +{ + int total, onlist; + + if (intptr_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding intptrs\n", total - onlist); + } + intptrfree_world (); +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCkdtree_3opt_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *incycle, int *outcycle, double *val, int run_silently) +#else +int CCkdtree_3opt_tour (kt, ncount, dat, incycle, outcycle, val, run_silently) +CCkdtree *kt; +int ncount; +CCdatagroup *dat; +int *incycle, *outcycle; +double *val; +int run_silently; +#endif +{ + CCkdtree localkt; + int i; + int rval = 0; + double szeit; + int newtree = 0; + intptr *ip; + int *tour = (int *) NULL; + int *neighbor = (int *) NULL; + CCkdtree *thetree = (CCkdtree *) NULL; + optqueue activequeue; + + *val = 0.0; + + if (kt == (CCkdtree *) NULL) { + if (CCkdtree_build (&localkt, ncount, dat, (double *) NULL)) { + fprintf (stderr, "Unable to build CCkdtree\n"); + return 1; + } + thetree = &localkt; + newtree = 1; + } else { + thetree = kt; + } + + activequeue.active = (char *) NULL; + activequeue.queue = (intptr *) NULL; + activequeue.bottom = (intptr *) NULL; + + if (!run_silently) { + printf ("Find 3-opt Tour starting with tour of length %.2f\n", + cycle_length (incycle, ncount, dat)); + fflush (stdout); + } + + szeit = CCutil_zeit (); + tour = CC_SAFE_MALLOC (ncount, int); + if (!tour) { + rval = 1; + goto CLEANUP; + } + activequeue.active = CC_SAFE_MALLOC (ncount, char); + if (!activequeue.active) { + rval = 1; + goto CLEANUP; + } + neighbor = CC_SAFE_MALLOC (ncount, int); + if (!neighbor) { + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < ncount; i++) + activequeue.active[i] = 0; + + randcycle (ncount, tour); /* init active_queue with random order */ + for (i = 0; i < ncount; i++) { + ADD_TO_ACTIVE_QUEUE (tour[i], ip, &activequeue); + } + + for (i = 0; i < ncount; i++) { + tour[i] = incycle[i]; + } + run_3_opt (ncount, run_silently, tour, neighbor, thetree, dat, + &activequeue); + + *val = cycle_length (tour, ncount, dat); + if (!run_silently) { + printf ("Length of 3-opt Cycle: %.2f\n", *val); + fflush (stdout); + } + if (outcycle != (int *) NULL) { + for (i = 0; i < ncount; i++) + outcycle[i] = tour[i]; + } + if (!run_silently) { + printf ("Running time for 3-Opt: %.2f\n", CCutil_zeit () - szeit); + fflush (stdout); + } + +CLEANUP: + + if (newtree) + CCkdtree_free (&localkt); + if (tour) + CC_FREE (tour, int); + if (activequeue.active) + CC_FREE (activequeue.active, char); + if (neighbor) + CC_FREE (neighbor, int); + twoopt_free_world (); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int run_3_opt (int ncount, int run_silently, int *tour, + int *neighbor, CCkdtree *thetree, CCdatagroup *dat, + optqueue *activequeue) +#else +static int run_3_opt (ncount, run_silently, tour, neighbor, thetree, dat, + activequeue) +int ncount; +int run_silently; +int *tour; +int *neighbor; +CCkdtree *thetree; +CCdatagroup *dat; +optqueue *activequeue; +#endif +{ + int i, hit; + int start; + intptr *ip; + flipper f; + + for (i = 0; i < ncount; i++) { + CCkdtree_delete (thetree, i); + neighbor[i] = CCkdtree_node_nearest (thetree, i, dat, (double *) NULL); + CCkdtree_undelete (thetree, i); + } + + flipper_init (&f, tour, ncount); + hit = 0; + while (activequeue->queue) { + ip = activequeue->queue; + start = ip->this; + activequeue->queue = ip->next; + if (ip == activequeue->bottom) + activequeue->bottom = (intptr *) NULL; + intptrfree (ip); + activequeue->active[start] = 0; + if (three_swap_from_node (start, neighbor, thetree, dat, activequeue, + &f)) { + hit++; + if (!run_silently && hit % 1000 == 0) { + printf ("."); + fflush (stdout); + if (hit % 50000 == 0) { + flipper_cycle (&f, tour); + printf ("\nCurrent length: %.2f\n", + cycle_length (tour, ncount, dat)); + fflush (stdout); + } + } + } + } + + if (!run_silently) { + printf ("\nMade %d swaps\n", hit); + fflush (stdout); + } + + flipper_cycle (&f, tour); + flipper_finish (&f); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int swap_from_node (int a, int run_two_and_a_half_opt, + int *neighbor, CCkdtree *thetree, CCdatagroup *dat, + optqueue *activequeue, flipper *f) +#else +static int swap_from_node (a, run_two_and_a_half_opt, neighbor, thetree, dat, + activequeue, f) +int run_two_and_a_half_opt; +int a; +int *neighbor; +CCkdtree *thetree; +CCdatagroup *dat; +optqueue *activequeue; +flipper *f; +#endif +{ + twoopt_param param2; + twoopt_param param2h; + int b; + + b = flipper_next (f, a); + if (neighbor[a] ==b) { + return 0; + } else { + int dist = Edgelen (a, b); + if (run_two_and_a_half_opt) { + param2h.dat = dat; + param2h.activequeue = activequeue; + param2h.node_b = b; + param2h.flipstuff = f; + return CCkdtree_fixed_radius_nearest (thetree, dat, (double *) NULL, + a, (double) dist, try_two_and_a_half_swap, + (void *) (¶m2h)); + } else { + param2.dat = dat; + param2.activequeue = activequeue; + param2.node_b = b; + param2.flipstuff = f; + return CCkdtree_fixed_radius_nearest (thetree, dat, (double *) NULL, + a, (double) dist, try_two_swap, (void *) (¶m2)); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int try_two_swap (int a, int c, void *pass_param) +#else +static int try_two_swap (a, c, pass_param) +int a, c; +void *pass_param; +#endif +{ + int d; + int b = ((twoopt_param *) pass_param)->node_b; + CCdatagroup *dat = ((twoopt_param *) pass_param)->dat; + optqueue *activequeue = ((twoopt_param *) pass_param)->activequeue; + flipper *flipstuff = ((twoopt_param *) pass_param)->flipstuff; + intptr *ip; + + d = flipper_next (flipstuff, c); + + if (d == a) + return 0; + + if (Edgelen (a, b) + Edgelen (c, d) > + Edgelen (a, c) + Edgelen (b, d)) { + flipper_flip (flipstuff, d, a); + ADD_TO_ACTIVE_QUEUE (a, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (b, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (c, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (d, ip, activequeue); + return 1; + } else + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int try_two_and_a_half_swap (int a, int c, void *pass_param) +#else +static int try_two_and_a_half_swap (a, c, pass_param) +int a, c; +void *pass_param; +#endif +{ + int d, e; + int b = ((twoopt_and_a_half_param *) pass_param)->node_b; + CCdatagroup *dat = ((twoopt_param *) pass_param)->dat; + optqueue *activequeue = ((twoopt_param *) pass_param)->activequeue; + flipper *flipstuff = ((twoopt_param *) pass_param)->flipstuff; + intptr *ip; + + d = flipper_next (flipstuff, c); + + if (d == a) + return 0; + + if (Edgelen (a, b) + Edgelen (c, d) > + Edgelen (a, c) + Edgelen (b, d)) { + flipper_flip (flipstuff, d, a); + ADD_TO_ACTIVE_QUEUE (a, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (b, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (c, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (d, ip, activequeue); + return 1; + } else { + e = flipper_prev (flipstuff, c); + if (e != b && + Edgelen (a, b) + Edgelen (c, d) + Edgelen (c, e) > + Edgelen (a, c) + Edgelen (b, c) + Edgelen (d, e)) { + flipper_flip (flipstuff, b, e); + flipper_flip (flipstuff, e, c); + ADD_TO_ACTIVE_QUEUE (a, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (b, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (c, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (d, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (e, ip, activequeue); + return 1; + } else { + return 0; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int three_swap_from_node (int a, int *neighbor, CCkdtree *thetree, + CCdatagroup *dat, optqueue *activequeue, flipper *f) +#else +static int three_swap_from_node (a, neighbor, thetree, dat, activequeue, f) +int a; +int *neighbor; +CCkdtree *thetree; +CCdatagroup *dat; +optqueue *activequeue; +flipper *f; +#endif +{ + threeopt_param param3; + int b, ab; + + b = flipper_next (f, a); + + if (neighbor[a] == b) { + return 0; + } else { + ab = Edgelen (a, b); + param3.dat = dat; + param3.activequeue = activequeue; + param3.node_a = a; + param3.node_b = b; + param3.thetree = thetree; + param3.ab_dist = ab; + param3.flipstuff = f; + return CCkdtree_fixed_radius_nearest (thetree, dat, (double *) NULL, + a, (double) ab, try_three_swap, (void *) (¶m3)); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int try_three_swap (int a, int c, void *pass_param) +#else +static int try_three_swap (a, c, pass_param) +int a, c; +void *pass_param; +#endif +{ + int d, b, ac, cd; + threeopt_param *p = (threeopt_param *) pass_param; + CCdatagroup *dat; + optqueue *activequeue; + intptr *ip; + + dat = p->dat; + activequeue = p->activequeue; + b = p->node_b; + d = flipper_next (p->flipstuff, c); + + ac = Edgelen (a, c); + cd = Edgelen (c, d); + if (p->ab_dist + cd > ac + Edgelen (b, d)) { + flipper_flip (p->flipstuff, d, a); + ADD_TO_ACTIVE_QUEUE (a, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (b, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (c, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (d, ip, activequeue); + return 1; + } else { + int e = flipper_prev (p->flipstuff, c); + if (e != b && d != a && + p->ab_dist + cd + Edgelen (c, e) > + ac + Edgelen (b, c) + Edgelen (d, e)) { + flipper_flip (p->flipstuff, b, e); + flipper_flip (p->flipstuff, e, c); + ADD_TO_ACTIVE_QUEUE (a, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (b, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (c, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (d, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (e, ip, activequeue); + return 1; + } else { + p->node_c = c; + p->ac_dist = ac; + p->cd_dist = cd; + + return CCkdtree_fixed_radius_nearest (p->thetree, dat, + (double *) NULL, d, (double) (p->ab_dist + cd - ac), + try_three_swap_2, pass_param); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int try_three_swap_2 (int d, int e, void *pass_param) +#else +static int try_three_swap_2 (d, e, pass_param) +int d, e; +void *pass_param; +#endif +{ + threeopt_param *p = (threeopt_param *) pass_param; + CCdatagroup *dat; + optqueue *activequeue; + int a, b, c, f; + intptr *ip; + + a = p->node_a; + b = p->node_b; + c = p->node_c; + dat = p->dat; + activequeue = p->activequeue; + + if (e == c) + return 0; + else if (flipper_sequence (p->flipstuff, b, e, c)) + f = flipper_next (p->flipstuff, e); + else + f = flipper_prev (p->flipstuff, e); + + if (p->ab_dist + p->cd_dist + Edgelen (e, f) > + p->ac_dist + Edgelen (b, f) + Edgelen (d, e)) { + flipper_flip (p->flipstuff, d, a); + flipper_flip (p->flipstuff, b, e); + ADD_TO_ACTIVE_QUEUE (a, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (b, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (c, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (d, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (e, ip, activequeue); + ADD_TO_ACTIVE_QUEUE (f, ip, activequeue); + return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static double cycle_length (int *cyc, int ncount, CCdatagroup *dat) +#else +static double cycle_length (cyc, ncount, dat) +int *cyc; +int ncount; +CCdatagroup *dat; +#endif +{ + int i; + double len; + + for (len = 0.0, i = 1; i < ncount; i++) + len += CCutil_dat_edgelen (cyc[i - 1], cyc[i], dat); + len += CCutil_dat_edgelen (cyc[0], cyc[ncount - 1], dat); + + return len; +} + +#ifdef CC_PROTOTYPE_ANSI +static void randcycle (int ncount, int *cyc) +#else +static void randcycle (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, k, temp; + + for (i = 0; i < ncount; i++) + cyc[i] = i; + + for (i = ncount; i > 1; i--) { + k = CCutil_lprand () % i; + SWAP (cyc[i - 1], cyc[k], temp); + } +} + + +/********** modified version of flipper3.c **********/ + +/* + flipper routines: + + flipper_init (flipper *f, int n) + initializes flipper3 to an initial * cycle from 0 to n-1. + flipper_cycle (flipper *f, int *p) + places the current * cycle in p. + flipper_finish (flipper *f, ) + frees up space * allocated by flipper. + flipper_next (flipper *f, int x) + returns the * successor to x in the current cycle. + flipper_prev (flipper *f, int x) + returns the predecessor of x in the current cycle. + flipper_flip (flipper *f, int * x, int y) + flips the portion of the cycle from x to y (inclusive). + flipper_sequence (flipper *f, int x, int y, int z) + returns 1 if x, y, z occur as an increasing + subsequence of the cycle, 0 otherwise. + + The basic implementation - uses a raw cycle and its inverse, but flips + the short side. +*/ + + +#ifdef CC_PROTOTYPE_ANSI +static int flipper_init (flipper *f, int *incyc, int n) +#else +static int flipper_init (f, incyc, n) +flipper *f; +int *incyc, n; +#endif +{ + int i; + + f->cyc_inv = (int *) NULL; + f->cyc = CC_SAFE_MALLOC (n, int); + if (!f->cyc) + return 1; + f->cyc_inv = CC_SAFE_MALLOC (n, int); + if (!f->cyc_inv) { + CC_FREE (f->cyc, int); + return 1; + } + + for (i = 0; i < n; i++) { + f->cyc[i] = incyc[i]; + f->cyc_inv[incyc[i]] = i; + } + + f->cycle_size = n; + f->short_size = n / 2; + f->reversed = 0; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper_cycle (flipper *f, int *x) +#else +static void flipper_cycle (f, x) +flipper *f; +int *x; +#endif +{ + int *p; + + if (f->reversed) { + p = f->cyc + f->cycle_size; + while (p > f->cyc) { + *x++ = *--p; + } + } else { + p = f->cyc + f->cycle_size; + x += f->cycle_size; + while (p > f->cyc) { + *--x = *--p; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper_finish (flipper *f) +#else +static void flipper_finish (f) +flipper *f; +#endif +{ + if (f->cyc) + CC_FREE (f->cyc, int); + if (f->cyc_inv) + CC_FREE (f->cyc_inv, int); + f->cycle_size = 0; + f->short_size = 0; + f->reversed = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int flipper_next (flipper *f, int x) +#else +static int flipper_next (f, x) +flipper *f; +int x; +#endif +{ + int y; + + if (f->reversed) { + y = f->cyc_inv[x] - 1; + return (y >= 0) ? f->cyc[y] : f->cyc[f->cycle_size - 1]; + } else { + y = f->cyc_inv[x] + 1; + return (y < f->cycle_size) ? f->cyc[y] : f->cyc[0]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int flipper_prev (flipper *f, int x) +#else +static int flipper_prev (f, x) +flipper *f; +int x; +#endif +{ + int y; + + if (f->reversed) { + y = f->cyc_inv[x] + 1; + return (y < f->cycle_size) ? f->cyc[y] : f->cyc[0]; + } else { + y = f->cyc_inv[x] - 1; + return (y >= 0) ? f->cyc[y] : f->cyc[f->cycle_size - 1]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper_flip (flipper *f, int x, int y) +#else +static void flipper_flip (f, x, y) +flipper *f; +int x, y; +#endif +{ + int xloc = f->cyc_inv[x]; + int yloc = f->cyc_inv[y]; + int temp; + int gap; + + if (f->reversed) { + SWAP (xloc, yloc, temp); + } + gap = yloc - xloc; + if (gap < 0) + gap += f->cycle_size; + if (gap > f->short_size) { + SWAP (xloc, yloc, temp); + f->reversed ^= 1; + xloc++; + if (xloc >= f->cycle_size) + xloc = 0; + yloc--; + if (yloc < 0) + yloc = f->cycle_size - 1; + gap = f->cycle_size - gap - 2; + } + + if (xloc > yloc) { + gap++; + gap /= 2; + for (; gap; gap--) { + x = f->cyc[xloc]; + y = f->cyc[yloc]; + f->cyc[xloc] = y; + f->cyc[yloc] = x; + f->cyc_inv[x] = yloc--; + f->cyc_inv[y] = xloc++; + if (xloc >= f->cycle_size) + xloc = 0; + if (yloc < 0) + yloc = f->cycle_size - 1; + } + } else { + gap++; + gap /= 2; + for (; gap; gap--) { + x = f->cyc[xloc]; + y = f->cyc[yloc]; + f->cyc[xloc] = y; + f->cyc[yloc] = x; + f->cyc_inv[x] = yloc--; + f->cyc_inv[y] = xloc++; + } + } + +/* + while (gap > 0) { + SWAP (f->cyc[xloc], f->cyc[yloc], temp); + SWAP (f->cyc_inv[cyc[xloc]], f->cyc_inv[cyc[yloc]], temp); + xloc++; + if (xloc >= f->cycle_size) + xloc = 0; + yloc--; + if (yloc < 0) + yloc = f->cycle_size - 1; + gap -= 2; + } +*/ +} + +#ifdef CC_PROTOTYPE_ANSI +static int flipper_sequence (flipper *f, int x, int y, int z) +#else +static int flipper_sequence (f, x, y, z) +flipper *f; +int x, y, z; +#endif +{ + int xloc = f->cyc_inv[x]; + int yloc = f->cyc_inv[y]; + int zloc = f->cyc_inv[z]; + + if (f->reversed) { + if (xloc >= yloc) + return yloc >= zloc || zloc >= xloc; + else + return yloc >= zloc && zloc >= xloc; + } else { + if (xloc <= yloc) + return yloc <= zloc || zloc <= xloc; + else + return yloc <= zloc && zloc <= xloc; + } +} + + diff --git a/contrib/blossom/concorde97/LINKERN/Makefile b/contrib/blossom/concorde97/LINKERN/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4faaca30def4564581cf7b97741c5f69b2c74b53 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/Makefile @@ -0,0 +1,72 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=linkern.a +LIBSRCS=linkern.c flip_two.c +ALLSRCS=lk_main.c linkern.c flip_ary.c flip_bt0.c flip_bt1.c \ + flip_bt2.c flip_bt3.c flip_bt4.c flip_bt5.c flip_btc.c \ + flip_btd.c flip_btr.c flip_ll0.c flip_ll1.c flip_ll2.c \ + flip_ll3.c flip_ll4.c flip_ll5.c flip_ll6.c flip_ll7.c \ + flip_ll8.c flip_ll9.c flip_llA.c flip_llB.c flip_llC.c \ + flip_llD.c flip_sg1.c flip_sg2.c flip_sg3.c flip_sp1.c \ + flip_sp2.c flip_try.c flip_tw2.c flip_two.c + +LIBS=$(ROOT)/EDGEGEN/edgegen.a $(ROOT)/KDTREE/kdtree.a \ + $(ROOT)/FMATCH/fmatch.a $(ROOT)/UTIL/util.a + +all: linkern $(LIB) + +linkern: lk_main.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ -lm + +clean: + -rm -f *.$o $(LIB) linkern + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +flip_ary.$o: flip_ary.c $(I)/machdefs.h $(I)/util.h +flip_bt0.$o: flip_bt0.c $(I)/machdefs.h $(I)/util.h +flip_bt1.$o: flip_bt1.c $(I)/machdefs.h $(I)/util.h +flip_bt2.$o: flip_bt2.c $(I)/machdefs.h $(I)/util.h +flip_bt3.$o: flip_bt3.c $(I)/machdefs.h $(I)/util.h +flip_bt4.$o: flip_bt4.c $(I)/machdefs.h $(I)/util.h +flip_bt5.$o: flip_bt5.c $(I)/machdefs.h $(I)/util.h +flip_btc.$o: flip_btc.c $(I)/machdefs.h $(I)/util.h +flip_btd.$o: flip_btd.c $(I)/machdefs.h $(I)/util.h +flip_btr.$o: flip_btr.c $(I)/machdefs.h $(I)/util.h +flip_ll0.$o: flip_ll0.c $(I)/machdefs.h $(I)/util.h +flip_ll1.$o: flip_ll1.c $(I)/machdefs.h $(I)/util.h +flip_ll2.$o: flip_ll2.c $(I)/machdefs.h $(I)/util.h +flip_ll3.$o: flip_ll3.c $(I)/machdefs.h $(I)/util.h +flip_ll4.$o: flip_ll4.c $(I)/machdefs.h $(I)/util.h +flip_ll5.$o: flip_ll5.c $(I)/machdefs.h $(I)/util.h +flip_ll6.$o: flip_ll6.c $(I)/machdefs.h $(I)/util.h +flip_ll7.$o: flip_ll7.c $(I)/machdefs.h $(I)/util.h +flip_ll8.$o: flip_ll8.c $(I)/machdefs.h $(I)/util.h +flip_ll9.$o: flip_ll9.c $(I)/machdefs.h $(I)/util.h +flip_llA.$o: flip_llA.c $(I)/machdefs.h $(I)/util.h +flip_llB.$o: flip_llB.c $(I)/machdefs.h $(I)/util.h +flip_llC.$o: flip_llC.c $(I)/machdefs.h $(I)/util.h +flip_llD.$o: flip_llD.c $(I)/machdefs.h $(I)/util.h +flip_sg1.$o: flip_sg1.c $(I)/machdefs.h $(I)/util.h +flip_sg2.$o: flip_sg2.c $(I)/machdefs.h $(I)/util.h +flip_sg3.$o: flip_sg3.c $(I)/machdefs.h $(I)/util.h +flip_sp1.$o: flip_sp1.c $(I)/machdefs.h $(I)/util.h +flip_sp2.$o: flip_sp2.c $(I)/machdefs.h $(I)/util.h +flip_try.$o: flip_try.c $(I)/machdefs.h $(I)/util.h +flip_tw2.$o: flip_tw2.c $(I)/machdefs.h $(I)/util.h +flip_two.$o: flip_two.c $(I)/machdefs.h $(I)/util.h $(I)/linkern.h +linkern.$o: linkern.c $(I)/machdefs.h $(I)/util.h $(I)/linkern.h \ + $(I)/kdtree.h +lk_main.$o: lk_main.c $(I)/machdefs.h $(I)/util.h $(I)/linkern.h \ + $(I)/kdtree.h $(I)/edgegen.h diff --git a/contrib/blossom/concorde97/LINKERN/flip_ary.c b/contrib/blossom/concorde97/LINKERN/flip_ary.c new file mode 100644 index 0000000000000000000000000000000000000000..4dc5b53508f2504cd5837e28fe11745a44a697d5 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ary.c @@ -0,0 +1,360 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Basic Array */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: April 21, 1995 (but mainly from March, 1990) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int x, int y) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version uses very little memory, and is reasonably fast */ +/* for small problems and for twoopts (but you should have SHORT_SIDE */ +/* defined so that the smaller side a flip is carried out. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#define SHORT_SIDE + +/***************************************************************************/ +/* */ +/* ARRAY FLIPPER (flipper2): */ +/* */ +/* 1. Uses a raw cycle and its inverse. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* */ +/* SHORT-SIDE-ARRAY FLIPPER (flipper3): */ +/* */ +/* 1. Uses a raw cycle and its inverse, but flips the shorter side. */ +/* */ +/* 2. Define SHORT_SIDE to use this. */ +/* */ +/***************************************************************************/ + + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static int cycle_size = 0; +#ifdef SHORT_SIDE +static int reversed = 0; +static int short_size = 0; +#endif +static int *flip3_cyc = (int *) NULL; +static int *flip3_cyc_inv = (int *) NULL; + +#ifdef WE_WANT_FLIP_STATS +int CClinkern_flipper_size (int a, int b); +#endif WE_WANT_FLIP_STATS + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + flip3_cyc = CC_SAFE_MALLOC (ncount, int); + if (!flip3_cyc) + return 1; + flip3_cyc_inv = CC_SAFE_MALLOC (ncount, int); + if (!flip3_cyc_inv) { + CC_FREE (cyc, int); + return 1; + } + + for (i = 0; i < ncount; i++) { + flip3_cyc[i] = cyc[i]; + flip3_cyc_inv[cyc[i]] = i; + } + cycle_size = ncount; +#ifdef SHORT_SIDE + short_size = ncount/2; + reversed = 0; +#endif + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + int *p; + +#ifdef SHORT_SIDE + if (reversed) { + p = flip3_cyc + cycle_size; + while (p > flip3_cyc) { + *x++ = *--p; + } + } else { +#endif + p = flip3_cyc + cycle_size; + x += cycle_size; + while (p > flip3_cyc) { + *--x = *--p; + } +#ifdef SHORT_SIDE + } +#endif + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + CC_FREE (flip3_cyc, int); + CC_FREE (flip3_cyc_inv, int); + cycle_size = 0; +#ifdef SHORT_SIDE + short_size = 0; + reversed = 0; +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + int y; + +#ifdef SHORT_SIDE + if (reversed) { + y = flip3_cyc_inv[x] - 1; + return (y >= 0) ? flip3_cyc[y] : flip3_cyc[cycle_size-1]; + } else { +#endif + y = flip3_cyc_inv[x] + 1; + return (y < cycle_size) ? flip3_cyc[y] : flip3_cyc[0]; +#ifdef SHORT_SIDE + } +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + int y; + +#ifdef SHORT_SIDE + if (reversed) { + y = flip3_cyc_inv[x] + 1; + return (y < cycle_size) ? flip3_cyc[y] : flip3_cyc[0]; + } else { +#endif + y = flip3_cyc_inv[x] - 1; + return (y >= 0) ? flip3_cyc[y] : flip3_cyc[cycle_size-1]; +#ifdef SHORT_SIDE + } +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int x, int y) +#else +void CClinkern_flipper_flip (x, y) +int x,y; +#endif +{ + int xloc = flip3_cyc_inv[x]; + int yloc = flip3_cyc_inv[y]; + int temp; + int gap; + +#ifdef SHORT_SIDE + if (reversed) { + SWAP (xloc, yloc, temp); + } + gap = yloc - xloc; + if (gap < 0) gap += cycle_size; + if (gap > short_size) { + SWAP (xloc, yloc, temp); + reversed ^= 1; + xloc++; + if (xloc >= cycle_size) + xloc = 0; + yloc--; + if (yloc < 0) + yloc = cycle_size - 1; + gap = cycle_size - gap - 2; + } + + if (xloc > yloc) { + gap++; + gap /= 2; + for (; gap; gap--) { + x = flip3_cyc[xloc]; + y = flip3_cyc[yloc]; + flip3_cyc[xloc] = y; + flip3_cyc[yloc] = x; + flip3_cyc_inv[x] = yloc--; + flip3_cyc_inv[y] = xloc++; + if (xloc >= cycle_size) + xloc = 0; + if (yloc < 0) + yloc = cycle_size - 1; + } + } else { + gap++; + gap /= 2; + for (; gap; gap--) { + x = flip3_cyc[xloc]; + y = flip3_cyc[yloc]; + flip3_cyc[xloc] = y; + flip3_cyc[yloc] = x; + flip3_cyc_inv[x] = yloc--; + flip3_cyc_inv[y] = xloc++; + } + } +#else + if (xloc > yloc) { + gap = yloc - xloc + cycle_size; + gap++; + gap /= 2; + for (; gap; gap--) { + x = flip3_cyc[xloc]; + y = flip3_cyc[yloc]; + flip3_cyc[xloc] = y; + flip3_cyc[yloc] = x; + flip3_cyc_inv[x] = yloc--; + flip3_cyc_inv[y] = xloc++; + if (xloc >= cycle_size) + xloc = 0; + if (yloc < 0) + yloc = cycle_size - 1; + } + } else { + gap = yloc - xloc; + gap++; + gap /= 2; + for (; gap; gap--) { + x = flip3_cyc[xloc]; + y = flip3_cyc[yloc]; + flip3_cyc[xloc] = y; + flip3_cyc[yloc] = x; + flip3_cyc_inv[x] = yloc--; + flip3_cyc_inv[y] = xloc++; + } + } +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + int xloc = flip3_cyc_inv[x]; + int yloc = flip3_cyc_inv[y]; + int zloc = flip3_cyc_inv[z]; + +#ifdef SHORT_SIDE + if (reversed) { + if (xloc >= yloc) + return yloc >= zloc || zloc >= xloc; + else + return yloc >= zloc && zloc >= xloc; + } else { +#endif + if (xloc <= yloc) + return yloc <= zloc || zloc <= xloc; + else + return yloc <= zloc && zloc <= xloc; +#ifdef SHORT_SIDE + } +#endif +} + +#ifdef WE_WANT_FLIP_STATS +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_size (int x, int y) +#else +int CClinkern_flipper_size (x, y) +int x,y; +#endif +{ + int xloc = flip3_cyc_inv[x]; + int yloc = flip3_cyc_inv[y]; + int temp, gap; + + if (reversed) { + SWAP (xloc, yloc, temp); + } + gap = yloc - xloc; + if (gap < 0) gap += cycle_size; + if (gap > short_size) { + gap = cycle_size - gap - 2; + } + + return gap + 1; +} +#endif /* WE_WANT_FLIP_STATS */ + diff --git a/contrib/blossom/concorde97/LINKERN/flip_bt0.c b/contrib/blossom/concorde97/LINKERN/flip_bt0.c new file mode 100644 index 0000000000000000000000000000000000000000..2dc5aef8ebffbd78a624c33ee9b25428a5135fdb --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_bt0.c @@ -0,0 +1,556 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/* #define SAVE_NEIGHBORS */ +#define INLINE_CLEAR_TO_ROOT + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; +#ifdef INLINE_CLEAR_TO_ROOT + struct btree *next; +#endif +#ifdef SAVE_NEIGHBORS + struct btree *neigh[2]; +#endif + int reversed; + int value; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right); + +static void + join (btree *left, btree *i, btree *right), + reverse (btree *p), + clearrev_toroot (btree *p); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (); + +static void + join (), + reverse (), + clearrev_toroot (); + +#endif + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static int btree_size; +static btree *root = (btree *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + +/* + printf ("Flipper flags:"); +#ifdef SAVE_NEIGHBORS + printf (" SAVE_NEIGHBORS"); +#else + printf (" !SAVE_NEIGHBORS"); +#endif +*/ + + btree_space = CC_SAFE_MALLOC (ncount, btree); + btree_size = ncount; + if (!btree_space) + return 1; + + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + btree_space[i].value = i; +#ifdef SAVE_NEIGHBORS + if (i==0) { + btree_space[cyc[0]].neigh[0] = &btree_space[cyc[ncount-1]]; + btree_space[cyc[ncount-1]].neigh[1] = &btree_space[cyc[0]]; + } else { + btree_space[cyc[i]].neigh[0] = &btree_space[cyc[i-1]]; + btree_space[cyc[i-1]].neigh[1] = &btree_space[cyc[i]]; + } +#endif + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ + if (!p) + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + CC_IFFREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *temp, *temp2; + btree *a, *b, *c, *d; + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d, *e, *f; + btree *r; + + if (y == z || x == z || x == y) + return 1; + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b */ + r = split (&e, pz, &f); + if (r == c) { /* e z f y d x b */ + join (e, pz, f); + join (d, px, b); + join (pz, py, px); + root = py; + return 0; + } else if (r == d) { /* c y e z f x b */ + join (c, py, e); + join (f, px, b); + join (py, pz, px); + root = pz; + return 1; + } else { /* c y d x e z f */ + join (c, py, d); + join (e, pz, f); + join (py, px, pz); + root = px; + return 0; + } + } else { /* a x c y d */ + r = split (&e, pz, &f); + if (r == a) { /* e z f x c y d */ + join (e, pz, f); + join (c, py, d); + join (pz, px, py); + root = px; + return 1; + } else if (r == c) { /* a x e z f y d */ + join (a, px, e); + join (f, py, d); + join (px, pz, py); + root = pz; + return 0; + } else { /* a x c y e z f */ + join (a, px, c); + join (e, pz, f); + join (px, py, pz); + root = py; + return 1; + } + } +} + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* void reverse (btree *p) */ +/* toggles the reversal bit of node p (and fixes the tree). */ +/* void clearrev_toroot (btree *p) */ +/* clears the reversal bits on the path from p to the root (and fixes */ +/* the tree). */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) + return (btree *) NULL; + + center = (a + b)/2; + p = btree_space + cyc[center]; + if ((p->child[0] = make_tree (a, center-1, cyc)) != (btree *) NULL) + p->child[0]->parent = p; + if ((p->child[1] = make_tree (center+1, b, cyc)) != (btree *) NULL) + p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ + if (left) left->parent = i; + if (right) right->parent = i; + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; + btree *isave = i; + + clearrev_toroot (i); + l = i->child[0]; + r = i->child[1]; + i->child[0] = (btree *) NULL; + i->child[1] = (btree *) NULL; + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; + if (r) r->parent = p; + r = p; + } else { + p->child[1] = l; + if (l) l->parent = p; + l = p; + } + i = p; + } + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; + *left = l; + *right = r; + if (isave) isave->parent = (btree *) NULL; + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static void reverse (btree *p) +#else +static void reverse (p) +btree *p; +#endif +{ + btree *t; + + SWAP(p->child[0], p->child[1], t); + if (p->child[0]) p->child[0]->reversed ^= 1; + if (p->child[1]) p->child[1]->reversed ^= 1; + p->reversed ^= 1; +#ifdef SAVE_NEIGHBORS + SWAP (p->neigh[0], p->neigh[1], t); +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static void clearrev_toroot (btree *p) +#else +static void clearrev_toroot (p) +btree *p; +#endif +{ +#ifndef INLINE_CLEAR_TO_ROOT + if (p->parent) clearrev_toroot (p->parent); + if (p->reversed) reverse (p); +#else + p->next = (btree *) NULL; + while (p->parent) { + p->parent->next = p; + p = p->parent; + } + while (p) { + if (p->reversed) reverse (p); + p = p->next; + } +#endif +} + + + diff --git a/contrib/blossom/concorde97/LINKERN/flip_bt1.c b/contrib/blossom/concorde97/LINKERN/flip_bt1.c new file mode 100644 index 0000000000000000000000000000000000000000..ce966c4b7a408dc31422736eeeda3416c03056b9 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_bt1.c @@ -0,0 +1,615 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* - added tests for depth */ +/* TSP CODE */ +/* */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes CClinkern_flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/* #define SAVE_NEIGHBORS */ +#define INLINE_CLEAR_TO_ROOT +#define REPORT_DEPTH + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; +#ifdef INLINE_CLEAR_TO_ROOT + struct btree *next; +#endif +#ifdef SAVE_NEIGHBORS + struct btree *neigh[2]; +#endif + int reversed; + int value; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right); + +static void + join (btree *left, btree *i, btree *right), + reverse (btree *p), + clearrev_toroot (btree *p); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (); + +static void + join (), + reverse (), + clearrev_toroot (); + +#endif + +#ifdef REPORT_DEPTH + +static double probecount = 1.0; +static double probedepth = 1.0; + +#ifdef CC_PROTOTYPE_ANSI +static void + find_depth (int x); +#else +static void + find_depth (); +#endif + +#endif /* REPORT_DEPTH */ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static int btree_size; +static btree *root = (btree *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + +/* + printf ("Flipper flags:"); +#ifdef SAVE_NEIGHBORS + printf (" SAVE_NEIGHBORS"); +#else + printf (" !SAVE_NEIGHBORS"); +#endif +*/ + + btree_space = CC_SAFE_MALLOC (ncount, btree); + btree_size = ncount; + if (!btree_space) + return 1; + + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + btree_space[i].value = i; +#ifdef SAVE_NEIGHBORS + if (i==0) { + btree_space[cyc[0]].neigh[0] = &btree_space[cyc[ncount-1]]; + btree_space[cyc[ncount-1]].neigh[1] = &btree_space[cyc[0]]; + } else { + btree_space[cyc[i]].neigh[0] = &btree_space[cyc[i-1]]; + btree_space[cyc[i-1]].neigh[1] = &btree_space[cyc[i]]; + } +#endif + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ + if (!p) + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + printf ("Number of Probes: %.0f Average Depth: %.2f\n", + probecount, probedepth / probecount); + fflush (stdout); + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (btree_space) + CC_FREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef REPORT_DEPTH +#ifdef CC_PROTOTYPE_ANSI +static void find_depth (int x) +#else +static void find_depth (x) +int x; +#endif +{ + btree *q = btree_space + x; + + probecount += 1.0; + while (q) { + probedepth += 1.0; + q = q->parent; + } +} +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + +#ifdef REPORT_DEPTH + find_depth (x); +#endif + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + +#ifdef REPORT_DEPTH + find_depth (x); +#endif + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *temp, *temp2; + btree *a, *b, *c, *d; + +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); +#endif + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d, *e, *f; + btree *r; + +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); + find_depth (z); +#endif + + + if (y == z || x == z || x == y) + return 1; + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b */ + r = split (&e, pz, &f); + if (r == c) { /* e z f y d x b */ + join (e, pz, f); + join (d, px, b); + join (pz, py, px); + root = py; + return 0; + } else if (r == d) { /* c y e z f x b */ + join (c, py, e); + join (f, px, b); + join (py, pz, px); + root = pz; + return 1; + } else { /* c y d x e z f */ + join (c, py, d); + join (e, pz, f); + join (py, px, pz); + root = px; + return 0; + } + } else { /* a x c y d */ + r = split (&e, pz, &f); + if (r == a) { /* e z f x c y d */ + join (e, pz, f); + join (c, py, d); + join (pz, px, py); + root = px; + return 1; + } else if (r == c) { /* a x e z f y d */ + join (a, px, e); + join (f, py, d); + join (px, pz, py); + root = pz; + return 0; + } else { /* a x c y e z f */ + join (a, px, c); + join (e, pz, f); + join (px, py, pz); + root = py; + return 1; + } + } +} + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* void reverse (btree *p) */ +/* toggles the reversal bit of node p (and fixes the tree). */ +/* void clearrev_toroot (btree *p) */ +/* clears the reversal bits on the path from p to the root (and fixes */ +/* the tree). */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) + return (btree *) NULL; + + center = (a + b)/2; + p = btree_space + cyc[center]; + if ((p->child[0] = make_tree (a, center-1, cyc)) != (btree *) NULL) + p->child[0]->parent = p; + if ((p->child[1] = make_tree (center+1, b, cyc)) != (btree *) NULL) + p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ + if (left) left->parent = i; + if (right) right->parent = i; + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; + btree *isave = i; + + clearrev_toroot (i); + l = i->child[0]; + r = i->child[1]; + i->child[0] = (btree *) NULL; + i->child[1] = (btree *) NULL; + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; + if (r) r->parent = p; + r = p; + } else { + p->child[1] = l; + if (l) l->parent = p; + l = p; + } + i = p; + } + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; + *left = l; + *right = r; + if (isave) isave->parent = (btree *) NULL; + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static void reverse (btree *p) +#else +static void reverse (p) +btree *p; +#endif +{ + btree *t; + + SWAP(p->child[0], p->child[1], t); + if (p->child[0]) p->child[0]->reversed ^= 1; + if (p->child[1]) p->child[1]->reversed ^= 1; + p->reversed ^= 1; +#ifdef SAVE_NEIGHBORS + SWAP (p->neigh[0], p->neigh[1], t); +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static void clearrev_toroot (btree *p) +#else +static void clearrev_toroot (p) +btree *p; +#endif +{ +#ifndef INLINE_CLEAR_TO_ROOT + if (p->parent) clearrev_toroot (p->parent); + if (p->reversed) reverse (p); +#else + p->next = (btree *) NULL; + while (p->parent) { + p->parent->next = p; + p = p->parent; + } + while (p) { + if (p->reversed) reverse (p); + p = p->next; + } +#endif +} + + + diff --git a/contrib/blossom/concorde97/LINKERN/flip_bt2.c b/contrib/blossom/concorde97/LINKERN/flip_bt2.c new file mode 100644 index 0000000000000000000000000000000000000000..1b8d4264af41aec84588b3a0bbe0980eca79d962 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_bt2.c @@ -0,0 +1,858 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* - added tests for depth */ +/* - added splays for seq */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/* #define SAVE_NEIGHBORS */ +/* #define INLINE_CLEAR_TO_ROOT */ +#define REPORT_DEPTH +#define USE_SPLAY_SEQUENCE +#define USE_SPLAY_FLIPS + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; +#ifdef INLINE_CLEAR_TO_ROOT + struct btree *next; +#endif +#ifdef SAVE_NEIGHBORS + struct btree *neigh[2]; +#endif + int reversed; + int value; + int mark; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right); + +static void + join (btree *left, btree *i, btree *right), + reverse (btree *p), + clearrev_toroot (btree *p); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (); + +static void + join (), + reverse (), + clearrev_toroot (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI + +static void + rotate (btree *x, btree *px), + splay (btree *x); + +#else + +static void + rotate (), + splay (); + +#endif + +#ifdef REPORT_DEPTH + +static double probecount = 1.0; +static double probedepth = 1.0; + +#ifdef CC_PROTOTYPE_ANSI +static void + find_depth (int x); +#else +static void + find_depth (); +#endif + +#endif /* REPORT_DEPTH */ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static int btree_size; +static btree *root = (btree *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + +/* + printf ("Flipper flags:"); +#ifdef SAVE_NEIGHBORS + printf (" SAVE_NEIGHBORS"); +#else + printf (" !SAVE_NEIGHBORS"); +#endif +*/ + + btree_space = CC_SAFE_MALLOC (ncount, btree); + btree_size = ncount; + if (!btree_space) + return 1; + + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + btree_space[i].value = i; + btree_space[i].mark = 0; +#ifdef SAVE_NEIGHBORS + if (i==0) { + btree_space[cyc[0]].neigh[0] = &btree_space[cyc[ncount-1]]; + btree_space[cyc[ncount-1]].neigh[1] = &btree_space[cyc[0]]; + } else { + btree_space[cyc[i]].neigh[0] = &btree_space[cyc[i-1]]; + btree_space[cyc[i-1]].neigh[1] = &btree_space[cyc[i]]; + } +#endif + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ + if (!p) + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ +#ifdef REPORT_DEPTH + printf ("Number of Probes: %.0f Average Depth: %.2f\n", + probecount, probedepth / probecount); + fflush (stdout); +#endif + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (btree_space) + CC_FREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef REPORT_DEPTH +#ifdef CC_PROTOTYPE_ANSI +static void find_depth (int x) +#else +static void find_depth (x) +int x; +#endif +{ + btree *q = btree_space + x; + + probecount += 1.0; + while (q) { + probedepth += 1.0; + q = q->parent; + } +} +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + +#ifdef REPORT_DEPTH + find_depth (x); +#endif + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + +#ifdef REPORT_DEPTH + find_depth (x); +#endif + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef USE_SPLIT_FLIPS +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; +#ifdef SAVE_NEIGHBORS + btree *temp, *temp2; +#endif + btree *a, *b, *c, *d; + +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); +#endif + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif +} +#endif /* USE_SPLIT_FLIPS */ + +#ifdef USE_SPLAY_FLIPS +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *temp; +#ifdef SAVE_NEIGHBORS + btree *temp2; +#endif + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + splay (px); + px->mark = 1; + splay (py); + px->mark = 0; + + if (px->reversed) + reverse (px); + if (py->reversed) + reverse (py); + if (px->child[1] == py) { +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif + if (py->child[0]) + py->child[0]->reversed ^= 1; + SWAP (px->child[0], py->child[0], temp); + if (px->child[0]) + px->child[0]->parent = px; + if (py->child[0]) + py->child[0]->parent = py; + px->child[1] = py->child[1]; + if (px->child[1]) + px->child[1]->parent = px; + py->child[1] = px; + px->parent = py; + py->parent = (btree *) NULL; + root = py; + } else { +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + py->neigh[1] = temp; + px->neigh[0] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif + px->reversed ^= 1; + py->child[1]->reversed ^= 1; + } +} +#endif /* USE_SPLAY_FLIPS */ + +#ifdef USE_SPLIT_SEQUENCE +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d, *e, *f; + btree *r; + +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); + find_depth (z); +#endif + + if (y == z || x == z || x == y) + return 1; + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b */ + r = split (&e, pz, &f); + if (r == c) { /* e z f y d x b */ + join (e, pz, f); + join (d, px, b); + join (pz, py, px); + root = py; + return 0; + } else if (r == d) { /* c y e z f x b */ + join (c, py, e); + join (f, px, b); + join (py, pz, px); + root = pz; + return 1; + } else { /* c y d x e z f */ + join (c, py, d); + join (e, pz, f); + join (py, px, pz); + root = px; + return 0; + } + } else { /* a x c y d */ + r = split (&e, pz, &f); + if (r == a) { /* e z f x c y d */ + join (e, pz, f); + join (c, py, d); + join (pz, px, py); + root = px; + return 1; + } else if (r == c) { /* a x e z f y d */ + join (a, px, e); + join (f, py, d); + join (px, pz, py); + root = pz; + return 0; + } else { /* a x c y e z f */ + join (a, px, c); + join (e, pz, f); + join (px, py, pz); + root = py; + return 1; + } + } +} +#endif + +#ifdef USE_SPLAY_SEQUENCE +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + + if (y == z || x == z || x == y) + return 1; + + splay (px); + px->mark = 1; + splay (pz); + px->mark = 0; + + if (px->reversed) + reverse (px); + if (pz->reversed) + reverse (pz); + + for (;;) { + if (py->parent == px) { + return px->child[1] == py; + } else if (py->parent == pz) { + return pz->child[0] == py; + } else { + py = py->parent; + } + } +} +#endif + + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* void reverse (btree *p) */ +/* toggles the reversal bit of node p (and fixes the tree). */ +/* void clearrev_toroot (btree *p) */ +/* clears the reversal bits on the path from p to the root (and fixes */ +/* the tree). */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) + return (btree *) NULL; + + center = (a + b)/2; + p = btree_space + cyc[center]; + if ((p->child[0] = make_tree (a, center-1, cyc)) != (btree *) NULL) + p->child[0]->parent = p; + if ((p->child[1] = make_tree (center+1, b, cyc)) != (btree *) NULL) + p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ + if (left) left->parent = i; + if (right) right->parent = i; + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; + btree *isave = i; + + clearrev_toroot (i); + l = i->child[0]; + r = i->child[1]; + i->child[0] = (btree *) NULL; + i->child[1] = (btree *) NULL; + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; + if (r) r->parent = p; + r = p; + } else { + p->child[1] = l; + if (l) l->parent = p; + l = p; + } + i = p; + } + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; + *left = l; + *right = r; + if (isave) isave->parent = (btree *) NULL; + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static void reverse (btree *p) +#else +static void reverse (p) +btree *p; +#endif +{ + btree *t; + + SWAP(p->child[0], p->child[1], t); + if (p->child[0]) p->child[0]->reversed ^= 1; + if (p->child[1]) p->child[1]->reversed ^= 1; + p->reversed ^= 1; +#ifdef SAVE_NEIGHBORS + SWAP (p->neigh[0], p->neigh[1], t); +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static void clearrev_toroot (btree *p) +#else +static void clearrev_toroot (p) +btree *p; +#endif +{ +#ifndef INLINE_CLEAR_TO_ROOT + if (p->parent) clearrev_toroot (p->parent); + if (p->reversed) reverse (p); +#else + p->next = (btree *) NULL; + while (p->parent) { + p->parent->next = p; + p = p->parent; + } + while (p) { + if (p->reversed) reverse (p); + p = p->next; + } +#endif +} + + +/************************* SPLAY STUFF ****************************/ + +#ifdef CC_PROTOTYPE_ANSI +static void rotate (btree *x, btree *px) +#else +static void rotate (x, px) +btree *x, *px; +#endif +{ + btree *b; + + if (px->child[0] == x) { + b = x->child[1]; + if (b) + b->parent = px; + x->child[1] = px; + x->parent = px->parent; + if (x->parent) { + if (x->parent->child[0] == px) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + } + px->child[0] = b; + px->parent = x; + } else { + b = x->child[0]; + if (b) + b->parent = px; + x->child[0] = px; + x->parent = px->parent; + if (x->parent) { + if (x->parent->child[0] == px) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + } + px->child[1] = b; + px->parent = x; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void splay (btree *x) +#else +static void splay (x) +btree *x; +#endif +{ + btree *px; + btree *ppx; + + for (;;) { + px = x->parent; + if (!px) { + root = x; + return; + } + if (px->mark) + return; + ppx = px->parent; + if (!ppx) { + if (px->reversed) + reverse (px); + if (x->reversed) + reverse (x); + rotate (x, px); + root = x; + return; + } + if (ppx->mark) { + if (px->reversed) + reverse (px); + if (x->reversed) + reverse (x); + rotate (x, px); + return; + } + if (ppx->reversed) + reverse (ppx); + if (px->reversed) + reverse (px); + if (x->reversed) + reverse (x); + if (ppx->child[0] == px) { + if (px->child[0] == x) { + rotate (px, ppx); + rotate (x, px); + } else { + rotate (x, px); + rotate (x, ppx); + } + } else { + if (px->child[1] == x) { + rotate (px, ppx); + rotate (x, px); + } else { + rotate (x, px); + rotate (x, ppx); + } + } + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_bt3.c b/contrib/blossom/concorde97/LINKERN/flip_bt3.c new file mode 100644 index 0000000000000000000000000000000000000000..8dd63a140b4f6dec357086736be0e10fac23816e --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_bt3.c @@ -0,0 +1,617 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* - added dummy children */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/* #define SAVE_NEIGHBORS */ +/* #define INLINE_CLEAR_TO_ROOT */ +/* #define REPORT_DEPTH */ + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; +#ifdef INLINE_CLEAR_TO_ROOT + struct btree *next; +#endif +#ifdef SAVE_NEIGHBORS + struct btree *neigh[2]; +#endif + int reversed; + int value; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right); + +static void + join (btree *left, btree *i, btree *right), + reverse (btree *p), + clearrev_toroot (btree *p); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (); + +static void + join (), + reverse (), + clearrev_toroot (); + +#endif + +#ifdef REPORT_DEPTH + +static double probecount = 1.0; +static double probedepth = 1.0; + +#ifdef CC_PROTOTYPE_ANSI +static void + find_depth (int x); +#else +static void + find_depth (); +#endif + +#endif /* REPORT_DEPTH */ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static int btree_size; +static btree *root = (btree *) NULL; +static btree dummy_leaf; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + +/* + printf ("Flipper flags:"); +#ifdef SAVE_NEIGHBORS + printf (" SAVE_NEIGHBORS"); +#else + printf (" !SAVE_NEIGHBORS"); +#endif +*/ + + btree_space = CC_SAFE_MALLOC (ncount, btree); + btree_size = ncount; + if (!btree_space) + return 1; + + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + btree_space[i].value = i; +#ifdef SAVE_NEIGHBORS + if (i==0) { + btree_space[cyc[0]].neigh[0] = &btree_space[cyc[ncount-1]]; + btree_space[cyc[ncount-1]].neigh[1] = &btree_space[cyc[0]]; + } else { + btree_space[cyc[i]].neigh[0] = &btree_space[cyc[i-1]]; + btree_space[cyc[i-1]].neigh[1] = &btree_space[cyc[i]]; + } +#endif + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ + if (p == &dummy_leaf) + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ +#ifdef REPORT_DEPTH + printf ("Number of Probes: %.0f Average Depth: %.2f\n", + probecount, probedepth / probecount); + fflush (stdout); +#endif + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (btree_space) + CC_FREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef REPORT_DEPTH +#ifdef CC_PROTOTYPE_ANSI +static void find_depth (int x) +#else +static void find_depth (x) +int x; +#endif +{ + btree *q = btree_space + x; + + probecount += 1.0; + while (q) { + probedepth += 1.0; + q = q->parent; + } +} +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + +#ifdef REPORT_DEPTH + find_depth (x); +#endif + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext != &dummy_leaf) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (pnext == &dummy_leaf) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (pnext == &dummy_leaf) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + +#ifdef REPORT_DEPTH + find_depth (x); +#endif + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext != &dummy_leaf) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (pnext == &dummy_leaf) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (pnext == &dummy_leaf) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; +#ifdef SAVE_NEIGHBORS + btree *temp, *temp2; +#endif + btree *a, *b, *c, *d; + +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); +#endif + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d, *e, *f; + btree *r; + +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); + find_depth (z); +#endif + + if (y == z || x == z || x == y) + return 1; + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b */ + r = split (&e, pz, &f); + if (r == c) { /* e z f y d x b */ + join (e, pz, f); + join (d, px, b); + join (pz, py, px); + root = py; + return 0; + } else if (r == d) { /* c y e z f x b */ + join (c, py, e); + join (f, px, b); + join (py, pz, px); + root = pz; + return 1; + } else { /* c y d x e z f */ + join (c, py, d); + join (e, pz, f); + join (py, px, pz); + root = px; + return 0; + } + } else { /* a x c y d */ + r = split (&e, pz, &f); + if (r == a) { /* e z f x c y d */ + join (e, pz, f); + join (c, py, d); + join (pz, px, py); + root = px; + return 1; + } else if (r == c) { /* a x e z f y d */ + join (a, px, e); + join (f, py, d); + join (px, pz, py); + root = pz; + return 0; + } else { /* a x c y e z f */ + join (a, px, c); + join (e, pz, f); + join (px, py, pz); + root = py; + return 1; + } + } +} + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* void reverse (btree *p) */ +/* toggles the reversal bit of node p (and fixes the tree). */ +/* void clearrev_toroot (btree *p) */ +/* clears the reversal bits on the path from p to the root (and fixes */ +/* the tree). */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) + return &dummy_leaf; + + center = (a + b)/2; + p = btree_space + cyc[center]; + p->child[0] = make_tree (a, center-1, cyc); + p->child[0]->parent = p; + p->child[1] = make_tree (center+1, b, cyc); + p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ + left->parent = i; + right->parent = i; + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; + btree *isave = i; + + clearrev_toroot (i); + l = i->child[0]; + r = i->child[1]; + i->child[0] = &dummy_leaf; + i->child[1] = &dummy_leaf; + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; + r->parent = p; + r = p; + } else { + p->child[1] = l; + l->parent = p; + l = p; + } + i = p; + } + l->parent = (btree *) NULL; + r->parent = (btree *) NULL; + *left = l; + *right = r; + isave->parent = (btree *) NULL; + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static void reverse (btree *p) +#else +static void reverse (p) +btree *p; +#endif +{ + btree *t; + + SWAP(p->child[0], p->child[1], t); + p->child[0]->reversed ^= 1; + p->child[1]->reversed ^= 1; + p->reversed ^= 1; +#ifdef SAVE_NEIGHBORS + SWAP (p->neigh[0], p->neigh[1], t); +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static void clearrev_toroot (btree *p) +#else +static void clearrev_toroot (p) +btree *p; +#endif +{ +#ifndef INLINE_CLEAR_TO_ROOT + if (p->parent) clearrev_toroot (p->parent); + if (p->reversed) reverse (p); +#else + p->next = (btree *) NULL; + while (p->parent) { + p->parent->next = p; + p = p->parent; + } + while (p) { + if (p->reversed) reverse (p); + p = p->next; + } +#endif +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_bt4.c b/contrib/blossom/concorde97/LINKERN/flip_bt4.c new file mode 100644 index 0000000000000000000000000000000000000000..11772e176405952689c7b56d45b2aef7bdf5152e --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_bt4.c @@ -0,0 +1,1310 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* - added dummy children */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/* #define TRACE */ +/* #define NEIGHTRACE */ +#define SAVE_NEIGHBORS +/* #define REPORT_DEPTH */ +#define DUMMY_LEAF +#define NO_CLEAR_TO_ROOT +/* #define INLINE_CLEAR_TO_ROOT */ +/* #define INLINE_CLEAR_TO_ROOT2 */ +#define SKIMPY_NULLS +/* #define MUNCHED_SEQUENCE_CODE */ +#define SEQUENCE_2SPLIT +#define UGLY_SPLIT + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; +#ifdef INLINE_CLEAR_TO_ROOT + struct btree *next; +#endif +#ifdef SAVE_NEIGHBORS + struct btree *neigh[2]; +#endif + int reversed; + int value; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right), + *find_root (btree *i); + +static void + join (btree *left, btree *i, btree *right), + reverse (btree *p), + clearrev_toroot (btree *p); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (), + *find_root (); + +static void + join (), + reverse (), + clearrev_toroot (); + +#endif + +#ifdef REPORT_DEPTH + +static double probecount = 1.0; +static double probedepth = 1.0; + +#ifdef CC_PROTOTYPE_ANSI +static void + find_depth (int x); +#else +static void + find_depth (); +#endif + +#endif /* REPORT_DEPTH */ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static int btree_size; +static btree *root = (btree *) NULL; +#ifdef DUMMY_LEAF +static btree dummy_leaf; +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + printf ("Flipper flags:"); +#ifdef SAVE_NEIGHBORS + printf (" SAVE_NEIGHBORS"); +#endif +#ifdef DUMMY_LEAF + printf (" DUMMY_LEAF"); +#endif +#ifdef NO_CLEAR_TO_ROOT + printf (" NO_CLEAR_TO_ROOT"); +#else +#ifdef INLINE_CLEAR_TO_ROOT + printf (" INLINE_CLEAR_TO_ROOT"); +#else +#ifdef INLINE_CLEAR_TO_ROOT2 + printf (" INLINE_CLEAR_TO_ROOT2"); +#endif +#endif +#endif +#ifdef SKIMPY_NULLS + printf (" SKIMPY_NULLS"); +#endif +#ifdef SEQUENCE_2SPLIT + printf (" SEQUENCE_2SPLIT"); +#else +#ifdef MUNCHED_SEQUENCE_CODE + printf (" MUNCHED_SEQUENCE_CODE"); +#endif +#endif +#ifdef UGLY_SPLIT + printf (" UGLY_SPLIT"); +#endif + printf ("\n"); + fflush (stdout); + + btree_space = CC_SAFE_MALLOC (ncount, btree); + btree_size = ncount; + if (!btree_space) + return 1; + +#ifdef TRACE + printf ("init:"); + for (i=0; i<ncount; i++) { + printf (" %d", cyc[i]); + } + printf ("\n"); + fflush (stdout); +#endif /* TRACE */ + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + btree_space[i].value = i; +#ifdef SAVE_NEIGHBORS + if (i==0) { + btree_space[cyc[0]].neigh[0] = &btree_space[cyc[ncount-1]]; + btree_space[cyc[ncount-1]].neigh[1] = &btree_space[cyc[0]]; + } else { + btree_space[cyc[i]].neigh[0] = &btree_space[cyc[i-1]]; + btree_space[cyc[i-1]].neigh[1] = &btree_space[cyc[i]]; + } +#endif + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ +#ifdef DUMMY_LEAF + if (p == &dummy_leaf) +#else + if (p == (btree *) NULL) +#endif + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ +#ifdef REPORT_DEPTH + printf ("Number of Probes: %.0f Average Depth: %.2f\n", + probecount, probedepth / probecount); + fflush (stdout); +#endif + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (btree_space) + CC_FREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef REPORT_DEPTH +#ifdef CC_PROTOTYPE_ANSI +static void find_depth (int x) +#else +static void find_depth (x) +int x; +#endif +{ + btree *q = btree_space + x; + + probecount += 1.0; + while (q) { + probedepth += 1.0; + q = q->parent; + } +} +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + +#ifdef TRACE + printf ("next %d", x); + fflush (stdout); +#endif /* TRACE */ +#ifdef REPORT_DEPTH + find_depth (x); +#endif + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS +#ifdef TRACE + printf ("==> %d (%d)\n", p->neigh[1-r] - btree_space, p->neigh[1-r]->value); + fflush (stdout); +#endif /* TRACE */ + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; +#ifdef DUMMY_LEAF + if (pnext != &dummy_leaf) { +#else + if (pnext) { +#endif + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; +#ifdef DUMMY_LEAF + if (pnext == &dummy_leaf) { +#else + if (!pnext) { +#endif +#ifdef TRACE + printf ("==> %d (%d)\n", p - btree_space, p->value); + fflush (stdout); +#endif /* TRACE */ + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { +#ifdef TRACE + printf ("==> %d (%d)\n", pnext - btree_space, pnext->value); + fflush (stdout); +#endif /* TRACE */ + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; +#ifdef DUMMY_LEAF + if (pnext == &dummy_leaf) { +#else + if (!pnext) { +#endif +#ifdef TRACE + printf ("==> %d (%d)\n", p - btree_space, p->value); + fflush (stdout); +#endif /* TRACE */ + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + +#ifdef TRACE + printf ("prev %d", x); + fflush (stdout); +#endif /* TRACE */ +#ifdef REPORT_DEPTH + find_depth (x); +#endif + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS +#ifdef TRACE + printf ("==> %d (%d)\n", p->neigh[r] - btree_space, p->neigh[r]->value); + fflush (stdout); +#endif /* TRACE */ + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; +#ifdef DUMMY_LEAF + if (pnext != &dummy_leaf) { +#else + if (pnext) { +#endif + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; +#ifdef DUMMY_LEAF + if (pnext == &dummy_leaf) { +#else + if (!pnext) { +#endif +#ifdef TRACE + printf ("==> %d (%d)\n", p - btree_space, p->value); + fflush (stdout); +#endif /* TRACE */ + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { +#ifdef TRACE + printf ("==> %d (%d)\n", pnext - btree_space, pnext->value); + fflush (stdout); +#endif /* TRACE */ + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; +#ifdef DUMMY_LEAF + if (pnext == &dummy_leaf) { +#else + if (!pnext) { +#endif +#ifdef TRACE + printf ("==> %d (%d)\n", p - btree_space, p->value); + fflush (stdout); +#endif /* TRACE */ + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; +#ifdef SAVE_NEIGHBORS + btree *temp, *temp2; +#endif + btree *a, *b, *c, *d; + +#ifdef TRACE + printf ("flip %d-%d %d-%d\n", xprev, x, y, ynext); + fflush (stdout); +#endif /* TRACE */ + +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); +#endif + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +#ifdef SAVE_NEIGHBORS +#ifdef NEIGHTRACE + printf ("neigh before:"); + printf (" %d-%d-%d", px->neigh[0]-btree_space,px-btree_space,px->neigh[1]-btree_space); + printf (" %d-%d-%d", py->neigh[0]-btree_space,py-btree_space,py->neigh[1]-btree_space); + printf (" %d-%d-%d", px->neigh[0]->neigh[0]-btree_space,px->neigh[0]-btree_space,px->neigh[0]->neigh[1]-btree_space); + printf (" %d-%d-%d", px->neigh[1]->neigh[0]-btree_space,px->neigh[1]-btree_space,px->neigh[1]->neigh[1]-btree_space); + printf (" %d-%d-%d", py->neigh[0]->neigh[0]-btree_space,py->neigh[0]-btree_space,py->neigh[0]->neigh[1]-btree_space); + printf (" %d-%d-%d", py->neigh[1]->neigh[0]-btree_space,py->neigh[1]-btree_space,py->neigh[1]->neigh[1]-btree_space); + printf ("\n"); + fflush (stdout); +#endif + + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#ifdef NEIGHTRACE + printf ("neigh after:"); + printf (" %d-%d-%d", px->neigh[0]-btree_space,px-btree_space,px->neigh[1]-btree_space); + printf (" %d-%d-%d", py->neigh[0]-btree_space,py-btree_space,py->neigh[1]-btree_space); + printf (" %d-%d-%d", px->neigh[0]->neigh[0]-btree_space,px->neigh[0]-btree_space,px->neigh[0]->neigh[1]-btree_space); + printf (" %d-%d-%d", px->neigh[1]->neigh[0]-btree_space,px->neigh[1]-btree_space,px->neigh[1]->neigh[1]-btree_space); + printf (" %d-%d-%d", py->neigh[0]->neigh[0]-btree_space,py->neigh[0]-btree_space,py->neigh[0]->neigh[1]-btree_space); + printf (" %d-%d-%d", py->neigh[1]->neigh[0]-btree_space,py->neigh[1]-btree_space,py->neigh[1]->neigh[1]-btree_space); + printf ("\n"); + fflush (stdout); +#endif +#endif +} + +#if defined(MUNCHED_SEQUENCE_CODE) || defined(SEQUENCE_2SPLIT) + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d, *e, *f; + btree *r; + +#ifdef TRACE + printf ("sequence %d %d %d", x, y, z); + fflush (stdout); +#endif /* TRACE */ +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); + find_depth (z); +#endif + + if (y == z || x == z || x == y) { +#ifdef TRACE + printf (" ==> 1\n"); + fflush (stdout); +#endif /* TRACE */ + return 1; + } + + split (&a, px, &b); + if (split (&c, pz, &d) == a) { /* c z d x b */ +#ifdef SEQUENCE_2SPLIT + r = find_root (py); + join (c,pz,d); + join (pz,px,b); + root = px; +#ifdef TRACE + printf (" ==> %d\n", r!=d); + fflush (stdout); +#endif /* TRACE */ + return (r!=d); +#else /* SEQUENCE_2SPLIT */ + r = split (&e, py, &f); + if (r == c) { /* e y f z d x b */ + join (e, py, f); + join (py, pz, d); + join (pz, px, b); + root = px; +#ifdef TRACE + printf (" ==> 1\n"); + fflush (stdout); +#endif /* TRACE */ + return 1; + } else if (r == d) { /* c z e y f x b */ + join (c, pz, e); + join (pz, py, f); + join (py, px, b); + root = px; +#ifdef TRACE + printf (" ==> 0\n"); + fflush (stdout); +#endif /* TRACE */ + return 0; + } else { /* c z d x e y f */ + join (c, pz, d); + join (e, py, f); + join (pz, px, py); + root = px; +#ifdef TRACE + printf (" ==> 1\n"); + fflush (stdout); +#endif /* TRACE */ + return 1; + } +#endif /* SEQUENCE_2SPLIT */ + } else { /* a x c z d */ +#ifdef SEQUENCE_2SPLIT + r = find_root (py); + join (c,pz,d); + join (a,px,pz); + root = px; +#ifdef TRACE + printf (" ==> %d\n", r==c); + fflush (stdout); +#endif /* TRACE */ + return (r==c); +#else /* SEQUENCE_2SPLIT */ + r = split (&e, py, &f); + if (r == a) { /* e y f x c z d */ + join (e, py, f); + join (c, pz, d); + join (py, px, pz); + root = px; +#ifdef TRACE + printf (" ==> 0\n"); + fflush (stdout); +#endif /* TRACE */ + return 0; + } else if (r == c) { /* a x e y f z d */ + join (e, py, f); + join (py, pz, d); + join (a, px, pz); + root = px; +#ifdef TRACE + printf (" ==> 1\n"); + fflush (stdout); +#endif /* TRACE */ + return 1; + } else { /* a x c z e y f */ + join (e, py, f); + join (c, pz, py); + join (a, px, pz); + root = px; +#ifdef TRACE + printf (" ==> 0\n"); + fflush (stdout); +#endif /* TRACE */ + return 0; + } +#endif /* SEQUENCE_2SPLIT */ + } +} + +#else /* defined(MUNCHED_SEQUENCE_CODE) || defined(SEQUENCE_2SPLIT) */ + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d, *e, *f; + btree *r; + +#ifdef TRACE + printf ("sequence %d %d %d", x, y, z); + fflush (stdout); +#endif /* TRACE */ +#ifdef REPORT_DEPTH + find_depth (x); + find_depth (y); + find_depth (z); +#endif + + if (y == z || x == z || x == y) { +#ifdef TRACE + printf (" ==> 1\n"); + fflush (stdout); +#endif /* TRACE */ + return 1; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b */ + r = split (&e, pz, &f); + if (r == c) { /* e z f y d x b */ + join (e, pz, f); + join (d, px, b); + join (pz, py, px); + root = py; +#ifdef TRACE + printf (" ==> 0\n"); + fflush (stdout); +#endif /* TRACE */ + return 0; + } else if (r == d) { /* c y e z f x b */ + join (c, py, e); + join (f, px, b); + join (py, pz, px); + root = pz; +#ifdef TRACE + printf (" ==> 1\n"); + fflush (stdout); +#endif /* TRACE */ + return 1; + } else { /* c y d x e z f */ + join (c, py, d); + join (e, pz, f); + join (py, px, pz); + root = px; +#ifdef TRACE + printf (" ==> 0\n"); + fflush (stdout); +#endif /* TRACE */ + return 0; + } + } else { /* a x c y d */ + r = split (&e, pz, &f); + if (r == a) { /* e z f x c y d */ + join (e, pz, f); + join (c, py, d); + join (pz, px, py); + root = px; +#ifdef TRACE + printf (" ==> 1\n"); + fflush (stdout); +#endif /* TRACE */ + return 1; + } else if (r == c) { /* a x e z f y d */ + join (a, px, e); + join (f, py, d); + join (px, pz, py); + root = pz; +#ifdef TRACE + printf (" ==> 0\n"); + fflush (stdout); +#endif /* TRACE */ + return 0; + } else { /* a x c y e z f */ + join (a, px, c); + join (e, pz, f); + join (px, py, pz); + root = py; +#ifdef TRACE + printf (" ==> 1\n"); + fflush (stdout); +#endif /* TRACE */ + return 1; + } + } +} + +#endif /* defined(MUNCHED_SEQUENCE_CODE) || defined(SEQUENCE_2SPLIT) */ + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* void reverse (btree *p) */ +/* toggles the reversal bit of node p (and fixes the tree). */ +/* void clearrev_toroot (btree *p) */ +/* clears the reversal bits on the path from p to the root (and fixes */ +/* the tree). */ +/* btree *find_root (btree *i) */ +/* returns the root of the tree containing i */ +/* */ +/***************************************************************************/ + +#ifdef TRACE +void dump_tree (btree *r, int rev) +{ + if (!r) { + printf ("()"); + return; + } + rev ^= r->reversed; + putchar ('('); + if (r->child[rev]) dump_tree (r->child[rev], rev); + printf (" %d%s ", r-btree_space, r->reversed?"R":""); + if (r->child[1-rev]) dump_tree (r->child[1-rev], rev); + putchar (')'); +} +#endif + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) +#ifdef DUMMY_LEAF + return &dummy_leaf; +#else + return (btree *) NULL; +#endif + + center = (a + b)/2; + p = btree_space + cyc[center]; + p->child[0] = make_tree (a, center-1, cyc); +#ifdef DUMMY_LEAF + p->child[0]->parent = p; +#else + if (p->child[0]) p->child[0]->parent = p; +#endif + p->child[1] = make_tree (center+1, b, cyc); +#ifdef DUMMY_LEAF + p->child[1]->parent = p; +#else + if (p->child[1]) p->child[1]->parent = p; +#endif + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ +#ifdef TRACE + printf ("join "); + dump_tree (left, 0); + printf (" %d ", i - btree_space); + dump_tree (right, 0); + printf ("\n"); + fflush (stdout); +#endif /* TRACE */ +#ifdef DUMMY_LEAF + left->parent = i; + right->parent = i; +#else + if (left) left->parent = i; + if (right) right->parent = i; +#endif + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; +#ifdef SKIMPY_NULLS + i->parent = (btree *) NULL; +#endif +#ifdef TRACE + printf ("==> "); + dump_tree (i, 0); + printf ("\n"); + fflush (stdout); +#endif /* TRACE */ +} + +#ifdef UGLY_SPLIT + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; +#if defined(SAVE_NEIGHBORS) && defined(NO_CLEAR_TO_ROOT) + int rev = i->reversed; + btree *t; +#endif + +#ifdef TRACE + printf ("split %d ", i - btree_space); + dump_tree (find_root (i), 0); + printf ("\n"); + fflush (stdout); +#endif /* TRACE */ + +#ifdef NO_CLEAR_TO_ROOT + if (i->reversed) { + l = i->child[1]; + r = i->child[0]; +#ifdef DUMMY_LEAF + l->reversed ^= 1; + r->reversed ^= 1; +#else + if (l) l->reversed ^= 1; + if (r) r->reversed ^= 1; +#endif +#ifndef SKIMPY_NULLS + i->reversed = 0; +#endif + } else { + l = i->child[0]; + r = i->child[1]; + } +#else + clearrev_toroot (i); + l = i->child[0]; + r = i->child[1]; +#endif + +#ifndef SKIMPY_NULLS +#ifdef DUMMY_LEAF + i->child[0] = &dummy_leaf; + i->child[1] = &dummy_leaf; +#else + i->child[0] = (btree *) NULL; + i->child[1] = (btree *) NULL; +#endif +#endif + + p = i->parent; + if (!p) {p = i; goto FINISH;} + else if (p->child[0] == i) goto START_0; + else goto START_1; + +I_IS_L: + if (p->parent == (btree *) NULL) goto FINISH; + p = p->parent; + if (p->child[1] == l) { +#ifdef NO_CLEAR_TO_ROOT + if (p->reversed) { + l = r; + r = p; +#ifdef DUMMY_LEAF + l->reversed ^= 1; +#else + if (l) l->reversed ^= 1; +#endif +#ifdef SAVE_NEIGHBORS + rev ^= 1; +#endif + goto I_IS_R; + } else { + l = p; + goto I_IS_L; + } +#else + l = p; + goto I_IS_L; +#endif + } else { +START_0: + p->child[0] = r; +#ifdef DUMMY_LEAF + r->parent = p; +#else + if (r) r->parent = p; +#endif +#ifdef NO_CLEAR_TO_ROOT + if (p->reversed) { + r = l; + l = p; +#ifdef DUMMY_LEAF + r->reversed ^= 1; +#else + if (r) r->reversed ^= 1; +#endif +#ifdef SAVE_NEIGHBORS + rev ^= 1; +#endif + goto I_IS_L; + } else { + r = p; + goto I_IS_R; + } +#else + r = p; + goto I_IS_R; +#endif + } +I_IS_R: + if (p->parent == (btree *) NULL) goto FINISH; + p = p->parent; + if (p->child[0] == r) { +#ifdef NO_CLEAR_TO_ROOT + if (p->reversed) { + r = l; + l = p; +#ifdef DUMMY_LEAF + r->reversed ^= 1; +#else + if (r) r->reversed ^= 1; +#endif +#ifdef SAVE_NEIGHBORS + rev ^= 1; +#endif + goto I_IS_L; + } else { + r = p; + goto I_IS_R; + } +#else + r = p; + goto I_IS_R; +#endif + } else { +START_1: + p->child[1] = l; +#ifdef DUMMY_LEAF + l->parent = p; +#else + if (l) l->parent = p; +#endif +#ifdef NO_CLEAR_TO_ROOT + if (p->reversed) { + l = r; + r = p; +#ifdef DUMMY_LEAF + l->reversed ^= 1; +#else + if (l) l->reversed ^= 1; +#endif +#ifdef SAVE_NEIGHBORS + rev ^= 1; +#endif + goto I_IS_R; + } else { + l = p; + goto I_IS_L; + } +#else + l = p; + goto I_IS_L; +#endif + } + +FINISH: +#ifdef DUMMY_LEAF + l->parent = (btree *) NULL; + r->parent = (btree *) NULL; +#else + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; +#endif + *left = l; + *right = r; +#ifndef SKIMPY_NULLS + i->parent = (btree *) NULL; +#endif +#if defined(SAVE_NEIGHBORS) && defined(NO_CLEAR_TO_ROOT) + if (rev) SWAP (i->neigh[0], i->neigh[1], t); +#endif + +#ifdef TRACE + printf ("==> "); + dump_tree (l, 0); + printf (" %d ", i - btree_space); + dump_tree (r, 0); + printf (" ret %d\n", p - btree_space); + fflush (stdout); +#endif /* TRACE */ + return p; +} + +#else /* UGLY_SPLIT */ + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; +#if defined(SAVE_NEIGHBORS) || !defined(SKIMPY_NULLS) + btree *isave = i; +#endif +#if defined(SAVE_NEIGHBORS) && defined(NO_CLEAR_TO_ROOT) + int rev = i->reversed; +#endif + +#ifdef TRACE + printf ("split %d ", i - btree_space); + dump_tree (find_root (i), 0); + printf ("\n"); + fflush (stdout); +#endif /* TRACE */ + +#ifdef NO_CLEAR_TO_ROOT + if (i->reversed) { + l = i->child[1]; + r = i->child[0]; +#ifdef DUMMY_LEAF + l->reversed ^= 1; + r->reversed ^= 1; +#else + if (l) l->reversed ^= 1; + if (r) r->reversed ^= 1; +#endif +#ifndef SKIMPY_NULLS + i->reversed = 0; +#endif + } else { + l = i->child[0]; + r = i->child[1]; + } +#else + clearrev_toroot (i); + l = i->child[0]; + r = i->child[1]; +#endif + +#ifndef SKIMPY_NULLS +#ifdef DUMMY_LEAF + i->child[0] = &dummy_leaf; + i->child[1] = &dummy_leaf; +#else + i->child[0] = (btree *) NULL; + i->child[1] = (btree *) NULL; +#endif +#endif + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; +#ifdef DUMMY_LEAF + r->parent = p; +#else + if (r) r->parent = p; +#endif +#ifdef NO_CLEAR_TO_ROOT + if (p->reversed) { + r = l; + l = p; +#ifdef DUMMY_LEAF + r->reversed ^= 1; +#else + if (r) r->reversed ^= 1; +#endif +#ifdef SAVE_NEIGHBORS + rev ^= 1; +#endif + } else { + r = p; + } +#else + r = p; +#endif + } else { + p->child[1] = l; +#ifdef DUMMY_LEAF + l->parent = p; +#else + if (l) l->parent = p; +#endif +#ifdef NO_CLEAR_TO_ROOT + if (p->reversed) { + l = r; + r = p; +#ifdef DUMMY_LEAF + l->reversed ^= 1; +#else + if (l) l->reversed ^= 1; +#endif +#ifdef SAVE_NEIGHBORS + rev ^= 1; +#endif + } else { + l = p; + } +#else + l = p; +#endif + } + i = p; + } +#ifdef DUMMY_LEAF + l->parent = (btree *) NULL; + r->parent = (btree *) NULL; +#else + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; +#endif + *left = l; + *right = r; +#ifndef SKIMPY_NULLS + isave->parent = (btree *) NULL; +#endif +#if defined(SAVE_NEIGHBORS) && defined(NO_CLEAR_TO_ROOT) + if (rev) SWAP (isave->neigh[0], isave->neigh[1], p); +#endif + +#ifdef TRACE + printf ("==> "); + dump_tree (l, 0); + printf (" %d ", isave - btree_space); + dump_tree (r, 0); + printf (" ret %d\n", i - btree_space); + fflush (stdout); +#endif /* TRACE */ + return i; +} + +#endif /* UGLY_SPLIT */ + +#ifdef CC_PROTOTYPE_ANSI +static void reverse (btree *p) +#else +static void reverse (p) +btree *p; +#endif +{ + btree *t; + + SWAP(p->child[0], p->child[1], t); +#ifdef DUMMY_LEAF + p->child[0]->reversed ^= 1; + p->child[1]->reversed ^= 1; +#else + if (p->child[0]) p->child[0]->reversed ^= 1; + if (p->child[1]) p->child[1]->reversed ^= 1; +#endif + p->reversed ^= 1; +#ifdef SAVE_NEIGHBORS + SWAP (p->neigh[0], p->neigh[1], t); +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static void clearrev_toroot (btree *p) +#else +static void clearrev_toroot (p) +btree *p; +#endif +{ +#ifdef INLINE_CLEAR_TO_ROOT + p->next = (btree *) NULL; + while (p->parent) { + p->parent->next = p; + p = p->parent; + } + while (p) { + if (p->reversed) reverse (p); + p = p->next; + } +#else +#ifdef INLINE_CLEAR_TO_ROOT2 + int rev; + btree *q; + + for (q = p, rev = 0; q; q = q->parent) rev ^= q->reversed; + if (rev) reverse(p); + while (p->parent) { + if (p->reversed) reverse(p->parent); + p = p->parent; + } +#else + if (p->parent) clearrev_toroot (p->parent); + if (p->reversed) reverse (p); +#endif +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *find_root (btree *i) +#else +static btree *find_root (i) +btree *i; +#endif +{ + while (i->parent) i = i->parent; + return i; +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_bt5.c b/contrib/blossom/concorde97/LINKERN/flip_bt5.c new file mode 100644 index 0000000000000000000000000000000000000000..02ae7301dad7dedfd8df205b91b321712b28fd0b --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_bt5.c @@ -0,0 +1,700 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* - Uses SKIMPY_NULLS, */ +/* NO_CLEAR_TO_ROOT, and */ +/* SEQUENCE_2SPLIT */ +/* - Adds splays */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#define USE_SPLAY_SEQUENCE +#define USE_SPLAY_FLIPS + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; + int reversed; + int mark; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right), + *find_root (btree *i); + +static void + join (btree *left, btree *i, btree *right); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (), + *find_root (); + +static void + join (); + +#endif + +#if defined(USE_SPLAY_SEQUENCE) || defined(USE_SPLAY_FLIPS) +#ifdef CC_PROTOTYPE_ANSI + +static void + rotate (btree *x, btree *px), + splay (btree *x), + reverse (btree *p); + +#else + +static void + rotate (), + splay (), + reverse (); + +#endif +#endif + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static btree *root = (btree *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + printf ("SIZE OF BTREE: %d\n", sizeof (btree)); + fflush (stdout); + + btree_space = CC_SAFE_MALLOC (ncount, btree); + if (!btree_space) + return 1; + + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + btree_space[i].mark = 0; + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ + if (p == (btree *) NULL) + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p - btree_space; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (btree_space) + CC_FREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p - btree_space; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { + return pnext - btree_space; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p - btree_space; + } + p = pnext; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p - btree_space; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { + return pnext - btree_space; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p - btree_space; + } + p = pnext; + } + } +} + + +#ifdef USE_SPLAY_FLIPS +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *temp; + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + splay (px); + px->mark = 1; + splay (py); + px->mark = 0; + + splay (px); + px->mark = 1; + splay (py); + px->mark = 0; + + if (px->reversed) + reverse (px); + if (py->reversed) + reverse (py); + if (px->child[1] == py) { + if (py->child[0]) + py->child[0]->reversed ^= 1; + SWAP (px->child[0], py->child[0], temp); + if (px->child[0]) + px->child[0]->parent = px; + if (py->child[0]) + py->child[0]->parent = py; + px->child[1] = py->child[1]; + if (px->child[1]) + px->child[1]->parent = px; + py->child[1] = px; + px->parent = py; + py->parent = (btree *) NULL; + root = py; + } else { + px->reversed ^= 1; + py->child[1]->reversed ^= 1; + } +} + +#else + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *a, *b, *c, *d; + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +} +#endif + +#ifdef USE_SPLAY_SEQUENCE +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + + if (y == z || x == z || x == y) + return 1; + + splay (px); + px->mark = 1; + splay (pz); + px->mark = 0; + + if (px->reversed) + reverse (px); + if (pz->reversed) + reverse (pz); + + for (;;) { + if (py->parent == px) { + return px->child[1] == py; + } else if (py->parent == pz) { + return pz->child[0] == py; + } else { + py = py->parent; + } + } +} + +#else + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d; + btree *r; + + if (y == z || x == z || x == y) { + return 1; + } + + split (&a, px, &b); + if (split (&c, pz, &d) == a) { /* c z d x b */ + r = find_root (py); + join (c,pz,d); + join (pz,px,b); + root = px; + return (r!=d); + } else { /* a x c z d */ + r = find_root (py); + join (c,pz,d); + join (a,px,pz); + root = px; + return (r==c); + } +} +#endif + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* btree *find_root (btree *i) */ +/* returns the root of the tree containing i */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) + return (btree *) NULL; + + center = (a + b)/2; + p = btree_space + cyc[center]; + p->child[0] = make_tree (a, center-1, cyc); + if (p->child[0]) p->child[0]->parent = p; + p->child[1] = make_tree (center+1, b, cyc); + if (p->child[1]) p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ + if (left) left->parent = i; + if (right) right->parent = i; + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; + i->parent = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; + + if (i->reversed) { + l = i->child[1]; + r = i->child[0]; + if (l) l->reversed ^= 1; + if (r) r->reversed ^= 1; + } else { + l = i->child[0]; + r = i->child[1]; + } + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; + if (r) r->parent = p; + if (p->reversed) { + r = l; + l = p; + if (r) r->reversed ^= 1; + } else { + r = p; + } + } else { + p->child[1] = l; + if (l) l->parent = p; + if (p->reversed) { + l = r; + r = p; + if (l) l->reversed ^= 1; + } else { + l = p; + } + } + i = p; + } + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; + *left = l; + *right = r; + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *find_root (btree *i) +#else +static btree *find_root (i) +btree *i; +#endif +{ + while (i->parent) i = i->parent; + return i; +} + + +/**************************** SPLAY STUFF ****************************/ + +#ifdef CC_PROTOTYPE_ANSI +static void rotate (btree *x, btree *px) +#else +static void rotate (x, px) +btree *x, *px; +#endif +{ + btree *b; + + if (px->child[0] == x) { + b = x->child[1]; + if (b) + b->parent = px; + x->child[1] = px; + x->parent = px->parent; + if (x->parent) { + if (x->parent->child[0] == px) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + } + px->child[0] = b; + px->parent = x; + } else { + b = x->child[0]; + if (b) + b->parent = px; + x->child[0] = px; + x->parent = px->parent; + if (x->parent) { + if (x->parent->child[0] == px) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + } + px->child[1] = b; + px->parent = x; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void splay (btree *x) +#else +static void splay (x) +btree *x; +#endif +{ + btree *px; + btree *ppx; + + for (;;) { + px = x->parent; + if (!px) { + root = x; + return; + } + if (px->mark) + return; + ppx = px->parent; + if (!ppx) { + if (px->reversed) + reverse (px); + if (x->reversed) + reverse (x); + rotate (x, px); + root = x; + return; + } + if (ppx->mark) { + if (px->reversed) + reverse (px); + if (x->reversed) + reverse (x); + rotate (x, px); + return; + } + if (ppx->reversed) + reverse (ppx); + if (px->reversed) + reverse (px); + if (x->reversed) + reverse (x); + if (ppx->child[0] == px) { + if (px->child[0] == x) { + rotate (px, ppx); + rotate (x, px); + } else { + rotate (x, px); + rotate (x, ppx); + } + } else { + if (px->child[1] == x) { + rotate (px, ppx); + rotate (x, px); + } else { + rotate (x, px); + rotate (x, ppx); + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void reverse (btree *p) +#else +static void reverse (p) +btree *p; +#endif +{ + btree *t; + + SWAP(p->child[0], p->child[1], t); + if (p->child[0]) p->child[0]->reversed ^= 1; + if (p->child[1]) p->child[1]->reversed ^= 1; + p->reversed ^= 1; +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_btc.c b/contrib/blossom/concorde97/LINKERN/flip_btc.c new file mode 100644 index 0000000000000000000000000000000000000000..9023e6547bbf796aa06bded8c697dfd25ef06be2 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_btc.c @@ -0,0 +1,459 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* - Uses SKIMPY_NULLS, */ +/* NO_CLEAR_TO_ROOT, and */ +/* SEQUENCE_2SPLIT */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; + int reversed; + int value; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right), + *find_root (btree *i); + +static void + join (btree *left, btree *i, btree *right); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (), + *find_root (); + +static void + join (); + +#endif + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static int btree_size; +static btree *root = (btree *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + btree_space = CC_SAFE_MALLOC (ncount, btree); + btree_size = ncount; + if (!btree_space) + return 1; + + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + btree_space[i].value = i; + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ + if (p == (btree *) NULL) + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (btree_space) + CC_FREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *a, *b, *c, *d; + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d; + btree *r; + + if (y == z || x == z || x == y) { + return 1; + } + + split (&a, px, &b); + if (split (&c, pz, &d) == a) { /* c z d x b */ + r = find_root (py); + join (c,pz,d); + join (pz,px,b); + root = px; + return (r!=d); + } else { /* a x c z d */ + r = find_root (py); + join (c,pz,d); + join (a,px,pz); + root = px; + return (r==c); + } +} + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* btree *find_root (btree *i) */ +/* returns the root of the tree containing i */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) + return (btree *) NULL; + + center = (a + b)/2; + p = btree_space + cyc[center]; + p->child[0] = make_tree (a, center-1, cyc); + if (p->child[0]) p->child[0]->parent = p; + p->child[1] = make_tree (center+1, b, cyc); + if (p->child[1]) p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ + if (left) left->parent = i; + if (right) right->parent = i; + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; + i->parent = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; + + if (i->reversed) { + l = i->child[1]; + r = i->child[0]; + if (l) l->reversed ^= 1; + if (r) r->reversed ^= 1; + } else { + l = i->child[0]; + r = i->child[1]; + } + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; + if (r) r->parent = p; + if (p->reversed) { + r = l; + l = p; + if (r) r->reversed ^= 1; + } else { + r = p; + } + } else { + p->child[1] = l; + if (l) l->parent = p; + if (p->reversed) { + l = r; + r = p; + if (l) l->reversed ^= 1; + } else { + l = p; + } + } + i = p; + } + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; + *left = l; + *right = r; + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *find_root (btree *i) +#else +static btree *find_root (i) +btree *i; +#endif +{ + while (i->parent) i = i->parent; + return i; +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_btd.c b/contrib/blossom/concorde97/LINKERN/flip_btd.c new file mode 100644 index 0000000000000000000000000000000000000000..b9b9d93fb6a357fcc8f9727189770761c57b5af8 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_btd.c @@ -0,0 +1,458 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* - Uses SKIMPY_NULLS, */ +/* NO_CLEAR_TO_ROOT, and */ +/* SEQUENCE_2SPLIT */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; + int reversed; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right), + *find_root (btree *i); + +static void + join (btree *left, btree *i, btree *right); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (), + *find_root (); + +static void + join (); + +#endif + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static btree *root = (btree *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + printf ("SIZE OF BTREE: %d\n", sizeof (btree)); + fflush (stdout); + + btree_space = CC_SAFE_MALLOC (ncount, btree); + if (!btree_space) + return 1; + + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ + if (p == (btree *) NULL) + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p - btree_space; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (btree_space) + CC_FREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p - btree_space; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { + return pnext - btree_space; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p - btree_space; + } + p = pnext; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p - btree_space; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { + return pnext - btree_space; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p - btree_space; + } + p = pnext; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *a, *b, *c, *d; + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d; + btree *r; + + if (y == z || x == z || x == y) { + return 1; + } + + split (&a, px, &b); + if (split (&c, pz, &d) == a) { /* c z d x b */ + r = find_root (py); + join (c,pz,d); + join (pz,px,b); + root = px; + return (r!=d); + } else { /* a x c z d */ + r = find_root (py); + join (c,pz,d); + join (a,px,pz); + root = px; + return (r==c); + } +} + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* btree *find_root (btree *i) */ +/* returns the root of the tree containing i */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) + return (btree *) NULL; + + center = (a + b)/2; + p = btree_space + cyc[center]; + p->child[0] = make_tree (a, center-1, cyc); + if (p->child[0]) p->child[0]->parent = p; + p->child[1] = make_tree (center+1, b, cyc); + if (p->child[1]) p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ + if (left) left->parent = i; + if (right) right->parent = i; + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; + i->parent = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; + + if (i->reversed) { + l = i->child[1]; + r = i->child[0]; + if (l) l->reversed ^= 1; + if (r) r->reversed ^= 1; + } else { + l = i->child[0]; + r = i->child[1]; + } + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; + if (r) r->parent = p; + if (p->reversed) { + r = l; + l = p; + if (r) r->reversed ^= 1; + } else { + r = p; + } + } else { + p->child[1] = l; + if (l) l->parent = p; + if (p->reversed) { + l = r; + r = p; + if (l) l->reversed ^= 1; + } else { + l = p; + } + } + i = p; + } + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; + *left = l; + *right = r; + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *find_root (btree *i) +#else +static btree *find_root (i) +btree *i; +#endif +{ + while (i->parent) i = i->parent; + return i; +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_btr.c b/contrib/blossom/concorde97/LINKERN/flip_btr.c new file mode 100644 index 0000000000000000000000000000000000000000..2dc5aef8ebffbd78a624c33ee9b25428a5135fdb --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_btr.c @@ -0,0 +1,556 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Binary Trees (unbalanced)*/ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/* #define SAVE_NEIGHBORS */ +#define INLINE_CLEAR_TO_ROOT + +typedef struct btree { + struct btree *parent; + struct btree *child[2]; +#ifdef INLINE_CLEAR_TO_ROOT + struct btree *next; +#endif +#ifdef SAVE_NEIGHBORS + struct btree *neigh[2]; +#endif + int reversed; + int value; +} btree; + +#ifdef CC_PROTOTYPE_ANSI + +static int + cycle_fillin(int *x, int i, btree *p, int r); + +static btree + *make_tree (int a, int b, int *cyc), + *split (btree **left, btree *i, btree **right); + +static void + join (btree *left, btree *i, btree *right), + reverse (btree *p), + clearrev_toroot (btree *p); + +#else + +static int + cycle_fillin(); + +static btree + *make_tree (), + *split (); + +static void + join (), + reverse (), + clearrev_toroot (); + +#endif + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +static btree *btree_space = (btree *) NULL; +static int btree_size; +static btree *root = (btree *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + +/* + printf ("Flipper flags:"); +#ifdef SAVE_NEIGHBORS + printf (" SAVE_NEIGHBORS"); +#else + printf (" !SAVE_NEIGHBORS"); +#endif +*/ + + btree_space = CC_SAFE_MALLOC (ncount, btree); + btree_size = ncount; + if (!btree_space) + return 1; + + for (i = 0; i < ncount; i++) { + btree_space[i].reversed = 0; + btree_space[i].value = i; +#ifdef SAVE_NEIGHBORS + if (i==0) { + btree_space[cyc[0]].neigh[0] = &btree_space[cyc[ncount-1]]; + btree_space[cyc[ncount-1]].neigh[1] = &btree_space[cyc[0]]; + } else { + btree_space[cyc[i]].neigh[0] = &btree_space[cyc[i-1]]; + btree_space[cyc[i-1]].neigh[1] = &btree_space[cyc[i]]; + } +#endif + } + + root = make_tree (0, ncount - 1, cyc); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cycle_fillin(int *x, int i, btree *p, int r) +#else +static int cycle_fillin(x, i, p, r) +int *x; +int i; +btree *p; +int r; +#endif +{ + if (!p) + return i; + + r ^= p->reversed; + i = cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + return cycle_fillin (x, 0, root, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + CC_IFFREE (btree_space, btree); + + root = (btree *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + btree *p = btree_space + x; + btree *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; pnext; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; + pnext = p->parent; + while (pnext) { + if (pnext->child[1 - r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *temp, *temp2; + btree *a, *b, *c, *d; + + if (x == y) return; + if (xprev == ynext) { + root->reversed ^= 1; + return; + } + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b ==> b^r x d y c^r */ + if (b) b->reversed ^= 1; + if (c) c->reversed ^= 1; + join (d,py,c); + join (b,px,py); + root = px; + } else { /* a x c y d ==> a y c^r x d */ + if (c) c->reversed ^= 1; + join (a,py,c); + join (py,px,d); + root = px; + } +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + btree *px = btree_space + x; + btree *py = btree_space + y; + btree *pz = btree_space + z; + btree *a, *b, *c, *d, *e, *f; + btree *r; + + if (y == z || x == z || x == y) + return 1; + + split (&a, px, &b); + if (split (&c, py, &d) == a) { /* c y d x b */ + r = split (&e, pz, &f); + if (r == c) { /* e z f y d x b */ + join (e, pz, f); + join (d, px, b); + join (pz, py, px); + root = py; + return 0; + } else if (r == d) { /* c y e z f x b */ + join (c, py, e); + join (f, px, b); + join (py, pz, px); + root = pz; + return 1; + } else { /* c y d x e z f */ + join (c, py, d); + join (e, pz, f); + join (py, px, pz); + root = px; + return 0; + } + } else { /* a x c y d */ + r = split (&e, pz, &f); + if (r == a) { /* e z f x c y d */ + join (e, pz, f); + join (c, py, d); + join (pz, px, py); + root = px; + return 1; + } else if (r == c) { /* a x e z f y d */ + join (a, px, e); + join (f, py, d); + join (px, pz, py); + root = pz; + return 0; + } else { /* a x c y e z f */ + join (a, px, c); + join (e, pz, f); + join (px, py, pz); + root = py; + return 1; + } + } +} + +/***************************************************************************/ +/* */ +/* REVERSIBLE BINARY TREE ROUTINES (UNBALANCED) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 16, 1995 */ +/* */ +/* */ +/* btree *make_tree (int a, int b, int *cyc) */ +/* builds a binary tree for cyc[a..b] and returns the root. */ +/* This assumes that btree_space has been allocated and initialized. */ +/* void join (btree *left, btree *i, btree *right) */ +/* makes left and right the children of i. */ +/* btree *split (btree **left, btree *i, btree **right) */ +/* splits the tree into *left (nodes < i) and *right (nodes > i) */ +/* returns the root of the (old) tree containing i. */ +/* void reverse (btree *p) */ +/* toggles the reversal bit of node p (and fixes the tree). */ +/* void clearrev_toroot (btree *p) */ +/* clears the reversal bits on the path from p to the root (and fixes */ +/* the tree). */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +static btree *make_tree (int a, int b, int *cyc) +#else +static btree *make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + btree *p; + int center; + + if (b < a) + return (btree *) NULL; + + center = (a + b)/2; + p = btree_space + cyc[center]; + if ((p->child[0] = make_tree (a, center-1, cyc)) != (btree *) NULL) + p->child[0]->parent = p; + if ((p->child[1] = make_tree (center+1, b, cyc)) != (btree *) NULL) + p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void join (btree *left, btree *i, btree *right) +#else +static void join (left, i, right) +btree *left; +btree *i; +btree *right; +#endif +{ + if (left) left->parent = i; + if (right) right->parent = i; + i->child[0] = left; + i->child[1] = right; + i->reversed = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static btree *split (btree **left, btree *i, btree **right) +#else +static btree *split (left, i, right) +btree **left; +btree *i; +btree **right; +#endif +{ + btree *l; + btree *r; + btree *p; + btree *isave = i; + + clearrev_toroot (i); + l = i->child[0]; + r = i->child[1]; + i->child[0] = (btree *) NULL; + i->child[1] = (btree *) NULL; + + while ((p = i->parent) != (btree *) NULL) { + if (p->child[0] == i) { + p->child[0] = r; + if (r) r->parent = p; + r = p; + } else { + p->child[1] = l; + if (l) l->parent = p; + l = p; + } + i = p; + } + if (l) l->parent = (btree *) NULL; + if (r) r->parent = (btree *) NULL; + *left = l; + *right = r; + if (isave) isave->parent = (btree *) NULL; + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static void reverse (btree *p) +#else +static void reverse (p) +btree *p; +#endif +{ + btree *t; + + SWAP(p->child[0], p->child[1], t); + if (p->child[0]) p->child[0]->reversed ^= 1; + if (p->child[1]) p->child[1]->reversed ^= 1; + p->reversed ^= 1; +#ifdef SAVE_NEIGHBORS + SWAP (p->neigh[0], p->neigh[1], t); +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static void clearrev_toroot (btree *p) +#else +static void clearrev_toroot (p) +btree *p; +#endif +{ +#ifndef INLINE_CLEAR_TO_ROOT + if (p->parent) clearrev_toroot (p->parent); + if (p->reversed) reverse (p); +#else + p->next = (btree *) NULL; + while (p->parent) { + p->parent->next = p; + p = p->parent; + } + while (p) { + if (p->reversed) reverse (p); + p = p->next; + } +#endif +} + + + diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll0.c b/contrib/blossom/concorde97/LINKERN/flip_ll0.c new file mode 100644 index 0000000000000000000000000000000000000000..8c1067ae541d6256e5936d41487569ceef9006ae --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll0.c @@ -0,0 +1,252 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Basic Linked List */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 0 (flip_ll0.c): */ +/* */ +/* 1. Uses linked list with known prev and next. */ +/* 2. No reversal bit. */ +/* 2. Next and prev given explicitly. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +typedef struct llnode { + struct llnode *next; + struct llnode *prev; + int name; + int mark; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + dump_cycle (void); + +#else + +static void + dump_cycle (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static cycle_size = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + cycle_size = ncount; + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].name = cyc[0]; + lltour[cyc[0]].mark = 0; + lltour[cyc[0]].next = &(lltour[cyc[1]]); + lltour[cyc[0]].prev = &(lltour[cyc[ncount - 1]]); + lltour[cyc[ncount - 1]].name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].mark = 0; + lltour[cyc[ncount - 1]].next = &(lltour[cyc[0]]); + lltour[cyc[ncount - 1]].prev = &(lltour[cyc[ncount - 2]]); + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].name = cyc[i]; + lltour[cyc[i]].mark = 0; + lltour[cyc[i]].next = &(lltour[cyc[i + 1]]); + lltour[cyc[i]].prev = &(lltour[cyc[i - 1]]); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_cycle (void) +#else +static void dump_cycle () +#endif +{ + llnode *n, *ns; + + printf ("TOUR:\n"); + + + n = ns = &(lltour[0]); + + do { + printf ("%2d ", n->name); + n = n->next; + } while (n != ns); + + printf ("\n"); + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + llnode *n, *start; + int k = 0; + + n = start = &(lltour[0]); + + do { + x[k++] = n->name; + n = n->next; + } while (n != start && k < cycle_size); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + return lltour[x].next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + return lltour[x].prev->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + llnode *nxprev = &(lltour[xprev]); + llnode *nynext = &(lltour[ynext]); + llnode *nx = &(lltour[x]); + llnode *ny = &(lltour[y]); + llnode *n, *next; + + if (x == y) + return; + + next = nx->next; + nx->next = nx->prev; + nx->prev = next; + + do { + n = next; + next = n->next; + n->next = n->prev; + n->prev = next; + } while (n != ny); + + if (nxprev != ny) { + ny->prev = nxprev; + nx->next = nynext; + nxprev->next = ny; + nynext->prev = nx; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + llnode *n; + + if (x == z) { + return 1; + } else { + lltour[y].mark = 1; + lltour[z].mark = 1; + + n = &(lltour[x]); + + while (!n->mark) { + n = n->next; + } + lltour[y].mark = 0; + lltour[z].mark = 0; + + return (n->name == y); + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll1.c b/contrib/blossom/concorde97/LINKERN/flip_ll1.c new file mode 100644 index 0000000000000000000000000000000000000000..d44a486113553ceec5bc8953928a1a2df7dcb7fb --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll1.c @@ -0,0 +1,258 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Linked List with Node Bit */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version is a real dud - the node bit idea takes longer than */ +/* simply swapping the next and prev fields as in flip_ll0. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 1 (flip_ll1.c): */ +/* */ +/* 1. Uses linked list with known prev and next. */ +/* 2. No reversal bit. */ +/* 3. Node bits to distingish between prev and next. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +typedef struct llnode { + struct llnode *neigh[2]; /* 0 is next, 1 is prev */ + int name; + char dir; + char mark; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + dump_cycle (void); + +#else + +static void + dump_cycle (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static cycle_size = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + cycle_size = ncount; + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].name = cyc[0]; + lltour[cyc[0]].dir = 0; + lltour[cyc[0]].mark = 0; + lltour[cyc[0]].neigh[0] = &(lltour[cyc[1]]); + lltour[cyc[0]].neigh[1] = &(lltour[cyc[ncount - 1]]); + lltour[cyc[ncount - 1]].name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].dir = 0; + lltour[cyc[ncount - 1]].mark = 0; + lltour[cyc[ncount - 1]].neigh[0] = &(lltour[cyc[0]]); + lltour[cyc[ncount - 1]].neigh[1] = &(lltour[cyc[ncount - 2]]); + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].name = cyc[i]; + lltour[cyc[i]].dir = 0; + lltour[cyc[i]].mark = 0; + lltour[cyc[i]].neigh[0] = &(lltour[cyc[i + 1]]); + lltour[cyc[i]].neigh[1] = &(lltour[cyc[i - 1]]); + } + +/* + dump_cycle (); +*/ + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_cycle (void) +#else +static void dump_cycle () +#endif +{ + llnode *n, *ns; + + printf ("TOUR:\n"); + + + n = ns = &(lltour[0]); + + do { + printf ("%2d ", n->name); + n = n->neigh[(int) n->dir]; + } while (n != ns); + + printf ("\n"); + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + llnode *n, *start; + int k = 0; + + n = start = &(lltour[0]); + + do { + x[k++] = n->name; + n = n->neigh[(int) n->dir]; + } while (n != start && k < cycle_size); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + return lltour[x].neigh[(int) lltour[x].dir]->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + return lltour[x].neigh[(int) ((lltour[x].dir)^1)]->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + llnode *nxprev = &(lltour[xprev]); + llnode *nynext = &(lltour[ynext]); + llnode *nx = &(lltour[x]); + llnode *ny = &(lltour[y]); + llnode *n; + + if (x == y) + return; + + n = nx; + n->dir ^= 1; + + do { + n = n->neigh[n->dir^1]; + n->dir ^= 1; + } while (n != ny); + + if (nxprev != ny) { + ny->neigh[(int) ny->dir^1] = nxprev; + nx->neigh[(int) nx->dir] = nynext; + nxprev->neigh[(int) nxprev->dir] = ny; + nynext->neigh[(int) nynext->dir^1] = nx; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + llnode *n; + + if (x == z) { + return 1; + } else { + lltour[y].mark = 1; + lltour[z].mark = 1; + + n = &(lltour[x]); + + while (!n->mark) { + n = n->neigh[(int) n->dir]; + } + lltour[y].mark = 0; + lltour[z].mark = 0; + + return (n->name == y); + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll2.c b/contrib/blossom/concorde97/LINKERN/flip_ll2.c new file mode 100644 index 0000000000000000000000000000000000000000..9f6a828671472cf903e164622757d1dbdd246260 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll2.c @@ -0,0 +1,325 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Basic Linked List w/ Rev */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version uses very little memory, and is reasonably fast */ +/* for small problems and for twoopts (but you should have SHORT_SIDE */ +/* defined so that the smaller side a flip is carried out. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 0 (flip_ll0.c): */ +/* */ +/* 1. Uses linked list with known prev and next. */ +/* 2. Tour reversal bit. */ +/* 2. Next and prev given explicitly. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +typedef struct llnode { + struct llnode *next; + struct llnode *prev; + int name; + int mark; +} llnode; + +static llnode *lltour = (llnode *) NULL; +static cycle_size = 0; +static int reversed = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + cycle_size = ncount; + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + reversed = 0; + lltour[cyc[0]].name = cyc[0]; + lltour[cyc[0]].mark = 0; + lltour[cyc[0]].next = &(lltour[cyc[1]]); + lltour[cyc[0]].prev = &(lltour[cyc[ncount - 1]]); + lltour[cyc[ncount - 1]].name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].mark = 0; + lltour[cyc[ncount - 1]].next = &(lltour[cyc[0]]); + lltour[cyc[ncount - 1]].prev = &(lltour[cyc[ncount - 2]]); + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].name = cyc[i]; + lltour[cyc[i]].mark = 0; + lltour[cyc[i]].next = &(lltour[cyc[i + 1]]); + lltour[cyc[i]].prev = &(lltour[cyc[i - 1]]); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + llnode *n, *start; + int k = 0; + + n = start = &(lltour[0]); + + if (reversed) { + do { + x[k++] = n->name; + n = n->prev; + } while (n != start && k < cycle_size); + } else { + do { + x[k++] = n->name; + n = n->next; + } while (n != start && k < cycle_size); + } + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (reversed) + return lltour[x].prev->name; + else + return lltour[x].next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (reversed) + return lltour[x].next->name; + else + return lltour[x].prev->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + llnode *nxprev = &(lltour[xprev]); + llnode *nynext = &(lltour[ynext]); + llnode *nx = &(lltour[x]); + llnode *ny = &(lltour[y]); + llnode *n, *next, *prev; + + if (x == y) + return; + + if (reversed) { + next = nx->prev; + prev = nxprev->next; + + while (next != ny && prev != nynext) { + next = next->prev; + prev = prev->next; + } + + if (next == ny) { + next = nx->prev; + nx->prev = nx->next; + nx->next = next; + do { + n = next; + next = n->prev; + n->prev = n->next; + n->next = next; + } while (n != ny); + if (nxprev != ny) { + ny->next = nxprev; + nx->prev = nynext; + nxprev->prev = ny; + nynext->next = nx; + } + } else { + prev = nxprev->next; + nxprev->next = nxprev->prev; + nxprev->prev = prev; + do { + n = prev; + prev = n->next; + n->next = n->prev; + n->prev = prev; + } while (n != nynext); + if (nxprev != ny) { + ny->prev = nxprev; + nx->next = nynext; + nxprev->next = ny; + nynext->prev = nx; + } + reversed = 0; + } + } else { + next = nx->next; + prev = nxprev->prev; + + while (next != ny && prev != nynext) { + next = next->next; + prev = prev->prev; + } + + if (next == ny) { + next = nx->next; + nx->next = nx->prev; + nx->prev = next; + do { + n = next; + next = n->next; + n->next = n->prev; + n->prev = next; + } while (n != ny); + if (nxprev != ny) { + ny->prev = nxprev; + nx->next = nynext; + nxprev->next = ny; + nynext->prev = nx; + } + } else { + prev = nxprev->prev; + nxprev->prev = nxprev->next; + nxprev->next = prev; + do { + n = prev; + prev = n->prev; + n->prev = n->next; + n->next = prev; + } while (n != nynext); + if (nxprev != ny) { + ny->next = nxprev; + nx->prev = nynext; + nxprev->prev = ny; + nynext->next = nx; + } + reversed = 1; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + llnode *next, *prev; + + if (x == z) { + return 1; + } else { + lltour[y].mark = 1; + lltour[z].mark = 1; + + next = prev = &(lltour[x]); + + while (!next->mark && !prev->mark) { + next = next->next; + prev = prev->prev; + } + + if (reversed) { + if (prev->mark) { + lltour[y].mark = 0; + lltour[z].mark = 0; + return (prev->name == y); + } else { + lltour[y].mark = 0; + lltour[z].mark = 0; + return (next->name == z); + } + } else { + if (next->mark) { + lltour[y].mark = 0; + lltour[z].mark = 0; + return (next->name == y); + } else { + lltour[y].mark = 0; + lltour[z].mark = 0; + return (prev->name == z); + } + } + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll3.c b/contrib/blossom/concorde97/LINKERN/flip_ll3.c new file mode 100644 index 0000000000000000000000000000000000000000..311b0e95263b9495769aaf7c1bf0b8adf7297a2e --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll3.c @@ -0,0 +1,341 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Linked List w/ Neighbors */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version should be very slow, since next and prev have to */ +/* hunt down an orientation node (since each node knows its neighbors */ +/* but not the direction). Flips will be fast, but there are not enough */ +/* enough of them to compensate for the next and prevs. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 3 (flip_ll3.c): */ +/* */ +/* 1. Uses linked list with neighbors. */ +/* 2. Need to track down a node of known orientation (the extra info */ +/* in the flips provides this). */ +/* 3. The hunt is done by a seqeunce of if tests, moving along the */ +/* linked list, checking that we reach new nodes). */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +typedef struct llnode { + struct llnode *next; + struct llnode *prev; + int name; + char orient; + char mark; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + dump_cycle (void); +static int + find_orientation (llnode *n); + +#else + +static void + dump_cycle (); +static int + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static llnode *orientnodes[2]; +static cycle_size = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + cycle_size = ncount; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].name = cyc[0]; + lltour[cyc[0]].mark = 0; + lltour[cyc[0]].orient = 0; + lltour[cyc[0]].next = &(lltour[cyc[1]]); + lltour[cyc[0]].prev = &(lltour[cyc[ncount - 1]]); + lltour[cyc[ncount - 1]].name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].mark = 0; + lltour[cyc[ncount - 1]].orient = 0; + lltour[cyc[ncount - 1]].next = &(lltour[cyc[0]]); + lltour[cyc[ncount - 1]].prev = &(lltour[cyc[ncount - 2]]); + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].name = cyc[i]; + lltour[cyc[i]].mark = 0; + lltour[cyc[i]].orient = 0; + lltour[cyc[i]].next = &(lltour[cyc[i + 1]]); + lltour[cyc[i]].prev = &(lltour[cyc[i - 1]]); + } + orientnodes[0] = &(lltour[cyc[0]]); + orientnodes[1] = &(lltour[cyc[ncount/2]]); + lltour[cyc[0]].orient = 1; + lltour[cyc[ncount/2]].orient = 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (llnode *s) +#else +static int find_orientation (s) +llnode *s; +#endif +{ + /* Returns 0 if next is next and 1 if next is really prev */ + + llnode *n, *p; + + if (s->orient) + return 0; + + p = s; + n = p->next; + + while (!n->orient) { + if (n->next == p) { + p = n; + n = n->prev; + } else { + p = n; + n = n->next; + } + } + return (p != n->prev); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + llnode *n, *p, *start; + int k = 0; + + p = start = &(lltour[0]); + n = (find_orientation (start) ? start->prev : start->next); + + x[k++] = start->name; + + do { + x[k++] = n->name; + if (n->next == p) { + p = n; + n = n->prev; + } else { + p = n; + n = n->next; + } + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (&(lltour[x]))) + return lltour[x].prev->name; + else + return lltour[x].next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (&(lltour[x]))) + return lltour[x].next->name; + else + return lltour[x].prev->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + llnode *nxprev = &(lltour[xprev]); + llnode *nynext = &(lltour[ynext]); + llnode *nx = &(lltour[x]); + llnode *ny = &(lltour[y]); + + if (x == y) { + return; + } + + orientnodes[0]->orient = 0; + orientnodes[1]->orient = 0; + orientnodes[0] = nxprev; + orientnodes[1] = nynext; + nxprev->orient = 1; + nynext->orient = 1; + + if (nxprev == ny) { + if (nx->prev == ny) { + nx->prev = nx->next; + nx->next = ny; + } + if (ny->next == nx) { + ny->next = ny->prev; + ny->prev = nx; + } + } else { + if (nxprev->prev == nx) + nxprev->prev = nxprev->next; + nxprev->next = ny; + + if (nynext->next == ny) + nynext->next = nynext->prev; + nynext->prev = nx; + + if (nx->prev == nxprev) + nx->prev = nynext; + else + nx->next = nynext; + + if (ny->next == nynext) + ny->next = nxprev; + else + ny->prev = nxprev; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + llnode *n, *p; + + if (x == z || x == y) { + return 1; + } else { + lltour[y].mark = 1; + lltour[z].mark = 1; + + p = &(lltour[x]); + n = (find_orientation (p) ? p->prev : p->next); + + while (!n->mark) { + if (n->next == p) { + p = n; + n = n->prev; + } else { + p = n; + n = n->next; + } + } + lltour[y].mark = 0; + lltour[z].mark = 0; + + return (n->name == y); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_cycle (void) +#else +static void dump_cycle () +#endif +{ + int *getit, i; + + getit = CC_SAFE_MALLOC (cycle_size, int); + CClinkern_flipper_cycle (getit); + + printf ("TOUR: "); + + for (i = 0; i < cycle_size; i++) + printf ("%2d ", getit[i]); + printf ("\n"); + fflush (stdout); + + CC_FREE (getit, int); +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll4.c b/contrib/blossom/concorde97/LINKERN/flip_ll4.c new file mode 100644 index 0000000000000000000000000000000000000000..44710410cbc26e6eec0875a02860f96d24f17cb9 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll4.c @@ -0,0 +1,398 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Linked Lists (fwd & bwd) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version should be slow, since next and prev have to */ +/* hunt down an orientation node (since each node knows its neighbors */ +/* but not the direction), like flip_ll3, but the two copies of the tour */ +/* (one in each direction) lets us avoid lost of if tests during the */ +/* hunt. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 4 (flip_ll4.c): */ +/* */ +/* 1. Uses two linked lists (forward and backward) */ +/* 2. Need to track down a node of known orientation (the extra info */ +/* in the flips provides this). */ +/* 3. The hunt is done by a moving along one of the tours, till we hit */ +/* an orientation node that will tell us if we are on the forward */ +/* or backward tour. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 + +typedef struct oneway { + struct oneway *next; + int name; + char dir; + char orient; + char mark; +} oneway; + +typedef struct llnode { + struct oneway fwd; + struct oneway bwd; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static int + find_orientation (int s); + +#else + +static int + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static llnode *orientnodes[2]; +static cycle_size = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + cycle_size = ncount; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].fwd.name = cyc[0]; + lltour[cyc[0]].fwd.mark = 0; + lltour[cyc[0]].fwd.dir = FORWARD_TOUR; + lltour[cyc[0]].fwd.orient = 0; + lltour[cyc[0]].fwd.next = &(lltour[cyc[1]].fwd); + lltour[cyc[0]].bwd.name = cyc[0]; + lltour[cyc[0]].bwd.mark = 0; + lltour[cyc[0]].bwd.dir = BACKWARD_TOUR; + lltour[cyc[0]].bwd.orient = 0; + lltour[cyc[0]].bwd.next = &(lltour[cyc[ncount - 1]].bwd); + lltour[cyc[ncount - 1]].fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].fwd.mark = 0; + lltour[cyc[ncount - 1]].fwd.dir = FORWARD_TOUR; + lltour[cyc[ncount - 1]].fwd.orient = 0; + lltour[cyc[ncount - 1]].fwd.next = &(lltour[cyc[0]].fwd); + lltour[cyc[ncount - 1]].bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].bwd.mark = 0; + lltour[cyc[ncount - 1]].bwd.dir = BACKWARD_TOUR; + lltour[cyc[ncount - 1]].bwd.orient = 0; + lltour[cyc[ncount - 1]].bwd.next = &(lltour[cyc[ncount - 2]].bwd); + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].fwd.name = cyc[i]; + lltour[cyc[i]].fwd.mark = 0; + lltour[cyc[i]].fwd.dir = FORWARD_TOUR; + lltour[cyc[i]].fwd.orient = 0; + lltour[cyc[i]].fwd.next = &(lltour[cyc[i + 1]].fwd); + lltour[cyc[i]].bwd.name = cyc[i]; + lltour[cyc[i]].bwd.mark = 0; + lltour[cyc[i]].bwd.dir = BACKWARD_TOUR; + lltour[cyc[i]].bwd.orient = 0; + lltour[cyc[i]].bwd.next = &(lltour[cyc[i - 1]].bwd); + } + orientnodes[0] = &(lltour[cyc[0]]); + orientnodes[1] = &(lltour[cyc[ncount/2]]); + lltour[cyc[0]].fwd.orient = 1; + lltour[cyc[0]].bwd.orient = 1; + lltour[cyc[ncount/2]].fwd.orient = 1; + lltour[cyc[ncount/2]].bwd.orient = 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = &(lltour[s].fwd); + + while (!n->orient) + n = n->next; + + return (n->dir != FORWARD_TOUR); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + n = start = (find_orientation (0) ? &(lltour[0].bwd) : &(lltour[0].fwd)); + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd.next->name; + else + return lltour[x].fwd.next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd.next->name; + else + return lltour[x].bwd.next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + int xnext, yprev; + + if (x == y) + return; + + orientnodes[0]->fwd.orient = 0; + orientnodes[0]->bwd.orient = 0; + orientnodes[1]->fwd.orient = 0; + orientnodes[1]->bwd.orient = 0; + orientnodes[0] = &(lltour[x]); + orientnodes[1] = &(lltour[y]); + orientnodes[0]->fwd.orient = 1; + orientnodes[0]->bwd.orient = 1; + orientnodes[1]->fwd.orient = 1; + orientnodes[1]->bwd.orient = 1; + + if (lltour[x].bwd.next->name == xprev) + xnext = lltour[x].fwd.next->name; + else + xnext = lltour[x].bwd.next->name; + + if (lltour[y].bwd.next->name == ynext) + yprev = lltour[y].fwd.next->name; + else + yprev = lltour[y].bwd.next->name; + + if (xprev == y) { + if (lltour[xnext].fwd.next->name == x) { + lltour[xnext].fwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].bwd); + } else { + lltour[xnext].bwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].fwd); + } + + if (lltour[yprev].fwd.next->name == y) { + lltour[yprev].fwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].bwd); + } else { + lltour[yprev].bwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].fwd); + } + + lltour[x].fwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[x].bwd); + } else if (xnext == y) { + if (lltour[xprev].fwd.next->name == x) { + lltour[xprev].fwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].bwd); + } else { + lltour[xprev].bwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].fwd); + } + + if (lltour[ynext].bwd.next->name == y) { + lltour[ynext].bwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[ynext].fwd); + } else { + lltour[ynext].fwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[ynext].bwd); + } + + lltour[x].bwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[x].fwd); + } else { + if (xnext == yprev) { + if (lltour[xnext].bwd.next->name == x) { + lltour[xnext].bwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].fwd); + lltour[xnext].fwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].bwd); + } else { + lltour[xnext].fwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].bwd); + lltour[xnext].bwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].fwd); + } + } else { + if (lltour[xnext].bwd.next->name == x) { + lltour[xnext].bwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].fwd); + } else { + lltour[xnext].fwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].bwd); + } + if (lltour[yprev].fwd.next->name == y) { + lltour[yprev].fwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].bwd); + } else { + lltour[yprev].bwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].fwd); + } + } + + if (xprev == ynext) { + if (lltour[xprev].fwd.next->name == x) { + lltour[xprev].fwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].bwd); + lltour[xprev].bwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[xprev].fwd); + } else { + lltour[xprev].bwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].fwd); + lltour[xprev].fwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[xprev].bwd); + } + } else { + if (lltour[ynext].bwd.next->name == y) { + lltour[ynext].bwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[ynext].fwd); + } else { + lltour[ynext].fwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[ynext].bwd); + } + if (lltour[xprev].fwd.next->name == x) { + lltour[xprev].fwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].bwd); + } else { + lltour[xprev].bwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].fwd); + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *n; + + if (x == z || x == y) { + return 1; + } else { + lltour[y].fwd.mark = 1; + lltour[y].bwd.mark = 1; + lltour[z].fwd.mark = 1; + lltour[z].bwd.mark = 1; + + if (find_orientation (x)) + n = &(lltour[x].bwd); + else + n = &(lltour[x].fwd); + + while (!n->mark) { + n = n->next; + } + lltour[y].fwd.mark = 0; + lltour[y].bwd.mark = 0; + lltour[z].fwd.mark = 0; + lltour[z].bwd.mark = 0; + + return (n->name == y); + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll5.c b/contrib/blossom/concorde97/LINKERN/flip_ll5.c new file mode 100644 index 0000000000000000000000000000000000000000..cef43db5563a04f6352076a906611b0013c77021 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll5.c @@ -0,0 +1,355 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Linked Lists (fwd & bwd) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* Like flip_ll4, but with fwd and bwd pointers. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 5 (flip_ll5.c): */ +/* */ +/* 1. Same as flip_ll4, but fwd and bwd are now pointers. */ +/* 2. The code is easier, and flips should be faster, but the hunts */ +/* should be slower(?). */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 + +typedef struct oneway { + struct oneway *next; + int name; + char dir; + char orient; + char mark; + char express; +} oneway; + +typedef struct llnode { + struct oneway actual_fwd; + struct oneway actual_bwd; + struct oneway *fwd; + struct oneway *bwd; + struct llnode *next_express; + struct llnode *prev_express; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static int + find_orientation (int s); + +#else + +static int + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static llnode *orientnodes[2]; +static cycle_size = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + cycle_size = ncount; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].actual_fwd.name = cyc[0]; + lltour[cyc[0]].actual_fwd.mark = 0; + lltour[cyc[0]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[0]].actual_fwd.orient = 0; + lltour[cyc[0]].actual_fwd.express = 0; + lltour[cyc[0]].actual_fwd.next = &(lltour[cyc[1]].actual_fwd); + lltour[cyc[0]].fwd = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[0]].actual_bwd.name = cyc[0]; + lltour[cyc[0]].actual_bwd.mark = 0; + lltour[cyc[0]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[0]].actual_bwd.orient = 0; + lltour[cyc[0]].actual_bwd.express = 0; + lltour[cyc[0]].actual_bwd.next = &(lltour[cyc[ncount - 1]].actual_bwd); + lltour[cyc[0]].bwd = &(lltour[cyc[0]].actual_bwd); + lltour[cyc[ncount - 1]].actual_fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_fwd.mark = 0; + lltour[cyc[ncount - 1]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[ncount - 1]].actual_fwd.orient = 0; + lltour[cyc[ncount - 1]].actual_fwd.express = 0; + lltour[cyc[ncount - 1]].actual_fwd.next = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[ncount - 1]].fwd = &(lltour[cyc[ncount - 1]].actual_fwd); + lltour[cyc[ncount - 1]].actual_bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_bwd.mark = 0; + lltour[cyc[ncount - 1]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[ncount - 1]].actual_bwd.orient = 0; + lltour[cyc[ncount - 1]].actual_bwd.express = 0; + lltour[cyc[ncount - 1]].actual_bwd.next = + &(lltour[cyc[ncount - 2]].actual_bwd); + lltour[cyc[ncount - 1]].bwd = &(lltour[cyc[ncount - 1]].actual_bwd); + + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].actual_fwd.name = cyc[i]; + lltour[cyc[i]].actual_fwd.mark = 0; + lltour[cyc[i]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[i]].actual_fwd.orient = 0; + lltour[cyc[i]].actual_fwd.express = 0; + lltour[cyc[i]].actual_fwd.next = &(lltour[cyc[i + 1]].actual_fwd); + lltour[cyc[i]].fwd = &(lltour[cyc[i]].actual_fwd); + lltour[cyc[i]].actual_bwd.name = cyc[i]; + lltour[cyc[i]].actual_bwd.mark = 0; + lltour[cyc[i]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[i]].actual_bwd.orient = 0; + lltour[cyc[i]].actual_bwd.express = 0; + lltour[cyc[i]].actual_bwd.next = &(lltour[cyc[i - 1]].actual_bwd); + lltour[cyc[i]].bwd = &(lltour[cyc[i]].actual_bwd); + } + orientnodes[0] = &(lltour[cyc[0]]); + orientnodes[1] = &(lltour[cyc[ncount/2]]); + lltour[cyc[0]].fwd->orient = 1; + lltour[cyc[0]].bwd->orient = 1; + lltour[cyc[ncount/2]].fwd->orient = 1; + lltour[cyc[ncount/2]].bwd->orient = 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = lltour[s].fwd; + + while (!n->orient) + n = n->next; + + return (n != lltour[n->name].fwd); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + start = (find_orientation (0) ? lltour[0].bwd : lltour[0].fwd); + n = start; + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd->next->name; + else + return lltour[x].fwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd->next->name; + else + return lltour[x].bwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + int xnext, yprev; + oneway *otemp; + + if (x == y) + return; + + orientnodes[0]->fwd->orient = 0; + orientnodes[0]->bwd->orient = 0; + orientnodes[1]->fwd->orient = 0; + orientnodes[1]->bwd->orient = 0; + orientnodes[0] = &(lltour[x]); + orientnodes[1] = &(lltour[y]); + orientnodes[0]->fwd->orient = 1; + orientnodes[0]->bwd->orient = 1; + orientnodes[1]->fwd->orient = 1; + orientnodes[1]->bwd->orient = 1; + + if (lltour[x].bwd->next->name == xprev) + xnext = lltour[x].fwd->next->name; + else + xnext = lltour[x].bwd->next->name; + + if (lltour[y].bwd->next->name == ynext) + yprev = lltour[y].fwd->next->name; + else + yprev = lltour[y].bwd->next->name; + + if (xprev == y) { + if (lltour[x].fwd->next->name != y) { + SWAP (lltour[x].fwd, lltour[x].bwd, otemp); + } + if (lltour[y].bwd->next->name != x) { + SWAP (lltour[y].fwd, lltour[y].bwd, otemp); + } + } else { + if (lltour[x].bwd->next->name == xprev) { + SWAP (lltour[x].fwd, lltour[x].bwd, otemp); + } + if (lltour[y].fwd->next->name == ynext) { + SWAP (lltour[y].fwd, lltour[y].bwd, otemp); + } + if (xprev == ynext) { + if (lltour[ynext].fwd->next->name == y) { + lltour[y].bwd->next = lltour[ynext].bwd; + lltour[x].fwd->next = lltour[ynext].fwd; + } else { + lltour[y].bwd->next = lltour[ynext].fwd; + lltour[x].fwd->next = lltour[ynext].bwd; + } + } else { + if (lltour[ynext].fwd->next->name == y) { + lltour[x].fwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].bwd; + } else { + lltour[x].fwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].bwd; + } + + if (lltour[xprev].fwd->next->name == x) { + lltour[y].bwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].fwd; + } else { + lltour[y].bwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].fwd; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *n; + + if (x == z || x == y) { + return 1; + } else { + lltour[y].fwd->mark = 1; + lltour[y].bwd->mark = 1; + lltour[z].fwd->mark = 1; + lltour[z].bwd->mark = 1; + + if (find_orientation (x)) + n = lltour[x].bwd; + else + n = lltour[x].fwd; + + while (!n->mark) { + n = n->next; + } + lltour[y].fwd->mark = 0; + lltour[y].bwd->mark = 0; + lltour[z].fwd->mark = 0; + lltour[z].bwd->mark = 0; + + return (n->name == y); + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll6.c b/contrib/blossom/concorde97/LINKERN/flip_ll6.c new file mode 100644 index 0000000000000000000000000000000000000000..24ffba99f6afc7c972a030dc540ef8a69cdcfb8c --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll6.c @@ -0,0 +1,467 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Linked Lists (express) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version uses 2-levels. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 6 (flip_ll6.c): */ +/* */ +/* 1. Like flip_ll5, but with an "express lane" subcircuit of about */ +/* sqrt (n) nodes. All nodes in the express lane have their fwd and */ +/* and bwd pointers correctly oriented. */ +/* 2. The express lane is maintained as a linked list with explicit */ +/* nexts and prevs. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 + +typedef struct oneway { + struct oneway *next; + int name; + char dir; + char mark; + char express; +} oneway; + +typedef struct llnode { + struct oneway actual_fwd; + struct oneway actual_bwd; + struct oneway *fwd; + struct oneway *bwd; + struct llnode *next_express; + struct llnode *prev_express; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + express_flip (int a, int b), + dump_cycle (void); +static int + find_orientation (int s); + +#else + +static void + express_flip (), + dump_cycle (); +static int + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static cycle_size = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j; + int groupsize; + + cycle_size = ncount; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].actual_fwd.name = cyc[0]; + lltour[cyc[0]].actual_fwd.mark = 0; + lltour[cyc[0]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[0]].actual_fwd.express = 0; + lltour[cyc[0]].actual_fwd.next = &(lltour[cyc[1]].actual_fwd); + lltour[cyc[0]].fwd = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[0]].actual_bwd.name = cyc[0]; + lltour[cyc[0]].actual_bwd.mark = 0; + lltour[cyc[0]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[0]].actual_bwd.express = 0; + lltour[cyc[0]].actual_bwd.next = &(lltour[cyc[ncount - 1]].actual_bwd); + lltour[cyc[0]].bwd = &(lltour[cyc[0]].actual_bwd); + lltour[cyc[ncount - 1]].actual_fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_fwd.mark = 0; + lltour[cyc[ncount - 1]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[ncount - 1]].actual_fwd.express = 0; + lltour[cyc[ncount - 1]].actual_fwd.next = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[ncount - 1]].fwd = &(lltour[cyc[ncount - 1]].actual_fwd); + lltour[cyc[ncount - 1]].actual_bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_bwd.mark = 0; + lltour[cyc[ncount - 1]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[ncount - 1]].actual_bwd.express = 0; + lltour[cyc[ncount - 1]].actual_bwd.next = + &(lltour[cyc[ncount - 2]].actual_bwd); + lltour[cyc[ncount - 1]].bwd = &(lltour[cyc[ncount - 1]].actual_bwd); + + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].actual_fwd.name = cyc[i]; + lltour[cyc[i]].actual_fwd.mark = 0; + lltour[cyc[i]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[i]].actual_fwd.express = 0; + lltour[cyc[i]].actual_fwd.next = &(lltour[cyc[i + 1]].actual_fwd); + lltour[cyc[i]].fwd = &(lltour[cyc[i]].actual_fwd); + lltour[cyc[i]].actual_bwd.name = cyc[i]; + lltour[cyc[i]].actual_bwd.mark = 0; + lltour[cyc[i]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[i]].actual_bwd.express = 0; + lltour[cyc[i]].actual_bwd.next = &(lltour[cyc[i - 1]].actual_bwd); + lltour[cyc[i]].bwd = &(lltour[cyc[i]].actual_bwd); + } + + groupsize = (int) sqrt ((double) ncount); + lltour[cyc[0]].actual_fwd.express = 1; + lltour[cyc[0]].actual_bwd.express = 1; + lltour[cyc[0]].next_express = &(lltour[cyc[groupsize]]); + i = groupsize; + j = ncount - groupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.express = 1; + lltour[cyc[i]].actual_bwd.express = 1; + lltour[cyc[i]].prev_express = &(lltour[cyc[i - groupsize]]); + lltour[cyc[i]].next_express = &(lltour[cyc[i + groupsize]]); + i += groupsize; + } + lltour[cyc[i]].actual_fwd.express = 1; + lltour[cyc[i]].actual_bwd.express = 1; + lltour[cyc[i]].next_express = &(lltour[cyc[0]]); + lltour[cyc[i]].prev_express = &(lltour[cyc[i - groupsize]]); + lltour[cyc[0]].prev_express = &(lltour[cyc[i]]); + + +/* + dump_cycle (); +*/ + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_cycle (void) +#else +static void dump_cycle () +#endif +{ + int *getit, i; + + getit = CC_SAFE_MALLOC (cycle_size, int); + CClinkern_flipper_cycle (getit); + + printf ("TOUR: "); + + for (i = 0; i < cycle_size; i++) + printf ("%2d ", getit[i]); + printf ("\n"); + fflush (stdout); + + { + llnode *n, *start; + oneway *p; + + printf ("Express TOUR: "); + p = (find_orientation (getit[0]) ? lltour[getit[0]].bwd : + lltour[getit[0]].fwd); + while (!p->express) + p = p->next; + + n = start = &(lltour[p->name]); + do { + printf ("%d ", n->fwd->name); + n = n->next_express; + } while (n != start); + printf ("\n"); + fflush (stdout); + } + + CC_FREE (getit, int); +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = lltour[s].fwd; + + while (!n->express) + n = n->next; + + return (n != lltour[n->name].fwd); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + start = (find_orientation (0) ? lltour[0].bwd : lltour[0].fwd); + n = start; + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd->next->name; + else + return lltour[x].fwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd->next->name; + else + return lltour[x].bwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *otemp; + + if (x == y) + return; + + if (lltour[x].bwd->next->name == xprev) + o = lltour[x].fwd; + else + o = lltour[x].bwd; + + while (!o->express && o->name != y) + o = o->next; + + if (o->express) { + if (lltour[y].fwd->next->name == ynext) + p = lltour[y].bwd; + else + p = lltour[y].fwd; + while (!p->express) + p = p->next; + express_flip (o->name, p->name); + } + + + if (x != ynext && xprev != ynext) { + if (lltour[ynext].fwd->next->name == y) { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].fwd; + } + } else { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].fwd; + } + } + + if (lltour[xprev].fwd->next->name == x) { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].fwd; + } + } else { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].fwd; + } + } + } else if (x != ynext) { + if (lltour[xprev].fwd->express) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void express_flip (int ix, int iy) +#else +static void express_flip (ix, iy) +int ix, iy; +#endif +{ + llnode *x = &(lltour[ix]); + llnode *y = &(lltour[iy]); + llnode *xprev, *ynext; + llnode *n, *next; + oneway *otemp; + + if (ix == iy) { + SWAP (x->fwd, x->bwd, otemp); + return; + } + + xprev = x->prev_express; + ynext = y->next_express; + + next = x->next_express; + x->next_express = x->prev_express; + x->prev_express = next; + SWAP (x->fwd, x->bwd, otemp); + + do { + n = next; + next = n->next_express; + n->next_express = n->prev_express; + n->prev_express = next; + SWAP (n->fwd, n->bwd, otemp); + } while (n != y); + + if (xprev != y) { + y->prev_express = xprev; + x->next_express = ynext; + xprev->next_express = y; + ynext->prev_express = x; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *next, *prev; + + if (x == z || x == y) { + return 1; + } else { + lltour[y].fwd->mark = 1; + lltour[y].bwd->mark = 1; + lltour[z].fwd->mark = 1; + lltour[z].bwd->mark = 1; + + if (find_orientation (x)) { + next = lltour[x].bwd; + prev = lltour[x].fwd; + } else { + next = lltour[x].fwd; + prev = lltour[x].bwd; + } + + while (!next->mark && !prev->mark) { + next = next->next; + prev = prev->next; + } + + if (next->mark) { + lltour[y].fwd->mark = 0; + lltour[y].bwd->mark = 0; + lltour[z].fwd->mark = 0; + lltour[z].bwd->mark = 0; + return (next->name == y); + } else { + lltour[y].fwd->mark = 0; + lltour[y].bwd->mark = 0; + lltour[z].fwd->mark = 0; + lltour[z].bwd->mark = 0; + return (prev->name == z); + } + } +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll7.c b/contrib/blossom/concorde97/LINKERN/flip_ll7.c new file mode 100644 index 0000000000000000000000000000000000000000..aefb72d4df5371d56dd348eec4b077a42ac37290 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll7.c @@ -0,0 +1,520 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Linked Lists (fwd & bwd) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* Like FLIPPER 6, but with reversal bit for the express cycle, and */ +/* and smaller groupsize (since flipping should be faster on bigger */ +/* cycles, so we can use the smaller groupsize to pick up the speed of */ +/* of the orientation finding routines). */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 7 (flip_ll7.c): */ +/* */ +/* 1. Like flip_ll6, but with reversal and smaller groupsize. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 + +typedef struct oneway { + struct oneway *next; + int name; + char dir; + char mark; + char express; +} oneway; + +typedef struct llnode { + struct oneway actual_fwd; + struct oneway actual_bwd; + struct oneway *fwd; + struct oneway *bwd; + struct llnode *next_express; + struct llnode *prev_express; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + express_flip (int a, int b); +static int + find_orientation (int s); + +#else + +static void + express_flip (); +static int + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static int cycle_size = 0; +static int reversed = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j; + int groupsize; + + cycle_size = ncount; + reversed = 0; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].actual_fwd.name = cyc[0]; + lltour[cyc[0]].actual_fwd.mark = 0; + lltour[cyc[0]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[0]].actual_fwd.express = 0; + lltour[cyc[0]].actual_fwd.next = &(lltour[cyc[1]].actual_fwd); + lltour[cyc[0]].fwd = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[0]].actual_bwd.name = cyc[0]; + lltour[cyc[0]].actual_bwd.mark = 0; + lltour[cyc[0]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[0]].actual_bwd.express = 0; + lltour[cyc[0]].actual_bwd.next = &(lltour[cyc[ncount - 1]].actual_bwd); + lltour[cyc[0]].bwd = &(lltour[cyc[0]].actual_bwd); + lltour[cyc[ncount - 1]].actual_fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_fwd.mark = 0; + lltour[cyc[ncount - 1]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[ncount - 1]].actual_fwd.express = 0; + lltour[cyc[ncount - 1]].actual_fwd.next = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[ncount - 1]].fwd = &(lltour[cyc[ncount - 1]].actual_fwd); + lltour[cyc[ncount - 1]].actual_bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_bwd.mark = 0; + lltour[cyc[ncount - 1]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[ncount - 1]].actual_bwd.express = 0; + lltour[cyc[ncount - 1]].actual_bwd.next = + &(lltour[cyc[ncount - 2]].actual_bwd); + lltour[cyc[ncount - 1]].bwd = &(lltour[cyc[ncount - 1]].actual_bwd); + + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].actual_fwd.name = cyc[i]; + lltour[cyc[i]].actual_fwd.mark = 0; + lltour[cyc[i]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[i]].actual_fwd.express = 0; + lltour[cyc[i]].actual_fwd.next = &(lltour[cyc[i + 1]].actual_fwd); + lltour[cyc[i]].fwd = &(lltour[cyc[i]].actual_fwd); + lltour[cyc[i]].actual_bwd.name = cyc[i]; + lltour[cyc[i]].actual_bwd.mark = 0; + lltour[cyc[i]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[i]].actual_bwd.express = 0; + lltour[cyc[i]].actual_bwd.next = &(lltour[cyc[i - 1]].actual_bwd); + lltour[cyc[i]].bwd = &(lltour[cyc[i]].actual_bwd); + } + + groupsize = (int) (sqrt ((double) ncount) / 4.0); + if (groupsize < 3) + groupsize = 3; + lltour[cyc[0]].actual_fwd.express = 1; + lltour[cyc[0]].actual_bwd.express = 1; + lltour[cyc[0]].next_express = &(lltour[cyc[groupsize]]); + i = groupsize; + j = ncount - groupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.express = 1; + lltour[cyc[i]].actual_bwd.express = 1; + lltour[cyc[i]].prev_express = &(lltour[cyc[i - groupsize]]); + lltour[cyc[i]].next_express = &(lltour[cyc[i + groupsize]]); + i += groupsize; + } + lltour[cyc[i]].actual_fwd.express = 1; + lltour[cyc[i]].actual_bwd.express = 1; + lltour[cyc[i]].next_express = &(lltour[cyc[0]]); + lltour[cyc[i]].prev_express = &(lltour[cyc[i - groupsize]]); + lltour[cyc[0]].prev_express = &(lltour[cyc[i]]); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = lltour[s].fwd; + + while (!n->express) + n = n->next; + + if (reversed) + return (n != lltour[n->name].bwd); + else + return (n != lltour[n->name].fwd); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + start = (find_orientation (0) ? lltour[0].bwd : lltour[0].fwd); + n = start; + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd->next->name; + else + return lltour[x].fwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd->next->name; + else + return lltour[x].bwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *otemp; + + if (x == y) + return; + + if (lltour[x].bwd->next->name == xprev) + o = lltour[x].fwd; + else + o = lltour[x].bwd; + + while (!o->express && o->name != y) + o = o->next; + + if (o->express) { + if (lltour[y].fwd->next->name == ynext) + p = lltour[y].bwd; + else + p = lltour[y].fwd; + while (!p->express) + p = p->next; + express_flip (o->name, p->name); + } + + + if (x != ynext && xprev != ynext) { + if (lltour[ynext].fwd->next->name == y) { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].fwd; + } + } else { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].fwd; + } + } + + if (lltour[xprev].fwd->next->name == x) { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].fwd; + } + } else { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].fwd; + } + } + } else if (x != ynext) { + if (lltour[xprev].fwd->express) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void express_flip (int ix, int iy) +#else +static void express_flip (ix, iy) +int ix, iy; +#endif +{ + llnode *x = &(lltour[ix]); + llnode *y = &(lltour[iy]); + llnode *xprev, *ynext; + llnode *n, *next, *prev; + oneway *otemp; + + if (x == y) { + SWAP (x->fwd, x->bwd, otemp); + return; + } + + if (reversed) { + xprev = x->next_express; + if (xprev == y) { + reversed = 0; + return; + } + ynext = y->prev_express; + + next = x->prev_express; + prev = xprev->next_express; + + while (next != y && prev != ynext) { + next = next->prev_express; + prev = prev->next_express; + } + + if (next == y) { + next = x->prev_express; + x->prev_express = x->next_express; + x->next_express = next; + SWAP (x->fwd, x->bwd, otemp); + + do { + n = next; + next = n->prev_express; + n->prev_express = n->next_express; + n->next_express = next; + SWAP (n->fwd, n->bwd, otemp); + } while (n != y); + + if (xprev != y) { + y->next_express = xprev; + x->prev_express = ynext; + xprev->prev_express = y; + ynext->next_express = x; + } + } else { + prev = xprev->next_express; + xprev->next_express = xprev->prev_express; + xprev->prev_express = prev; + SWAP (xprev->fwd, xprev->bwd, otemp); + + do { + n = prev; + prev = n->next_express; + n->next_express = n->prev_express; + n->prev_express = prev; + SWAP (n->fwd, n->bwd, otemp); + } while (n != ynext); + + if (xprev != y) { + y->prev_express = xprev; + x->next_express = ynext; + xprev->next_express = y; + ynext->prev_express = x; + } + reversed = 0; + } + } else { + xprev = x->prev_express; + if (xprev == y) { + reversed = 1; + return; + } + ynext = y->next_express; + + next = x->next_express; + prev = xprev->prev_express; + + while (next != y && prev != ynext) { + next = next->next_express; + prev = prev->prev_express; + } + + if (next == y) { + next = x->next_express; + x->next_express = x->prev_express; + x->prev_express = next; + SWAP (x->fwd, x->bwd, otemp); + + do { + n = next; + next = n->next_express; + n->next_express = n->prev_express; + n->prev_express = next; + SWAP (n->fwd, n->bwd, otemp); + } while (n != y); + + if (xprev != y) { + y->prev_express = xprev; + x->next_express = ynext; + xprev->next_express = y; + ynext->prev_express = x; + } + } else { + prev = xprev->prev_express; + xprev->prev_express = xprev->next_express; + xprev->next_express = prev; + SWAP (xprev->fwd, xprev->bwd, otemp); + + do { + n = prev; + prev = n->prev_express; + n->prev_express = n->next_express; + n->next_express = prev; + SWAP (n->fwd, n->bwd, otemp); + } while (n != ynext); + + if (xprev != y) { + y->next_express = xprev; + x->prev_express = ynext; + xprev->prev_express = y; + ynext->next_express = x; + } + reversed = 1; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *next, *prev; + + if (x == z || x == y) { + return 1; + } else { + lltour[y].fwd->mark = 1; + lltour[y].bwd->mark = 1; + lltour[z].fwd->mark = 1; + lltour[z].bwd->mark = 1; + + if (find_orientation (x)) { + next = lltour[x].bwd; + prev = lltour[x].fwd; + } else { + next = lltour[x].fwd; + prev = lltour[x].bwd; + } + + while (!next->mark && !prev->mark) { + next = next->next; + prev = prev->next; + } + + if (next->mark) { + lltour[y].fwd->mark = 0; + lltour[y].bwd->mark = 0; + lltour[z].fwd->mark = 0; + lltour[z].bwd->mark = 0; + return (next->name == y); + } else { + lltour[y].fwd->mark = 0; + lltour[y].bwd->mark = 0; + lltour[z].fwd->mark = 0; + lltour[z].bwd->mark = 0; + return (prev->name == z); + } + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll8.c b/contrib/blossom/concorde97/LINKERN/flip_ll8.c new file mode 100644 index 0000000000000000000000000000000000000000..c8a98c0f2bbdde886fa15b9dae9b465775b91f67 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll8.c @@ -0,0 +1,731 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - 3-Level Linked List */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: June 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version should be the best of the linked lists so far. */ +/* It combines the oneway approach, with three levels for an express */ +/* lane and a superexpress lane. Note that all superexpress nodes are */ +/* also express nodes. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 8 (flip_ll8.c): */ +/* */ +/* 1. Uses three levels, the top having n**(1/3) nodes. */ +/* 2. The top level has explicit next and prevs, the other levels */ +/* consist of two "oneway" cycles. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 + +typedef struct oneway { + struct oneway *next; + int name; + char mark; + char level; +} oneway; + +typedef struct llnode { + struct oneway actual_fwd; + struct oneway actual_bwd; + struct oneway actual_fwd_express; + struct oneway actual_bwd_express; + struct oneway *fwd; + struct oneway *bwd; + struct oneway *fwd_express; + struct oneway *bwd_express; + struct llnode *next_super; + struct llnode *prev_super; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + express_flip (int aprev, int a, int b, int bnext), + super_flip (int a, int b); +static int + express_flipper_sequence (int x, int y, int z), + find_orientation (int s); + +#else + +static void + express_flip (), + super_flip (); +static int + express_flipper_sequence (), + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static int cycle_size = 0; +static int reversed = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j; + int groupsize, supergroupsize; + + cycle_size = ncount; + reversed = 0; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].actual_fwd.name = cyc[0]; + lltour[cyc[0]].actual_fwd.mark = 0; + lltour[cyc[0]].actual_fwd.level = 0; + lltour[cyc[0]].actual_fwd.next = &(lltour[cyc[1]].actual_fwd); + lltour[cyc[0]].fwd = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[0]].actual_bwd.name = cyc[0]; + lltour[cyc[0]].actual_bwd.mark = 0; + lltour[cyc[0]].actual_bwd.level = 0; + lltour[cyc[0]].actual_bwd.next = &(lltour[cyc[ncount - 1]].actual_bwd); + lltour[cyc[0]].bwd = &(lltour[cyc[0]].actual_bwd); + lltour[cyc[ncount - 1]].actual_fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_fwd.mark = 0; + lltour[cyc[ncount - 1]].actual_fwd.level = 0; + lltour[cyc[ncount - 1]].actual_fwd.next = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[ncount - 1]].fwd = &(lltour[cyc[ncount - 1]].actual_fwd); + lltour[cyc[ncount - 1]].actual_bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_bwd.mark = 0; + lltour[cyc[ncount - 1]].actual_bwd.level = 0; + lltour[cyc[ncount - 1]].actual_bwd.next = + &(lltour[cyc[ncount - 2]].actual_bwd); + lltour[cyc[ncount - 1]].bwd = &(lltour[cyc[ncount - 1]].actual_bwd); + + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].actual_fwd.name = cyc[i]; + lltour[cyc[i]].actual_fwd.mark = 0; + lltour[cyc[i]].actual_fwd.level = 0; + lltour[cyc[i]].actual_fwd.next = &(lltour[cyc[i + 1]].actual_fwd); + lltour[cyc[i]].fwd = &(lltour[cyc[i]].actual_fwd); + lltour[cyc[i]].actual_bwd.name = cyc[i]; + lltour[cyc[i]].actual_bwd.mark = 0; + lltour[cyc[i]].actual_bwd.level = 0; + lltour[cyc[i]].actual_bwd.next = &(lltour[cyc[i - 1]].actual_bwd); + lltour[cyc[i]].bwd = &(lltour[cyc[i]].actual_bwd); + } + + groupsize = (int) (pow ((double) ncount, 1.0 / 3.0)/ 1.5); + supergroupsize = groupsize * groupsize; + lltour[cyc[0]].actual_fwd.level = 1; + lltour[cyc[0]].actual_bwd.level = 1; + lltour[cyc[0]].fwd_express = &(lltour[cyc[0]].actual_fwd_express); + lltour[cyc[0]].bwd_express = &(lltour[cyc[0]].actual_bwd_express); + lltour[cyc[0]].actual_fwd_express.mark = 0; + lltour[cyc[0]].actual_bwd_express.mark = 0; + lltour[cyc[0]].actual_fwd_express.level = 1; + lltour[cyc[0]].actual_bwd_express.level = 1; + lltour[cyc[0]].actual_fwd_express.name = cyc[0]; + lltour[cyc[0]].actual_bwd_express.name = cyc[0]; + lltour[cyc[0]].actual_fwd_express.next = + &(lltour[cyc[groupsize]].actual_fwd_express); + i = groupsize; + j = ncount - groupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 1; + lltour[cyc[i]].actual_bwd.level = 1; + lltour[cyc[i]].fwd_express = &(lltour[cyc[i]].actual_fwd_express); + lltour[cyc[i]].bwd_express = &(lltour[cyc[i]].actual_bwd_express); + lltour[cyc[i]].actual_fwd_express.mark = 0; + lltour[cyc[i]].actual_bwd_express.mark = 0; + lltour[cyc[i]].actual_fwd_express.level = 1; + lltour[cyc[i]].actual_bwd_express.level = 1; + lltour[cyc[i]].actual_fwd_express.name = cyc[i]; + lltour[cyc[i]].actual_bwd_express.name = cyc[i]; + lltour[cyc[i]].actual_fwd_express.next = + &(lltour[cyc[i + groupsize]].actual_fwd_express); + lltour[cyc[i]].actual_bwd_express.next = + &(lltour[cyc[i - groupsize]].actual_bwd_express); + i += groupsize; + } + + lltour[cyc[i]].actual_fwd.level = 1; + lltour[cyc[i]].actual_bwd.level = 1; + lltour[cyc[i]].fwd_express = &(lltour[cyc[i]].actual_fwd_express); + lltour[cyc[i]].bwd_express = &(lltour[cyc[i]].actual_bwd_express); + lltour[cyc[i]].actual_fwd_express.mark = 0; + lltour[cyc[i]].actual_bwd_express.mark = 0; + lltour[cyc[i]].actual_fwd_express.level = 1; + lltour[cyc[i]].actual_bwd_express.level = 1; + lltour[cyc[i]].actual_fwd_express.name = cyc[i]; + lltour[cyc[i]].actual_bwd_express.name = cyc[i]; + lltour[cyc[i]].actual_fwd_express.next = + &(lltour[cyc[0]].actual_fwd_express); + lltour[cyc[i]].actual_bwd_express.next = + &(lltour[cyc[i - groupsize]].actual_bwd_express); + lltour[cyc[0]].actual_bwd_express.next = + &(lltour[cyc[i]].actual_bwd_express); + + lltour[cyc[0]].actual_fwd.level = 2; + lltour[cyc[0]].actual_bwd.level = 2; + lltour[cyc[0]].actual_fwd_express.level = 2; + lltour[cyc[0]].actual_bwd_express.level = 2; + lltour[cyc[0]].next_super = &(lltour[cyc[supergroupsize]]); + i = supergroupsize; + j = ncount - supergroupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].prev_super = &(lltour[cyc[i - supergroupsize]]); + lltour[cyc[i]].next_super = &(lltour[cyc[i + supergroupsize]]); + i += supergroupsize; + } + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].next_super = &(lltour[cyc[0]]); + lltour[cyc[i]].prev_super = &(lltour[cyc[i - supergroupsize]]); + lltour[cyc[0]].prev_super = &(lltour[cyc[i]]); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = lltour[s].fwd; + + while (!n->level) + n = n->next; + + if (lltour[n->name].fwd == n) + n = lltour[n->name].fwd_express; + else + n = lltour[n->name].bwd_express; + + while (n->level != 2) + n = n->next; + + if (reversed) + return (n != lltour[n->name].bwd_express); + else + return (n != lltour[n->name].fwd_express); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + start = (find_orientation (0) ? lltour[0].bwd : lltour[0].fwd); + n = start; + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd->next->name; + else + return lltour[x].fwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd->next->name; + else + return lltour[x].bwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *oprev, *pnext; + + if (x == y) + return; + + if (lltour[x].bwd->next->name == xprev) + o = lltour[x].fwd; + else + o = lltour[x].bwd; + + while (!o->level && o->name != y) + o = o->next; + + if (o->level) { + if (lltour[o->name].fwd == o) + oprev = lltour[o->name].bwd->next; + else + oprev = lltour[o->name].fwd->next; + while (!oprev->level) + oprev = oprev->next; + if (lltour[y].fwd->next->name == ynext) + p = lltour[y].bwd; + else + p = lltour[y].fwd; + while (!p->level) + p = p->next; + if (lltour[p->name].fwd == p) + pnext = lltour[p->name].bwd->next; + else + pnext = lltour[p->name].fwd->next; + while (!pnext->level) + pnext = pnext->next; + express_flip (oprev->name, o->name, p->name, pnext->name); + } + + if (x != ynext && xprev != ynext) { + if (lltour[ynext].fwd->next->name == y) { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].fwd; + } + } else { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].fwd; + } + } + + if (lltour[xprev].fwd->next->name == x) { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].fwd; + } + } else { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].fwd; + } + } + } else if (x != ynext) { + oneway *otemp; + if (lltour[xprev].fwd->level) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void express_flip (int xprev, int x, int y, int ynext) +#else +static void express_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *otemp; + + if (x == y) { + SWAP (lltour[x].fwd, lltour[x].bwd, otemp); + return; + } else if (xprev == ynext) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + reversed ^= 1; + return; + } + + if (lltour[x].bwd_express->next->name == xprev) { + o = lltour[x].fwd_express; + } else { + o = lltour[x].bwd_express; + } + + while (o->level != 2 && o->name != y) + o = o->next; + + if (o->level == 2) { + if (lltour[y].fwd_express->next->name == ynext) + p = lltour[y].bwd_express; + else + p = lltour[y].fwd_express; + while (p->level != 2) + p = p->next; + super_flip (o->name, p->name); + } + + + if (x != ynext) { + if (lltour[ynext].fwd_express->next->name == y) { + if (lltour[x].fwd_express->next->name == xprev) { + lltour[x].fwd_express->next = lltour[ynext].bwd_express; + lltour[ynext].fwd_express->next = lltour[x].bwd_express; + } else { + lltour[x].bwd_express->next = lltour[ynext].bwd_express; + lltour[ynext].fwd_express->next = lltour[x].fwd_express; + } + } else { + if (lltour[x].fwd_express->next->name == xprev) { + lltour[x].fwd_express->next = lltour[ynext].fwd_express; + lltour[ynext].bwd_express->next = lltour[x].bwd_express; + } else { + lltour[x].bwd_express->next = lltour[ynext].fwd_express; + lltour[ynext].bwd_express->next = lltour[x].fwd_express; + } + } + + if (lltour[xprev].fwd_express->next->name == x) { + if (lltour[y].fwd_express->next->name == ynext) { + lltour[y].fwd_express->next = lltour[xprev].bwd_express; + lltour[xprev].fwd_express->next = lltour[y].bwd_express; + } else { + lltour[y].bwd_express->next = lltour[xprev].bwd_express; + lltour[xprev].fwd_express->next = lltour[y].fwd_express; + } + } else { + if (lltour[y].fwd_express->next->name == ynext) { + lltour[y].fwd_express->next = lltour[xprev].fwd_express; + lltour[xprev].bwd_express->next = lltour[y].bwd_express; + } else { + lltour[y].bwd_express->next = lltour[xprev].fwd_express; + lltour[xprev].bwd_express->next = lltour[y].fwd_express; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void super_flip (int ix, int iy) +#else +static void super_flip (ix, iy) +int ix, iy; +#endif +{ + llnode *x = &(lltour[ix]); + llnode *y = &(lltour[iy]); + llnode *xprev, *ynext; + llnode *n, *next, *prev; + oneway *otemp; + + if (x == y) { + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + return; + } + + if (reversed) { + xprev = x->next_super; + ynext = y->prev_super; + + next = x->prev_super; + prev = xprev->next_super; + + while (next != y && prev != ynext) { + next = next->prev_super; + prev = prev->next_super; + } + + if (next == y) { + next = x->prev_super; + x->prev_super = x->next_super; + x->next_super = next; + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + + do { + n = next; + next = n->prev_super; + n->prev_super = n->next_super; + n->next_super = next; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + } while (n != y); + + if (xprev != y) { + y->next_super = xprev; + x->prev_super = ynext; + xprev->prev_super = y; + ynext->next_super = x; + } + } else { + prev = xprev->next_super; + xprev->next_super = xprev->prev_super; + xprev->prev_super = prev; + SWAP (xprev->fwd_express, xprev->bwd_express, otemp); + SWAP (xprev->fwd, xprev->bwd, otemp); + + do { + n = prev; + prev = n->next_super; + n->next_super = n->prev_super; + n->prev_super = prev; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + } while (n != ynext); + + if (xprev != y) { + y->prev_super = xprev; + x->next_super = ynext; + xprev->next_super = y; + ynext->prev_super = x; + } + reversed = 0; + } + } else { + xprev = x->prev_super; + ynext = y->next_super; + + next = x->next_super; + prev = xprev->prev_super; + + while (next != y && prev != ynext) { + next = next->next_super; + prev = prev->prev_super; + } + + if (next == y) { + next = x->next_super; + x->next_super = x->prev_super; + x->prev_super = next; + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + + do { + n = next; + next = n->next_super; + n->next_super = n->prev_super; + n->prev_super = next; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + } while (n != y); + + if (xprev != y) { + y->prev_super = xprev; + x->next_super = ynext; + xprev->next_super = y; + ynext->prev_super = x; + } + } else { + prev = xprev->prev_super; + xprev->prev_super = xprev->next_super; + xprev->next_super = prev; + SWAP (xprev->fwd_express, xprev->bwd_express, otemp); + SWAP (xprev->fwd, xprev->bwd, otemp); + + do { + n = prev; + prev = n->prev_super; + n->prev_super = n->next_super; + n->next_super = prev; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + } while (n != ynext); + + if (xprev != y) { + y->next_super = xprev; + x->prev_super = ynext; + xprev->prev_super = y; + ynext->next_super = x; + } + reversed = 1; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *px, *py, *pz; + + if (x == z || x == y) + return 1; + if (find_orientation (x)) + px = lltour[x].bwd; + else + px = lltour[x].fwd; + while (!px->level) { + px = px->next; + if (px->name == y) + return 1; + else if (px->name == z) + return 0; + } + + if (z == y) + return 1; + if (find_orientation (z)) + pz = lltour[z].fwd; + else + pz = lltour[z].bwd; + while (!pz->level) { + pz = pz->next; + if (pz->name == y) { + return 1; + } else if (pz->name == x) { + return 0; + } else if (px->name == pz->name) { + return 0; + } + } + + if (find_orientation (y)) + py = lltour[y].bwd; + else + py = lltour[y].fwd; + while (!py->level) { + py = py->next; + if (py->name == z) { + return 1; + } else if (py->name == x) { + return 0; + } else if (py->name == pz->name) { + return 1; + } else if (py->name == px->name) { + return 0; + } + } + return express_flipper_sequence (px->name, py->name, pz->name); +} + +#ifdef CC_PROTOTYPE_ANSI +static int express_flipper_sequence (int x, int y, int z) +#else +static int express_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *next, *prev; + + lltour[y].fwd_express->mark = 1; + lltour[y].bwd_express->mark = 1; + lltour[z].fwd_express->mark = 1; + lltour[z].bwd_express->mark = 1; + + if (find_orientation (x)) { + next = lltour[x].bwd_express; + prev = lltour[x].fwd_express; + } else { + next = lltour[x].fwd_express; + prev = lltour[x].bwd_express; + } + + while (!next->mark && !prev->mark) { + next = next->next; + prev = prev->next; + } + + if (next->mark) { + lltour[y].fwd_express->mark = 0; + lltour[y].bwd_express->mark = 0; + lltour[z].fwd_express->mark = 0; + lltour[z].bwd_express->mark = 0; + return (next->name == y); + } else { + lltour[y].fwd_express->mark = 0; + lltour[y].bwd_express->mark = 0; + lltour[z].fwd_express->mark = 0; + lltour[z].bwd_express->mark = 0; + return (prev->name == z); + } +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_ll9.c b/contrib/blossom/concorde97/LINKERN/flip_ll9.c new file mode 100644 index 0000000000000000000000000000000000000000..f9e1011b6368c6001b4bffd02bcf6da02bcbb64b --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_ll9.c @@ -0,0 +1,299 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Basic Linked List w/ Rev */ +/* - USES INDEX */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version uses very little memory, and is reasonably fast */ +/* for small problems and for twoopts (but you should have SHORT_SIDE */ +/* defined so that the smaller side a flip is carried out. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 0 (flip_ll0.c): ADDS INDEX */ +/* */ +/* 1. Uses linked list with known prev and next. */ +/* 2. Tour reversal bit. */ +/* 2. Next and prev given explicitly. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +typedef struct llnode { + struct llnode *next; + struct llnode *prev; + int name; + int mark; + int index; +} llnode; + +static llnode *lltour = (llnode *) NULL; +static cycle_size = 0; +static int reversed = 0; + +#ifdef CC_PROTOTYPE_ANSI +static void + flipper_flip_work (int xprev, int x, int y, int ynext); +#else +static void + flipper_flip_work (); +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + cycle_size = ncount; + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + reversed = 0; + lltour[cyc[0]].name = cyc[0]; + lltour[cyc[0]].mark = 0; + lltour[cyc[0]].next = &(lltour[cyc[1]]); + lltour[cyc[0]].prev = &(lltour[cyc[ncount - 1]]); + lltour[cyc[0]].index = 0; + lltour[cyc[ncount - 1]].name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].mark = 0; + lltour[cyc[ncount - 1]].next = &(lltour[cyc[0]]); + lltour[cyc[ncount - 1]].prev = &(lltour[cyc[ncount - 2]]); + lltour[cyc[ncount - 1]].index = ncount - 1; + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].name = cyc[i]; + lltour[cyc[i]].mark = 0; + lltour[cyc[i]].next = &(lltour[cyc[i + 1]]); + lltour[cyc[i]].prev = &(lltour[cyc[i - 1]]); + lltour[cyc[i]].index = i; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + llnode *n, *start; + int k = 0; + + n = start = &(lltour[0]); + + if (reversed) { + do { + x[k++] = n->name; + n = n->prev; + } while (n != start && k < cycle_size); + } else { + do { + x[k++] = n->name; + n = n->next; + } while (n != start && k < cycle_size); + } + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (reversed) + return lltour[x].prev->name; + else + return lltour[x].next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (reversed) + return lltour[x].next->name; + else + return lltour[x].prev->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + int side; + + if (reversed) + side = lltour[x].index - lltour[y].index; + else + side = lltour[y].index - lltour[x].index; + if (side < 0) + side += cycle_size; + + if (side < cycle_size / 2) + flipper_flip_work (xprev, x, y, ynext); + else { + flipper_flip_work (y, ynext, xprev, x); + reversed ^= 1; + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static void flipper_flip_work (int xprev, int x, int y, int ynext) +#else +static void flipper_flip_work (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + llnode *nxprev = &(lltour[xprev]); + llnode *nynext = &(lltour[ynext]); + llnode *nx = &(lltour[x]); + llnode *ny = &(lltour[y]); + llnode *n, *next; + int id = lltour[x].index; + + if (x == y) + return; + + if (reversed) { + n = ny->next; + ny->next = ny->prev; + ny->prev = n; + ny->index = id--; + while (n != nx) { + next = n->next; + n->next = n->prev; + n->prev = next; + n->index = id--; + n = next; + } + next = nx->next; + nx->next = nx->prev; + nx->prev = next; + nx->index = id; + if (nxprev != ny) { + ny->next = nxprev; + nx->prev = nynext; + nxprev->prev = ny; + nynext->next = nx; + } + } else { + n = ny->prev; + ny->prev = ny->next; + ny->next = n; + ny->index = id++; + while (n != nx) { + next = n->prev; + n->prev = n->next; + n->next = next; + n->index = id++; + n = next; + } + next = nx->prev; + nx->prev = nx->next; + nx->next = next; + nx->index = id; + if (nxprev != ny) { + ny->prev = nxprev; + nx->next = nynext; + nxprev->next = ny; + nynext->prev = nx; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + int a = lltour[x].index; + int b = lltour[y].index; + int c = lltour[z].index; + + if (reversed) { + if (a >= b) + return (b >= c || c >= a); + else + return (b >= c && c >= a); + } else { + if (a <= b) + return (b <= c || c <= a); + else + return (b <= c && c <= a); + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_llA.c b/contrib/blossom/concorde97/LINKERN/flip_llA.c new file mode 100644 index 0000000000000000000000000000000000000000..d319eff2ee8c7b17ccafdf5fa5fde5a04a314295 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_llA.c @@ -0,0 +1,404 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Linked Lists (fwd & bwd) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version should be slow, since next and prev have to */ +/* hunt down an orientation node (since each node knows its neighbors */ +/* but not the direction), like flip_ll3, but the two copies of the tour */ +/* (one in each direction) lets us avoid lost of if tests during the */ +/* hunt. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 4 (flip_ll4.c): */ +/* */ +/* 1. Uses two linked lists (forward and backward) */ +/* 2. Need to track down a node of known orientation (the extra info */ +/* in the flips provides this). */ +/* 3. The hunt is done by a moving along one of the tours, till we hit */ +/* an orientation node that will tell us if we are on the forward */ +/* or backward tour. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 + +typedef struct oneway { + struct oneway *next; + int name; + char dir; + char orient; + char mark; +} oneway; + +typedef struct llnode { + struct oneway fwd; + struct oneway bwd; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static int + find_orientation (int s); + +#else + +static int + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static llnode *orientnodes[2]; +static cycle_size = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + cycle_size = ncount; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].fwd.name = cyc[0]; + lltour[cyc[0]].fwd.mark = 0; + lltour[cyc[0]].fwd.dir = FORWARD_TOUR; + lltour[cyc[0]].fwd.orient = 0; + lltour[cyc[0]].fwd.next = &(lltour[cyc[1]].fwd); + lltour[cyc[0]].bwd.name = cyc[0]; + lltour[cyc[0]].bwd.mark = 0; + lltour[cyc[0]].bwd.dir = BACKWARD_TOUR; + lltour[cyc[0]].bwd.orient = 0; + lltour[cyc[0]].bwd.next = &(lltour[cyc[ncount - 1]].bwd); + lltour[cyc[ncount - 1]].fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].fwd.mark = 0; + lltour[cyc[ncount - 1]].fwd.dir = FORWARD_TOUR; + lltour[cyc[ncount - 1]].fwd.orient = 0; + lltour[cyc[ncount - 1]].fwd.next = &(lltour[cyc[0]].fwd); + lltour[cyc[ncount - 1]].bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].bwd.mark = 0; + lltour[cyc[ncount - 1]].bwd.dir = BACKWARD_TOUR; + lltour[cyc[ncount - 1]].bwd.orient = 0; + lltour[cyc[ncount - 1]].bwd.next = &(lltour[cyc[ncount - 2]].bwd); + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].fwd.name = cyc[i]; + lltour[cyc[i]].fwd.mark = 0; + lltour[cyc[i]].fwd.dir = FORWARD_TOUR; + lltour[cyc[i]].fwd.orient = 0; + lltour[cyc[i]].fwd.next = &(lltour[cyc[i + 1]].fwd); + lltour[cyc[i]].bwd.name = cyc[i]; + lltour[cyc[i]].bwd.mark = 0; + lltour[cyc[i]].bwd.dir = BACKWARD_TOUR; + lltour[cyc[i]].bwd.orient = 0; + lltour[cyc[i]].bwd.next = &(lltour[cyc[i - 1]].bwd); + } + orientnodes[0] = &(lltour[cyc[0]]); + orientnodes[1] = &(lltour[cyc[ncount/2]]); + lltour[cyc[0]].fwd.orient = 1; + lltour[cyc[0]].bwd.orient = 1; + lltour[cyc[ncount/2]].fwd.orient = 1; + lltour[cyc[ncount/2]].bwd.orient = 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = &(lltour[s].fwd); + oneway *p = &(lltour[s].bwd); + + while (!n->orient && !p->orient) { + n = n->next; + p = p->next; + } + + if (n->orient) + return (n->dir != FORWARD_TOUR); + else + return (p->dir != BACKWARD_TOUR); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + n = start = (find_orientation (0) ? &(lltour[0].bwd) : &(lltour[0].fwd)); + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd.next->name; + else + return lltour[x].fwd.next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd.next->name; + else + return lltour[x].bwd.next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + int xnext, yprev; + + if (x == y) + return; + + orientnodes[0]->fwd.orient = 0; + orientnodes[0]->bwd.orient = 0; + orientnodes[1]->fwd.orient = 0; + orientnodes[1]->bwd.orient = 0; + orientnodes[0] = &(lltour[x]); + orientnodes[1] = &(lltour[y]); + orientnodes[0]->fwd.orient = 1; + orientnodes[0]->bwd.orient = 1; + orientnodes[1]->fwd.orient = 1; + orientnodes[1]->bwd.orient = 1; + + if (lltour[x].bwd.next->name == xprev) + xnext = lltour[x].fwd.next->name; + else + xnext = lltour[x].bwd.next->name; + + if (lltour[y].bwd.next->name == ynext) + yprev = lltour[y].fwd.next->name; + else + yprev = lltour[y].bwd.next->name; + + if (xprev == y) { + if (lltour[xnext].fwd.next->name == x) { + lltour[xnext].fwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].bwd); + } else { + lltour[xnext].bwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].fwd); + } + + if (lltour[yprev].fwd.next->name == y) { + lltour[yprev].fwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].bwd); + } else { + lltour[yprev].bwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].fwd); + } + + lltour[x].fwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[x].bwd); + } else if (xnext == y) { + if (lltour[xprev].fwd.next->name == x) { + lltour[xprev].fwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].bwd); + } else { + lltour[xprev].bwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].fwd); + } + + if (lltour[ynext].bwd.next->name == y) { + lltour[ynext].bwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[ynext].fwd); + } else { + lltour[ynext].fwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[ynext].bwd); + } + + lltour[x].bwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[x].fwd); + } else { + if (xnext == yprev) { + if (lltour[xnext].bwd.next->name == x) { + lltour[xnext].bwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].fwd); + lltour[xnext].fwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].bwd); + } else { + lltour[xnext].fwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].bwd); + lltour[xnext].bwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].fwd); + } + } else { + if (lltour[xnext].bwd.next->name == x) { + lltour[xnext].bwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].fwd); + } else { + lltour[xnext].fwd.next = &(lltour[x].fwd); + lltour[x].bwd.next = &(lltour[xnext].bwd); + } + if (lltour[yprev].fwd.next->name == y) { + lltour[yprev].fwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].bwd); + } else { + lltour[yprev].bwd.next = &(lltour[y].bwd); + lltour[y].fwd.next = &(lltour[yprev].fwd); + } + } + + if (xprev == ynext) { + if (lltour[xprev].fwd.next->name == x) { + lltour[xprev].fwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].bwd); + lltour[xprev].bwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[xprev].fwd); + } else { + lltour[xprev].bwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].fwd); + lltour[xprev].fwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[xprev].bwd); + } + } else { + if (lltour[ynext].bwd.next->name == y) { + lltour[ynext].bwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[ynext].fwd); + } else { + lltour[ynext].fwd.next = &(lltour[x].bwd); + lltour[x].fwd.next = &(lltour[ynext].bwd); + } + if (lltour[xprev].fwd.next->name == x) { + lltour[xprev].fwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].bwd); + } else { + lltour[xprev].bwd.next = &(lltour[y].fwd); + lltour[y].bwd.next = &(lltour[xprev].fwd); + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *n; + + if (x == z || x == y) { + return 1; + } else { + lltour[y].fwd.mark = 1; + lltour[y].bwd.mark = 1; + lltour[z].fwd.mark = 1; + lltour[z].bwd.mark = 1; + + if (find_orientation (x)) + n = &(lltour[x].bwd); + else + n = &(lltour[x].fwd); + + while (!n->mark) { + n = n->next; + } + lltour[y].fwd.mark = 0; + lltour[y].bwd.mark = 0; + lltour[z].fwd.mark = 0; + lltour[z].bwd.mark = 0; + + return (n->name == y); + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_llB.c b/contrib/blossom/concorde97/LINKERN/flip_llB.c new file mode 100644 index 0000000000000000000000000000000000000000..bd5c4954e9da895136c802f34acd880e3ccb5f55 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_llB.c @@ -0,0 +1,547 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Linked Lists (fwd & bwd) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* Like FLIPPER 6, but with reversal bit for the express cycle, and */ +/* and smaller groupsize (since flipping should be faster on bigger */ +/* cycles, so we can use the smaller groupsize to pick up the speed of */ +/* of the orientation finding routines). */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 7 (flip_ll7.c): (ADDS INDEX) */ +/* */ +/* 1. Like flip_ll6, but with reversal and smaller groupsize. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 +#define GROUP_FACTOR 8.0 + +typedef struct oneway { + struct oneway *next; + int name; + char dir; + char mark; + char express; +} oneway; + +typedef struct llnode { + struct oneway actual_fwd; + struct oneway actual_bwd; + struct oneway *fwd; + struct oneway *bwd; + struct llnode *next_express; + struct llnode *prev_express; + int index; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + express_flip (int a, int b), + express_flip_work (llnode *x, llnode *y); +static int + find_orientation (int s); + +#else + +static void + express_flip (), + express_flip_work (); +static int + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static int cycle_size = 0; +static int express_cycle_size = 0; +static int reversed = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j, k; + int groupsize; + + cycle_size = ncount; + reversed = 0; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].actual_fwd.name = cyc[0]; + lltour[cyc[0]].actual_fwd.mark = 0; + lltour[cyc[0]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[0]].actual_fwd.express = 0; + lltour[cyc[0]].actual_fwd.next = &(lltour[cyc[1]].actual_fwd); + lltour[cyc[0]].fwd = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[0]].actual_bwd.name = cyc[0]; + lltour[cyc[0]].actual_bwd.mark = 0; + lltour[cyc[0]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[0]].actual_bwd.express = 0; + lltour[cyc[0]].actual_bwd.next = &(lltour[cyc[ncount - 1]].actual_bwd); + lltour[cyc[0]].bwd = &(lltour[cyc[0]].actual_bwd); + lltour[cyc[ncount - 1]].actual_fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_fwd.mark = 0; + lltour[cyc[ncount - 1]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[ncount - 1]].actual_fwd.express = 0; + lltour[cyc[ncount - 1]].actual_fwd.next = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[ncount - 1]].fwd = &(lltour[cyc[ncount - 1]].actual_fwd); + lltour[cyc[ncount - 1]].actual_bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_bwd.mark = 0; + lltour[cyc[ncount - 1]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[ncount - 1]].actual_bwd.express = 0; + lltour[cyc[ncount - 1]].actual_bwd.next = + &(lltour[cyc[ncount - 2]].actual_bwd); + lltour[cyc[ncount - 1]].bwd = &(lltour[cyc[ncount - 1]].actual_bwd); + + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].actual_fwd.name = cyc[i]; + lltour[cyc[i]].actual_fwd.mark = 0; + lltour[cyc[i]].actual_fwd.dir = FORWARD_TOUR; + lltour[cyc[i]].actual_fwd.express = 0; + lltour[cyc[i]].actual_fwd.next = &(lltour[cyc[i + 1]].actual_fwd); + lltour[cyc[i]].fwd = &(lltour[cyc[i]].actual_fwd); + lltour[cyc[i]].actual_bwd.name = cyc[i]; + lltour[cyc[i]].actual_bwd.mark = 0; + lltour[cyc[i]].actual_bwd.dir = BACKWARD_TOUR; + lltour[cyc[i]].actual_bwd.express = 0; + lltour[cyc[i]].actual_bwd.next = &(lltour[cyc[i - 1]].actual_bwd); + lltour[cyc[i]].bwd = &(lltour[cyc[i]].actual_bwd); + } + + groupsize = (int) (sqrt ((double) ncount) / GROUP_FACTOR); + if (groupsize < 3) + groupsize = 3; + lltour[cyc[0]].actual_fwd.express = 1; + lltour[cyc[0]].actual_bwd.express = 1; + lltour[cyc[0]].next_express = &(lltour[cyc[groupsize]]); + lltour[cyc[0]].index = 0; + i = groupsize; + j = ncount - groupsize; + k = 1; + while (i < j) { + lltour[cyc[i]].actual_fwd.express = 1; + lltour[cyc[i]].actual_bwd.express = 1; + lltour[cyc[i]].prev_express = &(lltour[cyc[i - groupsize]]); + lltour[cyc[i]].next_express = &(lltour[cyc[i + groupsize]]); + lltour[cyc[i]].index = k++; + i += groupsize; + } + lltour[cyc[i]].actual_fwd.express = 1; + lltour[cyc[i]].actual_bwd.express = 1; + lltour[cyc[i]].index = k; + lltour[cyc[i]].next_express = &(lltour[cyc[0]]); + lltour[cyc[i]].prev_express = &(lltour[cyc[i - groupsize]]); + lltour[cyc[0]].prev_express = &(lltour[cyc[i]]); + express_cycle_size = k+1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = lltour[s].fwd; + + while (!n->express) + n = n->next; + + if (reversed) + return (n != lltour[n->name].bwd); + else + return (n != lltour[n->name].fwd); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + start = (find_orientation (0) ? lltour[0].bwd : lltour[0].fwd); + n = start; + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd->next->name; + else + return lltour[x].fwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd->next->name; + else + return lltour[x].bwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *otemp; + + if (x == y) + return; + + if (lltour[x].bwd->next->name == xprev) + o = lltour[x].fwd; + else + o = lltour[x].bwd; + + while (!o->express && o->name != y) + o = o->next; + + if (o->express) { + if (lltour[y].fwd->next->name == ynext) + p = lltour[y].bwd; + else + p = lltour[y].fwd; + while (!p->express) + p = p->next; + express_flip (o->name, p->name); + } + + + if (x != ynext && xprev != ynext) { + if (lltour[ynext].fwd->next->name == y) { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].fwd; + } + } else { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].fwd; + } + } + + if (lltour[xprev].fwd->next->name == x) { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].fwd; + } + } else { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].fwd; + } + } + } else if (x != ynext) { + if (lltour[xprev].fwd->express) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void express_flip (int ix, int iy) +#else +static void express_flip (ix, iy) +int ix, iy; +#endif +{ + int side; + llnode *x = &(lltour[ix]); + llnode *y = &(lltour[iy]); + llnode *xprev, *ynext; + oneway *otemp; + + if (x == y) { + SWAP (x->fwd, x->bwd, otemp); + return; + } + + if (reversed) { + xprev = lltour[ix].next_express; + ynext = lltour[iy].prev_express; + } else { + xprev = lltour[ix].prev_express; + ynext = lltour[iy].next_express; + } + + if (xprev == ynext) { + SWAP (xprev->fwd, xprev->bwd, otemp); + reversed ^= 1; + return; + } + + if (xprev == y) { + reversed ^= 1; + return; + } + + if (reversed) + side = x->index - y->index; + else + side = y->index - x->index; + if (side < 0) + side += express_cycle_size; + + if (side < express_cycle_size / 2) + express_flip_work (x, y); + else { + express_flip_work (ynext, xprev); + reversed ^= 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void express_flip_work (llnode *x, llnode *y) +#else +static void express_flip_work (x, y) +llnode *x, *y; +#endif +{ + llnode *xprev, *ynext; + llnode *n, *next; + oneway *otemp; + int id = x->index; + + if (reversed) { + xprev = x->next_express; + ynext = y->prev_express; + + n = y->next_express; + y->next_express = y->prev_express; + y->prev_express = n; + y->index = id--; + SWAP (y->fwd, y->bwd, otemp); + while (n != x) { + next = n->next_express; + n->next_express = n->prev_express; + n->prev_express = next; + n->index = id--; + SWAP (n->fwd, n->bwd, otemp); + n = next; + } + next = x->next_express; + x->next_express = x->prev_express; + x->prev_express = next; + x->index = id; + SWAP (x->fwd, x->bwd, otemp); + + y->next_express = xprev; + x->prev_express = ynext; + xprev->prev_express = y; + ynext->next_express = x; + } else { + xprev = x->prev_express; + ynext = y->next_express; + + n = y->prev_express; + y->prev_express = y->next_express; + y->next_express = n; + y->index = id++; + SWAP (y->fwd, y->bwd, otemp); + while (n != x) { + next = n->prev_express; + n->prev_express = n->next_express; + n->next_express = next; + n->index = id++; + SWAP (n->fwd, n->bwd, otemp); + n = next; + } + next = x->prev_express; + x->prev_express = x->next_express; + x->next_express = next; + x->index = id; + SWAP (x->fwd, x->bwd, otemp); + y->prev_express = xprev; + x->next_express = ynext; + xprev->next_express = y; + ynext->prev_express = x; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *px, *py, *pz; + int a, b, c; + + if (x == z || x == y) { + return 1; + } + + if (find_orientation (x)) + px = lltour[x].bwd; + else + px = lltour[x].fwd; + + while (!px->express) { + px = px->next; + if (px->name == y) { + return 1; + } else if (px->name == z) { + return 0; + } + } + + if (z == y) + return 1; + if (find_orientation (z)) + pz = lltour[z].fwd; + else + pz = lltour[z].bwd; + while (!pz->express) { + pz = pz->next; + if (pz->name == y) { + return 1; + } else if (pz->name == x) { + return 0; + } else if (px->name == pz->name) { + return 0; + } + } + + if (find_orientation (y)) + py = lltour[y].bwd; + else + py = lltour[y].fwd; + while (!py->express) { + py = py->next; + if (py->name == z) { + return 1; + } else if (py->name == x) { + return 0; + } else if (py->name == pz->name) { + return 1; + } else if (py->name == px->name) { + return 0; + } + } + + a = lltour[px->name].index; + b = lltour[py->name].index; + c = lltour[pz->name].index; + + if (reversed) { + if (a >= b) + return (b >= c || c >= a); + else + return (b >= c && c >= a); + } else { + if (a <= b) + return (b <= c || c <= a); + else + return (b <= c && c <= a); + } + +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_llC.c b/contrib/blossom/concorde97/LINKERN/flip_llC.c new file mode 100644 index 0000000000000000000000000000000000000000..b273ea02c032318e8f0518b17248e39a4af0762d --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_llC.c @@ -0,0 +1,812 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - 3-Level Linked List */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: June 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version should be the best of the linked lists so far. */ +/* It combines the oneway approach, with three levels for an express */ +/* lane and a superexpress lane. Note that all superexpress nodes are */ +/* also express nodes. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 8 (flip_ll8.c): */ +/* */ +/* 1. Uses three levels, the top having n**(1/3) nodes. */ +/* 2. The top level has explicit next and prevs, the other levels */ +/* consist of two "oneway" cycles. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 +#define GROUP_FACTOR 5.0 + +typedef struct oneway { + struct oneway *next; + int name; + char mark; + char level; +} oneway; + +typedef struct llnode { + struct oneway actual_fwd; + struct oneway actual_bwd; + struct oneway actual_fwd_express; + struct oneway actual_bwd_express; + struct oneway *fwd; + struct oneway *bwd; + struct oneway *fwd_express; + struct oneway *bwd_express; + struct llnode *next_super; + struct llnode *prev_super; + int index; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + express_flip (int aprev, int a, int b, int bnext), + super_flip (int a, int b), + super_flip_work (llnode *a, llnode *b); +static int + express_flipper_sequence (int x, int y, int z), + find_orientation (int s); + +#else + +static void + express_flip (), + super_flip (), + super_flip_work (); +static int + express_flipper_sequence (), + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static int cycle_size = 0; +static int super_cycle_size = 0; +static int reversed = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j, k; + int groupsize, supergroupsize; + + cycle_size = ncount; + reversed = 0; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].actual_fwd.name = cyc[0]; + lltour[cyc[0]].actual_fwd.mark = 0; + lltour[cyc[0]].actual_fwd.level = 0; + lltour[cyc[0]].actual_fwd.next = &(lltour[cyc[1]].actual_fwd); + lltour[cyc[0]].fwd = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[0]].actual_bwd.name = cyc[0]; + lltour[cyc[0]].actual_bwd.mark = 0; + lltour[cyc[0]].actual_bwd.level = 0; + lltour[cyc[0]].actual_bwd.next = &(lltour[cyc[ncount - 1]].actual_bwd); + lltour[cyc[0]].bwd = &(lltour[cyc[0]].actual_bwd); + lltour[cyc[ncount - 1]].actual_fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_fwd.mark = 0; + lltour[cyc[ncount - 1]].actual_fwd.level = 0; + lltour[cyc[ncount - 1]].actual_fwd.next = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[ncount - 1]].fwd = &(lltour[cyc[ncount - 1]].actual_fwd); + lltour[cyc[ncount - 1]].actual_bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_bwd.mark = 0; + lltour[cyc[ncount - 1]].actual_bwd.level = 0; + lltour[cyc[ncount - 1]].actual_bwd.next = + &(lltour[cyc[ncount - 2]].actual_bwd); + lltour[cyc[ncount - 1]].bwd = &(lltour[cyc[ncount - 1]].actual_bwd); + + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].actual_fwd.name = cyc[i]; + lltour[cyc[i]].actual_fwd.mark = 0; + lltour[cyc[i]].actual_fwd.level = 0; + lltour[cyc[i]].actual_fwd.next = &(lltour[cyc[i + 1]].actual_fwd); + lltour[cyc[i]].fwd = &(lltour[cyc[i]].actual_fwd); + lltour[cyc[i]].actual_bwd.name = cyc[i]; + lltour[cyc[i]].actual_bwd.mark = 0; + lltour[cyc[i]].actual_bwd.level = 0; + lltour[cyc[i]].actual_bwd.next = &(lltour[cyc[i - 1]].actual_bwd); + lltour[cyc[i]].bwd = &(lltour[cyc[i]].actual_bwd); + } + + groupsize = (int) (pow ((double) ncount, 1.0 / 3.0)/ GROUP_FACTOR); + supergroupsize = groupsize * groupsize; + lltour[cyc[0]].actual_fwd.level = 1; + lltour[cyc[0]].actual_bwd.level = 1; + lltour[cyc[0]].fwd_express = &(lltour[cyc[0]].actual_fwd_express); + lltour[cyc[0]].bwd_express = &(lltour[cyc[0]].actual_bwd_express); + lltour[cyc[0]].actual_fwd_express.mark = 0; + lltour[cyc[0]].actual_bwd_express.mark = 0; + lltour[cyc[0]].actual_fwd_express.level = 1; + lltour[cyc[0]].actual_bwd_express.level = 1; + lltour[cyc[0]].actual_fwd_express.name = cyc[0]; + lltour[cyc[0]].actual_bwd_express.name = cyc[0]; + lltour[cyc[0]].actual_fwd_express.next = + &(lltour[cyc[groupsize]].actual_fwd_express); + i = groupsize; + j = ncount - groupsize; + k = 1; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 1; + lltour[cyc[i]].actual_bwd.level = 1; + lltour[cyc[i]].fwd_express = &(lltour[cyc[i]].actual_fwd_express); + lltour[cyc[i]].bwd_express = &(lltour[cyc[i]].actual_bwd_express); + lltour[cyc[i]].actual_fwd_express.mark = 0; + lltour[cyc[i]].actual_bwd_express.mark = 0; + lltour[cyc[i]].actual_fwd_express.level = 1; + lltour[cyc[i]].actual_bwd_express.level = 1; + lltour[cyc[i]].actual_fwd_express.name = cyc[i]; + lltour[cyc[i]].actual_bwd_express.name = cyc[i]; + lltour[cyc[i]].actual_fwd_express.next = + &(lltour[cyc[i + groupsize]].actual_fwd_express); + lltour[cyc[i]].actual_bwd_express.next = + &(lltour[cyc[i - groupsize]].actual_bwd_express); + i += groupsize; + } + + lltour[cyc[i]].actual_fwd.level = 1; + lltour[cyc[i]].actual_bwd.level = 1; + lltour[cyc[i]].fwd_express = &(lltour[cyc[i]].actual_fwd_express); + lltour[cyc[i]].bwd_express = &(lltour[cyc[i]].actual_bwd_express); + lltour[cyc[i]].actual_fwd_express.mark = 0; + lltour[cyc[i]].actual_bwd_express.mark = 0; + lltour[cyc[i]].actual_fwd_express.level = 1; + lltour[cyc[i]].actual_bwd_express.level = 1; + lltour[cyc[i]].actual_fwd_express.name = cyc[i]; + lltour[cyc[i]].actual_bwd_express.name = cyc[i]; + lltour[cyc[i]].actual_fwd_express.next = + &(lltour[cyc[0]].actual_fwd_express); + lltour[cyc[i]].actual_bwd_express.next = + &(lltour[cyc[i - groupsize]].actual_bwd_express); + lltour[cyc[0]].actual_bwd_express.next = + &(lltour[cyc[i]].actual_bwd_express); + + lltour[cyc[0]].actual_fwd.level = 2; + lltour[cyc[0]].actual_bwd.level = 2; + lltour[cyc[0]].actual_fwd_express.level = 2; + lltour[cyc[0]].actual_bwd_express.level = 2; + lltour[cyc[0]].next_super = &(lltour[cyc[supergroupsize]]); + lltour[cyc[0]].index = 0; + i = supergroupsize; + j = ncount - supergroupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].prev_super = &(lltour[cyc[i - supergroupsize]]); + lltour[cyc[i]].next_super = &(lltour[cyc[i + supergroupsize]]); + lltour[cyc[i]].index = k++; + i += supergroupsize; + } + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].next_super = &(lltour[cyc[0]]); + lltour[cyc[i]].prev_super = &(lltour[cyc[i - supergroupsize]]); + lltour[cyc[0]].prev_super = &(lltour[cyc[i]]); + lltour[cyc[i]].index = k; + super_cycle_size = k + 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = lltour[s].fwd; + + while (!n->level) + n = n->next; + + if (lltour[n->name].fwd == n) + n = lltour[n->name].fwd_express; + else + n = lltour[n->name].bwd_express; + + while (n->level != 2) + n = n->next; + + if (reversed) + return (n != lltour[n->name].bwd_express); + else + return (n != lltour[n->name].fwd_express); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + start = (find_orientation (0) ? lltour[0].bwd : lltour[0].fwd); + n = start; + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd->next->name; + else + return lltour[x].fwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd->next->name; + else + return lltour[x].bwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *oprev, *pnext; + + if (x == y) + return; + + if (lltour[x].bwd->next->name == xprev) + o = lltour[x].fwd; + else + o = lltour[x].bwd; + + while (!o->level && o->name != y) + o = o->next; + + if (o->level) { + if (lltour[o->name].fwd == o) + oprev = lltour[o->name].bwd->next; + else + oprev = lltour[o->name].fwd->next; + while (!oprev->level) + oprev = oprev->next; + if (lltour[y].fwd->next->name == ynext) + p = lltour[y].bwd; + else + p = lltour[y].fwd; + while (!p->level) + p = p->next; + if (lltour[p->name].fwd == p) + pnext = lltour[p->name].bwd->next; + else + pnext = lltour[p->name].fwd->next; + while (!pnext->level) + pnext = pnext->next; + express_flip (oprev->name, o->name, p->name, pnext->name); + } + + if (x != ynext && xprev != ynext) { + if (lltour[ynext].fwd->next->name == y) { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].fwd; + } + } else { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].fwd; + } + } + + if (lltour[xprev].fwd->next->name == x) { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].fwd; + } + } else { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].fwd; + } + } + } else if (x != ynext) { + oneway *otemp; + if (lltour[xprev].fwd->level) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void express_flip (int xprev, int x, int y, int ynext) +#else +static void express_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *otemp; + + if (x == y) { + SWAP (lltour[x].fwd, lltour[x].bwd, otemp); + return; + } else if (xprev == ynext) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + reversed ^= 1; + return; + } + + if (lltour[x].bwd_express->next->name == xprev) { + o = lltour[x].fwd_express; + } else { + o = lltour[x].bwd_express; + } + + while (o->level != 2 && o->name != y) + o = o->next; + + if (o->level == 2) { + if (lltour[y].fwd_express->next->name == ynext) + p = lltour[y].bwd_express; + else + p = lltour[y].fwd_express; + while (p->level != 2) + p = p->next; + super_flip (o->name, p->name); + } + + + if (x != ynext) { + if (lltour[ynext].fwd_express->next->name == y) { + if (lltour[x].fwd_express->next->name == xprev) { + lltour[x].fwd_express->next = lltour[ynext].bwd_express; + lltour[ynext].fwd_express->next = lltour[x].bwd_express; + } else { + lltour[x].bwd_express->next = lltour[ynext].bwd_express; + lltour[ynext].fwd_express->next = lltour[x].fwd_express; + } + } else { + if (lltour[x].fwd_express->next->name == xprev) { + lltour[x].fwd_express->next = lltour[ynext].fwd_express; + lltour[ynext].bwd_express->next = lltour[x].bwd_express; + } else { + lltour[x].bwd_express->next = lltour[ynext].fwd_express; + lltour[ynext].bwd_express->next = lltour[x].fwd_express; + } + } + + if (lltour[xprev].fwd_express->next->name == x) { + if (lltour[y].fwd_express->next->name == ynext) { + lltour[y].fwd_express->next = lltour[xprev].bwd_express; + lltour[xprev].fwd_express->next = lltour[y].bwd_express; + } else { + lltour[y].bwd_express->next = lltour[xprev].bwd_express; + lltour[xprev].fwd_express->next = lltour[y].fwd_express; + } + } else { + if (lltour[y].fwd_express->next->name == ynext) { + lltour[y].fwd_express->next = lltour[xprev].fwd_express; + lltour[xprev].bwd_express->next = lltour[y].bwd_express; + } else { + lltour[y].bwd_express->next = lltour[xprev].fwd_express; + lltour[xprev].bwd_express->next = lltour[y].fwd_express; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void super_flip (int ix, int iy) +#else +static void super_flip (ix, iy) +int ix, iy; +#endif +{ + int side; + llnode *x = &(lltour[ix]); + llnode *y = &(lltour[iy]); + llnode *xprev, *ynext; + oneway *otemp; + + if (x == y) { + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + return; + } + + if (reversed) { + xprev = x->next_super; + ynext = y->prev_super; + } else { + xprev = x->prev_super; + ynext = y->next_super; + } + + if (xprev == ynext) { + SWAP (xprev->fwd_express, xprev->bwd_express, otemp); + SWAP (xprev->fwd, xprev->bwd, otemp); + reversed ^= 1; + return; + } + + if (xprev == y) { + reversed ^= 1; + return; + } + + if (reversed) + side = x->index - y->index; + else + side = y->index - x->index; + if (side < 0) + side += super_cycle_size; + + if (side < super_cycle_size / 2) + super_flip_work (x, y); + else { + super_flip_work (ynext, xprev); + reversed ^= 1; + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static void super_flip_work (llnode *x, llnode *y) +#else +static void super_flip_work (x, y) +llnode *x, *y; +#endif +{ + llnode *xprev, *ynext; + llnode *n, *next; + oneway *otemp; + int id = x->index; + + + if (reversed) { + xprev = x->next_super; + ynext = y->prev_super; + + n = y->next_super; + y->next_super = y->prev_super; + y->prev_super = n; + y->index = id--; + SWAP (y->fwd_express, y->bwd_express, otemp); + SWAP (y->fwd, y->bwd, otemp); + while (n != x) { + next = n->next_super; + n->next_super = n->prev_super; + n->prev_super = next; + n->index = id--; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + n = next; + } + next = x->next_super; + x->next_super = x->prev_super; + x->prev_super = next; + x->index = id; + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + + if (xprev != y) { + y->next_super = xprev; + x->prev_super = ynext; + xprev->prev_super = y; + ynext->next_super = x; + } + } else { + xprev = x->prev_super; + ynext = y->next_super; + + n = y->prev_super; + y->prev_super = y->next_super; + y->next_super = n; + y->index = id++; + SWAP (y->fwd_express, y->bwd_express, otemp); + SWAP (y->fwd, y->bwd, otemp); + while (n != x) { + next = n->prev_super; + n->prev_super = n->next_super; + n->next_super = next; + n->index = id++; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + n = next; + } + next = x->prev_super; + x->prev_super = x->next_super; + x->next_super = next; + x->index = id; + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + + if (xprev != y) { + y->prev_super = xprev; + x->next_super = ynext; + xprev->next_super = y; + ynext->prev_super = x; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *px, *py, *pz; + + if (x == z || x == y) + return 1; + if (find_orientation (x)) + px = lltour[x].bwd; + else + px = lltour[x].fwd; + while (!px->level) { + px = px->next; + if (px->name == y) + return 1; + else if (px->name == z) + return 0; + } + + if (z == y) + return 1; + if (find_orientation (z)) + pz = lltour[z].fwd; + else + pz = lltour[z].bwd; + while (!pz->level) { + pz = pz->next; + if (pz->name == y) { + return 1; + } else if (pz->name == x) { + return 0; + } else if (px->name == pz->name) { + return 0; + } + } + + if (find_orientation (y)) + py = lltour[y].bwd; + else + py = lltour[y].fwd; + while (!py->level) { + py = py->next; + if (py->name == z) { + return 1; + } else if (py->name == x) { + return 0; + } else if (py->name == pz->name) { + return 1; + } else if (py->name == px->name) { + return 0; + } + } + return express_flipper_sequence (px->name, py->name, pz->name); +} + +#ifdef CC_PROTOTYPE_ANSI +static int express_flipper_sequence (int x, int y, int z) +#else +static int express_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *px, *py, *pz; + int a, b, c; + + if (x == z || x == y) { + return 1; + } + + if (find_orientation (x)) + px = lltour[x].bwd_express; + else + px = lltour[x].fwd_express; + + while (px->level != 2) { + px = px->next; + if (px->name == y) { + return 1; + } else if (px->name == z) { + return 0; + } + } + + if (z == y) + return 1; + if (find_orientation (z)) + pz = lltour[z].fwd_express; + else + pz = lltour[z].bwd_express; + while (pz->level != 2) { + pz = pz->next; + if (pz->name == y) { + return 1; + } else if (pz->name == x) { + return 0; + } else if (px->name == pz->name) { + return 0; + } + } + + if (find_orientation (y)) + py = lltour[y].bwd_express; + else + py = lltour[y].fwd_express; + while (py->level != 2) { + py = py->next; + if (py->name == z) { + return 1; + } else if (py->name == x) { + return 0; + } else if (py->name == pz->name) { + return 1; + } else if (py->name == px->name) { + return 0; + } + } + + a = lltour[px->name].index; + b = lltour[py->name].index; + c = lltour[pz->name].index; + + if (reversed) { + if (a >= b) + return (b >= c || c >= a); + else + return (b >= c && c >= a); + } else { + if (a <= b) + return (b <= c || c <= a); + else + return (b <= c && c <= a); + } + + +/* + oneway *next, *prev; + + lltour[y].fwd_express->mark = 1; + lltour[y].bwd_express->mark = 1; + lltour[z].fwd_express->mark = 1; + lltour[z].bwd_express->mark = 1; + + if (find_orientation (x)) { + next = lltour[x].bwd_express; + prev = lltour[x].fwd_express; + } else { + next = lltour[x].fwd_express; + prev = lltour[x].bwd_express; + } + + while (!next->mark && !prev->mark) { + next = next->next; + prev = prev->next; + } + + if (next->mark) { + lltour[y].fwd_express->mark = 0; + lltour[y].bwd_express->mark = 0; + lltour[z].fwd_express->mark = 0; + lltour[z].bwd_express->mark = 0; + return (next->name == y); + } else { + lltour[y].fwd_express->mark = 0; + lltour[y].bwd_express->mark = 0; + lltour[z].fwd_express->mark = 0; + lltour[z].bwd_express->mark = 0; + return (prev->name == z); + } +*/ +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_llD.c b/contrib/blossom/concorde97/LINKERN/flip_llD.c new file mode 100644 index 0000000000000000000000000000000000000000..40bd709b8bef5082e3d2d2e5ee2adeafdab8e076 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_llD.c @@ -0,0 +1,1017 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - 4-Level Linked List */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: June 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version should be the best of the linked lists so far. */ +/* It combines the oneway approach, with four levels for an express */ +/* lane and a superexpress lane and an autobahn. Note that all */ +/* superexpress nodes are also express nodes, and all autobahn nodes */ +/* are also superexpress nodes. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER D (flip_llD.c): */ +/* */ +/* 1. Uses four levels, the top having n**(1/4) nodes. */ +/* 2. The top level has explicit next and prevs, the other levels */ +/* consist of two "oneway" cycles. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 +#define GROUP_FACTOR 3.0 + +typedef struct oneway { + struct oneway *next; + int name; + char mark; + char level; +} oneway; + +typedef struct llnode { + struct oneway actual_fwd; + struct oneway actual_bwd; + struct oneway actual_fwd_express; + struct oneway actual_bwd_express; + struct oneway actual_fwd_super; + struct oneway actual_bwd_super; + struct oneway *fwd; + struct oneway *bwd; + struct oneway *fwd_express; + struct oneway *bwd_express; + struct oneway *fwd_super; + struct oneway *bwd_super; + struct llnode *next_auto; + struct llnode *prev_auto; + int index; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + express_flip (int aprev, int a, int b, int bnext), + super_flip (int aprev, int a, int b, int bnext), + auto_flip (int a, int b), + auto_flip_work (llnode *a, llnode *b); +static int + express_flipper_sequence (int x, int y, int z), + super_flipper_sequence (int x, int y, int z), + find_orientation (int s); + +#else + +static void + express_flip (), + super_flip (), + auto_flip (), + auto_flip_work (); +static int + express_flipper_sequence (), + super_flipper_sequence (), + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static int cycle_size = 0; +static int auto_cycle_size = 0; +static int reversed = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j, k; + int groupsize, supergroupsize, autogroupsize; + + cycle_size = ncount; + reversed = 0; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].actual_fwd.name = cyc[0]; + lltour[cyc[0]].actual_fwd.mark = 0; + lltour[cyc[0]].actual_fwd.level = 0; + lltour[cyc[0]].actual_fwd.next = &(lltour[cyc[1]].actual_fwd); + lltour[cyc[0]].fwd = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[0]].actual_bwd.name = cyc[0]; + lltour[cyc[0]].actual_bwd.mark = 0; + lltour[cyc[0]].actual_bwd.level = 0; + lltour[cyc[0]].actual_bwd.next = &(lltour[cyc[ncount - 1]].actual_bwd); + lltour[cyc[0]].bwd = &(lltour[cyc[0]].actual_bwd); + lltour[cyc[ncount - 1]].actual_fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_fwd.mark = 0; + lltour[cyc[ncount - 1]].actual_fwd.level = 0; + lltour[cyc[ncount - 1]].actual_fwd.next = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[ncount - 1]].fwd = &(lltour[cyc[ncount - 1]].actual_fwd); + lltour[cyc[ncount - 1]].actual_bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_bwd.mark = 0; + lltour[cyc[ncount - 1]].actual_bwd.level = 0; + lltour[cyc[ncount - 1]].actual_bwd.next = + &(lltour[cyc[ncount - 2]].actual_bwd); + lltour[cyc[ncount - 1]].bwd = &(lltour[cyc[ncount - 1]].actual_bwd); + + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].actual_fwd.name = cyc[i]; + lltour[cyc[i]].actual_fwd.mark = 0; + lltour[cyc[i]].actual_fwd.level = 0; + lltour[cyc[i]].actual_fwd.next = &(lltour[cyc[i + 1]].actual_fwd); + lltour[cyc[i]].fwd = &(lltour[cyc[i]].actual_fwd); + lltour[cyc[i]].actual_bwd.name = cyc[i]; + lltour[cyc[i]].actual_bwd.mark = 0; + lltour[cyc[i]].actual_bwd.level = 0; + lltour[cyc[i]].actual_bwd.next = &(lltour[cyc[i - 1]].actual_bwd); + lltour[cyc[i]].bwd = &(lltour[cyc[i]].actual_bwd); + } + + groupsize = (int) (pow ((double) ncount, 1.0 / 4.0)/ GROUP_FACTOR); + supergroupsize = groupsize * groupsize; + autogroupsize = supergroupsize * groupsize; + + + lltour[cyc[0]].actual_fwd.level = 1; + lltour[cyc[0]].actual_bwd.level = 1; + lltour[cyc[0]].fwd_express = &(lltour[cyc[0]].actual_fwd_express); + lltour[cyc[0]].bwd_express = &(lltour[cyc[0]].actual_bwd_express); + lltour[cyc[0]].actual_fwd_express.mark = 0; + lltour[cyc[0]].actual_bwd_express.mark = 0; + lltour[cyc[0]].actual_fwd_express.level = 1; + lltour[cyc[0]].actual_bwd_express.level = 1; + lltour[cyc[0]].actual_fwd_express.name = cyc[0]; + lltour[cyc[0]].actual_bwd_express.name = cyc[0]; + lltour[cyc[0]].actual_fwd_express.next = + &(lltour[cyc[groupsize]].actual_fwd_express); + i = groupsize; + j = ncount - groupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 1; + lltour[cyc[i]].actual_bwd.level = 1; + lltour[cyc[i]].fwd_express = &(lltour[cyc[i]].actual_fwd_express); + lltour[cyc[i]].bwd_express = &(lltour[cyc[i]].actual_bwd_express); + lltour[cyc[i]].actual_fwd_express.mark = 0; + lltour[cyc[i]].actual_bwd_express.mark = 0; + lltour[cyc[i]].actual_fwd_express.level = 1; + lltour[cyc[i]].actual_bwd_express.level = 1; + lltour[cyc[i]].actual_fwd_express.name = cyc[i]; + lltour[cyc[i]].actual_bwd_express.name = cyc[i]; + lltour[cyc[i]].actual_fwd_express.next = + &(lltour[cyc[i + groupsize]].actual_fwd_express); + lltour[cyc[i]].actual_bwd_express.next = + &(lltour[cyc[i - groupsize]].actual_bwd_express); + i += groupsize; + } + lltour[cyc[i]].actual_fwd.level = 1; + lltour[cyc[i]].actual_bwd.level = 1; + lltour[cyc[i]].fwd_express = &(lltour[cyc[i]].actual_fwd_express); + lltour[cyc[i]].bwd_express = &(lltour[cyc[i]].actual_bwd_express); + lltour[cyc[i]].actual_fwd_express.mark = 0; + lltour[cyc[i]].actual_bwd_express.mark = 0; + lltour[cyc[i]].actual_fwd_express.level = 1; + lltour[cyc[i]].actual_bwd_express.level = 1; + lltour[cyc[i]].actual_fwd_express.name = cyc[i]; + lltour[cyc[i]].actual_bwd_express.name = cyc[i]; + lltour[cyc[i]].actual_fwd_express.next = + &(lltour[cyc[0]].actual_fwd_express); + lltour[cyc[i]].actual_bwd_express.next = + &(lltour[cyc[i - groupsize]].actual_bwd_express); + lltour[cyc[0]].actual_bwd_express.next = + &(lltour[cyc[i]].actual_bwd_express); + + + + lltour[cyc[0]].actual_fwd.level = 2; + lltour[cyc[0]].actual_bwd.level = 2; + lltour[cyc[0]].actual_fwd_express.level = 2; + lltour[cyc[0]].actual_bwd_express.level = 2; + lltour[cyc[0]].fwd_super = &(lltour[cyc[0]].actual_fwd_super); + lltour[cyc[0]].bwd_super = &(lltour[cyc[0]].actual_bwd_super); + lltour[cyc[0]].actual_fwd_super.level = 2; + lltour[cyc[0]].actual_bwd_super.level = 2; + lltour[cyc[0]].actual_fwd_super.mark = 0; + lltour[cyc[0]].actual_bwd_super.mark = 0; + lltour[cyc[0]].actual_fwd_super.name = cyc[0]; + lltour[cyc[0]].actual_bwd_super.name = cyc[0]; + lltour[cyc[0]].actual_fwd_super.next = + &(lltour[cyc[supergroupsize]].actual_fwd_super); + i = supergroupsize; + j = ncount - supergroupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].fwd_super = &(lltour[cyc[i]].actual_fwd_super); + lltour[cyc[i]].bwd_super = &(lltour[cyc[i]].actual_bwd_super); + lltour[cyc[i]].actual_fwd_super.level = 2; + lltour[cyc[i]].actual_bwd_super.level = 2; + lltour[cyc[i]].actual_fwd_super.mark = 0; + lltour[cyc[i]].actual_bwd_super.mark = 0; + lltour[cyc[i]].actual_fwd_super.name = cyc[i]; + lltour[cyc[i]].actual_bwd_super.name = cyc[i]; + lltour[cyc[i]].actual_fwd_super.next = + &(lltour[cyc[i + supergroupsize]].actual_fwd_super); + lltour[cyc[i]].actual_bwd_super.next = + &(lltour[cyc[i - supergroupsize]].actual_bwd_super); + i += supergroupsize; + } + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].fwd_super = &(lltour[cyc[i]].actual_fwd_super); + lltour[cyc[i]].bwd_super = &(lltour[cyc[i]].actual_bwd_super); + lltour[cyc[i]].actual_fwd_super.level = 2; + lltour[cyc[i]].actual_bwd_super.level = 2; + lltour[cyc[i]].actual_fwd_super.mark = 0; + lltour[cyc[i]].actual_bwd_super.mark = 0; + lltour[cyc[i]].actual_fwd_super.name = cyc[i]; + lltour[cyc[i]].actual_bwd_super.name = cyc[i]; + lltour[cyc[i]].actual_fwd_super.next = + &(lltour[cyc[0]].actual_fwd_super); + lltour[cyc[i]].actual_bwd_super.next = + &(lltour[cyc[i - supergroupsize]].actual_bwd_super); + lltour[cyc[0]].actual_bwd_super.next = + &(lltour[cyc[i]].actual_bwd_super); + + + lltour[cyc[0]].actual_fwd.level = 3; + lltour[cyc[0]].actual_bwd.level = 3; + lltour[cyc[0]].actual_fwd_express.level = 3; + lltour[cyc[0]].actual_bwd_express.level = 3; + lltour[cyc[0]].actual_fwd_super.level = 3; + lltour[cyc[0]].actual_bwd_super.level = 3; + lltour[cyc[0]].next_auto = &(lltour[cyc[autogroupsize]]); + lltour[cyc[0]].index = 0; + i = autogroupsize; + j = ncount - autogroupsize; + k = 1; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 3; + lltour[cyc[i]].actual_bwd.level = 3; + lltour[cyc[i]].actual_fwd_express.level = 3; + lltour[cyc[i]].actual_bwd_express.level = 3; + lltour[cyc[i]].actual_fwd_super.level = 3; + lltour[cyc[i]].actual_bwd_super.level = 3; + lltour[cyc[i]].prev_auto = &(lltour[cyc[i - autogroupsize]]); + lltour[cyc[i]].next_auto = &(lltour[cyc[i + autogroupsize]]); + lltour[cyc[i]].index = k++; + i += autogroupsize; + } + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].actual_fwd_super.level = 2; + lltour[cyc[i]].actual_bwd_super.level = 2; + lltour[cyc[i]].next_auto = &(lltour[cyc[0]]); + lltour[cyc[i]].prev_auto = &(lltour[cyc[i - autogroupsize]]); + lltour[cyc[0]].prev_auto = &(lltour[cyc[i]]); + lltour[cyc[i]].index = k; + auto_cycle_size = k + 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = lltour[s].fwd; + + while (!n->level) + n = n->next; + + if (lltour[n->name].fwd == n) + n = lltour[n->name].fwd_express; + else + n = lltour[n->name].bwd_express; + + while (n->level < 2) + n = n->next; + + if (lltour[n->name].fwd_express == n) + n = lltour[n->name].fwd_super; + else + n = lltour[n->name].bwd_super; + + while (n->level < 3) + n = n->next; + + if (reversed) + return (n != lltour[n->name].bwd_super); + else + return (n != lltour[n->name].fwd_super); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + oneway *start, *n; + int k = 0; + + start = (find_orientation (0) ? lltour[0].bwd : lltour[0].fwd); + n = start; + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].bwd->next->name; + else + return lltour[x].fwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + if (find_orientation (x)) + return lltour[x].fwd->next->name; + else + return lltour[x].bwd->next->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *oprev, *pnext; + + if (x == y) + return; + + if (lltour[x].bwd->next->name == xprev) + o = lltour[x].fwd; + else + o = lltour[x].bwd; + + while (!o->level && o->name != y) + o = o->next; + + if (o->level) { + if (lltour[o->name].fwd == o) + oprev = lltour[o->name].bwd->next; + else + oprev = lltour[o->name].fwd->next; + while (!oprev->level) + oprev = oprev->next; + if (lltour[y].fwd->next->name == ynext) + p = lltour[y].bwd; + else + p = lltour[y].fwd; + while (!p->level) + p = p->next; + if (lltour[p->name].fwd == p) + pnext = lltour[p->name].bwd->next; + else + pnext = lltour[p->name].fwd->next; + while (!pnext->level) + pnext = pnext->next; + express_flip (oprev->name, o->name, p->name, pnext->name); + } + + if (x != ynext && xprev != ynext) { + if (lltour[ynext].fwd->next->name == y) { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].fwd; + } + } else { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].fwd; + } + } + + if (lltour[xprev].fwd->next->name == x) { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].fwd; + } + } else { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].fwd; + } + } + } else if (x != ynext) { + oneway *otemp; + if (lltour[xprev].fwd->level) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void express_flip (int xprev, int x, int y, int ynext) +#else +static void express_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *otemp, *oprev, *pnext; + + if (x == y) { + SWAP (lltour[x].fwd, lltour[x].bwd, otemp); + return; + } else if (xprev == ynext) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + reversed ^= 1; + return; + } + + if (lltour[x].bwd_express->next->name == xprev) { + o = lltour[x].fwd_express; + } else { + o = lltour[x].bwd_express; + } + + while (o->level < 2 && o->name != y) + o = o->next; + + if (o->level >= 2) { + if (lltour[o->name].fwd_express == o) + oprev = lltour[o->name].bwd_express->next; + else + oprev = lltour[o->name].fwd_express->next; + while (oprev->level < 2) + oprev = oprev->next; + if (lltour[y].fwd_express->next->name == ynext) + p = lltour[y].bwd_express; + else + p = lltour[y].fwd_express; + while (p->level < 2) + p = p->next; + if (lltour[p->name].fwd_express == p) + pnext = lltour[p->name].bwd_express->next; + else + pnext = lltour[p->name].fwd_express->next; + while (pnext->level < 2) + pnext = pnext->next; + super_flip (oprev->name, o->name, p->name, pnext->name); + } + + if (x != ynext) { + if (lltour[ynext].fwd_express->next->name == y) { + if (lltour[x].fwd_express->next->name == xprev) { + lltour[x].fwd_express->next = lltour[ynext].bwd_express; + lltour[ynext].fwd_express->next = lltour[x].bwd_express; + } else { + lltour[x].bwd_express->next = lltour[ynext].bwd_express; + lltour[ynext].fwd_express->next = lltour[x].fwd_express; + } + } else { + if (lltour[x].fwd_express->next->name == xprev) { + lltour[x].fwd_express->next = lltour[ynext].fwd_express; + lltour[ynext].bwd_express->next = lltour[x].bwd_express; + } else { + lltour[x].bwd_express->next = lltour[ynext].fwd_express; + lltour[ynext].bwd_express->next = lltour[x].fwd_express; + } + } + + if (lltour[xprev].fwd_express->next->name == x) { + if (lltour[y].fwd_express->next->name == ynext) { + lltour[y].fwd_express->next = lltour[xprev].bwd_express; + lltour[xprev].fwd_express->next = lltour[y].bwd_express; + } else { + lltour[y].bwd_express->next = lltour[xprev].bwd_express; + lltour[xprev].fwd_express->next = lltour[y].fwd_express; + } + } else { + if (lltour[y].fwd_express->next->name == ynext) { + lltour[y].fwd_express->next = lltour[xprev].fwd_express; + lltour[xprev].bwd_express->next = lltour[y].bwd_express; + } else { + lltour[y].bwd_express->next = lltour[xprev].fwd_express; + lltour[xprev].bwd_express->next = lltour[y].fwd_express; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void super_flip (int xprev, int x, int y, int ynext) +#else +static void super_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *otemp; + + if (x == y) { + SWAP (lltour[x].fwd_express, lltour[x].bwd_express, otemp); + SWAP (lltour[x].fwd, lltour[x].bwd, otemp); + return; + } else if (xprev == ynext) { + SWAP (lltour[xprev].fwd_express, lltour[xprev].bwd_express, otemp); + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + reversed ^= 1; + return; + } + + if (lltour[x].bwd_super->next->name == xprev) { + o = lltour[x].fwd_super; + } else { + o = lltour[x].bwd_super; + } + + while (o->level < 3 && o->name != y) + o = o->next; + + if (o->level >= 3) { + if (lltour[y].fwd_super->next->name == ynext) + p = lltour[y].bwd_super; + else + p = lltour[y].fwd_super; + while (p->level < 3) + p = p->next; + auto_flip (o->name, p->name); + } + + if (x != ynext) { + if (lltour[ynext].fwd_super->next->name == y) { + if (lltour[x].fwd_super->next->name == xprev) { + lltour[x].fwd_super->next = lltour[ynext].bwd_super; + lltour[ynext].fwd_super->next = lltour[x].bwd_super; + } else { + lltour[x].bwd_super->next = lltour[ynext].bwd_super; + lltour[ynext].fwd_super->next = lltour[x].fwd_super; + } + } else { + if (lltour[x].fwd_super->next->name == xprev) { + lltour[x].fwd_super->next = lltour[ynext].fwd_super; + lltour[ynext].bwd_super->next = lltour[x].bwd_super; + } else { + lltour[x].bwd_super->next = lltour[ynext].fwd_super; + lltour[ynext].bwd_super->next = lltour[x].fwd_super; + } + } + + if (lltour[xprev].fwd_super->next->name == x) { + if (lltour[y].fwd_super->next->name == ynext) { + lltour[y].fwd_super->next = lltour[xprev].bwd_super; + lltour[xprev].fwd_super->next = lltour[y].bwd_super; + } else { + lltour[y].bwd_super->next = lltour[xprev].bwd_super; + lltour[xprev].fwd_super->next = lltour[y].fwd_super; + } + } else { + if (lltour[y].fwd_super->next->name == ynext) { + lltour[y].fwd_super->next = lltour[xprev].fwd_super; + lltour[xprev].bwd_super->next = lltour[y].bwd_super; + } else { + lltour[y].bwd_super->next = lltour[xprev].fwd_super; + lltour[xprev].bwd_super->next = lltour[y].fwd_super; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void auto_flip (int ix, int iy) +#else +static void auto_flip (ix, iy) +int ix, iy; +#endif +{ + int side; + llnode *x = &(lltour[ix]); + llnode *y = &(lltour[iy]); + llnode *xprev, *ynext; + oneway *otemp; + + if (x == y) { + SWAP (x->fwd_super, x->bwd_super, otemp); + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + return; + } + + if (reversed) { + xprev = x->next_auto; + ynext = y->prev_auto; + } else { + xprev = x->prev_auto; + ynext = y->next_auto; + } + + if (xprev == ynext) { + SWAP (xprev->fwd_super, xprev->bwd_super, otemp); + SWAP (xprev->fwd_express, xprev->bwd_express, otemp); + SWAP (xprev->fwd, xprev->bwd, otemp); + reversed ^= 1; + return; + } + + if (xprev == y) { + reversed ^= 1; + return; + } + + if (reversed) + side = x->index - y->index; + else + side = y->index - x->index; + if (side < 0) + side += auto_cycle_size; + + if (side < auto_cycle_size / 2) + auto_flip_work (x, y); + else { + auto_flip_work (ynext, xprev); + reversed ^= 1; + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static void auto_flip_work (llnode *x, llnode *y) +#else +static void auto_flip_work (x, y) +llnode *x, *y; +#endif +{ + llnode *xprev, *ynext; + llnode *n, *next; + oneway *otemp; + int id = x->index; + + if (reversed) { + xprev = x->next_auto; + ynext = y->prev_auto; + + n = y->next_auto; + y->next_auto = y->prev_auto; + y->prev_auto = n; + y->index = id--; + SWAP (y->fwd_super, y->bwd_super, otemp); + SWAP (y->fwd_express, y->bwd_express, otemp); + SWAP (y->fwd, y->bwd, otemp); + while (n != x) { + next = n->next_auto; + n->next_auto = n->prev_auto; + n->prev_auto = next; + n->index = id--; + SWAP (n->fwd_super, n->bwd_super, otemp); + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + n = next; + } + next = x->next_auto; + x->next_auto = x->prev_auto; + x->prev_auto = next; + x->index = id; + SWAP (x->fwd_super, x->bwd_super, otemp); + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + + if (xprev != y) { + y->next_auto = xprev; + x->prev_auto = ynext; + xprev->prev_auto = y; + ynext->next_auto = x; + } + } else { + xprev = x->prev_auto; + ynext = y->next_auto; + + n = y->prev_auto; + y->prev_auto = y->next_auto; + y->next_auto = n; + y->index = id++; + SWAP (y->fwd_super, y->bwd_super, otemp); + SWAP (y->fwd_express, y->bwd_express, otemp); + SWAP (y->fwd, y->bwd, otemp); + while (n != x) { + next = n->prev_auto; + n->prev_auto = n->next_auto; + n->next_auto = next; + n->index = id++; + SWAP (n->fwd_super, n->bwd_super, otemp); + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + n = next; + } + next = x->prev_auto; + x->prev_auto = x->next_auto; + x->next_auto = next; + x->index = id; + SWAP (x->fwd_super, x->bwd_super, otemp); + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + + if (xprev != y) { + y->prev_auto = xprev; + x->next_auto = ynext; + xprev->next_auto = y; + ynext->prev_auto = x; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *px, *py, *pz; + + if (x == z || x == y) + return 1; + if (find_orientation (x)) + px = lltour[x].bwd; + else + px = lltour[x].fwd; + while (!px->level) { + px = px->next; + if (px->name == y) + return 1; + else if (px->name == z) + return 0; + } + + if (z == y) + return 1; + if (find_orientation (z)) + pz = lltour[z].fwd; + else + pz = lltour[z].bwd; + while (!pz->level) { + pz = pz->next; + if (pz->name == y) { + return 1; + } else if (pz->name == x) { + return 0; + } else if (px->name == pz->name) { + return 0; + } + } + + if (find_orientation (y)) + py = lltour[y].bwd; + else + py = lltour[y].fwd; + while (!py->level) { + py = py->next; + if (py->name == z) { + return 1; + } else if (py->name == x) { + return 0; + } else if (py->name == pz->name) { + return 1; + } else if (py->name == px->name) { + return 0; + } + } + return express_flipper_sequence (px->name, py->name, pz->name); +} + +#ifdef CC_PROTOTYPE_ANSI +static int express_flipper_sequence (int x, int y, int z) +#else +static int express_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *px, *py, *pz; + + if (x == z || x == y) { + return 1; + } + + if (find_orientation (x)) + px = lltour[x].bwd_express; + else + px = lltour[x].fwd_express; + + while (px->level < 2) { + px = px->next; + if (px->name == y) { + return 1; + } else if (px->name == z) { + return 0; + } + } + + if (z == y) + return 1; + if (find_orientation (z)) + pz = lltour[z].fwd_express; + else + pz = lltour[z].bwd_express; + while (pz->level < 2) { + pz = pz->next; + if (pz->name == y) { + return 1; + } else if (pz->name == x) { + return 0; + } else if (px->name == pz->name) { + return 0; + } + } + + if (find_orientation (y)) + py = lltour[y].bwd_express; + else + py = lltour[y].fwd_express; + while (py->level < 2) { + py = py->next; + if (py->name == z) { + return 1; + } else if (py->name == x) { + return 0; + } else if (py->name == pz->name) { + return 1; + } else if (py->name == px->name) { + return 0; + } + } + + return super_flipper_sequence (px->name, py->name, pz->name); +} + +#ifdef CC_PROTOTYPE_ANSI +static int super_flipper_sequence (int x, int y, int z) +#else +static int super_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *px, *py, *pz; + int a, b, c; + + if (x == z || x == y) { + return 1; + } + + if (find_orientation (x)) + px = lltour[x].bwd_super; + else + px = lltour[x].fwd_super; + + while (px->level < 3) { + px = px->next; + if (px->name == y) { + return 1; + } else if (px->name == z) { + return 0; + } + } + + if (z == y) + return 1; + if (find_orientation (z)) + pz = lltour[z].fwd_super; + else + pz = lltour[z].bwd_super; + while (pz->level < 3) { + pz = pz->next; + if (pz->name == y) { + return 1; + } else if (pz->name == x) { + return 0; + } else if (px->name == pz->name) { + return 0; + } + } + + if (find_orientation (y)) + py = lltour[y].bwd_super; + else + py = lltour[y].fwd_super; + while (py->level < 3) { + py = py->next; + if (py->name == z) { + return 1; + } else if (py->name == x) { + return 0; + } else if (py->name == pz->name) { + return 1; + } else if (py->name == px->name) { + return 0; + } + } + + a = lltour[px->name].index; + b = lltour[py->name].index; + c = lltour[pz->name].index; + + if (reversed) { + if (a >= b) + return (b >= c || c >= a); + else + return (b >= c && c >= a); + } else { + if (a <= b) + return (b <= c || c <= a); + else + return (b <= c && c <= a); + } +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_sg1.c b/contrib/blossom/concorde97/LINKERN/flip_sg1.c new file mode 100644 index 0000000000000000000000000000000000000000..40bf9802b5dcb7f5ce5e946a8e796789744ebe0e --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_sg1.c @@ -0,0 +1,896 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Segments with UNDO */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: April 24, 1995 (but mainly from March, 1990) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_reset_temp (int ncount) */ +/* reinitializes the cycle to the current cycle - use this to keep the */ +/* number of segments small. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int x, int y) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version is closest to our orignal segment code. It undos the */ +/* flips that do not lead to an improvement. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/* #define USE_TIMESTAMP */ + +/***************************************************************************/ +/* */ +/* SEGMENT FLIPPER (flipper1): */ +/* */ +/* 1. flipper_cycle and flipper_cycle_inverse return the current */ +/* number of segments. */ +/* */ +/* 2. The cycle should be renumbered, freed, and initialized now and */ +/* and again to reduce the number of segments. */ +/* */ +/* 3. This is the first pass - uses a straight cycle of segments, and */ +/* a tree to find segment. No balance condition is maintained for */ +/* the tree. */ +/* */ +/***************************************************************************/ + + +typedef struct flipper1 { + struct { + struct flipper1 *parent; + struct flipper1 *lower; + struct flipper1 *higher; + } locate; + struct { + struct flipper1 *left; + struct flipper1 *right; + } order; + int low; + int high; + int reverse; + struct flipper1 *next; +} flipper1; + +#ifdef USE_TIMESTAMP +typedef struct cacheobj { + struct flipper1 *segment; + int stamp; +} cacheobj; +#endif + + +#ifdef CC_PROTOTYPE_ANSI + +static void + flipper1_tree_delete (flipper1 *), + flipper1_merge (flipper1 *), + flipper1_checkmerge (flipper1 *), + flipper1free (flipper1 *p), + flipper1_tree_free (flipper1 *, flipper1 *); + +static flipper1 + *flipper1_locate (int x), + *flipper1_split (flipper1 *, int); + +#else + +static void + flipper1_tree_delete (), + flipper1_merge (), + flipper1_checkmerge (), + flipper1free (), + flipper1_tree_free (); + +static flipper1 + *flipper1_locate (), + *flipper1_split (); + +#endif + +#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) + +#define LOCATE_CHILD(p, c) (*((p) ? ((p)->locate.lower == (c) ? \ + &(p)->locate.lower : &(p)->locate.higher) : \ + &locate_root)) + +#define PARENT_HOOKUP(q, p, c) (((q)->locate.parent = (p)), \ + (LOCATE_CHILD((p),(c)) = (q))) + +#define HIGHER_HOOKUP(p, c) (((p)->locate.higher = (c)), \ + ((c) ? (c)->locate.parent = (p) : (flipper1 *) NULL)) + +#define LOWER_HOOKUP(p, c) (((p)->locate.lower = (c)), \ + ((c) ? (c)->locate.parent = (p) : (flipper1 *) NULL)) + +static flipper1 *locate_root = (flipper1 *) NULL; +static flipper1 *order_root = (flipper1 *) NULL; +#ifdef USE_TIMESTAMP +static cacheobj *locate_cache = (cacheobj *) NULL; +static int locate_cache_magic = 0; +#else +static flipper1 **locate_cache = (flipper1 **) NULL; +#endif + +static int *flip1_cyc = (int *) NULL; +static int *flip1_inv = (int *) NULL; +static int segment_count = 1; + +/* +static int seghit = 0; +static int segtotal = 0; +*/ + +CC_PTR_ALLOC_ROUTINE (flipper1, flipper1alloc, flipper1chunklist, + flipper1freelist) +CC_PTR_FREE_WORLD_ROUTINE( flipper1, flipper1free_world, flipper1chunklist, + flipper1freelist) +CC_PTR_LEAKS_ROUTINE (flipper1, flipper1_check_leaks, flipper1chunklist, + flipper1freelist, reverse, int) + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1free (flipper1 *p) +#else +static void flipper1free (p) +flipper1 *p; +#endif +{ + p->next = flipper1freelist; + flipper1freelist = p; + p->low = p->high = -1; +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_tree_free (flipper1 *p, flipper1 *bigp) +#else +static void flipper1_tree_free (p, bigp) +flipper1 *p, *bigp; +#endif +{ + if (p) { + flipper1_tree_free (p->locate.lower, bigp); + flipper1_tree_free (p->locate.higher, bigp); + if (p != bigp) + flipper1free (p); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset_temp (int ncount) +#else +int CClinkern_flipper_reset_temp (ncount) +int ncount; +#endif +{ + int i, n, *cyc = (int *) NULL; + int nseg = 0, big = 0, bigreverse = 0; + flipper1 *p, *bigp = (flipper1 *) NULL; + + p = order_root; + do { + if (p->high - p->low > big) { + big = p->high - p->low; + bigp = p; + } + nseg++; + p = p->order.right; + } while (p != order_root); + + if (nseg == 1) + return 0; + + cyc = CC_SAFE_MALLOC (ncount, int); + if (!cyc) { +#ifdef USE_TIMESTAMP + CC_FREE (locate_cache, cacheobj); +#else + CC_FREE (locate_cache, flipper1 *); +#endif + return 1; + } + if (bigp->reverse) { + bigreverse = 1; + p = bigp->order.left; + n = bigp->high + 1; + do { + if (!p->reverse) { + for (i = p->high; i >= p->low; i--) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } else { + for (i = p->low; i <= p->high; i++) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } + p = p->order.left; + } while (p != bigp); + } else { + bigreverse = 0; + p = bigp->order.right; + n = bigp->high + 1; + do { + if (p->reverse) { + for (i = p->high; i >= p->low; i--) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } else { + for (i = p->low; i <= p->high; i++) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } + p = p->order.right; + } while (p != bigp); + } + + for (i = bigp->high + 1; i < ncount; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; +#ifndef USE_TIMESTAMP + locate_cache[i] = bigp; +#endif + } + for (i = 0; i < bigp->low; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; +#ifndef USE_TIMESTAMP + locate_cache[i] = bigp; +#endif + } + if (cyc) + CC_FREE (cyc, int); + + +#ifdef USE_TIMESTAMP + flipper1_tree_free (locate_root, (flipper1 *) NULL); + locate_root = flipper1alloc (); + if (!locate_root) + return 1; +#else + flipper1_tree_free (locate_root, bigp); + locate_root = bigp; +#endif + + order_root = locate_root; + locate_root->locate.parent = (flipper1 *) NULL; + locate_root->locate.lower = (flipper1 *) NULL; + locate_root->locate.higher = (flipper1 *) NULL; + locate_root->order.left = locate_root; + locate_root->order.right = locate_root; + locate_root->low = 0; + locate_root->high = ncount - 1; + locate_root->reverse = bigreverse; + segment_count = 1; + +#ifdef USE_TIMESTAMP + locate_cache_magic++; +#endif + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + locate_root = flipper1alloc (); + if (!locate_root) + return 1; + order_root = locate_root; + +#ifdef USE_TIMESTAMP + if (!locate_cache) { + locate_cache = CC_SAFE_MALLOC (ncount, cacheobj); + if (!locate_cache) { + flipper1free (locate_root); + return 1; + } + for (i = 0; i < ncount; i++) { + locate_cache[i].segment = locate_root; + locate_cache[i].stamp = 0; + } + locate_cache_magic = 0; + } else { + locate_cache_magic++; + } +#else + if (!locate_cache) { + locate_cache = CC_SAFE_MALLOC (ncount, flipper1 *); + if (!locate_cache) { + flipper1free (locate_root); + return 1; + } + } +#endif + + locate_root->locate.parent = (flipper1 *) NULL; + locate_root->locate.lower = (flipper1 *) NULL; + locate_root->locate.higher = (flipper1 *) NULL; + locate_root->order.left = locate_root; + locate_root->order.right = locate_root; + locate_root->low = 0; + locate_root->high = ncount - 1; + locate_root->reverse = 0; + segment_count = 1; + +#ifndef USE_TIMESTAMP + for (i = 0; i < ncount; i++) { + locate_cache[i] = locate_root; + } +#endif + + flip1_cyc = CC_SAFE_MALLOC (ncount, int); + if (!flip1_cyc) { +#ifdef USE_TIMESTAMP + CC_FREE (locate_cache, cacheobj); +#else + CC_FREE (locate_cache, flipper1 *); +#endif + return 1; + } + flip1_inv = CC_SAFE_MALLOC (ncount, int); + if (!flip1_inv) { +#ifdef USE_TIMESTAMP + CC_FREE (locate_cache, cacheobj); +#else + CC_FREE (locate_cache, flipper1 *); +#endif + CC_FREE (flip1_cyc, int); + return 1; + } + + for (i = 0; i < ncount; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + flipper1 *p; + int i; + int n = 0; + int nseg = 0; + + p = order_root; + do { + nseg++; + if (p->reverse) { + for (i = p->high; i >= p->low; i--) + x[n++] = flip1_cyc[i]; + } else { + for (i = p->low; i <= p->high; i++) + x[n++] = flip1_cyc[i]; + } + p = p->order.right; + } while (p != order_root); + + assert (nseg == segment_count); +/* + printf ("Segment Hits: %d (Total %d) (%.2f)\n", seghit, segtotal, + (double) seghit / (double) segtotal); + fflush (stdout); +*/ + return nseg; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + flipper1_tree_free (locate_root, (flipper1 *) NULL); + locate_root = (flipper1 *) NULL; + order_root = (flipper1 *) NULL; + + if (flip1_cyc) + CC_FREE (flip1_cyc, int); + if (flip1_inv) + CC_FREE (flip1_inv, int); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + int total, onlist; + + if (locate_cache) +#ifdef USE_TIMESTAMP + CC_FREE (locate_cache, cacheobj); +#else + CC_FREE (locate_cache, flipper1 *); +#endif + + if (flipper1_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding flippers\n", total - onlist); + } + flipper1free_world (); +} + + +#ifdef CC_PROTOTYPE_ANSI +static flipper1 *flipper1_locate (int x) +#else +static flipper1 *flipper1_locate (x) +int x; +#endif +{ + flipper1 *p; + +#ifdef USE_TIMESTAMP + if (locate_cache[x].stamp == locate_cache_magic) { + p = locate_cache[x].segment; + } else { + p = locate_root; + } +#else + p = locate_cache[x]; +#endif + + if (p->high < x) { + if (p->high != -1) { + if (p->locate.higher && p->locate.higher->high >= x) { + p = p->locate.higher; + } else if (p->locate.parent && p->locate.parent->high >= x) { + p = p->locate.parent; + } else { + p = locate_root; + } + } else { + p = locate_root; + } + } else if (p->low > x) { + if (p->locate.lower && p->locate.lower->low <= x) { + p = p->locate.lower; + } else if (p->locate.parent && p->locate.parent->low <= x) { + p = p->locate.parent; + } else { + p = locate_root; + } + } else { + return p; + } + +/* + while (p) { For some reason this is faster under linux +*/ + while (1) { + if (x < p->low) + p = p->locate.lower; + else if (x > p->high) + p = p->locate.higher; + else + break; + } +#ifdef USE_TIMESTAMP + locate_cache[x].segment = p; + locate_cache[x].stamp = locate_cache_magic; +#else + locate_cache[x] = p; +#endif + + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int ix) +#else +int CClinkern_flipper_next (ix) +int ix; +#endif +{ + int x = flip1_inv[ix]; + flipper1 *p; + + p = flipper1_locate (x); + + if (p->reverse) { + return x == p->low ? (p->order.right->reverse + ? flip1_cyc[p->order.right->high] + : flip1_cyc[p->order.right->low]) + : flip1_cyc[x - 1]; + } else { + return x == p->high ? (p->order.right->reverse + ? flip1_cyc[p->order.right->high] + : flip1_cyc[p->order.right->low]) + : flip1_cyc[x + 1]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int ix) +#else +int CClinkern_flipper_prev (ix) +int ix; +#endif +{ + int x = flip1_inv[ix]; + flipper1 *p; + + p = flipper1_locate (x); + + if (p->reverse) { + return x == p->high ? (p->order.left->reverse + ? flip1_cyc[p->order.left->low] + : flip1_cyc[p->order.left->high]) + : flip1_cyc[x + 1]; + } else { + return x == p->low ? (p->order.left->reverse + ? flip1_cyc[p->order.left->low] + : flip1_cyc[p->order.left->high]) + : flip1_cyc[x - 1]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_tree_delete (flipper1 *p) +#else +static void flipper1_tree_delete (p) +flipper1 *p; +#endif +{ + flipper1 *q; + + if (p->locate.lower == (flipper1 *) NULL) { + if (p->locate.higher) { + PARENT_HOOKUP (p->locate.higher, p->locate.parent, p); + } else { + LOCATE_CHILD (p->locate.parent, p) = (flipper1 *) NULL; + } + } else if (p->locate.higher == (flipper1 *) NULL) { + PARENT_HOOKUP (p->locate.lower, p->locate.parent, p); + } else { + q = p->locate.lower; + while (q->locate.higher) + q = q->locate.higher; + if (q->locate.parent == p) { + PARENT_HOOKUP (q, p->locate.parent, p); + HIGHER_HOOKUP (q, p->locate.higher); + } else { + HIGHER_HOOKUP (q->locate.parent, q->locate.lower); + PARENT_HOOKUP (q, p->locate.parent, p); + LOWER_HOOKUP (q, p->locate.lower); + HIGHER_HOOKUP (q, p->locate.higher); + } + } +} + +/* + flipper1_split breaks p between x-1 and x. +*/ + +#ifdef CC_PROTOTYPE_ANSI +static flipper1 *flipper1_split (flipper1 *p, int x) +#else +static flipper1 *flipper1_split (p, x) +flipper1 *p; +int x; +#endif +{ + flipper1 *q = flipper1alloc (); /* This will not fail - initial supply */ + static int side = 0; + + segment_count++; + if (side) { + HIGHER_HOOKUP (q, p->locate.higher); + HIGHER_HOOKUP (p, q); + q->locate.lower = (flipper1 *) NULL; + q->low = x; + q->high = p->high; + p->high = x - 1; + q->reverse = p->reverse; + if (p->reverse) { + p->order.left->order.right = q; + q->order.left = p->order.left; + q->order.right = p; + p->order.left = q; + } else { + p->order.right->order.left = q; + q->order.right = p->order.right; + q->order.left = p; + p->order.right = q; + } + side = 0; + return q; + } else { + LOWER_HOOKUP (q, p->locate.lower); + LOWER_HOOKUP (p, q); + q->locate.higher = (flipper1 *) NULL; + q->low = p->low; + q->high = x - 1; + p->low = x; + q->reverse = p->reverse; + if (p->reverse) { + p->order.right->order.left = q; + q->order.right = p->order.right; + q->order.left = p; + p->order.right = q; + } else { + p->order.left->order.right = q; + q->order.left = p->order.left; + q->order.right = p; + p->order.left = q; + } + side = 1; + return p; + } +} + +/* flipper1_merge merges p->right into p. */ + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_merge (flipper1 *p) +#else +static void flipper1_merge (p) +flipper1 *p; +#endif +{ + flipper1 *pr = p->order.right; + + if (pr->high > p->high) + p->high = pr->high; + if (pr->low < p->low) + p->low = pr->low; + p->order.right = pr->order.right; + p->order.right->order.left = p; + flipper1_tree_delete (pr); + if (order_root == pr) + order_root = p; + flipper1free (pr); + segment_count--; +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_checkmerge (flipper1 *x) +#else +static void flipper1_checkmerge (x) +flipper1 *x; +#endif +{ + flipper1 *xr = x->order.right; + + if (x->reverse || x->low == x->high) { + if ((xr->reverse || xr->low == xr->high) && xr->high + 1 == x->low) { + x->reverse = 1; + flipper1_merge (x); + } + } + if (!x->reverse || x->low == x->high) { + if ((!xr->reverse || xr->low == xr->high) && x->high + 1 == xr->low) { + x->reverse = 0; + flipper1_merge (x); + } + } +} + +#define HITSIZE 100 + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int ix, int iy) +#else +void CClinkern_flipper_flip (ix, iy) +int ix, iy; +#endif +{ + flipper1 *xp, *yp, *p, *ptemp, *rp, *lp; + int x, y; + + x = flip1_inv[ix]; + y = flip1_inv[iy]; + + xp = flipper1_locate (x); + + if (y >= xp->low && y <= xp->high) { + if (xp->reverse) { + if (x > y && x - y <= HITSIZE) { + int gap = x - y; + gap++; + gap /= 2; + for (; gap; gap--) { + ix = flip1_cyc[x]; + iy = flip1_cyc[y]; + flip1_cyc[x] = iy; + flip1_cyc[y] = ix; + flip1_inv[ix] = y++; + flip1_inv[iy] = x--; + } + return; + } + } else { + if (x < y && y - x <= HITSIZE) { + int gap = y - x; + gap++; + gap /= 2; + for (; gap; gap--) { + ix = flip1_cyc[x]; + iy = flip1_cyc[y]; + flip1_cyc[x] = iy; + flip1_cyc[y] = ix; + flip1_inv[ix] = y--; + flip1_inv[iy] = x++; + } + return; + } + } + } + + + /* split segments if necessary */ + if (xp->reverse) { + if (x != xp->high) { + xp = flipper1_split (xp, x + 1); + xp = xp->order.right; + } + } else { + if (x != xp->low) { + xp = flipper1_split (xp, x); + } + } + + yp = flipper1_locate (y); + if (yp->reverse) { + if (y != yp->low) { + yp = flipper1_split (yp, y); + } + } else { + if (y != yp->high) { + yp = flipper1_split (yp, y + 1); + yp = yp->order.left; + } + } + xp = flipper1_locate (x); + + /* reverse */ + p = xp; + for (;;) { + SWAP (p->order.right, p->order.left, ptemp); + p->reverse ^= 1; + if (p == yp) + break; + p = p->order.left; + } + + if (xp->order.right != yp) { + lp = xp->order.right; + rp = yp->order.left; + + lp->order.right = yp; + rp->order.left = xp; + xp->order.right = rp; + yp->order.left = lp; + } + /* merge segments if necessary */ + rp = xp->order.right; + if (yp != xp->order.right) { + flipper1_checkmerge (xp); + flipper1_checkmerge (yp->order.left); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int ix, int iy, int iz) +#else +int CClinkern_flipper_sequence (ix, iy, iz) +int ix, iy, iz; +#endif +{ + flipper1 *xp, *yp, *zp; + int x, y, z; + + x = flip1_inv[ix]; + y = flip1_inv[iy]; + z = flip1_inv[iz]; + + if (segment_count == 1) { + if (locate_root->reverse) { + if (x >= y) + return y >= z || z >= x; + else + return y >= z && z >= x; + } else { + if (x <= y) + return y <= z || z <= x; + else + return y <= z && z <= x; + } + } + + xp = flipper1_locate (x); + yp = flipper1_locate (y); + zp = flipper1_locate (z); + + if (xp == yp) { + if (xp == zp) { + if (xp->reverse) { + if (x >= y) { + return y >= z || z >= x; + } else { + return y >= z && z >= x; + } + } else { + if (x <= y) { + return y <= z || z <= x; + } else { + return y <= z && z <= x; + } + } + } else { + if (xp->reverse) { + return x >= y; + } else { + return x <= y; + } + } + } else if (xp == zp) { + if (xp->reverse) { + return z >= x; + } else { + return z <= x; + } + } else if (yp == zp) { + if (yp->reverse) { + return y >= z; + } else { + return y <= z; + } + } else { + while (xp != yp) { + if (xp == zp) { + return 0; + } + xp = xp->order.right; + } + return 1; + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_sg2.c b/contrib/blossom/concorde97/LINKERN/flip_sg2.c new file mode 100644 index 0000000000000000000000000000000000000000..432cc8e6d60ec9d1e29e7f2cea06513e7f6ad468 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_sg2.c @@ -0,0 +1,872 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Segments with no UNDO */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 13, 1995 (but mainly from March, 1990) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_reset_perm (int ncount) */ +/* reinitializes the cycle to the one current in the perm array. */ +/* int CClinkern_flipper_reset_temp (int ncount) */ +/* reinitializes the cycle to the current cycle - use this to keep the */ +/* number of segments small. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int x, int y) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* void CClinkern_flipper_flip_perm (int x, int y) */ +/* performs the flip on the reference (perm) cycle - use this to avoid */ +/* a reinitialization when there have not been too many flips. */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This is similar to the version of segments proposed by FJMO. It is */ +/* faster on smaller problems, but is not as flexible since it makes it */ +/* expensive to backtrack deep in the search. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* SEGMENT FLIPPER (flipper1): */ +/* */ +/* 1. CClinkern_flipper_cycle and CClinkern_flipper_cycle_inverse */ +/* return the current number of segments. */ +/* */ +/* 2. This is the first pass - uses a straight cycle of segments, and */ +/* a tree to find segment. */ +/* */ +/***************************************************************************/ + +/* #define CC_USE_QUICK_FLIPS */ + +typedef struct flipper1 { + struct { + struct flipper1 *lower; + struct flipper1 *higher; + } locate; + struct { + struct flipper1 *left; + struct flipper1 *right; + } order; + int low; + int high; + int reverse; + struct flipper1 *next; +} flipper1; + +typedef struct cacheobj { + struct flipper1 *segment; + int stamp; +} cacheobj; + +#ifdef CC_USE_QUICK_FLIPS +typedef struct quickpair { + int first; + int last; + int dir; + int reversed; +} quickpair; +#endif + + +#ifdef CC_PROTOTYPE_ANSI + +static void +#ifdef CC_USE_QUICK_FLIPS + undo_quick_flips (void), +#endif + flipper1free (flipper1 *p), + flipper1_tree_free (flipper1 *); + +static flipper1 + *flipper1_locate (int x), + *flipper1_split (flipper1 *, int); + +#else + +static void +#ifdef CC_USE_QUICK_FLIPS + undo_quick_flips (), +#endif + flipper1free (), + flipper1_tree_free (); + +static flipper1 + *flipper1_locate (), + *flipper1_split (); + +#endif + +#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) + +static flipper1 *locate_root = (flipper1 *) NULL; +static flipper1 *order_root = (flipper1 *) NULL; +static cacheobj *locate_cache = (cacheobj *) NULL; +static int locate_cache_magic = 0; + +#ifdef CC_USE_QUICK_FLIPS +static quickpair quickstack[1000]; +static top_quickstack = 0; +#endif + +static int *flip1_cyc = (int *) NULL; +static int *flip1_inv = (int *) NULL; +static int reversed = 0; +static int short_size = 0; +static int cycle_size = 0; +static int segment_count = 1; + +CC_PTR_ALLOC_ROUTINE (flipper1, flipper1alloc, flipper1chunklist, + flipper1freelist) +CC_PTR_FREE_WORLD_ROUTINE( flipper1, flipper1free_world, flipper1chunklist, + flipper1freelist) +CC_PTR_LEAKS_ROUTINE (flipper1, flipper1_check_leaks, flipper1chunklist, + flipper1freelist, reverse, int) + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1free (flipper1 *p) +#else +static void flipper1free (p) +flipper1 *p; +#endif +{ + p->next = flipper1freelist; + flipper1freelist = p; +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_tree_free (flipper1 *h) +#else +static void flipper1_tree_free (h) +flipper1 *h; +#endif +{ + flipper1 *p = order_root, *q = order_root; + + if (!p) + return; + + do { + p->next = flipper1freelist; /* this does flipper1free (p) */ + flipper1freelist = p; + p = p->order.right; + } while (p != q); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset_perm (int keeper) +#else +int CClinkern_flipper_reset_perm (keeper) +int keeper; +#endif +{ +/* + printf ("CClinkern_flipper_reset_perm (%d)\n", keeper); + fflush (stdout); +*/ + +#ifdef CC_USE_QUICK_FLIPS + if (!keeper) { + undo_quick_flips (); + } else { + top_quickstack = 0; + } +#endif + + flipper1_tree_free (locate_root); + + locate_root = flipper1alloc (); + if (!locate_root) + return 1; + + order_root = locate_root; + locate_root->locate.lower = (flipper1 *) NULL; + locate_root->locate.higher = (flipper1 *) NULL; + locate_root->order.left = locate_root; + locate_root->order.right = locate_root; + locate_root->low = 0; + locate_root->high = cycle_size - 1; + locate_root->reverse = reversed; + segment_count = 1; + locate_cache_magic++; + + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset_temp (int ncount) +#else +int CClinkern_flipper_reset_temp (ncount) +int ncount; +#endif +{ + int i, n, *cyc = (int *) NULL; + int nseg = 0, big = 0, bigreverse = 0; + flipper1 *p, *bigp = (flipper1 *) NULL; + + printf ("CClinkern_flipper_reset_temp ...\n"); + fflush (stdout); + + p = order_root; + do { + if (p->high - p->low > big) { + big = p->high - p->low; + bigp = p; + } + nseg++; + p = p->order.right; + } while (p != order_root); + + if (nseg == 1) + return 0; + + cyc = CC_SAFE_MALLOC (ncount, int); + if (!cyc) { + CC_FREE (locate_cache, cacheobj); + return 1; + } + if (bigp->reverse) { + bigreverse = 1; + p = bigp->order.left; + n = bigp->high + 1; + do { + if (!p->reverse) { + for (i = p->high; i >= p->low; i--) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } else { + for (i = p->low; i <= p->high; i++) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } + p = p->order.left; + } while (p != bigp); + } else { + bigreverse = 0; + p = bigp->order.right; + n = bigp->high + 1; + do { + if (p->reverse) { + for (i = p->high; i >= p->low; i--) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } else { + for (i = p->low; i <= p->high; i++) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } + p = p->order.right; + } while (p != bigp); + } + + for (i = bigp->high + 1; i < ncount; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; + } + for (i = 0; i < bigp->low; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; + } + if (cyc) + CC_FREE (cyc, int); + + + flipper1_tree_free (locate_root); + locate_root = flipper1alloc (); + if (!locate_root) + return 1; + + order_root = locate_root; + locate_root->locate.lower = (flipper1 *) NULL; + locate_root->locate.higher = (flipper1 *) NULL; + locate_root->order.left = locate_root; + locate_root->order.right = locate_root; + locate_root->low = 0; + locate_root->high = ncount - 1; + locate_root->reverse = bigreverse; + segment_count = 1; + reversed = bigreverse; + locate_cache_magic++; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + locate_root = flipper1alloc (); + if (!locate_root) + return 1; + order_root = locate_root; + + if (!locate_cache) { + locate_cache = CC_SAFE_MALLOC (ncount, cacheobj); + if (!locate_cache) { + flipper1free (locate_root); + return 1; + } + for (i = 0; i < ncount; i++) { + locate_cache[i].segment = locate_root; + locate_cache[i].stamp = 0; + } + locate_cache_magic = 0; + } else { + locate_cache_magic++; + } + + locate_root->locate.lower = (flipper1 *) NULL; + locate_root->locate.higher = (flipper1 *) NULL; + locate_root->order.left = locate_root; + locate_root->order.right = locate_root; + locate_root->low = 0; + locate_root->high = ncount - 1; + locate_root->reverse = 0; + segment_count = 1; + + flip1_cyc = CC_SAFE_MALLOC (ncount, int); + if (!flip1_cyc) { + CC_FREE (locate_cache, cacheobj); + return 1; + } + flip1_inv = CC_SAFE_MALLOC (ncount, int); + if (!flip1_inv) { + CC_FREE (locate_cache, cacheobj); + CC_FREE (flip1_cyc, int); + return 1; + } + + for (i = 0; i < ncount; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; + } + cycle_size = ncount; + short_size = ncount/2; + reversed = 0; + +#ifdef CC_USE_QUICK_FLIPS + top_quickstack = 0; +#endif + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + int *p; + +/* + printf ("CClinkern_flipper_cycle ...\n"); + fflush (stdout); +*/ + +#ifdef CC_USE_QUICK_FLIPS + while (top_quickstack) { + undo_quick_flips (); + } +#endif + + if (reversed) { + p = flip1_cyc + cycle_size; + while (p > flip1_cyc) { + *x++ = *--p; + } + } else { + p = flip1_cyc + cycle_size; + x += cycle_size; + while (p > flip1_cyc) { + *--x = *--p; + } + } + + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + flipper1_tree_free (locate_root); + locate_root = (flipper1 *) NULL; + order_root = (flipper1 *) NULL; + + if (flip1_cyc) + CC_FREE (flip1_cyc, int); + if (flip1_inv) + CC_FREE (flip1_inv, int); + cycle_size = 0; + short_size = 0; + reversed = 0; +#ifdef CC_USE_QUICK_FLIPS + top_quickstack = 0; +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + int total, onlist; + + if (locate_cache) + CC_FREE (locate_cache, cacheobj); + + if (flipper1_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding flippers\n", total - onlist); + } + flipper1free_world (); +} + + +#ifdef CC_PROTOTYPE_ANSI +static flipper1 *flipper1_locate (int x) +#else +static flipper1 *flipper1_locate (x) +int x; +#endif +{ + flipper1 *p; + + if (locate_cache[x].stamp == locate_cache_magic) { + p = locate_cache[x].segment; + } else { + p = locate_root; + } + +/* + while (p) { For some reason this is faster under linux +*/ + while (1) { + if (x < p->low) + p = p->locate.lower; + else if (x > p->high) + p = p->locate.higher; + else + break; + } + + locate_cache[x].segment = p; + locate_cache[x].stamp = locate_cache_magic; + + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int ix) +#else +int CClinkern_flipper_next (ix) +int ix; +#endif +{ + int x = flip1_inv[ix]; + flipper1 *p; + + if (segment_count == 1) { + int y; + if (locate_root->reverse) { + y = x - 1; + return (y >= 0) ? flip1_cyc[y] : flip1_cyc[cycle_size-1]; + } else { + y = x + 1; + return (y < cycle_size) ? flip1_cyc[y] : flip1_cyc[0]; + } + } + + p = flipper1_locate (x); + + if (p->reverse) { + return x == p->low ? (p->order.right->reverse + ? flip1_cyc[p->order.right->high] + : flip1_cyc[p->order.right->low]) + : flip1_cyc[x - 1]; + } else { + return x == p->high ? (p->order.right->reverse + ? flip1_cyc[p->order.right->high] + : flip1_cyc[p->order.right->low]) + : flip1_cyc[x + 1]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int ix) +#else +int CClinkern_flipper_prev (ix) +int ix; +#endif +{ + int x = flip1_inv[ix]; + flipper1 *p; + + if (segment_count == 1) { + int y; + if (locate_root->reverse) { + y = x + 1; + return (y < cycle_size) ? flip1_cyc[y] : flip1_cyc[0]; + } else { + y = x - 1; + return (y >= 0) ? flip1_cyc[y] : flip1_cyc[cycle_size-1]; + } + } + + p = flipper1_locate (x); + + if (p->reverse) { + return x == p->high ? (p->order.left->reverse + ? flip1_cyc[p->order.left->low] + : flip1_cyc[p->order.left->high]) + : flip1_cyc[x + 1]; + } else { + return x == p->low ? (p->order.left->reverse + ? flip1_cyc[p->order.left->low] + : flip1_cyc[p->order.left->high]) + : flip1_cyc[x - 1]; + } +} + +/* + flipper1_split breaks p between x-1 and x. returns segment containing x. +*/ + +#ifdef CC_PROTOTYPE_ANSI +static flipper1 *flipper1_split (flipper1 *p, int x) +#else +static flipper1 *flipper1_split (p, x) +flipper1 *p; +int x; +#endif +{ + flipper1 *q = flipper1alloc (); /* This will not fail - initial supply */ + static int side = 0; + + segment_count++; + if (side) { + q->locate.higher = p->locate.higher; + p->locate.higher = q; + q->locate.lower = (flipper1 *) NULL;; + q->low = x; + q->high = p->high; + p->high = x - 1; + q->reverse = p->reverse; + if (p->reverse) { + p->order.left->order.right = q; + q->order.left = p->order.left; + q->order.right = p; + p->order.left = q; + } else { + p->order.right->order.left = q; + q->order.right = p->order.right; + q->order.left = p; + p->order.right = q; + } + side = 1; + return q; + } else { + q->locate.lower = p->locate.lower; + p->locate.lower = q; + q->locate.higher = (flipper1 *) NULL; + q->low = p->low; + q->high = x - 1; + p->low = x; + q->reverse = p->reverse; + if (p->reverse) { + p->order.right->order.left = q; + q->order.right = p->order.right; + q->order.left = p; + p->order.right = q; + } else { + p->order.left->order.right = q; + q->order.left = p->order.left; + q->order.right = p; + p->order.left = q; + } + side = 0; + return p; + } +} + +#ifdef CC_USE_QUICK_FLIPS +#define HITSIZE 10 /* Cannot run problems of size < 2 * HITSIZE */ +#endif + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int ix, int iy) +#else +void CClinkern_flipper_flip (ix, iy) +int ix, iy; +#endif +{ + flipper1 *xp, *yp, *p, *ptemp, *rp, *lp; + int x, y; + + x = flip1_inv[ix]; + y = flip1_inv[iy]; + + xp = flipper1_locate (x); + +#ifdef CC_USE_QUICK_FLIPS + if (y >= xp->low && y <= xp->high) { + if (xp->reverse) { + if (x > y && x - y <= HITSIZE) { + int gap = x - y; + quickstack[top_quickstack].first = ix; + quickstack[top_quickstack].last = iy; + quickstack[top_quickstack].reversed = reversed; + quickstack[top_quickstack++].dir = 1; + gap++; + gap /= 2; + for (; gap; gap--) { + ix = flip1_cyc[x]; + iy = flip1_cyc[y]; + flip1_cyc[x] = iy; + flip1_cyc[y] = ix; + flip1_inv[ix] = y++; + flip1_inv[iy] = x--; + } + return; + } + } else { + if (x < y && y - x <= HITSIZE) { + int gap = y - x; + quickstack[top_quickstack].first = ix; + quickstack[top_quickstack].last = iy; + quickstack[top_quickstack].reversed = reversed; + quickstack[top_quickstack++].dir = 0; + gap++; + gap /= 2; + for (; gap; gap--) { + ix = flip1_cyc[x]; + iy = flip1_cyc[y]; + flip1_cyc[x] = iy; + flip1_cyc[y] = ix; + flip1_inv[ix] = y--; + flip1_inv[iy] = x++; + } + return; + } + } + } +#endif + + + /* split segments if necessary */ + if (xp->reverse) { + if (x != xp->high) { + xp = flipper1_split (xp, x + 1); + xp = xp->order.right; + } + } else { + if (x != xp->low) { + xp = flipper1_split (xp, x); + } + } + + yp = flipper1_locate (y); + if (yp->reverse) { + if (y != yp->low) { + yp = flipper1_split (yp, y); + } + } else { + if (y != yp->high) { + yp = flipper1_split (yp, y + 1); + yp = yp->order.left; + } + } + xp = flipper1_locate (x); + + /* reverse */ + p = xp; + for (;;) { + SWAP (p->order.right, p->order.left, ptemp); + p->reverse ^= 1; + if (p == yp) + break; + p = p->order.left; + } + + if (xp->order.right != yp) { + lp = xp->order.right; + rp = yp->order.left; + + lp->order.right = yp; + rp->order.left = xp; + xp->order.right = rp; + yp->order.left = lp; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + int xloc = flip1_inv[x]; + int yloc = flip1_inv[y]; + int zloc = flip1_inv[z]; + + if (reversed) { + if (xloc >= yloc) + return yloc >= zloc || zloc >= xloc; + else + return yloc >= zloc && zloc >= xloc; + } else { + if (xloc <= yloc) + return yloc <= zloc || zloc <= xloc; + else + return yloc <= zloc && zloc <= xloc; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip_perm (int x, int y) +#else +void CClinkern_flipper_flip_perm (x, y) +int x,y; +#endif +{ + int xloc = flip1_inv[x]; + int yloc = flip1_inv[y]; + int temp; + int gap; + +/* + printf ("CClinkern_flipper_flip_perm (%d, %d)\n", x, y); fflush (stdout); +*/ + + if (reversed) { + SWAP (xloc, yloc, temp); + } + gap = yloc - xloc; + if (gap < 0) gap += cycle_size; + + if (gap > short_size) { + SWAP (xloc, yloc, temp); + reversed ^= 1; + xloc++; + if (xloc >= cycle_size) + xloc = 0; + yloc--; + if (yloc < 0) + yloc = cycle_size - 1; + gap = cycle_size - gap - 2; + } + + if (xloc > yloc) { + gap++; + gap /= 2; + for (; gap; gap--) { + x = flip1_cyc[xloc]; + y = flip1_cyc[yloc]; + flip1_cyc[xloc] = y; + flip1_cyc[yloc] = x; + flip1_inv[x] = yloc--; + flip1_inv[y] = xloc++; + if (xloc >= cycle_size) + xloc = 0; + if (yloc < 0) + yloc = cycle_size - 1; + } + } else { + gap++; + gap /= 2; + for (; gap; gap--) { + x = flip1_cyc[xloc]; + y = flip1_cyc[yloc]; + flip1_cyc[xloc] = y; + flip1_cyc[yloc] = x; + flip1_inv[x] = yloc--; + flip1_inv[y] = xloc++; + } + } +} + +#ifdef CC_USE_QUICK_FLIPS +#ifdef CC_PROTOTYPE_ANSI +static void undo_quick_flips (void) +#else +static void undo_quick_flips () +#endif +{ + int x, y, ix, iy, gap; + +/* + printf ("undo_quick_flips (%d)\n", top_quickstack); + fflush (stdout); +*/ + + while (top_quickstack) { + top_quickstack--; + + assert (reversed == quickstack[top_quickstack].reversed); + + x = flip1_inv[quickstack[top_quickstack].first]; + y = flip1_inv[quickstack[top_quickstack].last]; + if (quickstack[top_quickstack].dir) { + SWAP (x, y , ix); + } + gap = x - y + 1; + if (gap < 0) { + printf ("AARG: %d\n", gap); fflush (stdout); + } + gap /= 2; + for (; gap; gap--) { + ix = flip1_cyc[x]; + iy = flip1_cyc[y]; + flip1_cyc[x] = iy; + flip1_cyc[y] = ix; + flip1_inv[ix] = y++; + flip1_inv[iy] = x--; + } + } +} +#endif diff --git a/contrib/blossom/concorde97/LINKERN/flip_sg3.c b/contrib/blossom/concorde97/LINKERN/flip_sg3.c new file mode 100644 index 0000000000000000000000000000000000000000..8433b8ebea7d485e593194cfcc53d79f317dc1cc --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_sg3.c @@ -0,0 +1,982 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Segments with UNDO */ +/* - No perm mucks */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: April 24, 1995 (but mainly from March, 1990) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_reset_temp (int ncount) */ +/* reinitializes the cycle to the current cycle - use this to keep the */ +/* number of segments small. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int x, int y) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version is closest to our orignal segment code. It undos the */ +/* flips that do not lead to an improvement. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#define USE_TIMESTAMP + +/***************************************************************************/ +/* */ +/* FULL SEGMENT FLIPPER (flipper1): */ +/* */ +/* 1. CClinkern_flipper_cycle and CClinkern_flipper_cycle_inverse */ +/* return the current number of segments. */ +/* */ +/* 2. this version wants to keep the segment tree around until a */ +/* Lin-Kern round is complete. If its an improving round, then */ +/* the perm tour is updated. If its not a winner, then the segment */ +/* tree is discarded. Sounds like it would be okay late in a run */ +/* not many winners are found (do not use ACCEPT_TIES), but the big */ +/* trees lead to long searches for the segment containing a node. */ +/* */ +/***************************************************************************/ + + +typedef struct flipper1 { + struct { + struct flipper1 *parent; + struct flipper1 *lower; + struct flipper1 *higher; + } locate; + struct { + struct flipper1 *left; + struct flipper1 *right; + } order; + int low; + int high; + int reverse; + struct flipper1 *next; +} flipper1; + +#ifdef USE_TIMESTAMP +typedef struct cacheobj { + struct flipper1 *segment; + int stamp; +} cacheobj; +#endif + + +#ifdef CC_PROTOTYPE_ANSI + +static void + flipper1_tree_delete (flipper1 *), + flipper1_merge (flipper1 *), + flipper1_checkmerge (flipper1 *), + flipper1free (flipper1 *p), + flipper1_tree_free (flipper1 *, flipper1 *); + +static flipper1 + *flipper1_locate (int x), + *flipper1_split (flipper1 *, int); + +#else + +static void + flipper1_tree_delete (), + flipper1_merge (), + flipper1_checkmerge (), + flipper1free (), + flipper1_tree_free (); + +static flipper1 + *flipper1_locate (), + *flipper1_split (); + +#endif + +#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) + +#define LOCATE_CHILD(p, c) (*((p) ? ((p)->locate.lower == (c) ? \ + &(p)->locate.lower : &(p)->locate.higher) : \ + &locate_root)) + +#define PARENT_HOOKUP(q, p, c) (((q)->locate.parent = (p)), \ + (LOCATE_CHILD((p),(c)) = (q))) + +#define HIGHER_HOOKUP(p, c) (((p)->locate.higher = (c)), \ + ((c) ? (c)->locate.parent = (p) : (flipper1 *) NULL)) + +#define LOWER_HOOKUP(p, c) (((p)->locate.lower = (c)), \ + ((c) ? (c)->locate.parent = (p) : (flipper1 *) NULL)) + +static flipper1 *locate_root = (flipper1 *) NULL; +static flipper1 *order_root = (flipper1 *) NULL; +#ifdef USE_TIMESTAMP +static cacheobj *locate_cache = (cacheobj *) NULL; +static int locate_cache_magic = 0; +#else +static flipper1 **locate_cache = (flipper1 **) NULL; +#endif + +static int *flip1_cyc = (int *) NULL; +static int *flip1_inv = (int *) NULL; +static int reversed = 0; +static int short_size = 0; +static int cycle_size = 0; +static int segment_count = 1; + +/* +static double totalsize = 1.0; +static double totaldepth = 1.0; +static int depthcalls = 1; +*/ + +CC_PTR_ALLOC_ROUTINE (flipper1, flipper1alloc, flipper1chunklist, + flipper1freelist) +CC_PTR_FREE_WORLD_ROUTINE (flipper1, flipper1free_world, flipper1chunklist, + flipper1freelist) +CC_PTR_LEAKS_ROUTINE (flipper1, flipper1_check_leaks, flipper1chunklist, + flipper1freelist, reverse, int) + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1free (flipper1 *p) +#else +static void flipper1free (p) +flipper1 *p; +#endif +{ + p->next = flipper1freelist; + flipper1freelist = p; + p->low = p->high = -1; +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_tree_free (flipper1 *p, flipper1 *bigp) +#else +static void flipper1_tree_free (p, bigp) +flipper1 *p, *bigp; +#endif +{ + if (p) { + flipper1_tree_free (p->locate.lower, bigp); + flipper1_tree_free (p->locate.higher, bigp); + if (p != bigp) + flipper1free (p); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset_perm (int ncount) +#else +int CClinkern_flipper_reset_perm (ncount) +int ncount; +#endif +{ + flipper1_tree_free (locate_root, (flipper1 *) NULL); + locate_root = flipper1alloc (); + if (!locate_root) + return 1; + + order_root = locate_root; + locate_root->locate.lower = (flipper1 *) NULL; + locate_root->locate.higher = (flipper1 *) NULL; + locate_root->order.left = locate_root; + locate_root->order.right = locate_root; + locate_root->low = 0; + locate_root->high = cycle_size - 1; + locate_root->reverse = reversed; + segment_count = 1; + locate_cache_magic++; + +/* + printf ("Locate Calls: %d Depth: %.0f Size: %.0f\n", + depthcalls, totaldepth/depthcalls, totalsize/depthcalls); + fflush (stdout); +*/ + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset_temp (int ncount) +#else +int CClinkern_flipper_reset_temp (ncount) +int ncount; +#endif +{ + int i, n, *cyc = (int *) NULL; + int nseg = 0, big = 0, bigreverse = 0; + flipper1 *p, *bigp = (flipper1 *) NULL; + +/* + printf ("CClinkern_flipper_reset_temp ....\n"); fflush (stdout); + printf ("Locate Calls: %d Depth: %.0f Size: %.0f\n", + depthcalls, totaldepth/depthcalls, totalsize/depthcalls); + fflush (stdout); +*/ + + p = order_root; + do { + if (p->high - p->low > big) { + big = p->high - p->low; + bigp = p; + } + nseg++; + p = p->order.right; + } while (p != order_root); + + if (nseg == 1) + return 0; + + cyc = CC_SAFE_MALLOC (ncount, int); + if (!cyc) { +#ifdef USE_TIMESTAMP + CC_FREE (locate_cache, cacheobj); +#else + CC_FREE (locate_cache, flipper1 *); +#endif + return 1; + } + if (bigp->reverse) { + bigreverse = 1; + p = bigp->order.left; + n = bigp->high + 1; + do { + if (!p->reverse) { + for (i = p->high; i >= p->low; i--) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } else { + for (i = p->low; i <= p->high; i++) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } + p = p->order.left; + } while (p != bigp); + } else { + bigreverse = 0; + p = bigp->order.right; + n = bigp->high + 1; + do { + if (p->reverse) { + for (i = p->high; i >= p->low; i--) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } else { + for (i = p->low; i <= p->high; i++) { + if (n == ncount) + n = 0; + cyc[n++] = flip1_cyc[i]; + } + } + p = p->order.right; + } while (p != bigp); + } + + for (i = bigp->high + 1; i < ncount; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; +#ifndef USE_TIMESTAMP + locate_cache[i] = bigp; +#endif + } + for (i = 0; i < bigp->low; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; +#ifndef USE_TIMESTAMP + locate_cache[i] = bigp; +#endif + } + if (cyc) + CC_FREE (cyc, int); + + +#ifdef USE_TIMESTAMP + flipper1_tree_free (locate_root, (flipper1 *) NULL); + locate_root = flipper1alloc (); + if (!locate_root) + return 1; +#else + flipper1_tree_free (locate_root, bigp); + locate_root = bigp; +#endif + + order_root = locate_root; + locate_root->locate.parent = (flipper1 *) NULL; + locate_root->locate.lower = (flipper1 *) NULL; + locate_root->locate.higher = (flipper1 *) NULL; + locate_root->order.left = locate_root; + locate_root->order.right = locate_root; + locate_root->low = 0; + locate_root->high = ncount - 1; + locate_root->reverse = bigreverse; + segment_count = 1; + reversed = bigreverse; + +#ifdef USE_TIMESTAMP + locate_cache_magic++; +#endif + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + locate_root = flipper1alloc (); + if (!locate_root) + return 1; + order_root = locate_root; + +#ifdef USE_TIMESTAMP + if (!locate_cache) { + locate_cache = CC_SAFE_MALLOC (ncount, cacheobj); + if (!locate_cache) { + flipper1free (locate_root); + return 1; + } + for (i = 0; i < ncount; i++) { + locate_cache[i].segment = locate_root; + locate_cache[i].stamp = 0; + } + locate_cache_magic = 0; + } else { + locate_cache_magic++; + } +#else + if (!locate_cache) { + locate_cache = CC_SAFE_MALLOC (ncount, flipper1 *); + if (!locate_cache) { + flipper1free (locate_root); + return 1; + } + } +#endif + + locate_root->locate.parent = (flipper1 *) NULL; + locate_root->locate.lower = (flipper1 *) NULL; + locate_root->locate.higher = (flipper1 *) NULL; + locate_root->order.left = locate_root; + locate_root->order.right = locate_root; + locate_root->low = 0; + locate_root->high = ncount - 1; + locate_root->reverse = 0; + segment_count = 1; + +#ifndef USE_TIMESTAMP + for (i = 0; i < ncount; i++) { + locate_cache[i] = locate_root; + } +#endif + + flip1_cyc = CC_SAFE_MALLOC (ncount, int); + if (!flip1_cyc) { +#ifdef USE_TIMESTAMP + CC_FREE (locate_cache, cacheobj); +#else + CC_FREE (locate_cache, flipper1 *); +#endif + return 1; + } + flip1_inv = CC_SAFE_MALLOC (ncount, int); + if (!flip1_inv) { +#ifdef USE_TIMESTAMP + CC_FREE (locate_cache, cacheobj); +#else + CC_FREE (locate_cache, flipper1 *); +#endif + CC_FREE (flip1_cyc, int); + return 1; + } + + for (i = 0; i < ncount; i++) { + flip1_cyc[i] = cyc[i]; + flip1_inv[cyc[i]] = i; + } + cycle_size = ncount; + short_size = ncount/2; + reversed = 0; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + flipper1 *p; + int i; + int n = 0; + int nseg = 0; + + p = order_root; + + do { + nseg++; + if (p->reverse) { + for (i = p->high; i >= p->low; i--) + x[n++] = flip1_cyc[i]; + } else { + for (i = p->low; i <= p->high; i++) + x[n++] = flip1_cyc[i]; + } + p = p->order.right; + } while (p != order_root); + + assert (nseg == segment_count); +/* + printf ("Segment Hits: %d (Total %d) (%.2f)\n", seghit, segtotal, + (double) seghit / (double) segtotal); + fflush (stdout); +*/ + return nseg; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + flipper1_tree_free (locate_root, (flipper1 *) NULL); + locate_root = (flipper1 *) NULL; + order_root = (flipper1 *) NULL; + + if (flip1_cyc) + CC_FREE (flip1_cyc, int); + if (flip1_inv) + CC_FREE (flip1_inv, int); + cycle_size = 0; + short_size = 0; + reversed = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + int total, onlist; + + if (locate_cache) +#ifdef USE_TIMESTAMP + CC_FREE (locate_cache, cacheobj); +#else + CC_FREE (locate_cache, flipper1 *); +#endif + + if (flipper1_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding flippers\n", total - onlist); + } + flipper1free_world (); +} + + +#ifdef CC_PROTOTYPE_ANSI +static flipper1 *flipper1_locate (int x) +#else +static flipper1 *flipper1_locate (x) +int x; +#endif +{ + flipper1 *p; + +#ifdef USE_TIMESTAMP + if (locate_cache[x].stamp == locate_cache_magic) { + p = locate_cache[x].segment; + } else { + p = locate_root; + } +#else + p = locate_cache[x]; +#endif + + if (x <= p->high && x >= p->low) + return p; + else + p = locate_root; + + if (p->high < x) { + if (p->high != -1) { + if (p->locate.higher && p->locate.higher->high >= x) { + p = p->locate.higher; + } else if (p->locate.parent && p->locate.parent->high >= x) { + p = p->locate.parent; + } else { + p = locate_root; + } + } else { + p = locate_root; + } + } else if (p->low > x) { + if (p->locate.lower && p->locate.lower->low <= x) { + p = p->locate.lower; + } else if (p->locate.parent && p->locate.parent->low <= x) { + p = p->locate.parent; + } else { + p = locate_root; + } + } else { + return p; + } + +/* + while (p) { For some reason this is faster under linux +*/ + while (1) { +/* + totaldepth += 1.0; +*/ + if (x < p->low) + p = p->locate.lower; + else if (x > p->high) + p = p->locate.higher; + else + break; + } +/* + totalsize += segment_count; + depthcalls++; +*/ + +#ifdef USE_TIMESTAMP + locate_cache[x].segment = p; + locate_cache[x].stamp = locate_cache_magic; +#else + locate_cache[x] = p; +#endif + + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int ix) +#else +int CClinkern_flipper_next (ix) +int ix; +#endif +{ + int x = flip1_inv[ix]; + flipper1 *p; + + p = flipper1_locate (x); + + if (p->reverse) { + return x == p->low ? (p->order.right->reverse + ? flip1_cyc[p->order.right->high] + : flip1_cyc[p->order.right->low]) + : flip1_cyc[x - 1]; + } else { + return x == p->high ? (p->order.right->reverse + ? flip1_cyc[p->order.right->high] + : flip1_cyc[p->order.right->low]) + : flip1_cyc[x + 1]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int ix) +#else +int CClinkern_flipper_prev (ix) +int ix; +#endif +{ + int x = flip1_inv[ix]; + flipper1 *p; + + p = flipper1_locate (x); + + if (p->reverse) { + return x == p->high ? (p->order.left->reverse + ? flip1_cyc[p->order.left->low] + : flip1_cyc[p->order.left->high]) + : flip1_cyc[x + 1]; + } else { + return x == p->low ? (p->order.left->reverse + ? flip1_cyc[p->order.left->low] + : flip1_cyc[p->order.left->high]) + : flip1_cyc[x - 1]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_tree_delete (flipper1 *p) +#else +static void flipper1_tree_delete (p) +flipper1 *p; +#endif +{ + flipper1 *q; + + if (p->locate.lower == (flipper1 *) NULL) { + if (p->locate.higher) { + PARENT_HOOKUP (p->locate.higher, p->locate.parent, p); + } else { + LOCATE_CHILD (p->locate.parent, p) = (flipper1 *) NULL; + } + } else if (p->locate.higher == (flipper1 *) NULL) { + PARENT_HOOKUP (p->locate.lower, p->locate.parent, p); + } else { + q = p->locate.lower; + while (q->locate.higher) + q = q->locate.higher; + if (q->locate.parent == p) { + PARENT_HOOKUP (q, p->locate.parent, p); + HIGHER_HOOKUP (q, p->locate.higher); + } else { + HIGHER_HOOKUP (q->locate.parent, q->locate.lower); + PARENT_HOOKUP (q, p->locate.parent, p); + LOWER_HOOKUP (q, p->locate.lower); + HIGHER_HOOKUP (q, p->locate.higher); + } + } +} + +/* + flipper1_split breaks p between x-1 and x. +*/ + +#ifdef CC_PROTOTYPE_ANSI +static flipper1 *flipper1_split (flipper1 *p, int x) +#else +static flipper1 *flipper1_split (p, x) +flipper1 *p; +int x; +#endif +{ + flipper1 *q = flipper1alloc (); /* This will not fail - initial supply */ + static int side = 0; + + segment_count++; + if (side) { + HIGHER_HOOKUP (q, p->locate.higher); + HIGHER_HOOKUP (p, q); + q->locate.lower = (flipper1 *) NULL; + q->low = x; + q->high = p->high; + p->high = x - 1; + q->reverse = p->reverse; + if (p->reverse) { + p->order.left->order.right = q; + q->order.left = p->order.left; + q->order.right = p; + p->order.left = q; + } else { + p->order.right->order.left = q; + q->order.right = p->order.right; + q->order.left = p; + p->order.right = q; + } + side = 0; + return q; + } else { + LOWER_HOOKUP (q, p->locate.lower); + LOWER_HOOKUP (p, q); + q->locate.higher = (flipper1 *) NULL; + q->low = p->low; + q->high = x - 1; + p->low = x; + q->reverse = p->reverse; + if (p->reverse) { + p->order.right->order.left = q; + q->order.right = p->order.right; + q->order.left = p; + p->order.right = q; + } else { + p->order.left->order.right = q; + q->order.left = p->order.left; + q->order.right = p; + p->order.left = q; + } + side = 1; + return p; + } +} + +/* flipper1_merge merges p->right into p. */ + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_merge (flipper1 *p) +#else +static void flipper1_merge (p) +flipper1 *p; +#endif +{ + flipper1 *pr = p->order.right; + + if (pr->high > p->high) + p->high = pr->high; + if (pr->low < p->low) + p->low = pr->low; + p->order.right = pr->order.right; + p->order.right->order.left = p; + flipper1_tree_delete (pr); + if (order_root == pr) + order_root = p; + flipper1free (pr); + segment_count--; +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper1_checkmerge (flipper1 *x) +#else +static void flipper1_checkmerge (x) +flipper1 *x; +#endif +{ + flipper1 *xr = x->order.right; + + if (x->reverse || x->low == x->high) { + if ((xr->reverse || xr->low == xr->high) && xr->high + 1 == x->low) { + x->reverse = 1; + flipper1_merge (x); + } + } + if (!x->reverse || x->low == x->high) { + if ((!xr->reverse || xr->low == xr->high) && x->high + 1 == xr->low) { + x->reverse = 0; + flipper1_merge (x); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int ix, int iy) +#else +void CClinkern_flipper_flip (ix, iy) +int ix, iy; +#endif +{ + flipper1 *xp, *yp, *p, *ptemp, *rp, *lp; + int x, y; + + x = flip1_inv[ix]; + y = flip1_inv[iy]; + + xp = flipper1_locate (x); + + /* split segments if necessary */ + if (xp->reverse) { + if (x != xp->high) { + xp = flipper1_split (xp, x + 1); + xp = xp->order.right; + } + } else { + if (x != xp->low) { + xp = flipper1_split (xp, x); + } + } + + yp = flipper1_locate (y); + if (yp->reverse) { + if (y != yp->low) { + yp = flipper1_split (yp, y); + } + } else { + if (y != yp->high) { + yp = flipper1_split (yp, y + 1); + yp = yp->order.left; + } + } + xp = flipper1_locate (x); + + /* reverse */ + p = xp; + for (;;) { + SWAP (p->order.right, p->order.left, ptemp); + p->reverse ^= 1; + if (p == yp) + break; + p = p->order.left; + } + + if (xp->order.right != yp) { + lp = xp->order.right; + rp = yp->order.left; + + lp->order.right = yp; + rp->order.left = xp; + xp->order.right = rp; + yp->order.left = lp; + } + /* merge segments if necessary */ + rp = xp->order.right; + if (yp != xp->order.right) { + flipper1_checkmerge (xp); + flipper1_checkmerge (yp->order.left); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int ix, int iy, int iz) +#else +int CClinkern_flipper_sequence (ix, iy, iz) +int ix, iy, iz; +#endif +{ + flipper1 *xp, *yp, *zp; + int x, y, z; + + x = flip1_inv[ix]; + y = flip1_inv[iy]; + z = flip1_inv[iz]; + + if (segment_count == 1) { + if (locate_root->reverse) { + if (x >= y) + return y >= z || z >= x; + else + return y >= z && z >= x; + } else { + if (x <= y) + return y <= z || z <= x; + else + return y <= z && z <= x; + } + } + + xp = flipper1_locate (x); + yp = flipper1_locate (y); + zp = flipper1_locate (z); + + if (xp == yp) { + if (xp == zp) { + if (xp->reverse) { + if (x >= y) { + return y >= z || z >= x; + } else { + return y >= z && z >= x; + } + } else { + if (x <= y) { + return y <= z || z <= x; + } else { + return y <= z && z <= x; + } + } + } else { + if (xp->reverse) { + return x >= y; + } else { + return x <= y; + } + } + } else if (xp == zp) { + if (xp->reverse) { + return z >= x; + } else { + return z <= x; + } + } else if (yp == zp) { + if (yp->reverse) { + return y >= z; + } else { + return y <= z; + } + } else { + while (xp != yp) { + if (xp == zp) { + return 0; + } + xp = xp->order.right; + } + return 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip_perm (int x, int y) +#else +void CClinkern_flipper_flip_perm (x, y) +int x,y; +#endif +{ + int xloc = flip1_inv[x]; + int yloc = flip1_inv[y]; + int temp; + int gap; + + if (reversed) { + SWAP (xloc, yloc, temp); + } + gap = yloc - xloc; + if (gap < 0) gap += cycle_size; + if (gap > short_size) { + SWAP (xloc, yloc, temp); + reversed ^= 1; + xloc++; + if (xloc >= cycle_size) + xloc = 0; + yloc--; + if (yloc < 0) + yloc = cycle_size - 1; + gap = cycle_size - gap - 2; + } + if (xloc > yloc) { + gap++; + gap /= 2; + for (; gap; gap--) { + x = flip1_cyc[xloc]; + y = flip1_cyc[yloc]; + flip1_cyc[xloc] = y; + flip1_cyc[yloc] = x; + flip1_inv[x] = yloc--; + flip1_inv[y] = xloc++; + if (xloc >= cycle_size) + xloc = 0; + if (yloc < 0) + yloc = cycle_size - 1; + } + } else { + gap++; + gap /= 2; + for (; gap; gap--) { + x = flip1_cyc[xloc]; + y = flip1_cyc[yloc]; + flip1_cyc[xloc] = y; + flip1_cyc[yloc] = x; + flip1_inv[x] = yloc--; + flip1_inv[y] = xloc++; + } + } +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_sp1.c b/contrib/blossom/concorde97/LINKERN/flip_sp1.c new file mode 100644 index 0000000000000000000000000000000000000000..c0a085371bc5c27e5205f5338d6babbcc291cdd1 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_sp1.c @@ -0,0 +1,1017 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Splay Trees (no dummy) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 28, 1995 (but mainly from March, 1990) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* void CClinkern_flipper_sequence_burst_init (int x, int z) */ +/* initilizes the tree for a sequence of (x, y, z) sequence queries. */ +/* int CClinkern_flipper_sequence_burst (int x, int y, int z) */ +/* can be called instead of CClinkern_flipper_sequence, after a call to*/ +/* CClinkern_flipper_sequence_burst_init (x, y), and before any flips */ +/* (but it requires that NEXT_PREV_NOSPLAY be defined). Does not seem */ +/* to improve the running time. */ +/* */ +/* NOTES: */ +/* Should work well on very large problems. */ +/* One of NEXT_PREV_SPLAY, NEXT_PREV_NOSPLAY, NEXT_PREV_NOSPLAY1, */ +/* or NEXT_PREV_NOSPLAY2 must be defined. (NEXT_PREV_NOSPLAY looks like */ +/* the fastest.) One of SEQUENCE_SPLAY or SEQUENCE_NOSPLAY must be */ +/* defined. (SEQUENCE_NOSPLAY looks like the fastest - it does not splay */ +/* the middle node in the query.) */ +/* */ +/* If USE_UGLY_SPLAY is defined, an uglier (but perhaps faster) splay */ +/* step is used. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* In this case, the neighbor is never splayed, so NEXT_PREV_SPLAY */ +/* and NEXT_PREV_NOSPLAY2 become equivalent, as do NEXT_PREV_NOSPLAY */ +/* NEXT_PREV_NOSPLAY1. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/*#define NEXT_PREV_SPLAY */ /* 1xxxx */ +#define NEXT_PREV_NOSPLAY /* 2xxxx */ +/*#define NEXT_PREV_NOSPLAY1 */ /* 3xxxx */ +/*#define NEXT_PREV_NOSPLAY2 */ /* 4xxxx */ +/*#define SEQUENCE_SPLAY */ /* x1xxx */ +#define SEQUENCE_NOSPLAY /* x2xxx */ +#define USE_UGLY_SPLAY /* xx2xx */ +#define SAVE_NEIGHBORS /* xxx2x */ + +/***************************************************************************/ +/* */ +/* SPLAY TREE FLIPPER (flipper4): */ +/* */ +/* 1. CClinkern_flipper_cycle and CClinkern_flipper_cycle_inverse return the number of */ +/* nodes. */ +/* */ +/* 2. The basic splay implementation - uses a splay tree with one node */ +/* per element. */ +/* */ +/***************************************************************************/ + +typedef struct splay { + struct splay *parent; + struct splay *child[2]; +#ifdef SAVE_NEIGHBORS + struct splay *neigh[2]; +#endif + int reversed; + int mark; + int value; +} splay; + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +#ifdef CC_PROTOTYPE_ANSI + +static int + flipper4_cycle_fillin(int *x, int i, splay *p, int r); +static void + flipper4_reverse (splay *p), + flipper4_rotate (splay *x, splay *px), + flipper4_splay (splay *x); +static splay + *flipper4_make_tree (int a, int b, int *cyc); + +#else + +static int + flipper4_cycle_fillin(); +static void + flipper4_reverse (), + flipper4_rotate (), + flipper4_splay (); +static splay + *flipper4_make_tree (); + +#endif + +static splay *splay_space = (splay *) NULL; +static splay root; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static splay *flipper4_make_tree (int a, int b, int *cyc) +#else +static splay *flipper4_make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + splay *p; + int center; + + if (b < a) + return (splay *) NULL; + + center = (a + b)/2; + p = splay_space + cyc[center]; + if ((p->child[0] = flipper4_make_tree (a, center-1, cyc)) != (splay *) NULL) + p->child[0]->parent = p; + if ((p->child[1] = flipper4_make_tree (center+1, b, cyc)) != (splay *) NULL) + p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + +/* + printf ("Flipper flags:"); +#ifdef NEXT_PREV_SPLAY + printf (" NEXT_PREV_SPLAY"); +#endif +#ifdef NEXT_PREV_NOSPLAY + printf (" NEXT_PREV_NOSPLAY"); +#endif +#ifdef NEXT_PREV_NOSPLAY1 + printf (" NEXT_PREV_NOSPLAY1"); +#endif +#ifdef NEXT_PREV_NOSPLAY2 + printf (" NEXT_PREV_NOSPLAY2"); +#endif +#ifdef SEQUENCE_SPLAY + printf (" SEQUENCE_SPLAY"); +#endif +#ifdef SEQUENCE_NOSPLAY + printf (" SEQUENCE_NOSPLAY"); +#endif +#ifdef USE_UGLY_SPLAY + printf (" USE_UGLY_SPLAY"); +#else + printf (" !USE_UGLY_SPLAY"); +#endif +#ifdef SAVE_NEIGHBORS + printf (" SAVE_NEIGHBORS"); +#else + printf (" !SAVE_NEIGHBORS"); +#endif + printf (" !DUMMY_LEAF\n"); +*/ + + root.reversed = 0; + root.parent = (splay *) NULL; + root.child[1] = (splay *) NULL; + root.value = ncount; + + splay_space = CC_SAFE_MALLOC (ncount, splay); + if (!splay_space) + return 1; + + for (i = 0; i < ncount; i++) { + splay_space[i].reversed = 0; + splay_space[i].value = i; + splay_space[i].mark = 0; +#ifdef SAVE_NEIGHBORS + if (i==0) { + splay_space[cyc[0]].neigh[0] = &splay_space[cyc[ncount-1]]; + splay_space[cyc[ncount-1]].neigh[1] = &splay_space[cyc[0]]; + } else { + splay_space[cyc[i]].neigh[0] = &splay_space[cyc[i-1]]; + splay_space[cyc[i-1]].neigh[1] = &splay_space[cyc[i]]; + } +#endif + } + + root.child[0] = flipper4_make_tree (0, ncount - 1, cyc); + root.child[0]->parent = &root; + root.mark = 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int flipper4_cycle_fillin(int *x, int i, splay *p, int r) +#else +static int flipper4_cycle_fillin(x, i, p, r) +int *x; +int i; +splay *p; +int r; +#endif +{ + if (!p) + return i; + + r ^= p->reversed; + i = flipper4_cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = flipper4_cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + return flipper4_cycle_fillin (x, 0, root.child[0], 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (splay_space) + CC_FREE (splay_space, splay); + + root.child[0] = (splay *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + + +#ifdef CC_PROTOTYPE_ANSI +static void flipper4_reverse (splay *p) +#else +static void flipper4_reverse (p) +splay *p; +#endif +{ + splay *temp; + + SWAP (p->child[0], p->child[1], temp); + if (p->child[0]) + p->child[0]->reversed ^= 1; + if (p->child[1]) + p->child[1]->reversed ^= 1; + p->reversed ^= 1; +#ifdef SAVE_NEIGHBORS + SWAP (p->neigh[0], p->neigh[1], temp); +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper4_rotate (splay *x, splay *px) +#else +static void flipper4_rotate (x, px) +splay *x, *px; +#endif +{ + splay *b; + + if (px->child[0] == x) { + b = x->child[1]; + if (b) b->parent = px; + x->child[1] = px; + x->parent = px->parent; + if (x->parent->child[0] == px) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + px->child[0] = b; + px->parent = x; + } else { + b = x->child[0]; + if (b) b->parent = px; + x->child[0] = px; + x->parent = px->parent; + if (x->parent->child[0] == px) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + px->child[1] = b; + px->parent = x; + } +} + +#ifdef USE_UGLY_SPLAY + +#ifdef CC_PROTOTYPE_ANSI +static void flipper4_splay (splay *x) +#else +static void flipper4_splay (x) +splay *x; +#endif +{ + splay *px; + splay *ppx; + splay *b, *c; + + for (;;) { + px = x->parent; + if (px->mark) + return; + ppx = px->parent; + if (ppx->mark) { + if (px->reversed) + flipper4_reverse (px); + if (x->reversed) + flipper4_reverse (x); + flipper4_rotate (x, px); + return; + } + if (ppx->reversed) + flipper4_reverse (ppx); + if (px->reversed) + flipper4_reverse (px); + if (x->reversed) + flipper4_reverse (x); + + x->parent = ppx->parent; + if (x->parent->child[0] == ppx) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + + if (ppx->child[0] == px) { + if (px->child[0] == x) { + b = x->child[1]; + c = px->child[1]; + if (b) b->parent = px; + if (c) c->parent = ppx; + x->child[1] = px; + px->child[0] = b; + px->child[1] = ppx; + ppx->child[0] = c; + px->parent = x; + ppx->parent = px; + } else { + b = x->child[0]; + c = x->child[1]; + if (b) b->parent = px; + if (c) c->parent = ppx; + x->child[0] = px; + x->child[1] = ppx; + px->child[1] = b; + ppx->child[0] = c; + px->parent = x; + ppx->parent = x; + } + } else { + if (px->child[1] == x) { + b = px->child[0]; + c = x->child[0]; + if (b) b->parent = ppx; + if (c) c->parent = px; + x->child[0] = px; + px->child[0] = ppx; + px->child[1] = c; + ppx->child[1] = b; + px->parent = x; + ppx->parent = px; + } else { + b = x->child[0]; + c = x->child[1]; + if (b) b->parent = ppx; + if (c) c->parent = px; + x->child[0] = ppx; + x->child[1] = px; + ppx->child[1] = b; + px->child[0] = c; + px->parent = x; + ppx->parent = x; + } + } + } +} + +#else /* USE_UGLY_SPLAY */ + +#ifdef CC_PROTOTYPE_ANSI +static void flipper4_splay (splay *x) +#else +static void flipper4_splay (x) +splay *x; +#endif +{ + splay *px; + splay *ppx; + + for (;;) { + px = x->parent; + if (px->mark) + return; + ppx = px->parent; + if (ppx->mark) { + if (px->reversed) + flipper4_reverse (px); + if (x->reversed) + flipper4_reverse (x); + flipper4_rotate (x, px); + return; + } + if (ppx->reversed) + flipper4_reverse (ppx); + if (px->reversed) + flipper4_reverse (px); + if (x->reversed) + flipper4_reverse (x); + if (ppx->child[0] == px) { + if (px->child[0] == x) { + flipper4_rotate (px, ppx); + flipper4_rotate (x, px); + } else { + flipper4_rotate (x, px); + flipper4_rotate (x, ppx); + } + } else { + if (px->child[1] == x) { + flipper4_rotate (px, ppx); + flipper4_rotate (x, px); + } else { + flipper4_rotate (x, px); + flipper4_rotate (x, ppx); + } + } + } +} + +#endif /* USE_UGLY_SPLAY */ + +#ifdef NEXT_PREV_SPLAY +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + flipper4_splay (p); + if (p->reversed) + flipper4_reverse (p); +#ifdef SAVE_NEIGHBORS + return p->neigh[1]->value; +#else /* SAVE_NEIGHBORS */ + if (p->child[1]) + p = p->child[1]; + r = 0; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) break; + p = pnext; + } + flipper4_splay (p); + return p->value; +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + flipper4_splay (p); + if (p->reversed) + flipper4_reverse (p); +#ifdef SAVE_NEIGHBORS + return p->neigh[0]->value; +#else /* SAVE_NEIGHBORS */ + if (p->child[0]) + p = p->child[0]; + r = 0; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) break; + p = pnext; + } + flipper4_splay (p); + return p->value; +#endif /* SAVE_NEIGHBORS */ +} +#endif /* NEXT_PREV_SPLAY */ + + +#ifdef NEXT_PREV_NOSPLAY +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) /* CClinkern_flipper_next_nspl */ +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + splay *p = splay_space + x; + splay *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; !pnext->mark; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; /* change */ + pnext = p->parent; + while (!pnext->mark) { + if (pnext->child[r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + splay *p = splay_space + x; + splay *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; !pnext->mark; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; /* change */ + pnext = p->parent; + while (!pnext->mark) { + if (pnext->child[1 - r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} +#endif /* NEXT_PREV_NOSPLAY */ + + +#ifdef NEXT_PREV_NOSPLAY1 +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) /* CClinkern_flipper_next_nspl1 */ +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; !pnext->mark; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + flipper4_splay (p); + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; /* change */ + pnext = p->parent; + while (!pnext->mark) { + if (pnext->child[r] == p) { + flipper4_splay (pnext); + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) { + flipper4_splay (p); + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl1 */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; !pnext->mark; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + flipper4_splay (p); + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; /* change */ + pnext = p->parent; + while (!pnext->mark) { + if (pnext->child[1 - r] == p) { + flipper4_splay (pnext); + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) { + flipper4_splay (p); + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} +#endif /* NEXT_PREV_NOSPLAY1 */ + + +#ifdef NEXT_PREV_NOSPLAY2 +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) /* CClinkern_flipper_next_nospl2 */ +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + flipper4_splay (p); + if (p->reversed) + flipper4_reverse (p); +#ifdef SAVE_NEIGHBORS + return p->neigh[1]->value; +#else /* SAVE_NEIGHBORS */ + if (p->child[1]) + p = p->child[1]; + r = 0; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (!pnext) break; + p = pnext; + } + return p->value; +#endif /* SAVE_NEIGHBORS */ +} + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nospl2 */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + flipper4_splay (p); + if (p->reversed) + flipper4_reverse (p); +#ifdef SAVE_NEIGHBORS + return p->neigh[0]->value; +#else /* SAVE_NEIGHBORS */ + if (p->child[0]) + p = p->child[0]; + r = 0; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (!pnext) break; + p = pnext; + } + return p->value; +#endif /* SAVE_NEIGHBORS */ +} +#endif /* NEXT_PREV_NOSPLAY2 */ + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + splay *px = splay_space + x; + splay *py = splay_space + y; + splay *temp, *temp2; + + if (x == y) return; + if (xprev == ynext) { + root.child[0]->reversed ^= 1; + return; + } + + flipper4_splay (px); + px->mark = 1; + flipper4_splay (py); + px->mark = 0; + + if (px->reversed) + flipper4_reverse (px); + if (py->reversed) + flipper4_reverse (py); + if (px->child[1] == py) { +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif + if (py->child[0]) + py->child[0]->reversed ^= 1; + SWAP (px->child[0], py->child[0], temp); + if (px->child[0]) + px->child[0]->parent = px; + if (py->child[0]) + py->child[0]->parent = py; + px->child[1] = py->child[1]; + if (px->child[1]) + px->child[1]->parent = px; + py->child[1] = px; + px->parent = py; + py->parent = &root; + root.child[0] = py; + } else { +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + py->neigh[1] = temp; + px->neigh[0] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif + px->reversed ^= 1; + if (py->child[1]) + py->child[1]->reversed ^= 1; + } +} + +#ifdef SEQUENCE_SPLAY +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + splay *px = splay_space + x; + splay *py = splay_space + y; + splay *pz = splay_space + z; + + if (y == z || x == z || x == y) + return 1; + + flipper4_splay (px); + px->mark = 1; + flipper4_splay (py); + py->mark = 1; + flipper4_splay (pz); + py->mark = 0; + px->mark = 0; + + if (px->reversed) + flipper4_reverse (px); + if (py->reversed) + flipper4_reverse (py); + + if (pz->parent == px) + return px->child[0] == pz; + else + return py->child[1] == pz; +} +#endif /* SEQUENCE_SPLAY */ + +#ifdef SEQUENCE_NOSPLAY +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) /* CClinkern_flipper_sequence_nospl */ +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + splay *px = splay_space + x; + splay *py = splay_space + y; + splay *pz = splay_space + z; + + if (y == z || x == z || x == y) + return 1; + + flipper4_splay (px); + px->mark = 1; + flipper4_splay (pz); + px->mark = 0; + + if (px->reversed) + flipper4_reverse (px); + if (pz->reversed) + flipper4_reverse (pz); + + for (;;) { + if (py->parent == px) { + return px->child[1] == py; + } else if (py->parent == pz) { + return pz->child[0] == py; + } else { + py = py->parent; + } + } +} +#endif /* SEQUENCE_NOSPLAY */ + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_sequence_burst_init (int x, int z) +#else +void CClinkern_flipper_sequence_burst_init (x, z) +int x, z; +#endif +{ + splay *px = splay_space + x; + splay *pz = splay_space + z; + + flipper4_splay (px); + px->mark = 1; + flipper4_splay (pz); + px->mark = 0; + + if (px->reversed) + flipper4_reverse (px); + if (pz->reversed) + flipper4_reverse (pz); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence_burst (int x, int y, int z) +#else +int CClinkern_flipper_sequence_burst (x, y, z) +int x, y, z; +#endif +{ + splay *px = splay_space + x; + splay *py = splay_space + y; + splay *pz = splay_space + z; + + if (y == z || y == x) + return 1; + + for (;;) { + if (py->parent == px) { + return px->child[1] == py; + } else if (py->parent == pz) { + return pz->child[0] == py; + } else { + py = py->parent; + } + } +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_sp2.c b/contrib/blossom/concorde97/LINKERN/flip_sp2.c new file mode 100644 index 0000000000000000000000000000000000000000..859f0d3456082645232f2de544256c8c7d095837 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_sp2.c @@ -0,0 +1,979 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Splay Trees (with dummy) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: April 21, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* int CClinkern_flipper_sequence (int x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* void CClinkern_flipper_sequence_burst_init (int x, int z) */ +/* initilizes the tree for a sequence of (x, y, z) sequence queries. */ +/* int CClinkern_flipper_sequence_burst (int x, int y, int z) */ +/* can be called instead of CClinkern_flipper_sequence, after a call to*/ +/* CClinkern_flipper_sequence_burst_init (x, y), and before any flips */ +/* (but it requires that NEXT_PREV_NOSPLAY be defined). Does not seem */ +/* to improve the running time. */ +/* */ +/* NOTES: */ +/* Should work well on very large problems. */ +/* One of NEXT_PREV_SPLAY, NEXT_PREV_NOSPLAY, NEXT_PREV_NOSPLAY1, */ +/* or NEXT_PREV_NOSPLAY2 must be defined. (NEXT_PREV_NOSPLAY looks like */ +/* the fastest.) One of SEQUENCE_SPLAY or SEQUENCE_NOSPLAY must be */ +/* defined. (SEQUENCE_NOSPLAY looks like the fastest - it does not splay */ +/* the middle node in the query.) */ +/* */ +/* If USE_UGLY_SPLAY is defined, an uglier (but perhaps faster) splay */ +/* step is used. */ +/* */ +/* If SAVE_NEIGHBORS is defined, the neighbors of each node are */ +/* remembered, saving some tree traversals for next and prev. */ +/* In this case, the neighbor is never splayed, so NEXT_PREV_SPLAY */ +/* and NEXT_PREV_NOSPLAY2 become equivalent, as do NEXT_PREV_NOSPLAY */ +/* NEXT_PREV_NOSPLAY1. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/* #define NEXT_PREV_SPLAY */ /* 1xxxx */ +#define NEXT_PREV_NOSPLAY /* 2xxxx */ +/* #define NEXT_PREV_NOSPLAY1 */ /* 3xxxx */ +/* #define NEXT_PREV_NOSPLAY2 */ /* 4xxxx */ +/* #define SEQUENCE_SPLAY */ /* x1xxx */ +#define SEQUENCE_NOSPLAY /* x2xxx */ +#define USE_UGLY_SPLAY /* xx2xx */ +#define SAVE_NEIGHBORS /* xxx2x */ + +/***************************************************************************/ +/* */ +/* SPLAY TREE FLIPPER (flipper4): */ +/* */ +/* 1. CClinkern_flipper_cycle and CClinkern_flipper_cycle_inverse return the number of */ +/* nodes. */ +/* */ +/* 2. The basic splay implementation - uses a splay tree with one node */ +/* per element. */ +/* */ +/***************************************************************************/ + +typedef struct splay { + struct splay *parent; + struct splay *child[2]; +#ifdef SAVE_NEIGHBORS + struct splay *neigh[2]; +#endif + int reversed; + int mark; + int value; +} splay; + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +#ifdef CC_PROTOTYPE_ANSI + +static int + flipper4_cycle_fillin(int *x, int i, splay *p, int r); +static void + flipper4_reverse (splay *p), + flipper4_rotate (splay *x, splay *px), + flipper4_splay (splay *x); +static splay + *flipper4_make_tree (int a, int b, int *cyc); + +#else + +static int + flipper4_cycle_fillin(); +static void + flipper4_reverse (), + flipper4_rotate (), + flipper4_splay (); +static splay + *flipper4_make_tree (); + +#endif + +static splay *splay_space = (splay *) NULL; +static splay root; +static splay dummy_leaf; + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_reset (int ncount) +#else +int CClinkern_flipper_reset (ncount) +int ncount; +#endif +{ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static splay *flipper4_make_tree (int a, int b, int *cyc) +#else +static splay *flipper4_make_tree (a, b, cyc) +int a; +int b; +int *cyc; +#endif +{ + splay *p; + int center; + + if (b < a) + return &dummy_leaf; + + center = (a + b)/2; + p = splay_space + cyc[center]; + p->child[0] = flipper4_make_tree (a, center-1, cyc); + p->child[0]->parent = p; + p->child[1] = flipper4_make_tree (center+1, b, cyc); + p->child[1]->parent = p; + return p; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + root.reversed = 0; + root.parent = (splay *) NULL; + root.child[1] = &dummy_leaf; + root.value = ncount; + + splay_space = CC_SAFE_MALLOC (ncount, splay); + if (!splay_space) + return 1; + + for (i = 0; i < ncount; i++) { + splay_space[i].reversed = 0; + splay_space[i].value = i; + splay_space[i].mark = 0; +#ifdef SAVE_NEIGHBORS + if (i==0) { + splay_space[cyc[0]].neigh[0] = &splay_space[cyc[ncount-1]]; + splay_space[cyc[ncount-1]].neigh[1] = &splay_space[cyc[0]]; + } else { + splay_space[cyc[i]].neigh[0] = &splay_space[cyc[i-1]]; + splay_space[cyc[i-1]].neigh[1] = &splay_space[cyc[i]]; + } +#endif + } + + root.child[0] = flipper4_make_tree (0, ncount - 1, cyc); + root.child[0]->parent = &root; + root.mark = 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int flipper4_cycle_fillin(int *x, int i, splay *p, int r) +#else +static int flipper4_cycle_fillin(x, i, p, r) +int *x; +int i; +splay *p; +int r; +#endif +{ + if (p == &dummy_leaf) + return i; + + r ^= p->reversed; + i = flipper4_cycle_fillin (x, i, p->child[r], r); + x[i++] = p->value; + i = flipper4_cycle_fillin (x, i, p->child[1 - r], r); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + return flipper4_cycle_fillin (x, 0, root.child[0], 0); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (splay_space) + CC_FREE (splay_space, splay); + + root.child[0] = (splay *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + + +#ifdef CC_PROTOTYPE_ANSI +static void flipper4_reverse (splay *p) +#else +static void flipper4_reverse (p) +splay *p; +#endif +{ + splay *temp; + + SWAP (p->child[0], p->child[1], temp); + p->child[0]->reversed ^= 1; + p->child[1]->reversed ^= 1; + p->reversed ^= 1; +#ifdef SAVE_NEIGHBORS + SWAP (p->neigh[0], p->neigh[1], temp); +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static void flipper4_rotate (splay *x, splay *px) +#else +static void flipper4_rotate (x, px) +splay *x, *px; +#endif +{ + splay *b; + + if (px->child[0] == x) { + b = x->child[1]; + b->parent = px; + x->child[1] = px; + x->parent = px->parent; + if (x->parent->child[0] == px) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + px->child[0] = b; + px->parent = x; + } else { + b = x->child[0]; + b->parent = px; + x->child[0] = px; + x->parent = px->parent; + if (x->parent->child[0] == px) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + px->child[1] = b; + px->parent = x; + } +} + +#ifdef USE_UGLY_SPLAY + +#ifdef CC_PROTOTYPE_ANSI +static void flipper4_splay (splay *x) +#else +static void flipper4_splay (x) +splay *x; +#endif +{ + splay *px; + splay *ppx; + splay *b, *c; + + for (;;) { + px = x->parent; + if (px->mark) + return; + ppx = px->parent; + if (ppx->mark) { + if (px->reversed) + flipper4_reverse (px); + if (x->reversed) + flipper4_reverse (x); + flipper4_rotate (x, px); + return; + } + if (ppx->reversed) + flipper4_reverse (ppx); + if (px->reversed) + flipper4_reverse (px); + if (x->reversed) + flipper4_reverse (x); + + x->parent = ppx->parent; + if (x->parent->child[0] == ppx) { + x->parent->child[0] = x; + } else { + x->parent->child[1] = x; + } + + if (ppx->child[0] == px) { + if (px->child[0] == x) { + b = x->child[1]; + c = px->child[1]; + b->parent = px; + c->parent = ppx; + x->child[1] = px; + px->child[0] = b; + px->child[1] = ppx; + ppx->child[0] = c; + px->parent = x; + ppx->parent = px; + } else { + b = x->child[0]; + c = x->child[1]; + b->parent = px; + c->parent = ppx; + x->child[0] = px; + x->child[1] = ppx; + px->child[1] = b; + ppx->child[0] = c; + px->parent = x; + ppx->parent = x; + } + } else { + if (px->child[1] == x) { + b = px->child[0]; + c = x->child[0]; + b->parent = ppx; + c->parent = px; + x->child[0] = px; + px->child[0] = ppx; + px->child[1] = c; + ppx->child[1] = b; + px->parent = x; + ppx->parent = px; + } else { + b = x->child[0]; + c = x->child[1]; + b->parent = ppx; + c->parent = px; + x->child[0] = ppx; + x->child[1] = px; + ppx->child[1] = b; + px->child[0] = c; + px->parent = x; + ppx->parent = x; + } + } + } +} + +#else /* USE_UGLY_SPLAY */ + +#ifdef CC_PROTOTYPE_ANSI +static void flipper4_splay (splay *x) +#else +static void flipper4_splay (x) +splay *x; +#endif +{ + splay *px; + splay *ppx; + + for (;;) { + px = x->parent; + if (px->mark) + return; + ppx = px->parent; + if (ppx->mark) { + if (px->reversed) + flipper4_reverse (px); + if (x->reversed) + flipper4_reverse (x); + flipper4_rotate (x, px); + return; + } + if (ppx->reversed) + flipper4_reverse (ppx); + if (px->reversed) + flipper4_reverse (px); + if (x->reversed) + flipper4_reverse (x); + if (ppx->child[0] == px) { + if (px->child[0] == x) { + flipper4_rotate (px, ppx); + flipper4_rotate (x, px); + } else { + flipper4_rotate (x, px); + flipper4_rotate (x, ppx); + } + } else { + if (px->child[1] == x) { + flipper4_rotate (px, ppx); + flipper4_rotate (x, px); + } else { + flipper4_rotate (x, px); + flipper4_rotate (x, ppx); + } + } + } +} + +#endif /* USE_UGLY_SPLAY */ + +#ifdef NEXT_PREV_SPLAY +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + flipper4_splay (p); + if (p->reversed) + flipper4_reverse (p); +#ifdef SAVE_NEIGHBORS + return p->neigh[1]->value; +#else /* SAVE_NEIGHBORS */ + if (p->child[1] != &dummy_leaf) + p = p->child[1]; + r = 0; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (pnext == &dummy_leaf) break; + p = pnext; + } + flipper4_splay (p); + return p->value; +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + flipper4_splay (p); + if (p->reversed) + flipper4_reverse (p); +#ifdef SAVE_NEIGHBORS + return p->neigh[0]->value; +#else /* SAVE_NEIGHBORS */ + if (p->child[0] != &dummy_leaf) + p = p->child[0]; + r = 0; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (pnext == &dummy_leaf) break; + p = pnext; + } + flipper4_splay (p); + return p->value; +#endif /* SAVE_NEIGHBORS */ +} +#endif /* NEXT_PREV_SPLAY */ + + +#ifdef NEXT_PREV_NOSPLAY +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) /* CClinkern_flipper_next_nspl */ +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + splay *p = splay_space + x; + splay *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; !pnext->mark; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext != &dummy_leaf) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (pnext == &dummy_leaf) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; /* change */ + pnext = p->parent; + while (!pnext->mark) { + if (pnext->child[r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (pnext == &dummy_leaf) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + splay *p = splay_space + x; + splay *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; !pnext->mark; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext != &dummy_leaf) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (pnext == &dummy_leaf) { + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; /* change */ + pnext = p->parent; + while (!pnext->mark) { + if (pnext->child[1 - r] == p) { + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (pnext == &dummy_leaf) { + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} +#endif /* NEXT_PREV_NOSPLAY */ + + +#ifdef NEXT_PREV_NOSPLAY1 +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) /* CClinkern_flipper_next_nspl1 */ +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; !pnext->mark; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[1-r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[1 - r]; + if (pnext != &dummy_leaf) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (pnext == &dummy_leaf) { + flipper4_splay (p); + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; /* change */ + pnext = p->parent; + while (!pnext->mark) { + if (pnext->child[r] == p) { + flipper4_splay (pnext); + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (pnext == &dummy_leaf) { + flipper4_splay (p); + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nspl1 */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + r = 0; + for (pnext = p, r = 0; !pnext->mark; pnext = pnext->parent) + r ^= pnext->reversed; +#ifdef SAVE_NEIGHBORS + return p->neigh[r]->value; +#else /* SAVE_NEIGHBORS */ + pnext = p->child[r]; + if (pnext != &dummy_leaf) { + p = pnext; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (pnext == &dummy_leaf) { + flipper4_splay (p); + return p->value; + } + p = pnext; + } + } else { + r ^= p->reversed; /* change */ + pnext = p->parent; + while (!pnext->mark) { + if (pnext->child[1 - r] == p) { + flipper4_splay (pnext); + return pnext->value; + } + r ^= pnext->reversed; + p = pnext; + pnext = p->parent; + } + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (pnext == &dummy_leaf) { + flipper4_splay (p); + return p->value; + } + p = pnext; + } + } +#endif /* SAVE_NEIGHBORS */ +} +#endif /* NEXT_PREV_NOSPLAY1 */ + + +#ifdef NEXT_PREV_NOSPLAY2 +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) /* CClinkern_flipper_next_nospl2 */ +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + flipper4_splay (p); + if (p->reversed) + flipper4_reverse (p); +#ifdef SAVE_NEIGHBORS + return p->neigh[1]->value; +#else /* SAVE_NEIGHBORS */ + if (p->child[1] != &dummy_leaf) + p = p->child[1]; + r = 0; + for (;;) { + r ^= p->reversed; + pnext = p->child[r]; + if (pnext == &dummy_leaf) break; + p = pnext; + } + return p->value; +#endif /* SAVE_NEIGHBORS */ +} + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) /* CClinkern_flipper_prev_nospl2 */ +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + splay *p = splay_space+x; + splay *pnext; + int r; + + flipper4_splay (p); + if (p->reversed) + flipper4_reverse (p); +#ifdef SAVE_NEIGHBORS + return p->neigh[0]->value; +#else /* SAVE_NEIGHBORS */ + if (p->child[0] != &dummy_leaf) + p = p->child[0]; + r = 0; + for (;;) { + r ^= p->reversed; + pnext = p->child[1 - r]; + if (pnext == &dummy_leaf) break; + p = pnext; + } + return p->value; +#endif /* SAVE_NEIGHBORS */ +} +#endif /* NEXT_PREV_NOSPLAY2 */ + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + splay *px = splay_space + x; + splay *py = splay_space + y; + splay *temp, *temp2; + + if (x == y) return; + if (xprev == ynext) { + root.child[0]->reversed ^= 1; + return; + } + + flipper4_splay (px); + px->mark = 1; + flipper4_splay (py); + px->mark = 0; + + if (px->reversed) + flipper4_reverse (px); + if (py->reversed) + flipper4_reverse (py); + if (px->child[1] == py) { +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + px->neigh[0] = px->neigh[1]; + py->neigh[1] = py->neigh[0]; + py->neigh[0] = temp; + px->neigh[1] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif + py->child[0]->reversed ^= 1; + SWAP (px->child[0], py->child[0], temp); + px->child[0]->parent = px; + py->child[0]->parent = py; + px->child[1] = py->child[1]; + px->child[1]->parent = px; + py->child[1] = px; + px->parent = py; + py->parent = &root; + root.child[0] = py; + } else { +#ifdef SAVE_NEIGHBORS + temp = px->neigh[0]; + temp2 = py->neigh[1]; + py->neigh[1] = temp; + px->neigh[0] = temp2; + if (temp->neigh[0] == px) temp->neigh[0] = py; + else temp->neigh[1] = py; + if (temp2->neigh[0] == py) temp2->neigh[0] = px; + else temp2->neigh[1] = px; +#endif + px->reversed ^= 1; + py->child[1]->reversed ^= 1; + } +} + +#ifdef SEQUENCE_SPLAY +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + splay *px = splay_space + x; + splay *py = splay_space + y; + splay *pz = splay_space + z; + + if (y == z || x == z || x == y) + return 1; + + flipper4_splay (px); + px->mark = 1; + flipper4_splay (py); + py->mark = 1; + flipper4_splay (pz); + py->mark = 0; + px->mark = 0; + + if (px->reversed) + flipper4_reverse (px); + if (py->reversed) + flipper4_reverse (py); + + if (pz->parent == px) + return px->child[0] == pz; + else + return py->child[1] == pz; +} +#endif /* SEQUENCE_SPLAY */ + +#ifdef SEQUENCE_NOSPLAY +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) /* CClinkern_flipper_sequence_nospl */ +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + splay *px = splay_space + x; + splay *py = splay_space + y; + splay *pz = splay_space + z; + + if (y == z || x == z || x == y) + return 1; + + flipper4_splay (px); + px->mark = 1; + flipper4_splay (pz); + px->mark = 0; + + if (px->reversed) + flipper4_reverse (px); + if (pz->reversed) + flipper4_reverse (pz); + + for (;;) { + if (py->parent == px) { + return px->child[1] == py; + } else if (py->parent == pz) { + return pz->child[0] == py; + } else { + py = py->parent; + } + } +} +#endif /* SEQUENCE_NOSPLAY */ + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_sequence_burst_init (int x, int z) +#else +void CClinkern_flipper_sequence_burst_init (x, z) +int x, z; +#endif +{ + splay *px = splay_space + x; + splay *pz = splay_space + z; + + flipper4_splay (px); + px->mark = 1; + flipper4_splay (pz); + px->mark = 0; + + if (px->reversed) + flipper4_reverse (px); + if (pz->reversed) + flipper4_reverse (pz); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence_burst (int x, int y, int z) +#else +int CClinkern_flipper_sequence_burst (x, y, z) +int x, y, z; +#endif +{ + splay *px = splay_space + x; + splay *py = splay_space + y; + splay *pz = splay_space + z; + + if (y == z || y == x) + return 1; + + for (;;) { + if (py->parent == px) { + return px->child[1] == py; + } else if (py->parent == pz) { + return pz->child[0] == py; + } else { + py = py->parent; + } + } +} + diff --git a/contrib/blossom/concorde97/LINKERN/flip_try.c b/contrib/blossom/concorde97/LINKERN/flip_try.c new file mode 100644 index 0000000000000000000000000000000000000000..54c66deb4ccd53cdd220e29597a1c8355c467efc --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_try.c @@ -0,0 +1,1241 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - 3-Level Linked List */ +/* (Contains debugging information) */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This version should be the best of the linked lists so far. */ +/* It combines the oneway approach, with three levels for an express */ +/* lane and a superexpress lane. Note that all superexpress nodes are */ +/* also express nodes. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* LINKDED LIST FLIPPER 8 (flip_ll8.c): */ +/* */ +/* 1. Uses three levels, the top having n**(1/3) nodes. */ +/* 2. The top level has explicit next and prevs, the other levels */ +/* consist of two "oneway" cycles. */ +/* */ +/***************************************************************************/ + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define FORWARD_TOUR 0 +#define BACKWARD_TOUR 1 + +static int test_cycle_size = 0; +static int test_reversed = 0; +static int test_short_size = 0; +static int *test_flip_cyc = (int *) NULL; +static int *test_flip_cyc_inv = (int *) NULL; + +#ifdef CC_PROTOTYPE_ANSI + +static int + test_flipper_init (int ncount, int *cyc), + test_flipper_next (int x), + test_flipper_prev (int x), + test_flipper_cycle (int *x), + test_flipper_sequence (int x, int y, int z); +static void + test_flipper_flip (int x, int y), + test_flipper_finish (void), + test_flipper_free_world (void); + +#else + +static int + test_flipper_init (), + test_flipper_next (), + test_flipper_prev (), + test_flipper_cycle (), + test_flipper_sequence (); +static void + test_flipper_flip (), + test_flipper_finish (), + test_flipper_free_world (); + +#endif + +typedef struct oneway { + struct oneway *next; + int name; + char mark; + char level; +} oneway; + +typedef struct llnode { + struct oneway actual_fwd; + struct oneway actual_bwd; + struct oneway actual_fwd_express; + struct oneway actual_bwd_express; + struct oneway *fwd; + struct oneway *bwd; + struct oneway *fwd_express; + struct oneway *bwd_express; + struct llnode *next_super; + struct llnode *prev_super; +} llnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + express_flip (int aprev, int a, int b, int bnext), + super_flip (int a, int b), + dump_raw_cycle (void), + dump_cycle (void); +static int + express_flipper_sequence (int x, int y, int z), + find_orientation (int s); + +#else + +static void + express_flip (), + super_flip (), + dump_raw_cycle (), + dump_cycle (); +static int + express_flipper_sequence (), + find_orientation (); + +#endif + +static llnode *lltour = (llnode *) NULL; +static int cycle_size = 0; +static int reversed = 0; + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j; + int groupsize, supergroupsize; + + if (test_flipper_init (ncount, cyc)) { + printf ("the test code failed\n"); + fflush (stdout); + return 1; + } + + cycle_size = ncount; + reversed = 0; + + lltour = CC_SAFE_MALLOC (ncount, llnode); + if (!lltour) + return 1; + + lltour[cyc[0]].actual_fwd.name = cyc[0]; + lltour[cyc[0]].actual_fwd.mark = 0; + lltour[cyc[0]].actual_fwd.level = 0; + lltour[cyc[0]].actual_fwd.next = &(lltour[cyc[1]].actual_fwd); + lltour[cyc[0]].fwd = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[0]].actual_bwd.name = cyc[0]; + lltour[cyc[0]].actual_bwd.mark = 0; + lltour[cyc[0]].actual_bwd.level = 0; + lltour[cyc[0]].actual_bwd.next = &(lltour[cyc[ncount - 1]].actual_bwd); + lltour[cyc[0]].bwd = &(lltour[cyc[0]].actual_bwd); + lltour[cyc[ncount - 1]].actual_fwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_fwd.mark = 0; + lltour[cyc[ncount - 1]].actual_fwd.level = 0; + lltour[cyc[ncount - 1]].actual_fwd.next = &(lltour[cyc[0]].actual_fwd); + lltour[cyc[ncount - 1]].fwd = &(lltour[cyc[ncount - 1]].actual_fwd); + lltour[cyc[ncount - 1]].actual_bwd.name = cyc[ncount - 1]; + lltour[cyc[ncount - 1]].actual_bwd.mark = 0; + lltour[cyc[ncount - 1]].actual_bwd.level = 0; + lltour[cyc[ncount - 1]].actual_bwd.next = + &(lltour[cyc[ncount - 2]].actual_bwd); + lltour[cyc[ncount - 1]].bwd = &(lltour[cyc[ncount - 1]].actual_bwd); + + + for (i = ncount - 2; i; i--) { + lltour[cyc[i]].actual_fwd.name = cyc[i]; + lltour[cyc[i]].actual_fwd.mark = 0; + lltour[cyc[i]].actual_fwd.level = 0; + lltour[cyc[i]].actual_fwd.next = &(lltour[cyc[i + 1]].actual_fwd); + lltour[cyc[i]].fwd = &(lltour[cyc[i]].actual_fwd); + lltour[cyc[i]].actual_bwd.name = cyc[i]; + lltour[cyc[i]].actual_bwd.mark = 0; + lltour[cyc[i]].actual_bwd.level = 0; + lltour[cyc[i]].actual_bwd.next = &(lltour[cyc[i - 1]].actual_bwd); + lltour[cyc[i]].bwd = &(lltour[cyc[i]].actual_bwd); + } + + groupsize = (int) cbrt ((double) ncount); + supergroupsize = groupsize * groupsize; + printf ("groupsize = %d supersize = %d\n", groupsize, supergroupsize); + fflush (stdout); + lltour[cyc[0]].actual_fwd.level = 1; + lltour[cyc[0]].actual_bwd.level = 1; + lltour[cyc[0]].fwd_express = &(lltour[cyc[0]].actual_fwd_express); + lltour[cyc[0]].bwd_express = &(lltour[cyc[0]].actual_bwd_express); + lltour[cyc[0]].actual_fwd_express.mark = 0; + lltour[cyc[0]].actual_bwd_express.mark = 0; + lltour[cyc[0]].actual_fwd_express.level = 1; + lltour[cyc[0]].actual_bwd_express.level = 1; + lltour[cyc[0]].actual_fwd_express.name = cyc[0]; + lltour[cyc[0]].actual_bwd_express.name = cyc[0]; + lltour[cyc[0]].actual_fwd_express.next = + &(lltour[cyc[groupsize]].actual_fwd_express); + i = groupsize; + j = ncount - groupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 1; + lltour[cyc[i]].actual_bwd.level = 1; + lltour[cyc[i]].fwd_express = &(lltour[cyc[i]].actual_fwd_express); + lltour[cyc[i]].bwd_express = &(lltour[cyc[i]].actual_bwd_express); + lltour[cyc[i]].actual_fwd_express.mark = 0; + lltour[cyc[i]].actual_bwd_express.mark = 0; + lltour[cyc[i]].actual_fwd_express.level = 1; + lltour[cyc[i]].actual_bwd_express.level = 1; + lltour[cyc[i]].actual_fwd_express.name = cyc[i]; + lltour[cyc[i]].actual_bwd_express.name = cyc[i]; + lltour[cyc[i]].actual_fwd_express.next = + &(lltour[cyc[i + groupsize]].actual_fwd_express); + lltour[cyc[i]].actual_bwd_express.next = + &(lltour[cyc[i - groupsize]].actual_bwd_express); + i += groupsize; + } + + lltour[cyc[i]].actual_fwd.level = 1; + lltour[cyc[i]].actual_bwd.level = 1; + lltour[cyc[i]].fwd_express = &(lltour[cyc[i]].actual_fwd_express); + lltour[cyc[i]].bwd_express = &(lltour[cyc[i]].actual_bwd_express); + lltour[cyc[i]].actual_fwd_express.mark = 0; + lltour[cyc[i]].actual_bwd_express.mark = 0; + lltour[cyc[i]].actual_fwd_express.level = 1; + lltour[cyc[i]].actual_bwd_express.level = 1; + lltour[cyc[i]].actual_fwd_express.name = cyc[i]; + lltour[cyc[i]].actual_bwd_express.name = cyc[i]; + lltour[cyc[i]].actual_fwd_express.next = + &(lltour[cyc[0]].actual_fwd_express); + lltour[cyc[i]].actual_bwd_express.next = + &(lltour[cyc[i - groupsize]].actual_bwd_express); + lltour[cyc[0]].actual_bwd_express.next = + &(lltour[cyc[i]].actual_bwd_express); + + lltour[cyc[0]].actual_fwd.level = 2; + lltour[cyc[0]].actual_bwd.level = 2; + lltour[cyc[0]].actual_fwd_express.level = 2; + lltour[cyc[0]].actual_bwd_express.level = 2; + lltour[cyc[0]].next_super = &(lltour[cyc[supergroupsize]]); + i = supergroupsize; + j = ncount - supergroupsize; + while (i < j) { + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].prev_super = &(lltour[cyc[i - supergroupsize]]); + lltour[cyc[i]].next_super = &(lltour[cyc[i + supergroupsize]]); + i += supergroupsize; + } + lltour[cyc[i]].actual_fwd.level = 2; + lltour[cyc[i]].actual_bwd.level = 2; + lltour[cyc[i]].actual_fwd_express.level = 2; + lltour[cyc[i]].actual_bwd_express.level = 2; + lltour[cyc[i]].next_super = &(lltour[cyc[0]]); + lltour[cyc[i]].prev_super = &(lltour[cyc[i - supergroupsize]]); + lltour[cyc[0]].prev_super = &(lltour[cyc[i]]); + +/* + dump_raw_cycle (); + dump_cycle (); +*/ + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_cycle (void) +#else +static void dump_cycle () +#endif +{ + int *getit, i; + + printf ("dump_cycle ...\n"); fflush (stdout); + + getit = CC_SAFE_MALLOC (cycle_size, int); + CClinkern_flipper_cycle (getit); + + printf ("TOUR: "); + fflush (stdout); + + for (i = 0; i < cycle_size; i++) + printf ("%2d ", getit[i]); + printf ("\n"); + fflush (stdout); + + { + oneway *p, *start; + + printf ("Express TOUR: "); + fflush (stdout); + p = (find_orientation (getit[0]) ? lltour[getit[0]].bwd : + lltour[getit[0]].fwd); + while (!p->level) + p = p->next; + if (p == lltour[p->name].fwd) + p = lltour[p->name].fwd_express; + else + p = lltour[p->name].bwd_express; + + i = 0; + start = p; + do { + printf ("%d ", p->name); + p = p->next; + i++; + } while (p != start && i < 2 * cycle_size); + printf ("\n"); + fflush (stdout); + } + + { + llnode *n, *start; + oneway *p; + + printf ("SUPER TOUR: "); + fflush (stdout); + p = (find_orientation (getit[0]) ? lltour[getit[0]].bwd : + lltour[getit[0]].fwd); + while (!p->level) + p = p->next; + p = lltour[p->name].fwd_express; + while (p->level != 2) + p = p->next; + + n = start = &(lltour[p->name]); + if (reversed) { + do { + printf ("%d ", n->fwd->name); + n = n->prev_super; + } while (n != start); + + } else { + do { + printf ("%d ", n->fwd->name); + n = n->next_super; + } while (n != start); + } + printf ("\n"); + fflush (stdout); + } + + CC_FREE (getit, int); + + printf ("Next-Prev test ... "); fflush (stdout); + for (i = 0; i < cycle_size; i++) { + CClinkern_flipper_prev (i); + CClinkern_flipper_next (i); + } + printf ("OK\n"); fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_orientation (int s) +#else +static int find_orientation (s) +int s; +#endif +{ + /* Returns 0 if next is fwd and 1 if next is bwd */ + + oneway *n = lltour[s].fwd; + + while (!n->level) + n = n->next; + + if (lltour[n->name].fwd == n) + n = lltour[n->name].fwd_express; + else + n = lltour[n->name].bwd_express; + + while (n->level != 2) + n = n->next; + + if (reversed) + return (n != lltour[n->name].bwd_express); + else + return (n != lltour[n->name].fwd_express); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + int *xtest; + oneway *start, *n; + int k = 0; + + xtest = CC_SAFE_MALLOC (cycle_size, int); + test_flipper_cycle (xtest); + + start = (find_orientation (xtest[0]) ? lltour[xtest[0]].bwd : + lltour[xtest[0]].fwd); + n = start; + do { + x[k++] = n->name; + n = n->next; + } while (n != start); + +#ifndef NDEBUG + for (k = 0; k < cycle_size; k++) { + assert (x[k] == xtest[k]); + } +#endif + + CC_FREE (xtest, int); + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (lltour) + CC_FREE (lltour, llnode); + + test_flipper_finish (); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + test_flipper_free_world (); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + int temp; + + if (find_orientation (x)) + temp = lltour[x].bwd->next->name; + else + temp = lltour[x].fwd->next->name; + + assert (temp == test_flipper_next (x)); + + return temp; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + int temp; + + if (find_orientation (x)) + temp = lltour[x].fwd->next->name; + else + temp = lltour[x].bwd->next->name; + + assert (temp == test_flipper_prev (x)); + + return temp; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int xprev, int x, int y, int ynext) +#else +void CClinkern_flipper_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *oprev, *pnext; + +/* + printf ("flipper_flip (%d, %d, %d, %d)\n", xprev, x, y, ynext); + fflush (stdout); +*/ + + assert (xprev == CClinkern_flipper_prev (x)); + assert (ynext == CClinkern_flipper_next (y)); + + if (x == y) + return; + + if (lltour[x].bwd->next->name == xprev) + o = lltour[x].fwd; + else + o = lltour[x].bwd; + + while (!o->level && o->name != y) + o = o->next; + + if (o->level) { + if (lltour[o->name].fwd == o) + oprev = lltour[o->name].bwd->next; + else + oprev = lltour[o->name].fwd->next; + while (!oprev->level) + oprev = oprev->next; + if (lltour[y].fwd->next->name == ynext) + p = lltour[y].bwd; + else + p = lltour[y].fwd; + while (!p->level) + p = p->next; + if (lltour[p->name].fwd == p) + pnext = lltour[p->name].bwd->next; + else + pnext = lltour[p->name].fwd->next; + while (!pnext->level) + pnext = pnext->next; + express_flip (oprev->name, o->name, p->name, pnext->name); + } + + if (x != ynext && xprev != ynext) { + if (lltour[ynext].fwd->next->name == y) { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].bwd; + lltour[ynext].fwd->next = lltour[x].fwd; + } + } else { + if (lltour[x].fwd->next->name == xprev) { + lltour[x].fwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].bwd; + } else { + lltour[x].bwd->next = lltour[ynext].fwd; + lltour[ynext].bwd->next = lltour[x].fwd; + } + } + + if (lltour[xprev].fwd->next->name == x) { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].bwd; + lltour[xprev].fwd->next = lltour[y].fwd; + } + } else { + if (lltour[y].fwd->next->name == ynext) { + lltour[y].fwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].bwd; + } else { + lltour[y].bwd->next = lltour[xprev].fwd; + lltour[xprev].bwd->next = lltour[y].fwd; + } + } + } else if (x != ynext) { + oneway *otemp; + if (lltour[xprev].fwd->level) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + } + } + + test_flipper_flip (x, y); + +/* + dump_raw_cycle (); + dump_cycle (); +*/ +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_raw_cycle (void) +#else +static void dump_raw_cycle () +#endif +{ + int i; + + printf ("Raw Cycle:\n"); + for (i = 0; i < cycle_size; i++) { + printf ("Node %d: %d%c %d%c [%d] ", lltour[i].fwd->name, + lltour[i].fwd->next->name, + (lltour[i].fwd->next == + lltour[lltour[i].fwd->next->name].fwd ? 'F' : 'B'), + lltour[i].bwd->next->name, + (lltour[i].bwd->next == + lltour[lltour[i].bwd->next->name].fwd ? 'F' : 'B'), + (int) lltour[i].fwd->level); + if (lltour[i].fwd->level) + printf ("X-fwd: %d%c X->bwd: %d%c ", + lltour[i].fwd_express->next->name, + (lltour[i].fwd_express->next == + lltour[lltour[i].fwd_express->next->name].fwd ? 'F' : 'B'), + lltour[i].bwd_express->next->name, + (lltour[i].bwd_express->next == + lltour[lltour[i].bwd_express->next->name].fwd ? 'F' : 'B')); + if (lltour[i].fwd->level == 2) + printf ("S-next: %d S->prev: %d\n", + lltour[i].next_super->fwd->name, + lltour[i].prev_super->fwd->name); + else + printf ("\n"); + fflush (stdout); + } + if (reversed) + printf ("REVERSED\n"); + fflush (stdout); +} + + +#ifdef CC_PROTOTYPE_ANSI +static void express_flip (int xprev, int x, int y, int ynext) +#else +static void express_flip (xprev, x, y, ynext) +int xprev, x, y, ynext; +#endif +{ + oneway *o, *p, *otemp; + +/* + printf ("express_flip (%d, %d, %d, %d)\n", xprev, x, y, ynext); + printf ("really (%d, %d, %d, %d)\n", lltour[xprev].bwd_express->name, + lltour[x].bwd_express->name, + lltour[y].bwd_express->name, + lltour[ynext].bwd_express->name); + fflush (stdout); +*/ + + + if (x == y) { + SWAP (lltour[x].fwd, lltour[x].bwd, otemp); + return; + } else if (xprev == ynext) { + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + reversed ^= 1; + return; + } + + if (lltour[x].bwd_express->next->name == xprev) { + o = lltour[x].fwd_express; + } else { + o = lltour[x].bwd_express; + } + + while (o->level != 2 && o->name != y) + o = o->next; + + if (o->level == 2) { + if (lltour[y].fwd_express->next->name == ynext) + p = lltour[y].bwd_express; + else + p = lltour[y].fwd_express; + while (p->level != 2) + p = p->next; + super_flip (o->name, p->name); + } + + + if (x != ynext && xprev != ynext) { + if (lltour[ynext].fwd_express->next->name == y) { + if (lltour[x].fwd_express->next->name == xprev) { + lltour[x].fwd_express->next = lltour[ynext].bwd_express; + lltour[ynext].fwd_express->next = lltour[x].bwd_express; + } else { + lltour[x].bwd_express->next = lltour[ynext].bwd_express; + lltour[ynext].fwd_express->next = lltour[x].fwd_express; + } + } else { + if (lltour[x].fwd_express->next->name == xprev) { + lltour[x].fwd_express->next = lltour[ynext].fwd_express; + lltour[ynext].bwd_express->next = lltour[x].bwd_express; + } else { + lltour[x].bwd_express->next = lltour[ynext].fwd_express; + lltour[ynext].bwd_express->next = lltour[x].fwd_express; + } + } + + if (lltour[xprev].fwd_express->next->name == x) { + if (lltour[y].fwd_express->next->name == ynext) { + lltour[y].fwd_express->next = lltour[xprev].bwd_express; + lltour[xprev].fwd_express->next = lltour[y].bwd_express; + } else { + lltour[y].bwd_express->next = lltour[xprev].bwd_express; + lltour[xprev].fwd_express->next = lltour[y].fwd_express; + } + } else { + if (lltour[y].fwd_express->next->name == ynext) { + lltour[y].fwd_express->next = lltour[xprev].fwd_express; + lltour[xprev].bwd_express->next = lltour[y].bwd_express; + } else { + lltour[y].bwd_express->next = lltour[xprev].fwd_express; + lltour[xprev].bwd_express->next = lltour[y].fwd_express; + } + } + } else if (x != ynext) { + printf ("Here we are\n"); fflush (stdout); + if (lltour[xprev].fwd_express->level != 2) + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); +/* + if (lltour[xprev].fwd_express->level == 2) { + SWAP (lltour[xprev].fwd_express, lltour[xprev].bwd_express, otemp); + SWAP (lltour[xprev].fwd, lltour[xprev].bwd, otemp); + } +*/ + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void super_flip (int ix, int iy) +#else +static void super_flip (ix, iy) +int ix, iy; +#endif +{ + llnode *x = &(lltour[ix]); + llnode *y = &(lltour[iy]); + llnode *xprev, *ynext; + llnode *n, *next, *prev; + oneway *otemp; + +/* + printf ("super_flip (%d, %d) ...\n", ix, iy); + fflush (stdout); +*/ + + if (x == y) { + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + return; + } + + if (reversed) { + xprev = x->next_super; + ynext = y->prev_super; + + next = x->prev_super; + prev = xprev->next_super; + + while (next != y && prev != ynext) { + next = next->prev_super; + prev = prev->next_super; + } + + if (next == y) { + next = x->prev_super; + x->prev_super = x->next_super; + x->next_super = next; + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + + do { + n = next; + next = n->prev_super; + n->prev_super = n->next_super; + n->next_super = next; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + } while (n != y); + + if (xprev != y) { + y->next_super = xprev; + x->prev_super = ynext; + xprev->prev_super = y; + ynext->next_super = x; + } + } else { + prev = xprev->next_super; + xprev->next_super = xprev->prev_super; + xprev->prev_super = prev; + SWAP (xprev->fwd_express, xprev->bwd_express, otemp); + SWAP (xprev->fwd, xprev->bwd, otemp); + + do { + n = prev; + prev = n->next_super; + n->next_super = n->prev_super; + n->prev_super = prev; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + } while (n != ynext); + + if (xprev != y) { + y->prev_super = xprev; + x->next_super = ynext; + xprev->next_super = y; + ynext->prev_super = x; + } + reversed = 0; + } + } else { + xprev = x->prev_super; + ynext = y->next_super; + + next = x->next_super; + prev = xprev->prev_super; + + while (next != y && prev != ynext) { + next = next->next_super; + prev = prev->prev_super; + } + + if (next == y) { + next = x->next_super; + x->next_super = x->prev_super; + x->prev_super = next; + SWAP (x->fwd_express, x->bwd_express, otemp); + SWAP (x->fwd, x->bwd, otemp); + + do { + n = next; + next = n->next_super; + n->next_super = n->prev_super; + n->prev_super = next; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + } while (n != y); + + if (xprev != y) { + y->prev_super = xprev; + x->next_super = ynext; + xprev->next_super = y; + ynext->prev_super = x; + } + } else { + prev = xprev->prev_super; + xprev->prev_super = xprev->next_super; + xprev->next_super = prev; + SWAP (xprev->fwd_express, xprev->bwd_express, otemp); + SWAP (xprev->fwd, xprev->bwd, otemp); + + do { + n = prev; + prev = n->prev_super; + n->prev_super = n->next_super; + n->next_super = prev; + SWAP (n->fwd_express, n->bwd_express, otemp); + SWAP (n->fwd, n->bwd, otemp); + } while (n != ynext); + + if (xprev != y) { + y->next_super = xprev; + x->prev_super = ynext; + xprev->prev_super = y; + ynext->next_super = x; + } + reversed = 1; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + int control, temp; + oneway *next, *prev; + int war = 0; + + if (x == z || x == y) { + temp = 1; + } else { + + { + oneway *px, *py, *pz; + + if (find_orientation (x)) + px = lltour[x].bwd; + else + px = lltour[x].fwd; + while (!px->level && px->name != y && px->name != z) + px = px->next; + if (px->name == y) { + temp = 1; + war = 1; + goto GET_OUT; + } else if (px->name == z) { + temp = 0; + war = 2; + goto GET_OUT; + } + + if (find_orientation (z)) + pz = lltour[z].fwd; + else + pz = lltour[z].bwd; + while (!pz->level && pz->name != x && pz->name != y) + pz = pz->next; + if (pz->name == y) { + temp = 1; + war = 3; + goto GET_OUT; + } else if (pz->name == x) { + temp = 0; + war = 4; + goto GET_OUT; + } else if (px == pz) { + temp = 0; + war = 5; + goto GET_OUT; + } + + if (find_orientation (y)) + py = lltour[y].bwd; + else + py = lltour[y].fwd; + while (!py->level && py->name != x && py->name != z) + py = py->next; + if (py->name == z) { + temp = 1; + war = 6; + goto GET_OUT; + } else if (py->name == x) { + temp = 0; + war = 7; + goto GET_OUT; + } else if (py == pz) { + temp = 1; + war = 8; + goto GET_OUT; + } else if (py == px) { + temp = 0; + war = 9; + goto GET_OUT; + } else { + temp = express_flipper_sequence (px->name, py->name, pz->name); + war = 10; + goto GET_OUT; + } + } + } + + +/* + lltour[y].fwd->mark = 1; + lltour[y].bwd->mark = 1; + lltour[z].fwd->mark = 1; + lltour[z].bwd->mark = 1; + + if (find_orientation (x)) { + next = lltour[x].bwd; + prev = lltour[x].fwd; + } else { + next = lltour[x].fwd; + prev = lltour[x].bwd; + } + + while (!next->mark && !prev->mark) { + next = next->next; + prev = prev->next; + } + + if (next->mark) { + lltour[y].fwd->mark = 0; + lltour[y].bwd->mark = 0; + lltour[z].fwd->mark = 0; + lltour[z].bwd->mark = 0; + temp = (next->name == y); + } else { + lltour[y].fwd->mark = 0; + lltour[y].bwd->mark = 0; + lltour[z].fwd->mark = 0; + lltour[z].bwd->mark = 0; + temp = (prev->name == z); + } + } +*/ + +GET_OUT: + + assert (temp == test_flipper_sequence (x, y, z)); + return temp; +} + +#ifdef CC_PROTOTYPE_ANSI +static int express_flipper_sequence (int x, int y, int z) +#else +static int express_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + oneway *next, *prev; + + lltour[y].fwd_express->mark = 1; + lltour[y].bwd_express->mark = 1; + lltour[z].fwd_express->mark = 1; + lltour[z].bwd_express->mark = 1; + + if (find_orientation (x)) { + next = lltour[x].bwd_express; + prev = lltour[x].fwd_express; + } else { + next = lltour[x].fwd_express; + prev = lltour[x].bwd_express; + } + + while (!next->mark && !prev->mark) { + next = next->next; + prev = prev->next; + } + + if (next->mark) { + lltour[y].fwd_express->mark = 0; + lltour[y].bwd_express->mark = 0; + lltour[z].fwd_express->mark = 0; + lltour[z].bwd_express->mark = 0; + return (next->name == y); + } else { + lltour[y].fwd_express->mark = 0; + lltour[y].bwd_express->mark = 0; + lltour[z].fwd_express->mark = 0; + lltour[z].bwd_express->mark = 0; + return (prev->name == z); + } +} + + +/************* TEST CODE **************/ + + +#ifdef CC_PROTOTYPE_ANSI +static int test_flipper_init (int ncount, int *cyc) +#else +static int test_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + + test_flip_cyc = CC_SAFE_MALLOC (ncount, int); + if (!test_flip_cyc) + return 1; + test_flip_cyc_inv = CC_SAFE_MALLOC (ncount, int); + if (!test_flip_cyc_inv) { + CC_FREE (cyc, int); + return 1; + } + + for (i = 0; i < ncount; i++) { + test_flip_cyc[i] = cyc[i]; + test_flip_cyc_inv[cyc[i]] = i; + } + test_cycle_size = ncount; + test_short_size = ncount/2; + test_reversed = 0; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int test_flipper_cycle (int *x) +#else +static int test_flipper_cycle (x) +int *x; +#endif +{ + int *p; + + if (test_reversed) { + p = test_flip_cyc + test_cycle_size; + while (p > test_flip_cyc) { + *x++ = *--p; + } + } else { + p = test_flip_cyc + test_cycle_size; + x += test_cycle_size; + while (p > test_flip_cyc) { + *--x = *--p; + } + } + return test_cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +static void test_flipper_finish (void) +#else +static void test_flipper_finish () +#endif +{ + if (test_flip_cyc) + CC_FREE (test_flip_cyc, int); + if (test_flip_cyc_inv) + CC_FREE (test_flip_cyc_inv, int); + test_cycle_size = 0; + test_short_size = 0; + test_reversed = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void test_flipper_free_world (void) +#else +static void test_flipper_free_world () +#endif +{ + return; +} + +#ifdef CC_PROTOTYPE_ANSI +static int test_flipper_next (int x) +#else +static int test_flipper_next (x) +int x; +#endif +{ + int y; + + if (test_reversed) { + y = test_flip_cyc_inv[x] - 1; + return (y >= 0) ? test_flip_cyc[y] : test_flip_cyc[test_cycle_size-1]; + } else { + y = test_flip_cyc_inv[x] + 1; + return (y < test_cycle_size) ? test_flip_cyc[y] : test_flip_cyc[0]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int test_flipper_prev (int x) +#else +static int test_flipper_prev (x) +int x; +#endif +{ + int y; + + if (test_reversed) { + y = test_flip_cyc_inv[x] + 1; + return (y < test_cycle_size) ? test_flip_cyc[y] : test_flip_cyc[0]; + } else { + y = test_flip_cyc_inv[x] - 1; + return (y >= 0) ? test_flip_cyc[y] : test_flip_cyc[test_cycle_size-1]; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void test_flipper_flip (int x, int y) +#else +static void test_flipper_flip (x, y) +int x,y; +#endif +{ + int xloc = test_flip_cyc_inv[x]; + int yloc = test_flip_cyc_inv[y]; + int temp; + int gap; + + if (test_reversed) { + SWAP (xloc, yloc, temp); + } + gap = yloc - xloc; + if (gap < 0) gap += test_cycle_size; + if (gap > test_short_size) { + SWAP (xloc, yloc, temp); + test_reversed ^= 1; + xloc++; + if (xloc >= test_cycle_size) + xloc = 0; + yloc--; + if (yloc < 0) + yloc = test_cycle_size - 1; + gap = test_cycle_size - gap - 2; + } + if (xloc > yloc) { + gap++; + gap /= 2; + for (; gap; gap--) { + x = test_flip_cyc[xloc]; + y = test_flip_cyc[yloc]; + test_flip_cyc[xloc] = y; + test_flip_cyc[yloc] = x; + test_flip_cyc_inv[x] = yloc--; + test_flip_cyc_inv[y] = xloc++; + if (xloc >= test_cycle_size) + xloc = 0; + if (yloc < 0) + yloc = test_cycle_size - 1; + } + } else { + gap++; + gap /= 2; + for (; gap; gap--) { + x = test_flip_cyc[xloc]; + y = test_flip_cyc[yloc]; + test_flip_cyc[xloc] = y; + test_flip_cyc[yloc] = x; + test_flip_cyc_inv[x] = yloc--; + test_flip_cyc_inv[y] = xloc++; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int test_flipper_sequence (int x, int y, int z) +#else +static int test_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + int xloc = test_flip_cyc_inv[x]; + int yloc = test_flip_cyc_inv[y]; + int zloc = test_flip_cyc_inv[z]; + + if (test_reversed) { + if (xloc >= yloc) + return yloc >= zloc || zloc >= xloc; + else + return yloc >= zloc && zloc >= xloc; + } else { + if (xloc <= yloc) + return yloc <= zloc || zloc <= xloc; + else + return yloc <= zloc && zloc <= xloc; + } +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_tw2.c b/contrib/blossom/concorde97/LINKERN/flip_tw2.c new file mode 100644 index 0000000000000000000000000000000000000000..236a3eadd1591167944fbbcdde6c29a42a7d8dd0 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_tw2.c @@ -0,0 +1,775 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Two-level Tree */ +/* - array for parent cyc */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 2, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int x, int y) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This is desribed in the paper "Data structures for traveling */ +/* salesman" by Fredman, Johnson, McGeoch, and Ostheimer. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +/***************************************************************************/ +/* */ +/* TWO-LEVEL TREES: */ +/* */ +/* 1. Uses the "groupsize" approach described in the paper. */ +/* */ +/***************************************************************************/ + +#define USE_SEGMENT_SPLIT +#define GROUPSIZE_FACTOR 0.50 +#define SEGMENT_SPLIT_CUTOFF 0.35 + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) + +typedef struct parentnode { + struct childnode *ends[2]; + int size; + int rev; + int index; +} parentnode; + +typedef struct childnode { + struct parentnode *parent; + struct childnode *adj[2]; + int id; + int name; +} childnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + same_segment_flip (childnode *a, childnode *b), + consecutive_segment_flip (parentnode *a, parentnode *b), + segment_split (parentnode *p, childnode *aprev, childnode *a, + int left_or_right), + parflip (parentnode *a, parentnode *b); + +static int + parsegsize (parentnode *a, parentnode *b); + +static parentnode + *parnext (parentnode *x), + *parprev (parentnode *x); + +#else + +static void + same_segment_flip (), + consecutive_segment_flip (), + segment_split (), + parflip (); + +static int + parsegsize (parentnode *a, parentnode *b); + +static parentnode + *parnext (), + *parprev (); + +#endif + +static parentnode *parents = (parentnode *) NULL; +static childnode *children = (childnode *) NULL; +static int *par_cyc = (int *) NULL; +static int *par_cyc_inv = (int *) NULL; +static int reversed = 0; +static cycle_size = 0; +static int nsegments = 0; +static groupsize = 100; +#ifdef USE_SEGMENT_SPLIT +static int split_cutoff = 100; +#endif + +#define SAME_SEGMENT(a, b) \ + (a->parent == b->parent && \ + ((!(reversed^(a->parent->rev)) && a->id <= b->id) || \ + ((reversed^(a->parent->rev)) && a->id >= b->id))) + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j, cind, remain; + childnode *c, *cprev, *cnext; + parentnode *p; + + reversed = 0; + cycle_size = ncount; + groupsize = (int) (sqrt ((double) ncount) * GROUPSIZE_FACTOR); + nsegments = (ncount + groupsize - 1) / groupsize; +#ifdef USE_SEGMENT_SPLIT + split_cutoff = groupsize * SEGMENT_SPLIT_CUTOFF; +#endif + + parents = CC_SAFE_MALLOC (nsegments, parentnode); + if (!parents) + return 1; + + children = CC_SAFE_MALLOC (ncount + 1, childnode); + /* The +1 will stop a purify burp later */ + if (!children) { + CC_FREE (parents, parentnode); + return 1; + } + + par_cyc = CC_SAFE_MALLOC (nsegments, int); + if (!par_cyc) { + CC_FREE (parents, parentnode); + CC_FREE (children, childnode); + return 1; + } + par_cyc_inv = CC_SAFE_MALLOC (nsegments, int); + if (!par_cyc_inv) { + CC_FREE (parents, parentnode); + CC_FREE (children, childnode); + CC_FREE (par_cyc, int); + return 1; + } + + remain = ncount; + i = 0; + j = 2 * groupsize; + while (remain >= j) { + parents[i].size = groupsize; + remain -= groupsize; + i++; + } + if (remain > groupsize) { + parents[i].size = remain / 2; + remain -= (remain / 2); + i++; + } + parents[i].size = remain; + i++; + + if (i != nsegments) { + printf ("seg count is wrong\n"); + fflush (stdout); + CC_FREE (parents, parentnode); + CC_FREE (children, childnode); + CC_FREE (par_cyc, int); + CC_FREE (par_cyc_inv, int); + return 1; + } + + c = (childnode *) NULL; + cnext = &(children[cyc[0]]); + for (i = 0, p = parents, c = children, cind = 0; i < nsegments; p++, i++) { + par_cyc[i] = i; + par_cyc_inv[i] = i; + p->index = i; + p->rev = 0; + p->ends[0] = cnext; + for (j = p->size; j > 0; j--) { + cprev = c; + c = cnext; + cnext = &(children[cyc[cind + 1]]); + c->id = cind; + c->name = cyc[cind]; + c->parent = p; + c->adj[0] = cprev; + c->adj[1] = cnext; + cind++; + } + p->ends[1] = c; + } + children[cyc[0]].adj[0] = &(children[cyc[ncount - 1]]); + children[cyc[ncount - 1]].adj[1] = &(children[cyc[0]]); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + childnode *c, *start; + int k = 0; + + start = &(children[0]); + c = start->adj[!(reversed^(start->parent->rev))]; + + x[k++] = start->name; + while (c != start) { + x[k++] = c->name; + c = c->adj[!(reversed^(c->parent->rev))]; + } + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (parents) + CC_FREE (parents, parentnode); + if (children) + CC_FREE (children, childnode); + if (par_cyc) + CC_FREE (par_cyc, int); + if (par_cyc_inv) + CC_FREE (par_cyc_inv, int); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + return children[x].adj[!(reversed^(children[x].parent->rev))]->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + return children[x].adj[reversed^(children[x].parent->rev)]->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int x, int y) +#else +void CClinkern_flipper_flip (x, y) +int x,y; +#endif +{ + childnode *xc = &(children[x]); + childnode *yc = &(children[y]); + + if (SAME_SEGMENT (xc, yc)) { + if (xc != yc) { + same_segment_flip (xc, yc); + } + } else { + int xdir = (reversed^(xc->parent->rev)); + int ydir = (reversed^(yc->parent->rev)); + childnode *xprev = xc->adj[xdir]; + childnode *ynext = yc->adj[!ydir]; + if (SAME_SEGMENT (ynext, xprev)) { + if (ynext != xprev) { + same_segment_flip (ynext, xprev); + } + reversed ^= 1; + } else { + if (xc->parent->ends[xdir] == xc && + yc->parent->ends[!ydir] == yc) { + if (parsegsize (xc->parent, yc->parent) < nsegments / 2) { + consecutive_segment_flip (xc->parent, yc->parent); + } else { + consecutive_segment_flip(parnext(yc->parent), + parprev(xc->parent)); + reversed ^= 1; + } + } else { + if (xprev->parent == xc->parent) { + segment_split (xc->parent, xprev, xc, 0); + if (SAME_SEGMENT (xc, yc)) { + if (xc != yc) + same_segment_flip (xc, yc); + return; + } else if (SAME_SEGMENT (ynext, xprev)) { + if (ynext != xprev) { + same_segment_flip (ynext, xprev); + } + reversed ^= 1; + return; + } + } + if (ynext->parent == yc->parent) { + segment_split (yc->parent, yc, ynext, 0); + if (SAME_SEGMENT (xc, yc)) { + if (xc != yc) + same_segment_flip (xc, yc); + return; + } else if (SAME_SEGMENT (ynext, xprev)) { + if (ynext != xprev) { + same_segment_flip (ynext, xprev); + } + reversed ^= 1; + return; + } + } + if (parsegsize (xc->parent, yc->parent) < nsegments / 2) { + consecutive_segment_flip (xc->parent, yc->parent); + } else { + consecutive_segment_flip(parnext(yc->parent), + parprev(xc->parent)); + reversed ^= 1; + } + + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void same_segment_flip (childnode *a, childnode *b) +#else +static void same_segment_flip (a, b) +childnode *a, *b; +#endif +{ + parentnode *parent = a->parent; + int dir = (reversed^(parent->rev)); + childnode *aprev = a->adj[dir]; + childnode *bnext = b->adj[!dir]; + childnode *c, *cnext; + +#ifdef USE_SEGMENT_SPLIT + if ((dir && a->id - b->id > split_cutoff) || + (!dir && b->id - a->id > split_cutoff)) { + if (aprev->parent == parent) + segment_split (parent, aprev, a, 1); + if (bnext->parent == parent) + segment_split (parent, b, bnext, 2); + aprev->adj[!(reversed^(aprev->parent->rev))] = b; + bnext->adj[reversed^(bnext->parent->rev)] = a; + a->adj[dir] = bnext; + b->adj[!dir] = aprev; + parent->rev ^= 1; + return; + } +#endif + + if (dir) { + int id = a->id; + aprev->adj[!(reversed^(aprev->parent->rev))] = b; + bnext->adj[reversed^(bnext->parent->rev)] = a; + cnext = b->adj[1]; + b->adj[1] = aprev; + b->adj[0] = cnext; + b->id = id--; + c = cnext; + while (c != a) { + cnext = c->adj[1]; + c->adj[1] = c->adj[0]; + c->adj[0] = cnext; + c->id = id--; + c = cnext; + } + a->adj[1] = a->adj[0]; + a->adj[0] = bnext; + a->id = id; + if (parent->ends[1] == a) + parent->ends[1] = b; + if (parent->ends[0] == b) + parent->ends[0] = a; + } else { + int id = a->id; + aprev->adj[!(reversed^(aprev->parent->rev))] = b; + bnext->adj[reversed^(bnext->parent->rev)] = a; + c = b->adj[0]; + b->adj[0] = aprev; + b->adj[1] = c; + b->id = id++; + while (c != a) { + cnext = c->adj[0]; + c->adj[0] = c->adj[1]; + c->adj[1] = cnext; + c->id = id++; + c = cnext; + } + a->adj[0] = a->adj[1]; + a->adj[1] = bnext; + a->id = id; + if (parent->ends[0] == a) + parent->ends[0] = b; + if (parent->ends[1] == b) + parent->ends[1] = a; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void consecutive_segment_flip (parentnode *a, parentnode *b) +#else +static void consecutive_segment_flip (a, b) +parentnode *a, *b; +#endif +{ + childnode *achild = a->ends[reversed^(a->rev)]; + childnode *bchild = b->ends[!(reversed^(b->rev))]; + childnode *childprev, *childnext; + + if (reversed) { + childprev = achild->adj[!a->rev]; + childnext = bchild->adj[b->rev]; + childprev->adj[childprev->parent->rev] = bchild; + childnext->adj[!childnext->parent->rev] = achild; + bchild->adj[b->rev] = childprev; + achild->adj[!a->rev] = childnext; + parflip (a, b); + } else { + childprev = achild->adj[a->rev]; + childnext = bchild->adj[!b->rev]; + childprev->adj[!childprev->parent->rev] = bchild; + childnext->adj[childnext->parent->rev] = achild; + bchild->adj[!b->rev] = childprev; + achild->adj[a->rev] = childnext; + parflip (a, b); + } +} + +/* split between a and aprev */ + +#ifdef CC_PROTOTYPE_ANSI +static void segment_split (parentnode *p, childnode *aprev, childnode *a, + int left_or_right) +#else +static void segment_split (p, aprev, a, left_or_right) +parentnode *p; +childnode *aprev, *a; +int left_or_right; +#endif +{ + int side; + int dir = (reversed^(p->rev)); + int id; + parentnode *pnext; + childnode *b, *bnext; + + if (dir) + side = p->ends[1]->id - aprev->id + 1; + else + side = aprev->id - p->ends[0]->id + 1; + + if ((left_or_right == 0 && side <= p->size / 2) || left_or_right == 1) { + pnext = parprev(p); + pnext->size += side; + p->size -= side; + if (pnext->rev == p->rev) { + b = pnext->ends[!dir]; + id = b->id; + if (dir) { + do { + b = b->adj[0]; + b->id = --id; + b->parent = pnext; + } while (b != aprev); + } else { + do { + b = b->adj[1]; + b->id = ++id; + b->parent = pnext; + } while (b != aprev); + } + pnext->ends[!dir] = aprev; + p->ends[dir] = a; + } else { + b = pnext->ends[dir]; + id = b->id; + if (!dir) { + bnext = b->adj[0]; + do { + b = bnext; + b->id = --id; + b->parent = pnext; + bnext = b->adj[1]; + b->adj[1] = b->adj[0]; + b->adj[0] = bnext; + } while (b != aprev); + } else { + bnext = b->adj[1]; + do { + b = bnext; + b->id = ++id; + b->parent = pnext; + bnext = b->adj[0]; + b->adj[0] = b->adj[1]; + b->adj[1] = bnext; + } while (b != aprev); + } + pnext->ends[dir] = aprev; + p->ends[dir] = a; + } + } else { + pnext = parnext(p); + pnext->size += (p->size - side); + p->size = side; + if (pnext->rev == p->rev) { + b = pnext->ends[dir]; + id = b->id; + if (dir) { + do { + b = b->adj[1]; + b->id = ++id; + b->parent = pnext; + } while (b != a); + } else { + do { + b = b->adj[0]; + b->id = --id; + b->parent = pnext; + } while (b != a); + } + pnext->ends[dir] = a; + p->ends[!dir] = aprev; + } else { + b = pnext->ends[!dir]; + id = b->id; + if (!dir) { + bnext = b->adj[1]; + do { + b = bnext; + b->id = ++id; + b->parent = pnext; + bnext = b->adj[0]; + b->adj[0] = b->adj[1]; + b->adj[1] = bnext; + } while (b != a); + } else { + bnext = b->adj[0]; + do { + b = bnext; + b->id = --id; + b->parent = pnext; + bnext = b->adj[1]; + b->adj[1] = b->adj[0]; + b->adj[0] = bnext; + } while (b != a); + } + pnext->ends[!dir] = a; + p->ends[!dir] = aprev; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + childnode *a = &(children[x]); + childnode *b = &(children[y]); + childnode *c = &(children[z]); + parentnode *pa = a->parent; + parentnode *pb = b->parent; + parentnode *pc = c->parent; + + if (pa == pb) { + if (pa == pc) { + if (reversed^(pa->rev)) { + if (a->id >= b->id) { + return (b->id >= c->id || c->id >= a->id); + } else { + return (b->id >= c->id && c->id >= a->id); + } + } else { + if (a->id <= b->id) { + return (b->id <= c->id || c->id <= a->id); + } else { + return (b->id <= c->id && c->id <= a->id); + } + } + } else { + if (reversed^(pa->rev)) { + return (a->id >= b->id); + } else { + return (a->id <= b->id); + } + } + } else if (pa == pc) { + if (reversed^(pa->rev)) { + return (a->id <= c->id); + } else { + return (a->id >= c->id); + } + } else if (pb == pc) { + if (reversed^(pb->rev)) { + return (b->id >= c->id); + } else { + return (b->id <= c->id); + } + } else { + int aloc = par_cyc_inv[pa->index]; + int bloc = par_cyc_inv[pb->index]; + int cloc = par_cyc_inv[pc->index]; + + if (reversed) { + if (aloc >= bloc) + return (bloc >= cloc || cloc >= aloc); + else + return (bloc >= cloc && cloc >= aloc); + } else { + if (aloc <= bloc) + return (bloc <= cloc || cloc <= aloc); + else + return (bloc <= cloc && cloc <= aloc); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static parentnode *parnext (parentnode *x) +#else +static parentnode *parnext (x) +parentnode *x; +#endif +{ + int y; + + if (reversed) { + y = par_cyc_inv[x->index] - 1; + return (y >= 0 ? &(parents[par_cyc[y]]) : + &(parents[par_cyc[nsegments-1]])); + } else { + y = par_cyc_inv[x->index] + 1; + return (y < nsegments ? &(parents[par_cyc[y]]) : + &(parents[par_cyc[0]])); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static parentnode *parprev (parentnode *x) +#else +static parentnode *parprev (x) +parentnode *x; +#endif +{ + int y; + + if (!reversed) { + y = par_cyc_inv[x->index] - 1; + return (y >= 0 ? &(parents[par_cyc[y]]) : + &(parents[par_cyc[nsegments-1]])); + } else { + y = par_cyc_inv[x->index] + 1; + return (y < nsegments ? &(parents[par_cyc[y]]) : + &(parents[par_cyc[0]])); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void parflip (parentnode *a, parentnode *b) +#else +static void parflip (a, b) +parentnode *a, *b; +#endif +{ + int x = a->index; + int y = b->index; + int xloc = par_cyc_inv[x]; + int yloc = par_cyc_inv[y]; + int temp; + int gap; + + if (reversed) { + SWAP (xloc, yloc, temp); + } + gap = yloc - xloc; + if (gap < 0) gap += nsegments; + + if (xloc > yloc) { + gap++; + gap /= 2; + for (; gap; gap--) { + x = par_cyc[xloc]; + y = par_cyc[yloc]; + parents[x].rev ^= 1; + parents[y].rev ^= 1; + par_cyc[xloc] = y; + par_cyc[yloc] = x; + par_cyc_inv[x] = yloc--; + par_cyc_inv[y] = xloc++; + if (xloc >= nsegments) + xloc = 0; + if (yloc < 0) + yloc = nsegments - 1; + } + } else { + gap++; + gap /= 2; + for (; gap; gap--) { + x = par_cyc[xloc]; + y = par_cyc[yloc]; + parents[x].rev ^= 1; + parents[y].rev ^= 1; + par_cyc[xloc] = y; + par_cyc[yloc] = x; + par_cyc_inv[x] = yloc--; + par_cyc_inv[y] = xloc++; + } + } + if (xloc == yloc) + parents[par_cyc[xloc]].rev ^= 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parsegsize (parentnode *a, parentnode *b) +#else +static int parsegsize (a, b) +parentnode *a, *b; +#endif +{ + int gap; + + if (reversed) + gap = par_cyc_inv[a->index] - par_cyc_inv[b->index]; + else + gap = par_cyc_inv[b->index] - par_cyc_inv[a->index]; + + if (gap < 0) + return gap + nsegments; + else + return gap; +} diff --git a/contrib/blossom/concorde97/LINKERN/flip_two.c b/contrib/blossom/concorde97/LINKERN/flip_two.c new file mode 100644 index 0000000000000000000000000000000000000000..15430b69260f8e59abd990166fc1134bf8c783ad --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/flip_two.c @@ -0,0 +1,678 @@ +/***************************************************************************/ +/* */ +/* TOUR MAINTANENCE ROUTINES FOR LIN-KERNIGHAN - Two-level Tree */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 2, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_flipper_init (int ncount, int *cyc) */ +/* initializes flipper1 to an initial cycle given in cyc. */ +/* returns 0 on success, nonzero on failure. */ +/* int CClinkern_flipper_cycle (int *p) */ +/* places the current cycle in p. */ +/* returns the number of segments in current representation. */ +/* void CClinkern_flipper_finish (void) */ +/* frees up temporary space allocated by CClinkern_flipper_init. */ +/* every flipper_init should lead to a flipper_finish call. */ +/* void CClinkern_flipper_free_world (void) */ +/* frees up all remaining space (including ptrs) */ +/* should be called when we are finished with linkern */ +/* int CClinkern_flipper_next (int x) */ +/* returns the successor to x in the current cycle. */ +/* int CClinkern_flipper_prev (int x) */ +/* returns the predecessor of x in the current cycle. */ +/* void CClinkern_flipper_flip (int x, int y) */ +/* flips the portion of the cycle from x to y (inclusive). */ +/* int CClinkern_flipper_sequence (int * x, int y, int z) */ +/* returns 1 if xyz occur as an increasing subsequence of the cycle, */ +/* returns 0 otherwise. */ +/* */ +/* NOTES: */ +/* This is desribed in the paper "Data structures for traveling */ +/* salesman" by Fredman, Johnson, McGeoch, and Ostheimer. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "linkern.h" + +/***************************************************************************/ +/* */ +/* TWO-LEVEL TREES: */ +/* */ +/* 1. Uses the "groupsize" approach described in the paper. */ +/* */ +/***************************************************************************/ + +#define USE_SEGMENT_SPLIT +#define GROUPSIZE_FACTOR 0.50 +#define SEGMENT_SPLIT_CUTOFF 0.35 + +typedef struct parentnode { + struct parentnode *adj[2]; + struct childnode *ends[2]; + int size; + int id; + int rev; +} parentnode; + +typedef struct childnode { + struct parentnode *parent; + struct childnode *adj[2]; + int id; + int name; +} childnode; + +#ifdef CC_PROTOTYPE_ANSI + +static void + same_segment_flip (childnode *a, childnode *b), + consecutive_segment_flip (parentnode *a, parentnode *b), + segment_split (parentnode *p, childnode *aprev, childnode *a, + int left_or_right); + +#else + +static void + same_segment_flip (), + consecutive_segment_flip (), + segment_split (); + +#endif + +static parentnode *parents = (parentnode *) NULL; +static childnode *children = (childnode *) NULL; +static int reversed = 0; +static cycle_size = 0; +static int nsegments = 0; +static groupsize = 100; +#ifdef USE_SEGMENT_SPLIT +static int split_cutoff = 100; +#endif + +#define SAME_SEGMENT(a, b) \ + (a->parent == b->parent && \ + ((!(reversed^(a->parent->rev)) && a->id <= b->id) || \ + ((reversed^(a->parent->rev)) && a->id >= b->id))) + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_init (int ncount, int *cyc) +#else +int CClinkern_flipper_init (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, j, cind, remain; + childnode *c, *cprev, *cnext; + parentnode *p; + + reversed = 0; + cycle_size = ncount; + groupsize = (int) (sqrt ((double) ncount) * GROUPSIZE_FACTOR); + nsegments = (ncount + groupsize - 1) / groupsize; +#ifdef USE_SEGMENT_SPLIT + split_cutoff = (int) (groupsize * SEGMENT_SPLIT_CUTOFF); +#endif + + parents = CC_SAFE_MALLOC (nsegments, parentnode); + if (!parents) + return 1; + + children = CC_SAFE_MALLOC (ncount + 1, childnode); + /* The +1 will stop a purify burp later */ + if (!children) { + CC_FREE (parents, parentnode); + return 1; + } + + remain = ncount; + i = 0; + j = 2 * groupsize; + while (remain >= j) { + parents[i].size = groupsize; + remain -= groupsize; + i++; + } + if (remain > groupsize) { + parents[i].size = remain / 2; + remain -= (remain / 2); + i++; + } + parents[i].size = remain; + i++; + + if (i != nsegments) { + printf ("seg count is wrong\n"); + fflush (stdout); + CC_FREE (parents, parentnode); + CC_FREE (children, childnode); + return 1; + } + + c = (childnode *) NULL; + cnext = &(children[cyc[0]]); + for (i = 0, p = parents, c = children, cind = 0; i < nsegments; p++, i++) { + p->id = i; + p->rev = 0; + p->ends[0] = cnext; + for (j = p->size; j > 0; j--) { + cprev = c; + c = cnext; + c->id = cind; + c->name = cyc[cind]; + c->parent = p; + c->adj[0] = cprev; + cind++; + if (cind != ncount) { + cnext = &(children[cyc[cind]]); + c->adj[1] = cnext; + } + } + p->ends[1] = c; + p->adj[0] = p - 1; + p->adj[1] = p + 1; + } + parents[0].adj[0] = &(parents[nsegments - 1]); + parents[nsegments - 1].adj[1] = &(parents[0]); + children[cyc[0]].adj[0] = &(children[cyc[ncount - 1]]); + children[cyc[ncount - 1]].adj[1] = &(children[cyc[0]]); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_cycle (int *x) +#else +int CClinkern_flipper_cycle (x) +int *x; +#endif +{ + childnode *c, *start; + int k = 0; + + start = &(children[0]); + c = start->adj[!(reversed^(start->parent->rev))]; + + x[k++] = start->name; + while (c != start) { + x[k++] = c->name; + c = c->adj[!(reversed^(c->parent->rev))]; + } + return cycle_size; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_finish (void) +#else +void CClinkern_flipper_finish () +#endif +{ + if (parents) + CC_FREE (parents, parentnode); + if (children) + CC_FREE (children, childnode); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_free_world (void) +#else +void CClinkern_flipper_free_world () +#endif +{ + return; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_next (int x) +#else +int CClinkern_flipper_next (x) +int x; +#endif +{ + return children[x].adj[!(reversed^(children[x].parent->rev))]->name; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_prev (int x) +#else +int CClinkern_flipper_prev (x) +int x; +#endif +{ + return children[x].adj[reversed^(children[x].parent->rev)]->name; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClinkern_flipper_flip (int x, int y) +#else +void CClinkern_flipper_flip (x, y) +int x,y; +#endif +{ + childnode *xc = &(children[x]); + childnode *yc = &(children[y]); + + if (SAME_SEGMENT (xc, yc)) { + if (xc != yc) { + same_segment_flip (xc, yc); + } + } else { + int xdir = (reversed^(xc->parent->rev)); + int ydir = (reversed^(yc->parent->rev)); + childnode *xprev = xc->adj[xdir]; + childnode *ynext = yc->adj[!ydir]; + if (SAME_SEGMENT (ynext, xprev)) { + if (ynext != xprev) { + same_segment_flip (ynext, xprev); + } + reversed ^= 1; + } else { + int side; + if (xc->parent->ends[xdir] == xc && + yc->parent->ends[!ydir] == yc) { + if (reversed) + side = xc->parent->id - yc->parent->id; + else + side = yc->parent->id - xc->parent->id; + if (side < 0) + side += nsegments; + if (side < nsegments / 2) { + consecutive_segment_flip (xc->parent, yc->parent); + } else { + consecutive_segment_flip(yc->parent->adj[!reversed], + xc->parent->adj[reversed]); + reversed ^= 1; + } + } else { + if (xprev->parent == xc->parent) { + segment_split (xc->parent, xprev, xc, 0); + if (SAME_SEGMENT (xc, yc)) { + if (xc != yc) + same_segment_flip (xc, yc); + return; + } else if (SAME_SEGMENT (ynext, xprev)) { + if (ynext != xprev) { + same_segment_flip (ynext, xprev); + } + reversed ^= 1; + return; + } + } + if (ynext->parent == yc->parent) { + segment_split (yc->parent, yc, ynext, 0); + if (SAME_SEGMENT (xc, yc)) { + if (xc != yc) + same_segment_flip (xc, yc); + return; + } else if (SAME_SEGMENT (ynext, xprev)) { + if (ynext != xprev) { + same_segment_flip (ynext, xprev); + } + reversed ^= 1; + return; + } + } + if (reversed) + side = xc->parent->id - yc->parent->id; + else + side = yc->parent->id - xc->parent->id; + if (side < 0) + side += nsegments; + if (side < nsegments / 2) { + consecutive_segment_flip (xc->parent, yc->parent); + } else { + consecutive_segment_flip(yc->parent->adj[!reversed], + xc->parent->adj[reversed]); + reversed ^= 1; + } + + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void same_segment_flip (childnode *a, childnode *b) +#else +static void same_segment_flip (a, b) +childnode *a, *b; +#endif +{ + parentnode *parent = a->parent; + int dir = (reversed^(parent->rev)); + childnode *aprev = a->adj[dir]; + childnode *bnext = b->adj[!dir]; + childnode *c, *cnext; + +#ifdef USE_SEGMENT_SPLIT + if ((dir && a->id - b->id > split_cutoff) || + (!dir && b->id - a->id > split_cutoff)) { + if (aprev->parent == parent) + segment_split (parent, aprev, a, 1); + if (bnext->parent == parent) + segment_split (parent, b, bnext, 2); + aprev->adj[!(reversed^(aprev->parent->rev))] = b; + bnext->adj[reversed^(bnext->parent->rev)] = a; + a->adj[dir] = bnext; + b->adj[!dir] = aprev; + parent->rev ^= 1; + return; + } +#endif + + if (dir) { + int id = a->id; + aprev->adj[!(reversed^(aprev->parent->rev))] = b; + bnext->adj[reversed^(bnext->parent->rev)] = a; + cnext = b->adj[1]; + b->adj[1] = aprev; + b->adj[0] = cnext; + b->id = id--; + c = cnext; + while (c != a) { + cnext = c->adj[1]; + c->adj[1] = c->adj[0]; + c->adj[0] = cnext; + c->id = id--; + c = cnext; + } + a->adj[1] = a->adj[0]; + a->adj[0] = bnext; + a->id = id; + if (parent->ends[1] == a) + parent->ends[1] = b; + if (parent->ends[0] == b) + parent->ends[0] = a; + } else { + int id = a->id; + aprev->adj[!(reversed^(aprev->parent->rev))] = b; + bnext->adj[reversed^(bnext->parent->rev)] = a; + c = b->adj[0]; + b->adj[0] = aprev; + b->adj[1] = c; + b->id = id++; + while (c != a) { + cnext = c->adj[0]; + c->adj[0] = c->adj[1]; + c->adj[1] = cnext; + c->id = id++; + c = cnext; + } + a->adj[0] = a->adj[1]; + a->adj[1] = bnext; + a->id = id; + if (parent->ends[0] == a) + parent->ends[0] = b; + if (parent->ends[1] == b) + parent->ends[1] = a; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void consecutive_segment_flip (parentnode *a, parentnode *b) +#else +static void consecutive_segment_flip (a, b) +parentnode *a, *b; +#endif +{ + parentnode *aprev = a->adj[reversed]; + parentnode *bnext = b->adj[!reversed]; + parentnode *c, *cnext; + childnode *achild = a->ends[reversed^(a->rev)]; + childnode *bchild = b->ends[!(reversed^(b->rev))]; + childnode *childprev, *childnext; + int id = a->id; + + if (reversed) { + childprev = achild->adj[!a->rev]; + childnext = bchild->adj[b->rev]; + childprev->adj[childprev->parent->rev] = bchild; + childnext->adj[!childnext->parent->rev] = achild; + bchild->adj[b->rev] = childprev; + achild->adj[!a->rev] = childnext; + + aprev->adj[0] = b; + bnext->adj[1] = a; + c = b->adj[1]; + b->adj[1] = aprev; + b->adj[0] = c; + b->id = id--; + b->rev ^= 1; + while (c != a) { + cnext = c->adj[1]; + c->adj[1] = c->adj[0]; + c->adj[0] = cnext; + c->id = id--; + c->rev ^= 1; + c = cnext; + } + a->adj[1] = a->adj[0]; + a->adj[0] = bnext; + a->id = id; + a->rev ^= 1; + } else { + childprev = achild->adj[a->rev]; + childnext = bchild->adj[!b->rev]; + childprev->adj[!childprev->parent->rev] = bchild; + childnext->adj[childnext->parent->rev] = achild; + bchild->adj[!b->rev] = childprev; + achild->adj[a->rev] = childnext; + + aprev->adj[1] = b; + bnext->adj[0] = a; + c = b->adj[0]; + b->adj[0] = aprev; + b->adj[1] = c; + b->id = id++; + b->rev ^= 1; + while (c != a) { + cnext = c->adj[0]; + c->adj[0] = c->adj[1]; + c->adj[1] = cnext; + c->id = id++; + c->rev ^= 1; + c = cnext; + } + a->adj[0] = a->adj[1]; + a->adj[1] = bnext; + a->id = id; + a->rev ^= 1; + } +} + +/* split between a and aprev */ + +#ifdef CC_PROTOTYPE_ANSI +static void segment_split (parentnode *p, childnode *aprev, childnode *a, + int left_or_right) +#else +static void segment_split (p, aprev, a, left_or_right) +parentnode *p; +childnode *aprev, *a; +int left_or_right; +#endif +{ + int side; + int dir = (reversed^(p->rev)); + int id; + parentnode *pnext; + childnode *b, *bnext; + + if (dir) + side = p->ends[1]->id - aprev->id + 1; + else + side = aprev->id - p->ends[0]->id + 1; + + if ((left_or_right == 0 && side <= p->size / 2) || left_or_right == 1) { + pnext = p->adj[reversed]; + pnext->size += side; + p->size -= side; + if (pnext->rev == p->rev) { + b = pnext->ends[!dir]; + id = b->id; + if (dir) { + do { + b = b->adj[0]; + b->id = --id; + b->parent = pnext; + } while (b != aprev); + } else { + do { + b = b->adj[1]; + b->id = ++id; + b->parent = pnext; + } while (b != aprev); + } + pnext->ends[!dir] = aprev; + p->ends[dir] = a; + } else { + b = pnext->ends[dir]; + id = b->id; + if (!dir) { + bnext = b->adj[0]; + do { + b = bnext; + b->id = --id; + b->parent = pnext; + bnext = b->adj[1]; + b->adj[1] = b->adj[0]; + b->adj[0] = bnext; + } while (b != aprev); + } else { + bnext = b->adj[1]; + do { + b = bnext; + b->id = ++id; + b->parent = pnext; + bnext = b->adj[0]; + b->adj[0] = b->adj[1]; + b->adj[1] = bnext; + } while (b != aprev); + } + pnext->ends[dir] = aprev; + p->ends[dir] = a; + } + } else { + pnext = p->adj[!reversed]; + pnext->size += (p->size - side); + p->size = side; + if (pnext->rev == p->rev) { + b = pnext->ends[dir]; + id = b->id; + if (dir) { + do { + b = b->adj[1]; + b->id = ++id; + b->parent = pnext; + } while (b != a); + } else { + do { + b = b->adj[0]; + b->id = --id; + b->parent = pnext; + } while (b != a); + } + pnext->ends[dir] = a; + p->ends[!dir] = aprev; + } else { + b = pnext->ends[!dir]; + id = b->id; + if (!dir) { + bnext = b->adj[1]; + do { + b = bnext; + b->id = ++id; + b->parent = pnext; + bnext = b->adj[0]; + b->adj[0] = b->adj[1]; + b->adj[1] = bnext; + } while (b != a); + } else { + bnext = b->adj[0]; + do { + b = bnext; + b->id = --id; + b->parent = pnext; + bnext = b->adj[1]; + b->adj[1] = b->adj[0]; + b->adj[0] = bnext; + } while (b != a); + } + pnext->ends[!dir] = a; + p->ends[!dir] = aprev; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_flipper_sequence (int x, int y, int z) +#else +int CClinkern_flipper_sequence (x, y, z) +int x, y, z; +#endif +{ + childnode *a = &(children[x]); + childnode *b = &(children[y]); + childnode *c = &(children[z]); + parentnode *pa = a->parent; + parentnode *pb = b->parent; + parentnode *pc = c->parent; + + if (pa == pb) { + if (pa == pc) { + if (reversed^(pa->rev)) { + if (a->id >= b->id) { + return (b->id >= c->id || c->id >= a->id); + } else { + return (b->id >= c->id && c->id >= a->id); + } + } else { + if (a->id <= b->id) { + return (b->id <= c->id || c->id <= a->id); + } else { + return (b->id <= c->id && c->id <= a->id); + } + } + } else { + if (reversed^(pa->rev)) { + return (a->id >= b->id); + } else { + return (a->id <= b->id); + } + } + } else if (pa == pc) { + if (reversed^(pa->rev)) { + return (a->id <= c->id); + } else { + return (a->id >= c->id); + } + } else if (pb == pc) { + if (reversed^(pb->rev)) { + return (b->id >= c->id); + } else { + return (b->id <= c->id); + } + } else { + if (reversed) { + if (pa->id >= pb->id) { + return (pb->id >= pc->id || pc->id >= pa->id); + } else { + return (pb->id >= pc->id && pc->id >= pa->id); + } + } else { + if (pa->id <= pb->id) { + return (pb->id <= pc->id || pc->id <= pa->id); + } else { + return (pb->id <= pc->id && pc->id <= pa->id); + } + } + } +} diff --git a/contrib/blossom/concorde97/LINKERN/linkern.c b/contrib/blossom/concorde97/LINKERN/linkern.c new file mode 100644 index 0000000000000000000000000000000000000000..09c47339df18fb42e1f4d156c29ee10624295ef2 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/linkern.c @@ -0,0 +1,2781 @@ +/***************************************************************************/ +/* */ +/* ITERATED LIN-KERNIGHAN */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 22, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CClinkern_tour (int ncount, CCdatagroup *dat, int ecount, */ +/* int *elist, int stallcount, int repeatcount, int *incycle, */ +/* int *outcycle, double *val */ +/* int run_silently, double time_bound, double length_bound, */ +/* char *saveit_name) */ +/* RUNS Chained Lin-Kernighan. */ +/* -ncount (the number of nodes int the graph) */ +/* -dat (coordinate dat) */ +/* -ecount (the number of good edges - should not be 0) */ +/* -elist (the good edges in end1 end2 format) */ +/* -stallcount (the max number of 4-swaps without progress */ +/* -repeatcount (the number of 4-swap kicks) */ +/* -incycle (a starting cycle, in node node node format - can be NULL) */ +/* -outcycle (returns the cycle - can be NULL) */ +/* -run_slightly (if nonzero, then very little info will be printed) */ +/* -time_bound (if postive, then the search will stop after the kick */ +/* that puts the running time above this number of seconds) */ +/* -length_bound (if postive, then the search will stop after the kick */ +/* that puts the tour at or below this length) */ +/* -saveit_name (if non NULL then the tour will be saved to this file */ +/* after every 10000 kicks - if it has improved) */ +/* */ +/* NOTES: If incycle is NULL, then a random starting cycle is used. If */ +/* outcycle is not NULL, then it should point to an array of length at */ +/* least ncount. The type of flipper to be used should be defined in */ +/* linkern.h and added to the makefile). */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "linkern.h" + +#define MAX_OUTPUT 0 /* Define to 1 to have more output */ + +#define MAXDEPTH 50 /* Shouldn't be less than 2. */ +#define MAK_MORTON /* Define to some of the Mak-Morton moves */ +#undef NODE_INSERTIONS /* Define to use Reinelt's moves */ +#undef FULL_MAK_MORTON /* Define to use all of the Mak-Morton moves */ +#define USE_LESS_OR_EQUAL +#define SUBTRACT_GSTAR +#undef SWITCH_LATE_DEPTH /* To give more search freedom before LATE_DEPTH */ +#define LATE_DEPTH 10 /* Should be less than MAXDEPTH */ + +#define GEOM_FOUR_SWAPS /* Use geometry to find close 4-swap kicks */ +#undef CLOSE_FOUR_SWAPS /* Use distances to find close 4-swap kicks */ +#undef IMPROVE_FOUR_SWAPS /* Use an LK search as a kick */ +#define IMPROVE_SWITCH 0 /* Depth to start using IMPROVE_FOUR_SWAPS */ +#define KICK_MAXDEPTH 50 /* Max # of swaps in an IMPROVE_FOUR_SWAP kick */ +#define LONG_KICKER /* Guides choice of first edge in a kick */ + +#define ACCEPT_TIES /* In Chained LK, keep new tours that tie best */ +#undef ACCEPT_BAD_TOURS /* Define to use a simulated-annealing approach */ + +#undef MARK_NEIGHBORS /* Mark the good-edge neighbors after swaps */ +#define USE_LESS_MARKING /* Do not mark the tour neighbors after swaps */ +#define MARK_LEVEL 10 /* Number of tour neighbors after 4-swap kick */ + +#define BACKTRACK 2 +#define MAX_BACK 10 /* Upper bound on the XXX_count entries */ +static int backtrack_count[BACKTRACK] = {10, 5}; /* Breadth of backtrack */ +static int weird_backtrack_count[3] = {10, 5, 2}; /* For weird backtrack */ + +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* SETTING THE PARAMETERS */ +/* */ +/* At this point (27.8.97), we have not yet made a detailed */ +/* computational study to choose a good selection of the various */ +/* parameters that can be set. The default settings appear to work well */ +/* for large examples, where we want to obtain a good quality tour */ +/* quickly. For small instances where we may want to get very close to an */ +/* optimal tour, better performance can often be obtained by using random */ +/* four swaps, using a denser set of good edges, and by using a wider */ +/* (or deeper) search in the backtracking. */ +/* The default settings are as follows: */ +/* */ +/* MAXDEPTH 50 (this means that Lin-Kernighan will not consider */ +/* sequences of 2-opt moves longer than 50) */ +/* MAX_MORTON (this permits the code to perform the "inverse" */ +/* moves described in the paper by Mak and Morton. */ +/* USE_LESS_OR_EQUAL (this tells the code to consider edges that */ +/* have length <= the current gain (it is usually */ +/* the case that LK is implemented to allow only */ +/* edges that are < the current gain)) */ +/* SUBTRACT_GSTAR (restricts the freedom of the search to avoid */ +/* long sequences of 2-opt moves that do not have */ +/* a good chance of improving on the current best */ +/* gain (gstar)) */ +/* GEOM_FOUR_SWAPS (uses 4-swap kicks between nodes that are */ +/* geometrically close, this is better than random */ +/* 4-swaps for very large instances) */ +/* LONG_KICKER (choose the initial edge in a 4-swap kick to be */ +/* one that is long relative to the length of the */ +/* shortest good edge meeting the node (this is an */ +/* idea of Andre Rohe)) */ +/* USE_LESS_MARKING (do not mark the tour neighbors of the nodes */ +/* appearing in an improving swap sequence) */ +/* BACKTRACK 2 (backtrack at the first two levels of the search) */ +/* MAX_BACK 10 (do not use more than breadth 10 in a backtrack) */ +/* backtrack_count[BACKTRACK] = {10, 5} (to use breadth 10 at the */ +/* first level and breadth 5 at the second level) */ +/* weird_backtrack_count[3] = {10, 5, 2} (in the weird step, use */ +/* breadth 10 at first level, 5 at second level) */ +/* */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + + +#ifdef GEOM_FOUR_SWAPS +#include "kdtree.h" +#endif + +#define BIGINT 1000000000 +#define BIGDOUBLE 100000000000.0 + +#define OTHEREND(e,n) (e->ends[0] == n ? e->ends[1] : e->ends[0]) +#define SWAP(x,y,temp) {(temp) = (x); (x) = (y); (y) = (temp);} +#define Edgelen(n1, n2) dist (n1, n2) +/* +#define Edgelen(n1, n2) CCutil_dat_edgelen (n1, n2, gdat) +*/ + + +#ifdef CC_EXTRA_INFO_FLIP +#define FLIP(aprev, a, b, bnext, numi) { \ + CClinkern_flipper_flip ((aprev), (a), (b), (bnext)); \ + flipstack[flip_counter].first = (a); \ + flipstack[flip_counter].last = (b); \ + flipstack[flip_counter].firstprev = (aprev); \ + flipstack[flip_counter++].lastnext = (bnext); \ +} +#else +#define FLIP(aprev, a, b, bnext, numi) { \ + CClinkern_flipper_flip ((a), (b)); \ + flipstack[flip_counter].first = (a); \ + flipstack[flip_counter++].last = (b); \ +} +#endif + +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER +#define UNFLIP(aprev, a, b, bnext, numi) { \ + flip_counter--; \ +} +#else /* CC_NO_UNDO_SEGMENTS_FLIPPER */ +#ifdef CC_EXTRA_INFO_FLIP +#define UNFLIP(aprev, a, b, bnext, numi) { \ + CClinkern_flipper_flip ((aprev), (b), (a), (bnext)); \ + flip_counter--; \ +} +#else +#define UNFLIP(aprev, a, b, bnext, numi) { \ + CClinkern_flipper_flip ((b), (a)); \ + flip_counter--; \ +} +#endif +#endif /* CC_NO_UNDO_SEGMENTS_FLIPPER */ + +#define markedge_add(n1, n2) add_edges[n1 ^ n2] = 1 +#define markedge_del(n1, n2) del_edges[n1 ^ n2] = 1 +#define unmarkedge_add(n1, n2) add_edges[n1 ^ n2] = 0 +#define unmarkedge_del(n1, n2) del_edges[n1 ^ n2] = 0 +#define is_it_added(n1, n2) add_edges[n1 ^ n2] +#define is_it_deleted(n1, n2) del_edges[n1 ^ n2] + +#define ADD_TO_ACTIVE_QUEUE(n, ip) { \ + if (!active[(n)]) { \ + active[(n)] = 1; \ + (ip) = intptralloc (); \ + (ip)->this = (n); \ + (ip)->next = (intptr *) NULL; \ + if (bottom_active_queue) \ + bottom_active_queue->next = (ip); \ + else \ + active_queue = (ip); \ + bottom_active_queue = (ip); \ + } \ +} + +typedef struct edge { + int other; + int weight; +} edge; + +typedef struct edgelook { + struct edgelook *next; + int other; + int diff; + int over; + int seq; + int side; +#ifdef MAK_MORTON + int mm; +#endif +#ifdef NODE_INSERTIONS + int ni; + int under; +#endif +} edgelook; + +typedef struct intptr { + int this; + struct intptr *next; +} intptr; + +typedef struct flippair { + int firstprev; + int first; + int last; + int lastnext; +} flippair; + + +#ifdef CC_PROTOTYPE_ANSI + +static void + look_ahead_noback (int first, int last, int G, edgelook *winner), + turn (int n), +#ifdef IMPROVE_FOUR_SWAPS + kickturn (int n), +#endif + bigturn (int n, int tonext), +#ifdef LONG_KICKER + first_long_kicker (int ncount, int *t1, int *t2), +#endif +#if defined(CLOSE_FOUR_SWAPS) || defined(GEOM_FOUR_SWAPS) + find_close_four (int ncount, int *t1, int *t2, int *t3, int *t4, + int *t5, int *t6, int *t7, int *t8), +#endif + randcycle (int ncount, int *cyc), + insertedge (int n1, int n2, int w), + free_graph (int ncount), + linkern_free_world (void); + +static int + buildgraph (int ncount, int ecount, int *elist), + repeated_lin_kernighan (int ncount, int *cyc, int stallcount, + int repeatcount, double *val, double time_bound, + double length_bound, char *saveit_name), + lin_kernighan (int ncount, double *val), + weird_second_step (int G, int t1, int t2), + step (int level, int G, int *Gstar, int first, int last), + step_noback (int level, int G, int *Gstar, int first, int last), +#ifdef IMPROVE_FOUR_SWAPS + kick_step_noback (int level, int G, int *Gstar, int first, int last), +#endif +#ifdef GEOM_FOUR_SWAPS + find_geometric_four (int ncount, CCkdtree *kdt, + int *t1, int *t2, int *t3, int *t4, + int *t5, int *t6, int *t7, int *t8), + random_four_swap (int ncount, CCkdtree *kdt, int *delta), +#else + random_four_swap (int ncount), +#endif + initarrays (int ncount), + initcache (int ncount), + dist (int i, int j); + +static double + improve_tour (int start), +#ifdef IMPROVE_FOUR_SWAPS + kick_improve (int ncount), +#endif + cycle_length (int ncount, int *cyc); + +static edgelook + *look_ahead (int first, int last, int G, int level), + *weird_look_ahead (int G, int t1, int t2), + *weird_look_ahead2 (int G, int t2, int t3, int t4), + *weird_look_ahead3 (int G, int t2, int t3, int t6); + +#else + +static void + look_ahead_noback (), + turn (), +#ifdef IMPROVE_FOUR_SWAPS + kickturn (), +#endif + bigturn (), +#ifdef LONG_KICKER + first_long_kicker (), +#endif +#if defined(CLOSE_FOUR_SWAPS) || defined(GEOM_FOUR_SWAPS) + find_close_four (), +#endif + randcycle (), + insertedge (), + free_graph (), + linkern_free_world (); + +static int + buildgraph (), + repeated_lin_kernighan (), + lin_kernighan (), + weird_second_step (), + step (), + step_noback (), +#ifdef IMPROVE_FOUR_SWAPS + kick_step_noback (), +#endif +#ifdef GEOM_FOUR_SWAPS + find_geometric_four (), + random_four_swap (), +#else + random_four_swap (), +#endif + initarrays (), + initcache (), + dist (); + +static double + improve_tour (), +#ifdef IMPROVE_FOUR_SWAPS + kick_improve (), +#endif + cycle_length (); + +static edgelook + *look_ahead (), + *weird_look_ahead (), + *weird_look_ahead2 (), + *weird_look_ahead3 (); + +#endif + +static int no_output = 0; +static char *add_edges = (char *) NULL; +static char *del_edges = (char *) NULL; +static char *active = (char *) NULL; +static int *weirdmark = (int *) NULL; +static int *cacheind = (int *) NULL; +static int *cacheval = (int *) NULL; +static intptr *active_queue = (intptr *) NULL; +static intptr *bottom_active_queue = (intptr *) NULL; +static int weirdmagic = 0; +static int new_tour_time = 0; +#if defined(CC_NO_UNDO_SEGMENTS_FLIPPER) || defined(CC_FULL_SEGMENTS_FLIPPER) +static int new_tour_cutoff = 1; +#endif +static int flip_counter = 0; +static flippair *flipstack = (flippair *) NULL; +#ifdef CC_USE_FLIP_CLEANING +static int winstack_max = 0; +static int win_counter = 0; +static flippair *winstack = (flippair *) NULL; +static int *win_cycle = (int *) NULL; +#endif + +static edge **goodlist = (edge **) NULL; +static intptr **fixlist = (intptr **) NULL; +static CCdatagroup *gdat = (CCdatagroup *) NULL; +static edge *edgespace = (edge *) NULL; +static int *degree = (int *) NULL; + +CC_PTR_ALLOC_ROUTINE (intptr, intptralloc, intptrchunklist, intptrfreelist) +CC_PTR_FREE_ROUTINE (intptr, intptrfree, intptrfreelist) +CC_PTR_FREE_LIST_ROUTINE (intptr, intptr_list_free, intptrfree) +CC_PTR_FREE_WORLD_ROUTINE (intptr, intptrfree_world, intptrchunklist, + intptrfreelist) +CC_PTR_LEAKS_ROUTINE (intptr, intptr_check_leaks, intptrchunklist, + intptrfreelist, this, int) + +CC_PTR_ALLOC_ROUTINE (edgelook, edgelookalloc, edgelookchunklist, + edgelookfreelist) +CC_PTR_FREE_ROUTINE (edgelook, edgelookfree, edgelookfreelist) +CC_PTR_FREE_LIST_ROUTINE(edgelook, edgelook_list_free, edgelookfree) +CC_PTR_FREE_WORLD_ROUTINE( edgelook, edgelookfree_world, edgelookchunklist, + edgelookfreelist) +CC_PTR_LEAKS_ROUTINE (edgelook, edgelook_check_leaks, edgelookchunklist, + edgelookfreelist, diff, int) + + +#ifdef CC_PROTOTYPE_ANSI +int CClinkern_tour (int ncount, CCdatagroup *dat, int ecount, + int *elist, int stallcount, int repeatcount, int *incycle, + int *outcycle, double *val, int run_silently, double time_bound, + double length_bound, char *saveit_name) +#else +int CClinkern_tour (ncount, dat, ecount, elist, stallcount, repeatcount, + incycle, outcycle, val, run_silently, time_bound, length_bound, + saveit_name) +int ncount; +CCdatagroup *dat; +int ecount; +int *elist; +int stallcount, repeatcount; +int *incycle; +int *outcycle; +double *val; +int run_silently; +double time_bound; +double length_bound; +char *saveit_name; +#endif +{ + int i; + double startzeit, goodzeit; + int *tcyc = (int *) NULL; + intptr *ip; + int rval = 0; + + if (!run_silently) { + printf ("linkern with %d nodes ...\n", ncount); + fflush (stdout); + } + startzeit = CCutil_zeit (); + + no_output = run_silently; + gdat = dat; + fixlist = (intptr **) NULL; + active_queue = (intptr *) NULL; + bottom_active_queue = (intptr *) NULL; +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + new_tour_time = 0; +#endif +#ifdef CC_FULL_SEGMENTS_FLIPPER + new_tour_time = 100000; +#endif +#ifdef CC_SEGMENTS_FLIPPER + new_tour_time = (ncount / 250) + 1; /* 5.5.95 - 250 now looks okay */ +#endif + +#if defined(CC_NO_UNDO_SEGMENTS_FLIPPER) || defined(CC_FULL_SEGMENTS_FLIPPER) + new_tour_cutoff = 500 + ncount / 50; +#endif + +#ifdef NODE_INSERTIONS + flipstack = CC_SAFE_MALLOC (new_tour_time + 2*MAXDEPTH + 7 + KICK_MAXDEPTH, + flippair); +#else + flipstack = CC_SAFE_MALLOC (new_tour_time + MAXDEPTH + 7 + KICK_MAXDEPTH, + flippair); +#endif + if (!flipstack) { + rval = 1; + goto CLEANUP; + } +#ifdef CC_USE_FLIP_CLEANING + win_counter = 0; +#ifdef CC_FULL_SEGMENTS_FLIPPER + winstack_max = 100000; +#else + winstack_max = (500 + ncount / 50) + + (2 * (new_tour_time + MAXDEPTH + 7 + KICK_MAXDEPTH)); +#endif + winstack = CC_SAFE_MALLOC (winstack_max, flippair); + if (!winstack) { + rval = 1; + goto CLEANUP; + } +#ifndef CC_FULL_SEGMENTS_FLIPPER + winstack_max -= ( 2 * (new_tour_time + MAXDEPTH + 7 + KICK_MAXDEPTH)); +#endif + win_cycle = CC_SAFE_MALLOC (ncount, int); + if (!win_cycle) { + rval = 1; + goto CLEANUP; + } + win_cycle[0] = -1; +#endif /* CC_USE_FLIP_CLEANING */ + tcyc = CC_SAFE_MALLOC (ncount, int); + if (!tcyc) { + rval = 1; + goto CLEANUP; + } + if (initarrays (ncount)) { + rval = 1; + goto CLEANUP; + } + if (initcache (ncount)) { + rval = 1; + goto CLEANUP; + } + + if (buildgraph (ncount, ecount, elist)) { + fprintf (stderr, "buildgraph failed\n"); + rval = 1; + goto CLEANUP; + } +#ifdef BIG_PROBLEM + CC_FREE (elist, int); +#endif + + randcycle (ncount, tcyc); /* init active_queue with random order */ + for (i = 0; i < ncount; i++) { + ADD_TO_ACTIVE_QUEUE (tcyc[i], ip); + } + + if (incycle) { + for (i = 0; i < ncount; i++) + tcyc[i] = incycle[i]; + *val = cycle_length (ncount, tcyc); + if (!no_output) { + printf ("Starting Cycle: %.0f\n", *val); + fflush (stdout); + } + } else { + goodzeit = CCutil_zeit (); + randcycle (ncount, tcyc); + *val = cycle_length (ncount, tcyc); + if (!no_output) { + printf ("Random Cycle: %.0f (Running Time: %.2f seconds)\n", + *val, CCutil_zeit () - goodzeit); + fflush (stdout); + } + } + if (repeated_lin_kernighan (ncount, tcyc, stallcount, + repeatcount, val, time_bound, length_bound, saveit_name)) { + fprintf (stderr, "repeated_lin_kernighan failed\n"); + rval = 1; + goto CLEANUP; + } + + if (!no_output) { + printf ("Best cycle length: %.0f\n", *val); + printf ("Lin-Kernighan Running Time: %.2f\n", + CCutil_zeit () - startzeit); + fflush (stdout); + } + + if (outcycle) { + for (i = 0; i < ncount; i++) + outcycle[i] = tcyc[i]; + } + +CLEANUP: + + CC_IFFREE (flipstack, flippair); + CC_IFFREE (tcyc, int); + CC_IFFREE (add_edges, char); + CC_IFFREE (del_edges, char); + CC_IFFREE (active, char); + CC_IFFREE (weirdmark, int); + CC_IFFREE (cacheind, int); + CC_IFFREE (cacheval, int); +#ifdef CC_USE_FLIP_CLEANING + CC_IFFREE (winstack, flippair); + CC_IFFREE (win_cycle, int); +#endif + + free_graph (ncount); + CClinkern_flipper_free_world (); + linkern_free_world (); + + return rval; +} + +#ifdef ACCEPT_BAD_TOURS +#define HEAT_FACTOR 0.999 +#define HEAT_RESET 100000 +#define HEAT_MULT 20 +#endif + +#ifdef CC_PROTOTYPE_ANSI +static int repeated_lin_kernighan (int ncount, int *cyc, int stallcount, + int count, double *val, double time_bound, double length_bound, + char *saveit_name) +#else +static int repeated_lin_kernighan (ncount, cyc, stallcount, count, val, + time_bound, length_bound, saveit_name) +int ncount; +int *cyc; +int stallcount, count; +double *val; +double time_bound; +double length_bound; +char *saveit_name; +#endif +{ + int round = 0, quitcount, hit; + double t, best = *val, oldbest = *val; + int delta; + double szeit = CCutil_zeit (); +#ifdef ACCEPT_BAD_TOURS + double heat = *val / (double) (HEAT_MULT * ncount), tdelta; +#endif +#ifdef GEOM_FOUR_SWAPS + CCkdtree kdt; +#endif + +#ifdef GEOM_FOUR_SWAPS + if (((gdat->norm) & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + if (CCkdtree_build (&kdt, ncount, gdat, (double *) NULL)) { + fprintf (stderr, "CCkdtree_build failed\n"); + fflush (stdout); + return 1; + } + } +#endif + + quitcount = stallcount; + if (quitcount > count) + quitcount = count; + + CClinkern_flipper_init (ncount, cyc); + flip_counter = 0; +#ifdef CC_USE_FLIP_CLEANING + win_counter = 0; + win_cycle[0] = -1; +#endif + if (lin_kernighan (ncount, &best)) { + fprintf (stderr, "lin_kernighan failed\n"); +#ifdef GEOM_FOUR_SWAPS + if (((gdat->norm) & CC_NORM_BITS) == CC_KD_NORM_TYPE) + CCkdtree_free (&kdt); +#endif + return 1; + } +#ifdef CC_USE_FLIP_CLEANING +#ifdef CC_FULL_SEGMENTS_FLIPPER + { + int i; + + if (flip_counter > 0) { + if (flip_counter < new_tour_cutoff) { + for (i = 0; i < flip_counter; i++) + CClinkern_flipper_flip_perm (flipstack[i].first, + flipstack[i].last); + CClinkern_flipper_reset_perm (1); + } else { + CClinkern_flipper_reset_temp (ncount); + } + flip_counter = 0; + } + } +#endif /* CC_FULL_SEGMENTS_FLIPPER */ + win_counter = 0; + win_cycle[0] = -1; +#else + CClinkern_flipper_cycle (cyc); + CClinkern_flipper_finish (); +#endif + + if (!no_output) { + if (quitcount > 0) + printf ("%d Steps Best: %.0f %.2f seconds\n", round, best, + CCutil_zeit () - szeit); + else + printf ("LK Cycle: %.0f\n", best); + fflush (stdout); + } + + while (round < quitcount) { + hit = 0; + +#ifndef CC_USE_FLIP_CLEANING + CClinkern_flipper_init (ncount, cyc); +#endif + flip_counter = 0; + +#ifdef IMPROVE_FOUR_SWAPS + if (round < IMPROVE_SWITCH) + delta = random_four_swap (ncount); + else + delta = kick_improve (ncount); +#else +#ifdef GEOM_FOUR_SWAPS + if (random_four_swap (ncount, &kdt, &delta)) { + fprintf (stderr, "random_four_swap failed\n"); + fflush (stdout); + CCkdtree_free (&kdt); + return 1; + } +#else + delta = random_four_swap (ncount); +#endif /* GEOM_FOUR_SWAPS */ +#endif /* IMPROVE_FOUR_SWAPS */ + +#if defined(CC_NO_UNDO_SEGMENTS_FLIPPER) || defined(CC_FULL_SEGMENTS_FLIPPER) + { + int fi; + CClinkern_flipper_reset_perm (0); /* For Quick Flips */ + for (fi = 0; fi < flip_counter; fi++) { + CClinkern_flipper_flip_perm (flipstack[fi].first, + flipstack[fi].last); + } + CClinkern_flipper_reset_perm (1); + } +#endif + flip_counter = 0; + t = best + delta; + + if (lin_kernighan (ncount, &t)) { + fprintf (stderr, "lin_kernighan failed\n"); +#ifdef GEOM_FOUR_SWAPS + if (((gdat->norm) & CC_NORM_BITS) == CC_KD_NORM_TYPE) + CCkdtree_free (&kdt); +#endif + return 1; + } + +#ifdef ACCEPT_BAD_TOURS + if (round % HEAT_RESET == HEAT_RESET - 1) { + heat = oldbest / (HEAT_MULT * ncount); + printf ("Reset Accept-Probablility\n"); + fflush (stdout); + } + tdelta = t - best; + heat *= HEAT_FACTOR; + if (t < best || (t > best && exp (-tdelta/heat) > + (double) (CCutil_lprand () % ncount) / (double) ncount)) { +#else +#ifdef ACCEPT_TIES + if (t <= best) { +#else + if (t < best) { +#endif /* ACCEPT_TIES */ +#endif /* ACCEPT_BAD_TOURS */ +#ifdef CC_USE_FLIP_CLEANING +#ifdef CC_FULL_SEGMENTS_FLIPPER + { + int i; + + if (flip_counter > 0) { + if (flip_counter < new_tour_cutoff) { + for (i = 0; i < flip_counter; i++) + CClinkern_flipper_flip_perm (flipstack[i].first, + flipstack[i].last); + CClinkern_flipper_reset_perm (1); + } else { + CClinkern_flipper_reset_temp (ncount); + } + flip_counter = 0; + } + } +#endif /* CC_FULL_SEGMENTS_FLIPPER */ + win_counter = 0; + win_cycle[0] = -1; +#else + CClinkern_flipper_cycle (cyc); + CClinkern_flipper_finish (); +#endif + if (t < best) { + best = t; + quitcount = round + stallcount; + if (quitcount > count) + quitcount = count; + hit++; + } +#ifdef ACCEPT_BAD_TOURS + else { + if (!no_output && t > best) { + printf ("%d Steps Best: %.0f %.2f seconds (Negative %.0f) (%.0f)\n", + round, t, CCutil_zeit () - szeit, t - best, oldbest); + fflush (stdout); + } + best = t; + } +#endif + } else { +#ifdef CC_USE_FLIP_CLEANING +#ifdef CC_FULL_SEGMENTS_FLIPPER + { + /* WON'T WORK WITH IMPROVE_FOUR_SWAPS */ + int i; + for (i = 2; i >= 0; i--) { + CClinkern_flipper_flip_perm (winstack[i].last, + winstack[i].first); + } + } + CClinkern_flipper_reset_perm (1); + win_cycle[0] = -1; + win_counter = 0; +#else + if (win_cycle[0] == -1) { + while (win_counter) { + win_counter--; +#ifdef CC_EXTRA_INFO_FLIP + CClinkern_flipper_flip (winstack[win_counter].firstprev, + winstack[win_counter].last, + winstack[win_counter].first, + winstack[win_counter].lastnext); +#else +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + CClinkern_flipper_flip_perm (winstack[win_counter].last, + winstack[win_counter].first); +#else + CClinkern_flipper_flip (winstack[win_counter].last, + winstack[win_counter].first); +#endif +#endif /* CC_EXTRA_INFO_FLIP */ + } + } else { + CClinkern_flipper_finish (); + CClinkern_flipper_init (ncount, win_cycle); + while (win_counter) { + win_counter--; +#ifdef CC_EXTRA_INFO_FLIP + CClinkern_flipper_flip (winstack[win_counter].firstprev, + winstack[win_counter].last, + winstack[win_counter].first, + winstack[win_counter].lastnext); +#else +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + CClinkern_flipper_flip_perm (winstack[win_counter].last, + winstack[win_counter].first); +#else + CClinkern_flipper_flip (winstack[win_counter].last, + winstack[win_counter].first); +#endif +#endif /* CC_EXTRA_INFO_FLIP */ + } + win_cycle[0] = -1; + } +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + CClinkern_flipper_reset_perm (1); +#endif +#endif /* CC_FULL_SEGMENTS_FLIPPER */ + +#else /* CC_USE_FLIP_CLEANING */ + CClinkern_flipper_finish (); +#endif + } + + round++; + if (!no_output && (hit || (round % 1000 == 999) || MAX_OUTPUT)) { + printf ("%d Steps Best: %.0f %.2f seconds\n", round, best, + CCutil_zeit () - szeit); + fflush (stdout); + } + +#ifdef BIG_PROBLEM + if (saveit_name && (round % 10000 == 9999) && best < oldbest) { +#else + if (saveit_name && (round % 100 == 99) && best < oldbest) { +#endif + int *ctemp = (int *) NULL; + + ctemp = CC_SAFE_MALLOC (ncount, int); + if (!ctemp) { +#ifdef GEOM_FOUR_SWAPS + if (((gdat->norm) & CC_NORM_BITS) == CC_KD_NORM_TYPE) + CCkdtree_free (&kdt); +#endif + return 1; + } + CClinkern_flipper_cycle (ctemp); +#ifdef BIG_PROBLEM + if (CCutil_writecycle (ncount, saveit_name, ctemp)) { +#else + if (CCutil_writecycle_edgelist (ncount, saveit_name, ctemp, gdat)) { +#endif + fprintf (stderr, "could not write the cycle\n"); + CC_FREE (ctemp, int); +#ifdef GEOM_FOUR_SWAPS + if (((gdat->norm) & CC_NORM_BITS) == CC_KD_NORM_TYPE) + CCkdtree_free (&kdt); +#endif + return 1; + } + printf ("Wrote the tour to %s\n", saveit_name); + fflush (stdout); + CC_FREE (ctemp, int); + oldbest = best; + } + + if (time_bound > 0.0 && (CCutil_zeit () - szeit) > time_bound) { + if (!no_output) { + printf ("STOP - timebound reached (%.2f seconds)\n", + CCutil_zeit () - szeit); + fflush (stdout); + } else { + printf ("%d Steps\n", round); + fflush (stdout); + } + break; + } + if (length_bound > 0.0 && best <= length_bound) { + if (!no_output) { + printf ("STOP - length bound reached (%.0f)\n", length_bound); + fflush (stdout); + } else { + printf ("%d Steps\n", round); + fflush (stdout); + } + break; + } + } + if (!no_output && round > 0) { + printf ("%d Total Steps.\n", round); + fflush (stdout); + } + +#ifdef CC_USE_FLIP_CLEANING + CClinkern_flipper_cycle (cyc); + CClinkern_flipper_finish (); +#endif + + if (saveit_name && best < oldbest) { +#ifdef BIG_PROBLEM + if (CCutil_writecycle (ncount, saveit_name, cyc)) { +#else + if (CCutil_writecycle_edgelist (ncount, saveit_name, cyc, gdat)) { +#endif + fprintf (stderr, "could not write the cycle\n"); +#ifdef GEOM_FOUR_SWAPS + if (((gdat->norm) & CC_NORM_BITS) == CC_KD_NORM_TYPE) + CCkdtree_free (&kdt); +#endif + return 1; + } + printf ("Wrote the last tour to %s\n", saveit_name); + fflush (stdout); + } + + t = cycle_length (ncount, cyc); + if (t != best) { + printf ("WARNING: LK incremental counter was off by %.0f\n", t - best); + fflush (stdout); + best = t; + } + + *val = best; + +#ifdef GEOM_FOUR_SWAPS + if (((gdat->norm) & CC_NORM_BITS) == CC_KD_NORM_TYPE) + CCkdtree_free (&kdt); +#endif + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int lin_kernighan (int ncount, double *val) +#else +static int lin_kernighan (ncount, val) +int ncount; +double *val; +#endif +{ + int start; + double win, totalwin = 0.0; + intptr *ip; + + if (ncount < 0) { + printf ("Bad ncount: %d\n", ncount); + return 1; + } + + while (active_queue) { + ip = active_queue; + start = ip->this; + active_queue = ip->next; + if (ip == bottom_active_queue) + bottom_active_queue = (intptr *) NULL; + intptrfree (ip); + active[start] = 0; + + win = improve_tour (start); + if (win > 0.0) { + totalwin += win; + if (flip_counter >= new_tour_time) { +#if defined(CC_NO_UNDO_SEGMENTS_FLIPPER) || defined(CC_FULL_SEGMENTS_FLIPPER) + { + int i; + + if (flip_counter < new_tour_cutoff) { + CClinkern_flipper_reset_perm (0); /* QUICK FLIPS */ + for (i = 0; i < flip_counter; i++) + CClinkern_flipper_flip_perm (flipstack[i].first, + flipstack[i].last); + CClinkern_flipper_reset_perm (1); + } else { +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + CClinkern_flipper_reset_perm (1); + for (i = 0; i < flip_counter; i++) + CClinkern_flipper_flip (flipstack[i].first, + flipstack[i].last); +#endif + CClinkern_flipper_reset_temp (ncount); + } + } +#endif +#ifdef CC_USE_FLIP_CLEANING + { + if (win_counter < winstack_max) { + int i; + for (i = 0; i < flip_counter; i++) { + winstack[win_counter].first = flipstack[i].first; + winstack[win_counter].last = flipstack[i].last; +#ifdef CC_EXTRA_INFO_FLIP + winstack[win_counter].firstprev = + flipstack[i].firstprev; + winstack[win_counter].lastnext = + flipstack[i].lastnext; +#endif + win_counter++; + } + } else if (win_cycle[0] == -1) { + int i; + for (i = 0; i < flip_counter; i++) { + winstack[win_counter].first = flipstack[i].first; + winstack[win_counter].last = flipstack[i].last; +#ifdef CC_EXTRA_INFO_FLIP + winstack[win_counter].firstprev = + flipstack[i].firstprev; + winstack[win_counter].lastnext = + flipstack[i].lastnext; +#endif + win_counter++; + } + CClinkern_flipper_cycle (win_cycle); + } + } +#endif +#ifdef CC_SEGMENTS_FLIPPER + CClinkern_flipper_reset_temp (ncount); +#endif + flip_counter = 0; + } + if (MAX_OUTPUT && !no_output) { + printf ("."); + fflush (stdout); + } + } +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + else { + CClinkern_flipper_reset_perm (0); + } +#endif + } + +#ifdef CC_USE_FLIP_CLEANING + { + if (win_cycle[0] == -1) { + int i; + for (i = 0; i < flip_counter; i++) { + winstack[win_counter].first = flipstack[i].first; + winstack[win_counter].last = flipstack[i].last; +#ifdef CC_EXTRA_INFO_FLIP + winstack[win_counter].firstprev = flipstack[i].firstprev; + winstack[win_counter].lastnext = flipstack[i].lastnext; +#endif + win_counter++; + } + } + } +#endif + + (*val) -= totalwin; + + if (MAX_OUTPUT && !no_output) { + printf ("\nCYCLE LENGTH: %.0f\n", *val); + fflush (stdout); + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static double improve_tour (int t1) +#else +static double improve_tour (t1) +int t1; +#endif +{ + int t2 = CClinkern_flipper_next (t1); + int G, Gstar = 0; + + G = Edgelen (t1, t2); + + markedge_del (t1, t2); + + + if (!step (0, G, &Gstar, t1, t2)) { +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + CClinkern_flipper_reset_perm (0); +#endif + Gstar = weird_second_step (G, t1, t2); + } + unmarkedge_del (t1, t2); + + if (Gstar) { + turn (t1); + turn (t2); + } + return (double) Gstar; +} + +#ifdef CC_PROTOTYPE_ANSI +static int step (int level, int G, int *Gstar, int first, int last) +#else +static int step (level, G, Gstar, first, last) +int level, G, *Gstar; +int first, last; +#endif +{ + int val, hit = 0, oldG = G; + int this, newlast; +#if defined(MAK_MORTON) && defined(FULL_MAK_MORTON) + int newfirst; +#endif + edgelook *list, *e; + + if (level >= BACKTRACK) + return step_noback (level, G, Gstar, first, last); + + list = look_ahead (first, last, G, level); + for (e = list; e; e = e->next) { +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + if (e != list) { + int i; + CClinkern_flipper_reset_perm (0); + for (i = 0; i < flip_counter; i++) + CClinkern_flipper_flip (flipstack[i].first, flipstack[i].last); + } +#endif +#if defined(MAK_MORTON) && defined(FULL_MAK_MORTON) + if (e->mm) { + this = e->other; + newfirst = e->over; + + G = oldG - e->diff; + val = G - Edgelen (newfirst, last); + if (val > *Gstar) { + *Gstar = val; + hit++; + } + FLIP (this, newfirst, first, last, 22220); + + if (level < MAXDEPTH) { + markedge_add (first, this); + markedge_del (this, newfirst); + hit += step (level + 1, G, Gstar, newfirst, last); + unmarkedge_add (first, this); + unmarkedge_del (this, newfirst); + } + + if (!hit) { + UNFLIP (this, newfirst, first, last, 9910); + } else { + turn (this); + turn (newfirst); + edgelook_list_free (list); + return 1; + } + } else +#endif + { + this = e->other; + newlast = e->over; + + G = oldG - e->diff; + val = G - Edgelen (newlast, first); + if (val > *Gstar) { + *Gstar = val; + hit++; + } + + FLIP (first, last, newlast, this, 2222); + + if (level < MAXDEPTH) { + markedge_add (last, this); + markedge_del (this, newlast); + hit += step (level + 1, G, Gstar, first, newlast); + unmarkedge_add (last, this); + unmarkedge_del (this, newlast); + } + + if (!hit) { + UNFLIP (first, last, newlast, this, 991); + } else { + turn (this); + turn (newlast); + edgelook_list_free (list); + return 1; + } + } + } + edgelook_list_free (list); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int step_noback (int level, int G, int *Gstar, int first, int last) +#else +static int step_noback (level, G, Gstar, first, last) +int level, G, *Gstar; +int first, last; +#endif +{ + edgelook e; + +#ifdef SUBTRACT_GSTAR +#ifdef SWITCH_LATE_DEPTH + if (level < LATE_DEPTH) + look_ahead_noback (first, last, G - *Gstar, &e); + else + look_ahead_noback (first, last, G - *Gstar - level, &e); +#else + look_ahead_noback (first, last, G - *Gstar - level, &e); +#endif /* SWITCH_LATE_DEPTH */ +#else +#ifdef SWITCH_LATE_DEPTH + if (level < LATE_DEPTH) + look_ahead_noback (first, last, G, &e); + else + look_ahead_noback (first, last, G - level, &e); +#else + look_ahead_noback (first, last, G - level, &e); +#endif /* SWITCH_LATE_DEPTH */ +#endif /* SUBTRACT_GSTAR */ + + if (e.diff < BIGINT) { +#ifdef NODE_INSERTIONS + if (e.ni) { + int hit = 0; + int newlast = e.other; + int next = e.under; + int prev = e.over; + int val; + + G -= e.diff; + val = G - Edgelen (newlast, first); + + if (val > *Gstar) { + *Gstar = val; + hit++; + } + + FLIP (first, last, newlast, next, 222211); + FLIP (newlast, prev, last, next, 222212); + + if (level < MAXDEPTH) { + markedge_add (last, newlast); + markedge_add (next, prev); + markedge_del (newlast, prev); + markedge_del (newlast, next); + hit += step_noback (level + 1, G, Gstar, first, newlast); + unmarkedge_add (last, newlast); + unmarkedge_add (next, prev); + unmarkedge_del (newlast, prev); + unmarkedge_del (newlast, next); + } + + if (!hit) { + UNFLIP (newlast, prev, last, next, 222214); + UNFLIP (first, last, newlast, next, 222213); + return 0; + } else { + turn (newlast); + turn (next); + turn (prev); + return 1; + } + } else +#endif /* NODE_INSERTIONS */ + { +#ifdef MAK_MORTON + if (e.mm) { + int hit = 0; + int this = e.other; + int newfirst = e.over; + int val; + + G -= e.diff; + val = G - Edgelen (newfirst, last); + if (val > *Gstar) { + *Gstar = val; + hit++; + } + FLIP (this, newfirst, first, last, 22220); + + if (level < MAXDEPTH) { + markedge_add (first, this); + markedge_del (this, newfirst); + hit += step_noback (level + 1, G, Gstar, newfirst, last); + unmarkedge_add (first, this); + unmarkedge_del (this, newfirst); + } + + if (!hit) { + UNFLIP (this, newfirst, first, last, 9910); + return 0; + } else { + turn (this); + turn (newfirst); + return 1; + } + } else +#endif /* MAK_MORTON */ + { + int hit = 0; + int this = e.other; + int newlast = e.over; + int val; + + G -= e.diff; + val = G - Edgelen (newlast, first); + if (val > *Gstar) { + *Gstar = val; + hit++; + } + + FLIP (first, last, newlast, this, 2222); + + if (level < MAXDEPTH) { + markedge_add (last, this); + markedge_del (this, newlast); + hit += step_noback (level + 1, G, Gstar, first, newlast); + unmarkedge_add (last, this); + unmarkedge_del (this, newlast); + } + + if (!hit) { + UNFLIP (first, last, newlast, this, 991); + return 0; + } else { + turn (this); + turn (newlast); + return 1; + } + } + } + } else { + return 0; + } +} + +#ifdef IMPROVE_FOUR_SWAPS +#ifdef CC_PROTOTYPE_ANSI +static double kick_improve (int ncount) +#else +static double kick_improve (ncount) +int ncount; +#endif +{ + int t1, t2; + int G, Gstar = 0; + int hit = 0; + + do { +#ifdef LONG_KICKER + first_long_kicker (ncount, &t1, &t2); +#else + t1 = CCutil_lprand () % ncount; + t2 = CClinkern_flipper_next (t1); +#endif + G = Edgelen (t1, t2); + markedge_del (t1, t2); + hit = kick_step_noback (0, G, &Gstar, t1, t2); + unmarkedge_del (t1, t2); + } while (!hit); + + kickturn (t1); + kickturn (t2); + + return (double) -Gstar; +} + +#define G_MULT 1.5 + +#ifdef CC_PROTOTYPE_ANSI +static int kick_step_noback (int level, int G, int *Gstar, int first, int last) +#else +static int kick_step_noback (level, G, Gstar, first, last) +int level, G, *Gstar; +int first, last; +#endif +{ + edgelook winner; + int val; + int this, prev, newlast; + int lastnext = CClinkern_flipper_next (last); + int i; + int cutoff = (int) (G_MULT * (double) G); + + /* NOTE: not set up for fixed edges */ + + winner.diff = BIGINT; + for (i = 0; goodlist[last][i].weight < cutoff; i++) { + this = goodlist[last][i].other; + if (!is_it_deleted (last, this) && this != first && this != lastnext) { + prev = CClinkern_flipper_prev (this); + if (!is_it_added (this, prev)) { + val = goodlist[last][i].weight - Edgelen (this, prev); + if (val < winner.diff) { + winner.diff = val; + winner.other = this; + winner.over = prev; + } + } + } + } + + if (winner.diff < BIGINT) { + this = winner.other; + newlast = winner.over; + G -= winner.diff; + *Gstar = G - Edgelen (newlast, first); + + FLIP (first, last, newlast, this, 2222); + kickturn (this); + kickturn (newlast); +#ifdef CC_USE_FLIP_CLEANING + if (win_counter < winstack_max) { + winstack[win_counter].first = last; + winstack[win_counter].last = newlast; +#ifdef CC_EXTRA_INFO_FLIP + winstack[win_counter].firstprev = first; + winstack[win_counter].lastnext = this; +#endif + win_counter++; + } +#endif + + if (level < KICK_MAXDEPTH) { + markedge_add (last, this); + markedge_del (this, newlast); + kick_step_noback (level + 1, G, Gstar, first, newlast); + unmarkedge_add (last, this); + unmarkedge_del (this, newlast); + } + return 1; + } else { + return 0; + } +} +#endif /* IMPROVE_FOUR_SWAPS */ + +#ifdef CC_PROTOTYPE_ANSI +static int weird_second_step (int len_t1_t2, int t1, int t2) +#else +static int weird_second_step (len_t1_t2, t1, t2) +int len_t1_t2, t1, t2; +#endif +{ + int t3, t4, t5, t6, t7, t8; + int oldG, G, tG, Gstar = 0, val, hit; + int t4next; + edgelook *e, *f, *h, *list, *list2, *list3; + + list = weird_look_ahead (len_t1_t2, t1, t2); + for (h = list; h; h = h->next) { +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + if (h != list) { + int i; + CClinkern_flipper_reset_perm (0); + for (i = 0; i < flip_counter; i++) + CClinkern_flipper_flip (flipstack[i].first, flipstack[i].last); + } +#endif + t3 = h->other; + t4 = h->over; + + oldG = len_t1_t2 - h->diff; + t4next = CClinkern_flipper_next (t4); + + markedge_add (t2, t3); + markedge_del (t3, t4); + weirdmagic++; + weirdmark[t1] = weirdmagic; + weirdmark[t2] = weirdmagic; + weirdmark[t3] = weirdmagic; + weirdmark[t4next] = weirdmagic; + + list2 = weird_look_ahead2 (oldG, t2, t3, t4); + for (e = list2; e; e = e->next) { +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + if (e != list2) { + int i; + CClinkern_flipper_reset_perm (0); + for (i = 0; i < flip_counter; i++) + CClinkern_flipper_flip (flipstack[i].first, flipstack[i].last); + } +#endif + t5 = e->other; + t6 = e->over; + + markedge_add (t4, t5); + if (e->seq) { + if (!e->side) { + G = oldG - e->diff; + val = G - Edgelen (t6, t1); + if (val > Gstar) + Gstar = val; + FLIP (t1, t2, t6, t5, 3); + FLIP (t2, t5, t3, t4, 4); + + markedge_del (t5, t6); + hit = step (2, G, &Gstar, t1, t6); + unmarkedge_del (t5, t6); + + if (!hit && Gstar) + hit = 1; + + if (!hit) { + UNFLIP (t2, t5, t3, t4, 992); + UNFLIP (t1, t2, t6, t5, 993); + } else { + unmarkedge_add (t2, t3); + unmarkedge_del (t3, t4); + unmarkedge_add (t4, t5); + turn (t3); turn (t4); + turn (t5); turn (t6); + edgelook_list_free (list); + edgelook_list_free (list2); + return Gstar; + } + } else { + G = oldG - e->diff; + val = G - Edgelen (t6, t1); + if (val > Gstar) + Gstar = val; + FLIP (t1, t2, t3, t4, 5000); + FLIP (t6, t5, t2, t4, 6); + FLIP (t1, t3, t6, t2, 7); + + markedge_del (t5, t6); + hit = step (2, G, &Gstar, t1, t6); + unmarkedge_del (t5, t6); + + if (!hit && Gstar) + hit = 1; + + if (!hit) { + UNFLIP (t1, t3, t6, t2, 994); + UNFLIP (t6, t5, t2, t4, 995); + UNFLIP (t1, t2, t3, t4, 996); + } else { + unmarkedge_add (t2, t3); + unmarkedge_del (t3, t4); + unmarkedge_add (t4, t5); + turn (t3); turn (t4); + turn (t5); turn (t6); + edgelook_list_free (list); + edgelook_list_free (list2); + return Gstar; + } + } + } else { + tG = oldG - e->diff; + markedge_del (t5, t6); + list3 = weird_look_ahead3 (tG, t2, t3, t6); + for (f = list3; f; f = f->next) { +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER + if (f != list3) { + int i; + CClinkern_flipper_reset_perm (0); + for (i = 0; i < flip_counter; i++) + CClinkern_flipper_flip (flipstack[i].first, + flipstack[i].last); + } +#endif + t7 = f->other; + t8 = f->over; + + G = tG - f->diff; + if (!f->side) { + val = G - Edgelen (t8, t1); + if (val > Gstar) + Gstar = val; + FLIP (t1, t2, t8, t7, 8); + FLIP (t2, t7, t3, t4, 9); + FLIP (t7, t4, t6, t5, 10); + + markedge_add (t6, t7); + markedge_del (t7, t8); + hit = step (3, G, &Gstar, t1, t8); + unmarkedge_del (t6, t7); + unmarkedge_del (t7, t8); + + if (!hit && Gstar) + hit = 1; + + if (!hit) { + UNFLIP (t7, t4, t6, t5, 997); + UNFLIP (t2, t7, t3, t4, 998); + UNFLIP (t1, t2, t8, t7, 999); + } else { + unmarkedge_add (t2, t3); + unmarkedge_del (t3, t4); + unmarkedge_add (t4, t5); + unmarkedge_del (t5, t6); + turn (t3); turn (t4); turn (t5); + turn (t6); turn (t7); turn (t8); + edgelook_list_free (list); + edgelook_list_free (list2); + edgelook_list_free (list3); + return Gstar; + } + } else { + val = G - Edgelen (t8, t1); + if (val > Gstar) + Gstar = val; + FLIP (t1, t2, t6, t5, 11); + FLIP (t1, t6, t8, t7, 12); + FLIP (t3, t4, t2, t5, 13); + + markedge_add (t6, t7); + markedge_del (t7, t8); + hit = step (3, G, &Gstar, t1, t8); + unmarkedge_add (t6, t7); + unmarkedge_del (t7, t8); + + if (!hit && Gstar) + hit = 1; + + if (!hit) { + UNFLIP (t3, t4, t2, t5, 9910); + UNFLIP (t1, t6, t8, t7, 9911); + UNFLIP (t1, t2, t6, t5, 9912); + } else { + unmarkedge_add (t2, t3); + unmarkedge_del (t3, t4); + unmarkedge_add (t4, t5); + unmarkedge_del (t5, t6); + turn (t3); turn (t4); turn (t5); + turn (t6); turn (t7); turn (t8); + edgelook_list_free (list); + edgelook_list_free (list2); + edgelook_list_free (list3); + return Gstar; + } + } + } + edgelook_list_free (list3); + unmarkedge_del (t5, t6); + } + unmarkedge_add (t4, t5); + } + edgelook_list_free (list2); + unmarkedge_add (t2, t3); + unmarkedge_del (t3, t4); + } + edgelook_list_free (list); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static edgelook *look_ahead (int first, int last, int G, int level) +#else +static edgelook *look_ahead (first, last, G, level) +int first, last; +int G, level; +#endif +{ + edgelook *list = (edgelook *) NULL, *el; + int i, val; + int this, prev; + int lastnext = CClinkern_flipper_next (last); + int other[MAX_BACK], save[MAX_BACK]; + int value[MAX_BACK + 1]; +#if defined(MAK_MORTON) && defined(FULL_MAK_MORTON) + int mm[MAX_BACK]; +#endif + int k, ahead = backtrack_count[level]; + + for (i = 0; i < ahead; i++) { + value[i] = BIGINT; +#if defined(MAK_MORTON) && defined(FULL_MAK_MORTON) + mm[i] = 0; +#endif + } + value[ahead] = -BIGINT; + +#ifdef USE_LESS_OR_EQUAL + for (i = 0; goodlist[last][i].weight <= G; i++) { +#else + for (i = 0; goodlist[last][i].weight < G; i++) { +#endif + this = goodlist[last][i].other; + if (!is_it_deleted (last, this) && this != first && this != lastnext) { + prev = CClinkern_flipper_prev (this); + if (!is_it_added (this, prev)) { + val = goodlist[last][i].weight - Edgelen (this, prev); + if (val < value[0]) { + for (k = 0; value[k+1] > val; k++) { + value[k] = value[k+1]; + other[k] = other[k+1]; + save[k] = save[k+1]; + } + value[k] = val; + other[k] = this; + save[k] = prev; + } + } + } + } + +#if defined(MAK_MORTON) && defined(FULL_MAK_MORTON) + { + int firstprev = CClinkern_flipper_prev (first); + int next; + +#ifdef USE_LESS_OR_EQUAL + for (i = 0; goodlist[first][i].weight <= G; i++) { +#else + for (i = 0; goodlist[first][i].weight < G; i++) { +#endif + this = goodlist[first][i].other; + if (!is_it_deleted (first, this) && this != last && + this != firstprev) { + next = CClinkern_flipper_next (this); + if (!is_it_added (this, next)) { + val = goodlist[first][i].weight - Edgelen (this, next); + if (val < value[0]) { + for (k = 0; value[k+1] > val; k++) { + value[k] = value[k+1]; + other[k] = other[k+1]; + save[k] = save[k+1]; + mm[k] = mm[k+1]; + } + value[k] = val; + other[k] = this; + save[k] = next; + mm[k] = 1; + } + } + } + } + } +#endif + + for (i = 0; i < ahead; i++) { + if (value[i] < BIGINT) { + el = edgelookalloc (); + el->diff = value[i]; + el->other = other[i]; + el->over = save[i]; + el->next = list; +#if defined(MAK_MORTON) && defined(FULL_MAK_MORTON) + el->mm = mm[i]; +#endif + list = el; + } + } + + return list; +} + +#ifdef CC_PROTOTYPE_ANSI +static void look_ahead_noback (int first, int last, int G, edgelook *winner) +#else +static void look_ahead_noback (first, last, G, winner) +int first, last; +int G; +edgelook *winner; +#endif +{ + int val; + int this, prev; + int lastnext = CClinkern_flipper_next (last); + int i; +#if defined(MAK_MORTON) || defined(NODE_INSERTIONS) + int next; +#endif + + winner->diff = BIGINT; + for (i = 0; goodlist[last][i].weight < G; i++) { + this = goodlist[last][i].other; + if (!is_it_deleted (last, this) && this != first && this != lastnext) { + prev = CClinkern_flipper_prev (this); + if (!is_it_added (this, prev)) { + val = goodlist[last][i].weight - Edgelen (this, prev); + if (val < winner->diff) { + winner->diff = val; + winner->other = this; + winner->over = prev; +#ifdef MAK_MORTON + winner->mm = 0; +#endif +#ifdef NODE_INSERTIONS + winner->ni = 0; +#endif + } +#ifdef NODE_INSERTIONS + next = CClinkern_flipper_next (this); + if (!is_it_added (this, next) && !is_it_deleted (prev, next)) { + val += (Edgelen (next, prev) - Edgelen (this, next)); + if (val < winner->diff) { + winner->diff = val; + winner->other = this; + winner->over = prev; + winner->under = next; + winner->ni = 1; + } + } +#endif + } + } + } +#ifdef MAK_MORTON + { + int firstprev = CClinkern_flipper_prev (first); + + for (i = 0; goodlist[first][i].weight < G; i++) { + this = goodlist[first][i].other; + if (!is_it_deleted (first, this) && this != last && + this != firstprev) { + next = CClinkern_flipper_next (this); + if (!is_it_added (this, next)) { + val = goodlist[first][i].weight - Edgelen (this, next); + if (val < winner->diff) { + winner->diff = val; + winner->other = this; + winner->over = next; + winner->mm = 1; +#ifdef NODE_INSERTIONS + winner->ni = 0; +#endif + } + } + } + } + } +#endif +} + +#ifdef CC_PROTOTYPE_ANSI +static edgelook *weird_look_ahead (int G, int t1, int t2) +#else +static edgelook *weird_look_ahead (G, t1, t2) +int G, t1, t2; +#endif +{ + edgelook *list, *el; + int i, this, next; + int other[MAX_BACK], save[MAX_BACK]; + int value[MAX_BACK + 1]; + int k, val, ahead; + + + list = (edgelook *) NULL; + ahead = weird_backtrack_count[0]; + for (i = 0; i < ahead; i++) + value[i] = BIGINT; + value[ahead] = -BIGINT; + +#ifdef USE_LESS_OR_EQUAL + for (i = 0; goodlist[t2][i].weight <= G; i++) { +#else + for (i = 0; goodlist[t2][i].weight < G; i++) { +#endif + this = goodlist[t2][i].other; + if (this != t1) { + next = CClinkern_flipper_next (this); + val = goodlist[t2][i].weight - Edgelen (this, next); + if (val < value[0]) { + for (k = 0; value[k+1] > val; k++) { + value[k] = value[k+1]; + other[k] = other[k+1]; + save[k] = save[k+1]; + } + value[k] = val; + other[k] = this; + save[k] = next; + } + } + } + for (i = 0; i < ahead; i++) { + if (value[i] < BIGINT) { + el = edgelookalloc (); + el->diff = value[i]; + el->other = other[i]; + el->over = save[i]; + el->next = list; + list = el; + } + } + return list; +} + +#ifdef CC_PROTOTYPE_ANSI +static edgelook *weird_look_ahead2 (int G, int t2, int t3, int t4) +#else +static edgelook *weird_look_ahead2 (G, t2, t3, t4) +int G, t2, t3, t4; +#endif +{ + edgelook *list = (edgelook *) NULL; + edgelook *el; + int i, t5, t6; + int other[MAX_BACK], save[MAX_BACK], seq[MAX_BACK], side[MAX_BACK]; + int value[MAX_BACK + 1]; + int k, val; + int ahead = weird_backtrack_count[1]; + + for (i = 0; i < ahead; i++) + value[i] = BIGINT; + value[ahead] = -BIGINT; + +#ifdef USE_SEQUENCE_BURST + CClinkern_flipper_sequence_burst_init (t2, t3); +#endif + +#ifdef USE_LESS_OR_EQUAL + for (i = 0; goodlist[t4][i].weight <= G; i++) { +#else + for (i = 0; goodlist[t4][i].weight < G; i++) { +#endif + t5 = goodlist[t4][i].other; + if (weirdmark[t5] != weirdmagic) { +#ifdef USE_SEQUENCE_BURST + if (CClinkern_flipper_sequence_burst (t2, t5, t3)) { +#else + if (CClinkern_flipper_sequence (t2, t5, t3)) { +#endif + t6 = CClinkern_flipper_prev (t5); + val = goodlist[t4][i].weight - Edgelen (t5, t6); + if (val < value[0]) { + for (k = 0; value[k+1] > val; k++) { + value[k] = value[k+1]; + other[k] = other[k+1]; + save[k] = save[k+1]; + seq[k] = seq[k+1]; + side[k] = side[k+1]; + } + value[k] = val; + other[k] = t5; + save[k] = t6; + seq[k] = 1; + side[k] = 0; + } + t6 = CClinkern_flipper_next (t5); + val = goodlist[t4][i].weight - Edgelen (t5, t6); + if (val < value[0]) { + for (k = 0; value[k+1] > val; k++) { + value[k] = value[k+1]; + other[k] = other[k+1]; + save[k] = save[k+1]; + seq[k] = seq[k+1]; + side[k] = side[k+1]; + } + value[k] = val; + other[k] = t5; + save[k] = t6; + seq[k] = 1; + side[k] = 1; + } + } else { + t6 = CClinkern_flipper_prev (t5); + val = goodlist[t4][i].weight - Edgelen (t5, t6); + if (val < value[0]) { + for (k = 0; value[k+1] > val; k++) { + value[k] = value[k+1]; + other[k] = other[k+1]; + save[k] = save[k+1]; + seq[k] = seq[k+1]; + side[k] = side[k+1]; + } + value[k] = val; + other[k] = t5; + save[k] = t6; + seq[k] = 0; + side[k] = 0; + } + } + } + } + + for (i = 0; i < ahead; i++) { + if (value[i] < BIGINT) { + el = edgelookalloc (); + el->diff = value[i]; + el->other = other[i]; + el->over = save[i]; + el->seq = seq[i]; + el->side = side[i]; + el->next = list; + list = el; + } + } + return list; +} + +#ifdef CC_PROTOTYPE_ANSI +static edgelook *weird_look_ahead3 (int G, int t2, int t3, int t6) +#else +static edgelook *weird_look_ahead3 (G, t2, t3, t6) +int G, t2, t3, t6; +#endif +{ + edgelook *list = (edgelook *) NULL; + edgelook *el; + int i, t7, t8; + int other[MAX_BACK], save[MAX_BACK], side[MAX_BACK]; + int value[MAX_BACK + 1]; + int k, val; + int ahead = weird_backtrack_count[2]; + + for (i = 0; i < ahead; i++) + value[i] = BIGINT; + value[ahead] = -BIGINT; + +#ifdef USE_SEQUENCE_BURST + CClinkern_flipper_sequence_burst_init (t2, t3); +#endif + +#ifdef USE_LESS_OR_EQUAL + for (i = 0; goodlist[t6][i].weight <= G; i++) { +#else + for (i = 0; goodlist[t6][i].weight < G; i++) { +#endif + t7 = goodlist[t6][i].other; /* Need t7 != t2, t3, t2next, t3prev */ + if (weirdmark[t7] != weirdmagic && +#ifdef USE_SEQUENCE_BURST + CClinkern_flipper_sequence_burst (t2, t7, t3)) { +#else + CClinkern_flipper_sequence (t2, t7, t3)) { +#endif + t8 = CClinkern_flipper_prev (t7); + val = goodlist[t6][i].weight - Edgelen (t7, t8); + if (val < value[0]) { + for (k = 0; value[k+1] > val; k++) { + value[k] = value[k+1]; + other[k] = other[k+1]; + save[k] = save[k+1]; + side[k] = side[k+1]; + } + value[k] = val; + other[k] = t7; + save[k] = t8; + side[k] = 0; + } + t8 = CClinkern_flipper_next (t7); + val = goodlist[t6][i].weight - Edgelen (t7, t8); + if (val < value[0]) { + for (k = 0; value[k+1] > val; k++) { + value[k] = value[k+1]; + other[k] = other[k+1]; + save[k] = save[k+1]; + side[k] = side[k+1]; + } + value[k] = val; + other[k] = t7; + save[k] = t8; + side[k] = 1; + } + } + } + + for (i = 0; i < ahead; i++) { + if (value[i] < BIGINT) { + el = edgelookalloc (); + el->diff = value[i]; + el->other = other[i]; + el->over = save[i]; + el->side = side[i]; + el->next = list; + list = el; + } + } + return list; +} + + + +/********************* misc ********************/ + + +#ifdef CC_PROTOTYPE_ANSI +static double cycle_length (int ncount, int *cyc) +#else +static double cycle_length (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i; + double val = 0; + + for (i = 1; i < ncount; i++) + val += (double) Edgelen (cyc[i - 1], cyc[i]); + val += (double) Edgelen (cyc[0], cyc[ncount - 1]); + + return val; +} + +#ifdef GEOM_FOUR_SWAPS +#ifdef CC_PROTOTYPE_ANSI +static int random_four_swap (int ncount, CCkdtree *kdt, int *delta) +#else +static int random_four_swap (ncount, kdt, delta) +int ncount; +CCkdtree *kdt; +int *delta; +#endif +#else +#ifdef CC_PROTOTYPE_ANSI +static int random_four_swap (int ncount) +#else +static int random_four_swap (ncount) +int ncount; +#endif +#endif +{ + int t1, t2, t3, t4, t5, t6, t7, t8, temp; + +#ifdef GEOM_FOUR_SWAPS + if (((gdat->norm) & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + if (find_geometric_four (ncount, kdt, &t1, &t2, &t3, &t4, + &t5, &t6, &t7, &t8)) { + fprintf (stderr, "find_geometric_four failed\n"); + return 1; + } + } else { + find_close_four (ncount, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8); + } +#else +#ifdef CLOSE_FOUR_SWAPS + find_close_four (ncount, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8); +#else + +#ifdef LONG_KICKER + first_long_kicker (ncount, &t1, &t2); +#else + t1 = CCutil_lprand () % ncount; + t2 = CClinkern_flipper_next (t1); +#endif + + do { + t3 = CCutil_lprand () % ncount; + t4 = CClinkern_flipper_next (t3); + } while (t3 == t1 || t3 == t2 || t4 == t1); + + do { + t5 = CCutil_lprand () % ncount; + t6 = CClinkern_flipper_next (t5); + } while (t5 == t1 || t5 == t2 || t5 == t3 || t5 == t4 || + t6 == t1 || t6 == t3); + + do { + t7 = CCutil_lprand () % ncount; + t8 = CClinkern_flipper_next (t7); + } while (t7 == t1 || t7 == t2 || + t7 == t3 || t7 == t4 || t7 == t5 || t7 == t6 || t8 == t1 || + t8 == t3 || t8 == t5 ); +#endif /* CLOSE_FOUR_SWAPS */ +#endif /* GEOM_FOUR_SWAPS */ + + if (!CClinkern_flipper_sequence (t1, t3, t5)) { + SWAP (t3, t5, temp); + SWAP (t4, t6, temp); + } + if (!CClinkern_flipper_sequence (t1, t5, t7)) { + SWAP (t5, t7, temp); + SWAP (t6, t8, temp); + if (!CClinkern_flipper_sequence (t1, t3, t5)) { + SWAP (t3, t5, temp); + SWAP (t4, t6, temp); + } + } + FLIP (t1, t2, t5, t6, 20); + FLIP (t4, t3, t7, t8, 21); + FLIP (t1, t5, t6, t2, 22); + +#ifdef CC_USE_FLIP_CLEANING + if (win_counter < winstack_max) { + winstack[win_counter].first = t2; + winstack[win_counter].last = t5; +#ifdef CC_EXTRA_INFO_FLIP + winstack[win_counter].firstprev = t1; + winstack[win_counter].lastnext = t6; +#endif + win_counter++; + } + if (win_counter < winstack_max) { + winstack[win_counter].first = t3; + winstack[win_counter].last = t7; +#ifdef CC_EXTRA_INFO_FLIP + winstack[win_counter].firstprev = t4; + winstack[win_counter].lastnext = t8; +#endif + win_counter++; + } + if (win_counter < winstack_max) { + winstack[win_counter].first = t5; + winstack[win_counter].last = t6; +#ifdef CC_EXTRA_INFO_FLIP + winstack[win_counter].firstprev = t1; + winstack[win_counter].lastnext = t2; +#endif + win_counter++; + } +#endif /* CC_USE_FLIP_CLEANING */ + + bigturn (t1, 0); + bigturn (t2, 1); + bigturn (t3, 0); + bigturn (t4, 1); + bigturn (t5, 0); + bigturn (t6, 1); + bigturn (t7, 0); + bigturn (t8, 1); + +#ifdef GEOM_FOUR_SWAPS + *delta = + Edgelen (t1, t6) + Edgelen (t2, t5) + + Edgelen (t3, t8) + Edgelen (t4, t7) - + Edgelen (t1, t2) - Edgelen (t3, t4) - + Edgelen (t5, t6) - Edgelen (t7, t8); + return 0; + +#else + return Edgelen (t1, t6) + Edgelen (t2, t5) + + Edgelen (t3, t8) + Edgelen (t4, t7) - + Edgelen (t1, t2) - Edgelen (t3, t4) - + Edgelen (t5, t6) - Edgelen (t7, t8); +#endif +} + +#ifdef LONG_KICKER +#define HUNT_PORTION_LONG 0.001 + +#ifdef CC_PROTOTYPE_ANSI +static void first_long_kicker (int ncount, int *t1, int *t2) +#else +static void first_long_kicker (ncount, t1, t2) +int ncount; +int *t1, *t2; +#endif +{ + int longcount = (int) ((double) ncount * HUNT_PORTION_LONG) + 10; + int i, best, try, len, next, prev, nextl, prevl; + + try = CCutil_lprand () % ncount; + next = CClinkern_flipper_next (try); + prev = CClinkern_flipper_prev (try); + nextl = Edgelen (try, next); + prevl = Edgelen (try, prev); + if (nextl >= prevl) { + *t1 = try; + *t2 = next; + best = nextl - goodlist[*t1][0].weight; + } else { + *t1 = prev; + *t2 = try; + best = prevl - goodlist[*t1][0].weight; + } + + for (i = 0; i < longcount; i++) { + try = CCutil_lprand () % ncount; + next = CClinkern_flipper_next (try); + prev = CClinkern_flipper_prev (try); + nextl = Edgelen (try, next); + prevl = Edgelen (try, prev); + if (nextl >= prevl) { + len = nextl - goodlist[try][0].weight; + if (len > best) { + *t1 = try; + *t2 = next; + } + } else { + len = prevl - goodlist[try][0].weight; + if (len > best) { + *t1 = prev; + *t2 = try; + } + } + } +} +#endif /* LONG_KICKER */ + +#if defined(CLOSE_FOUR_SWAPS) || defined(GEOM_FOUR_SWAPS) +#ifdef BIG_PROBLEM +#define HUNT_PORTION 0.001 +#define HUNT_PORTION_LONG 0.001 +#else +#define HUNT_PORTION 0.03 +#define HUNT_PORTION_LONG 0.001 +#endif +#endif + +#if defined(CLOSE_FOUR_SWAPS) || defined(GEOM_FOUR_SWAPS) +#define RAND_TRYS 6 /* To find the 3 other edges */ + +#ifdef CC_PROTOTYPE_ANSI +static void find_close_four (int ncount, + int *t1, int *t2, int *t3, int *t4, + int *t5, int *t6, int *t7, int *t8) +#else +static void find_close_four (ncount, t1, t2, t3, t4, t5, t6, t7, t8) +int ncount; +int *t1, *t2, *t3, *t4, *t5, *t6, *t7, *t8; +#endif +{ + int s1, s2, s3, s4, s5, s6, s7, s8; + int i, try; + int count = (int) ((double) ncount * HUNT_PORTION) + 1 + RAND_TRYS; + + /* Not set up for fixed edges */ + +#ifdef LONG_KICKER + first_long_kicker (ncount, &s1, &s2); +#else + s1 = CCutil_lprand () % ncount; + s2 = CClinkern_flipper_next (s1); +#endif + + { + int trials[RAND_TRYS + 1]; + int tdist[RAND_TRYS + 1]; + int trydist; + int k; + + tdist[RAND_TRYS] = -BIGINT; + +TRY_AGAIN: + + for (k = 0; k < RAND_TRYS; k++) + tdist[k] = BIGINT; + for (i = 0; i < count; i++) { + try = CCutil_lprand () % ncount; + trydist = Edgelen (try, s1); + if (trydist < tdist[0]) { + for (k = 0; tdist[k + 1] > trydist; k++) { + tdist[k] = tdist[k + 1]; + trials[k] = trials[k + 1]; + } + tdist[k] = trydist; + trials[k] = try; + } + } + + k = 0; + do { + if (k == RAND_TRYS) + goto TRY_AGAIN; + s3 = trials[k++]; + s4 = CClinkern_flipper_next (s3); + } while (s3 == s1 || s3 == s2 || s4 == s1); + + do { + if (k == RAND_TRYS) + goto TRY_AGAIN; + s5 = trials[k++]; + s6 = CClinkern_flipper_next (s5); + } while (s5 == s1 || s5 == s2 || s5 == s3 || + s5 == s4 || s6 == s1 || s6 == s3); + + do { + if (k == RAND_TRYS) + goto TRY_AGAIN; + s7 = trials[k++]; + s8 = CClinkern_flipper_next (s7); + } while (s7 == s1 || s7 == s2 || s7 == s3 || s7 == s4 || + s7 == s5 || s7 == s6 || s8 == s1 || s8 == s3 || + s8 == s5); + } + + *t1 = s1; *t2 = s2; *t3 = s3; *t4 = s4; + *t5 = s5; *t6 = s6; *t7 = s7; *t8 = s8; +} +#endif /* CLOSE_FOUR_SWAPS */ + + +#ifdef GEOM_FOUR_SWAPS +#define GEO_FACTOR 50 +#define GEO_MAX 250 + +#ifdef CC_PROTOTYPE_ANSI +static int find_geometric_four (int ncount, CCkdtree *kdt, + int *t1, int *t2, int *t3, int *t4, + int *t5, int *t6, int *t7, int *t8) +#else +static int find_geometric_four (ncount, kdt, t1, t2, t3, t4, t5, t6, t7, t8) +int ncount; +CCkdtree *kdt; +int *t1, *t2, *t3, *t4, *t5, *t6, *t7, *t8; +#endif +{ + int neigh[GEO_MAX]; + int temp, i, k, s1, s2, s3, s4, s5, s6, s7, s8; + int trys; + +#ifdef LONG_KICKER + first_long_kicker (ncount, &s1, &s2); +#else + s1 = CCutil_lprand () % ncount; + s2 = CClinkern_flipper_next (s1); +#endif + + trys = ((ncount / 50) + 25 > GEO_MAX ? GEO_MAX : (ncount / 50) + 25); + if (trys > ncount-1) trys = ncount-1; + if (CCkdtree_node_k_nearest (kdt, ncount, s1, trys, gdat, (double *) NULL, + neigh)) { + fprintf (stderr, "CCkdtree_node_k_nearest failed\n"); + return 1; + } + + for (i = trys; i > trys - 9; i--) { + k = CCutil_lprand () % i; + SWAP (neigh[i - 1], neigh[k], temp); + } + + k = trys - 1; + do { + s3 = neigh[k--]; + s4 = CClinkern_flipper_next (s3); + } while (s3 == s2 || s4 == s1); + + do { + s5 = neigh[k--]; + s6 = CClinkern_flipper_next (s5); + } while (s5 == s2 || s5 == s4 || s6 == s1 || s6 == s3); + + do { + s7 = neigh[k--]; + s8 = CClinkern_flipper_next (s7); + } while (s7 == s2 || s7 == s4 || s7 == s6 || s8 == s1 || s8 == s3 || + s8 == s5); + + + *t1 = s1; *t2 = s2; *t3 = s3; *t4 = s4; + *t5 = s5; *t6 = s6; *t7 = s7; *t8 = s8; + + return 0; +} +#endif + +#ifdef CC_PROTOTYPE_ANSI +static void turn (int n) +#else +static void turn (n) +int n; +#endif +{ + intptr *ip; + + /* intptralloc will not fail - the initial supply is large enough */ + + ADD_TO_ACTIVE_QUEUE (n, ip); + +#ifdef MARK_NEIGHBORS + { + int i = 0; + for (i = 0; i < degree[n]; i++) { + if (lprand () % 2) { + ADD_TO_ACTIVE_QUEUE (goodlist[n][i].other, ip); + } + } + } +#else +#ifndef USE_LESS_MARKING + { + int k; + k = CClinkern_flipper_next (n); + ADD_TO_ACTIVE_QUEUE (k, ip); + k = CClinkern_flipper_next (k); + ADD_TO_ACTIVE_QUEUE (k, ip); + k = CClinkern_flipper_prev (n); + ADD_TO_ACTIVE_QUEUE (k, ip); + k = CClinkern_flipper_prev (k); + ADD_TO_ACTIVE_QUEUE (k, ip); + } +#endif +#endif +} + +#ifdef IMPROVE_FOUR_SWAPS +#ifdef CC_PROTOTYPE_ANSI +static void kickturn (int n) +#else +static void kickturn (n) +int n; +#endif +{ + intptr *ip; + + ADD_TO_ACTIVE_QUEUE (n, ip); + { + int k; + k = CClinkern_flipper_next (n); + ADD_TO_ACTIVE_QUEUE (k, ip); + k = CClinkern_flipper_next (k); + ADD_TO_ACTIVE_QUEUE (k, ip); + k = CClinkern_flipper_prev (n); + ADD_TO_ACTIVE_QUEUE (k, ip); + k = CClinkern_flipper_prev (k); + ADD_TO_ACTIVE_QUEUE (k, ip); + } +} +#endif + +#ifdef CC_PROTOTYPE_ANSI +static void bigturn (int n, int tonext) +#else +static void bigturn (n, tonext) +int n, tonext; +#endif +{ + intptr *ip; + int i, k; + + /* intptralloc will not fail - the initial supply is large enough */ + + ADD_TO_ACTIVE_QUEUE (n, ip); + + if (tonext) { + for (i = 0, k = n; i < MARK_LEVEL; i++) { + k = CClinkern_flipper_next (k); + ADD_TO_ACTIVE_QUEUE (k, ip); + } + } else { + for (i = 0, k = n; i < MARK_LEVEL; i++) { + k = CClinkern_flipper_prev (k); + ADD_TO_ACTIVE_QUEUE (k, ip); + } + } + + for (i = 0; i < degree[n]; i++) { + ADD_TO_ACTIVE_QUEUE (goodlist[n][i].other, ip); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void randcycle (int ncount, int *cyc) +#else +static void randcycle (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, k, temp; + + for (i = 0; i < ncount; i++) + cyc[i] = i; + + for (i = ncount; i > 1; i--) { + k = CCutil_lprand () % i; + SWAP (cyc[i - 1], cyc[k], temp); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int buildgraph (int ncount, int ecount, int *elist) +#else +static int buildgraph (ncount, ecount, elist) +int ncount, ecount, *elist; +#endif +{ + int n1, n2, w, i; + edge *p; + + goodlist = CC_SAFE_MALLOC (ncount, edge *); + if (!goodlist) + return 1; + degree = CC_SAFE_MALLOC (ncount, int); + if (!degree) { + CC_FREE (goodlist, edge *); + return 1; + } +#if defined(HALF_LOOKS) || defined(LATE_HALF_LOOKS) + edgespace = CC_SAFE_MALLOC ((2 * ecount) + (2 * ncount), edge); +#else + edgespace = CC_SAFE_MALLOC ((2 * ecount) + ncount, edge); +#endif + if (!edgespace) { + CC_FREE (goodlist, edge *); + CC_FREE (degree, int); + return 1; + } + + for (i = 0; i < ncount; i++) { +#if defined(HALF_LOOKS) || defined(LATE_HALF_LOOKS) + degree[i] = 2; +#else + degree[i] = 1; +#endif + } + for (i = ecount - 1; i >= 0; i--) { + degree[elist[2 * i]]++; + degree[elist[(2 * i) + 1]]++; + } + + for (i = 0, p = edgespace; i < ncount; i++) { + goodlist[i] = p; + p += (degree[i]); +#if defined(HALF_LOOKS) || defined(LATE_HALF_LOOKS) + goodlist[i][degree[i] - 2].weight = BIGINT; +#endif + goodlist[i][degree[i] - 1].weight = BIGINT; + degree[i] = 0; + } + + + for (i = ecount - 1; i >= 0; i--) { + n1 = elist[2 * i]; + n2 = elist[(2 * i) + 1]; + w = Edgelen (n1, n2); + insertedge (n1, n2, w); + insertedge (n2, n1, w); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void insertedge (int n1, int n2, int w) +#else +static void insertedge (n1, n2, w) +int n1; +int n2; +int w; +#endif +{ + int i; + edge *e = goodlist[n1]; + + for (i = degree[n1] - 1; i >= 0 && e[i].weight >= w; i--) { + e[i + 1].weight = e[i].weight; + e[i + 1].other = e[i].other; + } + e[i + 1].weight = w; + e[i + 1].other = n2; + degree[n1]++; +} + + +#ifdef CC_PROTOTYPE_ANSI +static void free_graph (int ncount) +#else +static void free_graph (ncount) +int ncount; +#endif +{ + int i; + + if (goodlist) + CC_FREE (goodlist, edge *); + if (edgespace) + CC_FREE (edgespace, edge); + if (degree) + CC_FREE (degree, int); + if (fixlist) { + for (i = 0; i < ncount; i++) { + intptr_list_free (fixlist[i]); + } + CC_FREE (fixlist, intptr *); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void linkern_free_world (void) +#else +static void linkern_free_world () +#endif +{ + int total, onlist; + + if (intptr_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding intptrs\n", total - onlist); + } + if (edgelook_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding edgelooks\n", total - onlist); + } + intptrfree_world (); + edgelookfree_world (); +} + + +#ifdef CC_PROTOTYPE_ANSI +static int initarrays (int ncount) +#else +static int initarrays (ncount) +int ncount; +#endif +{ + int i, M; + + i = 0; + while ((1 << i) < ncount) + i++; + M = (1 << i); + + add_edges = CC_SAFE_MALLOC (M, char); + if (!add_edges) + return 1; + del_edges = CC_SAFE_MALLOC (M, char); + if (!del_edges) { + CC_FREE (add_edges, char); + return 1; + } + for (i = 0; i < M; i++) { + add_edges[i] = 0; + del_edges[i] = 0; + } + + active = CC_SAFE_MALLOC (ncount, char); + if (!active) { + CC_FREE (add_edges, char); + CC_FREE (del_edges, char); + return 1; + } + weirdmark = CC_SAFE_MALLOC (ncount, int); + if (!weirdmark) { + CC_FREE (add_edges, char); + CC_FREE (del_edges, char); + CC_FREE (active, char); + return 1; + } + for (i = 0; i < ncount; i++) { + active[i] = 0; + weirdmark[i] = 0; + } + + return 0; +} + +static int cacheM = 0; + +#ifdef CC_PROTOTYPE_ANSI +static int initcache (int ncount) +#else +static int initcache (ncount) +int ncount; +#endif +{ + int i; + +#ifndef BENTLEY_CACHE + i = 0; + while ((1 << i) < (ncount << 2)) + i++; + cacheM = (1 << i); +#else + i = 0; + while ((1 << i) < ncount) + i++; + cacheM = (1 << i); +#endif + + cacheind = CC_SAFE_MALLOC (cacheM, int); + if (!cacheind) return 1; + + cacheval = CC_SAFE_MALLOC (cacheM, int); + if (!cacheval) return 1; + + for (i = 0; i < cacheM; i++) { + cacheind[i] = -1; + } + +#ifndef BENTLEY_CACHE + cacheM--; +#endif + + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +static int dist (int i, int j) /* As in Bentley's CCkdtree paper */ +#else +static int dist (i, j) +int i, j; +#endif +{ + int ind; + + if (i > j) { + int temp; + SWAP (i, j, temp); + } + +#ifndef BENTLEY_CACHE + ind = (((i << 8) + i + j) & (cacheM)); +#else + ind = i ^ j; +#endif + + if (cacheind[ind] != i) { + cacheind[ind] = i; + cacheval[ind] = CCutil_dat_edgelen (i, j, gdat); + } + + return cacheval[ind]; +} diff --git a/contrib/blossom/concorde97/LINKERN/lk_main.c b/contrib/blossom/concorde97/LINKERN/lk_main.c new file mode 100644 index 0000000000000000000000000000000000000000..63094e815a05b143ff344a27675c057e4543f5d1 --- /dev/null +++ b/contrib/blossom/concorde97/LINKERN/lk_main.c @@ -0,0 +1,628 @@ +/***************************************************************************/ +/* */ +/* CODE FOR TESTING ITERATED LIN-KERNIGHAN */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 17, 1995 */ +/* */ +/* For a short describtion see usage () */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "linkern.h" +#include "kdtree.h" +#include "edgegen.h" + +#define BIGDOUBLE 1000000000.0 +#define SWAP(x,y,temp) {(temp) = (x); (x) = (y); (y) = (temp);} + +static int norm = CC_EUCLIDEAN; +static int seed = 0; +static int binary_in = 0; +static int tsplib_in = 0; +static int nnodes_want = 0; +static int usegreedy = 0; +static int useqboruvka = 0; +static int useboruvka = 0; +static int userandom = 0; +static int nearnum = 0; +static int quadtry = 2; +static int run_silently = 0; + +static int in_repeater = 0; +static int number_runs = 0; +static int print_final = 0; +static double time_bound = -1.0; +static double length_bound = -1.0; + +static char *nodefile = (char *) NULL; +static char *goodfname = (char *) NULL; +static char *cycfname = (char *) NULL; +static char *edgegenfname = (char *) NULL; +static char *edgecycfname = (char *) NULL; +static char *process_name = (char *) NULL; +static char *saveit_name = (char *) NULL; +static char edgecyclefilename[256]; + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int, char **); +static int + parseargs (int, char **); +static void + setupnames (char *n1, char *n2, int ncount), + randcycle (int ncount, int *cyc), + usage (char *f); + +#else + +int + main (); +static int + parseargs (); +static void + setupnames (), + randcycle (), + usage (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + int k, ncount; + double val, best; + double startzeit; + int tempcount, *templist; + int *incycle = (int *) NULL, *outcycle = (int *) NULL; + CCdatagroup dat; + int rval = 0; + + seed = (int) CCutil_real_zeit (); + if (parseargs (ac, av)) + return 1; + CCutil_sprand (seed); + + printf ("Chained Lin-Kernighan with seed %d\n", seed); + fflush (stdout); + + if ((!nnodes_want && !nodefile) || (tsplib_in && !nodefile)) { + usage (av[0]); + return 1; + } + + startzeit = CCutil_zeit (); + setupnames (nodefile, process_name, nnodes_want); + + dat.x = (double *) NULL; + dat.y = (double *) NULL; + dat.z = (double *) NULL; + dat.adj = (int **) NULL; + + if (tsplib_in) { + if (CCutil_gettsplib (nodefile, &ncount, &dat)) { + fprintf (stderr, "could not read the TSPLIB file\n"); + rval = 1; + goto CLEANUP; + } + norm = dat.norm; + } else { + ncount = nnodes_want; + if (CCutil_getdata (nodefile, binary_in, norm, &ncount, &dat)) { + rval = 1; + goto CLEANUP; + } + } + + if (CCutil_init_dat_edgelen (&dat)) { + fprintf (stderr, "CCutil_init_dat_edgelen failed\n"); + rval = 1; + goto CLEANUP; + } + + incycle = CC_SAFE_MALLOC (ncount, int); + if (!incycle) { + rval = 1; + goto CLEANUP; + } + if (cycfname) { + if (CCutil_getcycle (ncount, cycfname, incycle)) { + fprintf (stderr, "CCutil_getcycle failed\n"); + rval = 1; + goto CLEANUP; + } + } else if (edgecycfname) { + if (CCutil_getcycle_edgelist (ncount, edgecycfname, incycle)) { + fprintf (stderr, "CCutil_getcycle_edgelist failed\n"); + rval = 1; + goto CLEANUP; + } + } + + if (goodfname) { + int *templen = (int *) NULL; + if (CCutil_getedgelist (ncount, goodfname, &tempcount, &templist, + &templen)) { + rval = 1; + goto CLEANUP; + } + if (templen) + CC_FREE (templen, int); + printf ("Read good-edge file: %d edges\n", tempcount); + fflush (stdout); + } else if (edgegenfname) { + CCedgegengroup plan; + if (CCedgegen_read (edgegenfname, &plan)) { + fprintf (stderr, "CCedgegen_read failed\n"); + rval = 1; + goto CLEANUP; + } + if (CCedgegen_edges (&plan, ncount, &dat, (double *) NULL, &tempcount, + &templist)) { + fprintf (stderr, "CCedgegen_edges failed\n"); + rval = 1; + goto CLEANUP; + } + } + + if ((norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + CCkdtree localkt; + double kzeit = CCutil_zeit (); + + if ((!goodfname && !edgegenfname) || (!cycfname && !edgecycfname)) { + if (CCkdtree_build (&localkt, ncount, &dat, (double *) NULL)) { + fprintf (stderr, "CCkdtree_build failed\n"); + rval = 1; + goto CLEANUP; + } + printf ("Time to build kdtree: %.2f\n", CCutil_zeit () - kzeit); + fflush (stdout); + + if (!goodfname && !edgegenfname) { + kzeit = CCutil_zeit (); + if (nearnum) { + if (CCkdtree_k_nearest (&localkt, ncount, nearnum, &dat, + (double *) NULL, 1, &tempcount, &templist)) { + fprintf (stderr, "CCkdtree_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + if (!run_silently) { + printf ("Time to find %d-nearest: %.2f\n", nearnum, + CCutil_zeit () - kzeit); + fflush (stdout); + } + } else { + if (CCkdtree_quadrant_k_nearest (&localkt, ncount, quadtry, + &dat, (double *) NULL, 1, &tempcount, &templist)) { + fprintf (stderr, "CCkdtree-quad nearest code failed\n"); + rval = 1; + goto CLEANUP; + } + if (!run_silently) { + printf ("Time to find quad %d-nearest: %.2f\n", quadtry, + CCutil_zeit () - kzeit); + fflush (stdout); + } + } + } + if (!cycfname && !edgecycfname) { + kzeit = CCutil_zeit (); + if (usegreedy) { + if (CCkdtree_greedy_tour (&localkt, ncount, + &dat, incycle, &val)) { + fprintf (stderr, "CCkdtree greedy-tour failed\n"); + rval = 1; + goto CLEANUP; + } + } else if (useqboruvka) { + if (CCkdtree_qboruvka_tour (&localkt, ncount, + &dat, incycle, &val)) { + fprintf (stderr, "CCkdtree qboruvak-tour failed\n"); + rval = 1; + goto CLEANUP; + } + } else if (useboruvka) { + if (CCkdtree_boruvka_tour (&localkt, ncount, + &dat, incycle, &val)) { + fprintf (stderr, "CCkdtree boruvka-tour failed\n"); + rval = 1; + goto CLEANUP; + } + } else if (userandom) { + randcycle (ncount, incycle); + } else { + if (CCkdtree_nearest_neighbor_tour (&localkt, ncount, + CCutil_lprand () % ncount, &dat, incycle, &val)) { + fprintf (stderr, "CCkdtree NN-tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (!run_silently) { + printf ("Time to grow tour: %.2f\n", CCutil_zeit() - kzeit); + fflush (stdout); + } + } + CCkdtree_free (&localkt); + } + } else if ((norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + double xzeit = CCutil_zeit (); + if (!goodfname && !edgegenfname) { + if (nearnum) { + if (CCedgegen_x_k_nearest (ncount, nearnum, &dat, + (double *) NULL, 1, &tempcount, &templist)) { + fprintf (stderr, "CCedgegen_x_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + if (!run_silently) { + printf ("Time to find %d-nearest: %.2f\n", nearnum, + CCutil_zeit () - xzeit); + fflush (stdout); + } + } else { + if (CCedgegen_x_quadrant_k_nearest (ncount, quadtry, &dat, + (double *) NULL, 1, &tempcount, &templist)) { + fprintf (stderr, "x-quad nearest code failed\n"); + rval = 1; + goto CLEANUP; + } + if (!run_silently) { + printf ("Time to find quad %d-nearest: %.2f\n", quadtry, + CCutil_zeit () - xzeit); + fflush (stdout); + } + } + } + if (!cycfname && !edgecycfname) { + xzeit = CCutil_zeit (); + if (userandom) { + randcycle (ncount, incycle); + } else { + if (CCedgegen_x_nearest_neighbor_tour (ncount, + CCutil_lprand () % ncount, &dat, incycle, &val)) { + fprintf (stderr, "x_nearest_neighbor_tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (!run_silently) { + printf ("Time to grow tour: %.2f\n", CCutil_zeit () - xzeit); + fflush (stdout); + } + } + } else { + double jzeit = CCutil_zeit (); + if (!goodfname && !edgegenfname) { + if (!nearnum) + nearnum = 4 * quadtry; + if (CCedgegen_junk_k_nearest (ncount, nearnum, &dat, + (double *) NULL, 1, &tempcount, &templist)) { + fprintf (stderr, "CCedgegen_junk_k_nearest failed\n"); + rval = 1; + goto CLEANUP; + } + if (!run_silently) { + printf ("Time to find %d nearest: %.2f\n", + nearnum, CCutil_zeit () - jzeit); + fflush (stdout); + } + } + if (!cycfname && !edgecycfname) { + if (userandom) { + randcycle (ncount, incycle); + } else { + if (CCedgegen_junk_nearest_neighbor_tour (ncount, + CCutil_lprand () % ncount, &dat, incycle, &val)) { + fprintf (stderr, "junk_nearest_neighbor_tour failed\n"); + rval = 1; + goto CLEANUP; + } + } + if (!run_silently) { + printf ("Time to grow tour: %.2f\n", CCutil_zeit () - jzeit); + fflush (stdout); + } + } + } + + outcycle = CC_SAFE_MALLOC (ncount, int); + if (!outcycle) { + rval = 1; + goto CLEANUP; + } + + if (number_runs) { + k = 0; + best = BIGDOUBLE; + do { + printf ("\nStarting Run %d\n", k); + if (CClinkern_tour (ncount, &dat, tempcount, templist, 100000000, + in_repeater, incycle, outcycle, &val, run_silently, + time_bound, length_bound, (char *) NULL)) { + fprintf (stderr, "CClinkern_tour failed\n"); + rval = 1; + goto CLEANUP; + } + if (val < best) { + best = val; + if (print_final) { + if (CCutil_writecycle_edgelist (ncount, edgecyclefilename, + outcycle, &dat)) { + fprintf (stderr, "could not write the cycle\n"); + rval = 1; + goto CLEANUP; + } + } + } + } while (++k < number_runs); + printf ("Overall Best Cycle: %.0f\n", val); + fflush (stdout); + } else { + double lkzeit = CCutil_zeit (); + int attempt = 1; + do { + if (CClinkern_tour (ncount, &dat, tempcount, templist, 10000000, + in_repeater, incycle, outcycle, &val, + run_silently, time_bound, length_bound, saveit_name)) { + fprintf (stderr, "CClinkern_tour failed\n"); + rval = 1; + goto CLEANUP; + } + if (length_bound != -1 && val > length_bound) { + printf ("Cycle of value %.0f - did not reach %.0f\n", + val, length_bound); + printf ("Try again. Number of attempts: %d\n", ++attempt); + } + } while (length_bound != -1 && val > length_bound); + if (print_final) { + if (CCutil_writecycle_edgelist (ncount, edgecyclefilename, + outcycle, &dat)) { + fprintf (stderr, "could not write the cycle\n"); + rval = 1; + goto CLEANUP; + } + } + if (run_silently) + printf ("Lin-Kernighan Running Time: %.2f\n", CCutil_zeit()-lkzeit); + printf ("Final Cycle: %.0f\n", val); + fflush (stdout); + } + printf ("Total Running Time: %.2f\n", CCutil_zeit () - startzeit); + fflush (stdout); + +CLEANUP: + +#ifndef BIG_PROBLEM + if (templist) + CC_FREE (templist, int); +#endif + if (incycle) + CC_FREE (incycle, int); + if (outcycle) + CC_FREE (outcycle, int); + CCutil_freedatagroup (ncount, &dat); + + if (CCutil_bigchunk_free_world ()) { + fprintf (stderr, "ERROR: CCuitl_bigcunk free world failed\n"); + return 1; + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void setupnames (char *n1, char *n2, int ncount) +#else +static void setupnames (n1, n2, ncount) +char *n1; +char *n2; +int ncount; +#endif +{ + if (n2) { + sprintf (edgecyclefilename, "ecycle.out.%s", n2); + } else if (n1) { + char *p = CCutil_strrchr (n1, '/'); + if (!p) + p = n1; + else + p++; + sprintf (edgecyclefilename, "ecycle.out.%s", p); + } else { + sprintf (edgecyclefilename, "ecycle.out.%d", ncount); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void randcycle (int ncount, int *cyc) +#else +static void randcycle (ncount, cyc) +int ncount; +int *cyc; +#endif +{ + int i, k, temp; + + for (i = 0; i < ncount; i++) + cyc[i] = i; + + for (i = ncount; i > 1; i--) { + k = CCutil_lprand () % i; + SWAP (cyc[i - 1], cyc[k], temp); + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "a:bD:g:h:jk:ln:pq:Qr:R:s:S:t:Tuvy:Y:0123456789")) != EOF) + switch (c) { + case 'a': + nearnum = atoi (CCutil_bix_optarg); + break; + case 'b': + binary_in = 1; + break; + case 'D': + edgegenfname = CCutil_bix_optarg; + break; + case 'g': + goodfname = CCutil_bix_optarg; + break; + case 'h': + length_bound = atof (CCutil_bix_optarg); + break; + case 'j': + useqboruvka++; + break; + case 'k': + nnodes_want = atoi (CCutil_bix_optarg); + break; + case 'l': + userandom++; + break; + case 'n': + process_name = CCutil_bix_optarg; + break; + case 'p': + print_final++; + break; + case 'q': + quadtry = atoi (CCutil_bix_optarg); + break; + case 'Q': + run_silently++; + break; + case 'r': + number_runs = atoi (CCutil_bix_optarg); + break; + case 'R': + in_repeater = atoi (CCutil_bix_optarg); + break; + case 's': + seed = atoi (CCutil_bix_optarg); + break; + case 'S': + saveit_name = CCutil_bix_optarg; + break; + case 't': + time_bound = atof (CCutil_bix_optarg); + break; + case 'T': + tsplib_in = 1; + break; + case 'u': + usegreedy++; + break; + case 'v': + useboruvka++; + break; + case 'y': + cycfname = CCutil_bix_optarg; + break; + case 'Y': + edgecycfname = CCutil_bix_optarg; + break; + case '0': + norm = CC_MAXNORM; + break; + case '1': + norm = CC_EUCLIDEAN_CEIL; + break; + case '2': + norm = CC_EUCLIDEAN; + break; + case '3': + norm = CC_EUCLIDEAN_3D; + break; + case '4': + norm = CC_IBM; + break; + case '5': + norm = CC_ATT; + break; + case '6': + norm = CC_GEOGRAPHIC; + break; + case '7': + norm = CC_MATRIXNORM; + break; + case '8': + norm = CC_DSJRANDNORM; + break; + case '9': + norm = CC_CRYSTAL; + break; + case CC_BIX_GETOPT_UNKNOWN: + case '?': + default: + usage (av[0]); + break; + } + if (CCutil_bix_optind < ac) + nodefile = av[CCutil_bix_optind++]; + + if (CCutil_bix_optind > ac) { + usage (av[0]); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "usage: %s [- see below -] [dat_file]\n", f); + fprintf (stderr, " -b dat file in binary ints\n"); + fprintf (stderr, " -k # number of nodes for random problem\n"); + fprintf (stderr, " -s # random number seed\n"); + fprintf (stderr, " -n s process name (used for naming output file)\n"); + fprintf (stderr, " -p dump final cycle\n"); + fprintf (stderr, " -S s save tour in S after every 10000 kicks\n"); + fprintf (stderr, " -a # use #-nearest as good edge set\n"); + fprintf (stderr, " -D f edgegen description file\n"); + fprintf (stderr, " -g f good edge file\n"); + fprintf (stderr, " -q # use quad #-nearest as edge set (default 3)\n"); + fprintf (stderr, " -r # number of runs\n"); + fprintf (stderr, " -R # number of kicks in iterated Lin-Kernighan\n"); + fprintf (stderr, " -y f starting cycle\n"); + fprintf (stderr, " -Y f starting cycle (as an edgelist)\n"); + fprintf (stderr, " -u greedy starting cycle (for kd-norms)\n"); + fprintf (stderr, " -j quick-boruvka starting cycle (for kd-norms)\n"); + fprintf (stderr, " -v boruvka starting cycle (for kd-norms)\n"); + fprintf (stderr, " -l random starting cycle\n"); + fprintf (stderr, " -T the dat file is a TSPLIB file\n"); + fprintf (stderr, " -t d running time bound in seconds\n"); + fprintf (stderr, " -h d tour length bound (stop when we hit d)\n"); + fprintf (stderr, " -Q run silently\n"); + fprintf (stderr, " -0 Max norm for edge lengths\n"); + fprintf (stderr, " -1 Ceiling Euclidean norm - from DSJ\n"); + fprintf (stderr, " -2 Rounded Euclidean norm (default)\n"); + fprintf (stderr, " -3 Rounded Euclidean 3D norm\n"); + fprintf (stderr, " -(4 5 6 7 8 9) IBM ATT GEO MATRIX DSJRAND CRYSTAL norm\n"); +} diff --git a/contrib/blossom/concorde97/LP/Makefile b/contrib/blossom/concorde97/LP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b3d32923c04f3b46ebba59a816ed9735df359722 --- /dev/null +++ b/contrib/blossom/concorde97/LP/Makefile @@ -0,0 +1,33 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=lp.a + +ifneq ($(CPLEX_LIB),) +LIBSRCS=lpcplex.c +else +LIBSRCS=lpsolve.c +endif +ALLSRCS=lpsolve.c lpcplex.c + +all: $(LIB) + +clean: + -rm -f *.$o $(LIB) + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +lpcplex.$o: lpcplex.c $(I)/machdefs.h $(I)/util.h $(I)/macrorus.h \ + $(I)/lp.h +lpsolve.$o: lpsolve.c $(I)/machdefs.h $(I)/util.h $(I)/macrorus.h \ + $(I)/lp.h diff --git a/contrib/blossom/concorde97/LP/lpcplex.c b/contrib/blossom/concorde97/LP/lpcplex.c new file mode 100644 index 0000000000000000000000000000000000000000..e2affa81108533b293116d2ebb5607891afcfb84 --- /dev/null +++ b/contrib/blossom/concorde97/LP/lpcplex.c @@ -0,0 +1,1408 @@ +/***************************************************************************/ +/* */ +/* Interface Routines to The CPLEX LP Solver */ +/* */ +/* NOTE: Use this code in place of lpsolve.c to access the Cplex 4.1 */ +/* library. You will also need to link the cplex library via the */ +/* makefile. */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: April 17, 1997 */ +/* June 19, 1997 (bico, REB) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void CClp_init_struct (CClp *lp) */ +/* INITIALIZES the fields of the LP structure to NULL. */ +/* */ +/* int CClp_init (CClp *lp) */ +/* INITIALIZES the LP. */ +/* */ +/* void CClp_free (CClp *lp) */ +/* FREES the LP (but not pointer to the LP). */ +/* */ +/* int CClp_loadlp (CClp *lp, char *name, int ncols, int nrows, */ +/* int objsense, double *obj, double *rhs, char *sense, */ +/* int *matbeg, int *matcnt, */ +/* int *matind, double *matval, */ +/* double *lb, double *ub) */ +/* LOADS the data into the LP. The memory is used by the LP solver, */ +/* and thus should not be freed until after a call to CClp_free. */ +/* -name attaches a name to the LP (it can be used by the LP solver */ +/* in io routines) */ +/* -ncols and nrows give the number of columns and rows in the LP */ +/* -objsense should be -1 for minimize and 1 for maximize */ +/* -obj and rhs are arrays giving the objective function and rhs */ +/* -sense is an array specifying 'L', 'E', or 'G' for each of the */ +/* rows */ +/* -matbeg, matcnt, matind, and matval give the coefficients of */ +/* the contraint matrix in column by column order. matbeg gives */ +/* gives the index of the start of each column; matcnt gives the */ +/* number of coefficients in each column; matind gives the indices */ +/* of the rows where the coefficients are located in the contraint */ +/* matrix (so for column j, the indices are given in matcnt[j] */ +/* locations starting at matind[matbeg[j]]; and matval gives the */ +/* actual coefficients (organized like matind). */ +/* -lb and ub are arrays giving the upper and lower bounds of */ +/* the variables. */ +/* */ +/* int CClp_opt (CClp *lp, int method) */ +/* CALLS designated LP solution method. */ +/* */ +/* int CClp_dualopt (CClp *lp) */ +/* CALLS the dual simplex method. */ +/* */ +/* int CClp_limited_dualopt (CClp *lp, int lim, double *upperbound, */ +/* int *status) */ +/* CALLS the dual simplex method with a limit on the number of pivots.*/ +/* -upperbound it is used to cutoff the dual simplex method (when */ +/* the objective value reaches upperbound); it can be NULL */ +/* -status returns the status of the optimization (it can be NULL) */ +/* */ +/* void CClp_pivotin (CClp *lp, int i) */ +/* Puts slack/artificial on row i into the resident basis */ +/* If there is no resident basis, the call fails */ +/* */ +/* int CClp_primalopt (CClp *lp) */ +/* CALLS the primal simplex method. */ +/* */ +/* int CClp_addrows (CClp *lp, int newrows, int newnz, double *rhs, */ +/* char *sense, int *rmatbeg, int *rmatind, double *rmatval) */ +/* ADDS the rows to the LP. */ +/* -newrows is the number of rows to be added */ +/* -newnz is the number of nonzero coefficients in the new rows */ +/* -rhs is an array of the rhs values for the new rows */ +/* -sense is 'L', 'E', or 'G' for each of the new rows */ +/* -rmatbeg, rmatind, and rmatval give the coefficients of the */ +/* new rows in sparse format. The arrays can be freed after the */ +/* call. */ +/* */ +/* int CClp_addcols (CClp *lp, int newcols, int newnz, double *obj, */ +/* int *cmatbeg, int *cmatind, double *cmatval, */ +/* double *lb, double *ub) */ +/* ADDS the columns to the LP. */ +/* */ +/* int CClp_delete_row (CClp *lp, int i) */ +/* DELETES row i of the LP. */ +/* */ +/* int CClp_delete_set_of_rows (CClp *lp, int *delstat) */ +/* DELETES the rows corresponding to 1 entries in delstat. */ +/* -delstat is a 0/1 array having an entry for each row */ +/* */ +/* int CClp_delete_column (CClp *lp, int i) */ +/* DELETES column i from the LP. */ +/* */ +/* int CClp_delete_set_of_columns (CClp *lp, int *delstat) */ +/* DELETES the columns corresponding to the 1 entries in delstat. */ +/* -delstat is a 0/1 array having an entry for each column */ +/* */ +/* int CClp_setbnd (CClp *lp, int col, char lower_or_upper, double bnd) */ +/* SETS the bound on the variable index by col. */ +/* -lower_or_upper should be either 'L' or 'U' */ +/* */ +/* void CClp_init_basis (CClpbasis *b) */ +/* INITIALIZES the fields of the basis structure. */ +/* */ +/* void CClp_free_basis (CClpbasis *b) */ +/* FREEs the basis structure. */ +/* */ +/* int CClp_get_basis_and_norms (CClp *lp, CClpbasis *b) */ +/* RETURNS the current basis and dual norms. */ +/* Note: The arrays are allocated by this function are should be */ +/* freed by a call to CC_lp_free_basis (). */ +/* */ +/* int CClp_load_basis_and_norms (CClp *lp, CClpbasis *b) */ +/* LOADS the basis and norm int the LP. */ +/* Note: If the norms field is not set, then just the basis is loaded.*/ +/* */ +/* int CClp_basis (CClp *lp, int *cstat, int *rstat) */ +/* RETURNS the current basis. cstat or rstat can by NULL. */ +/* -cstat should be an array of length at least ncols */ +/* -rstat should be an array of length at least nrows */ +/* */ +/* int CClp_loadbasis (CClp *lp, int *cstat, int *rstat) */ +/* LOADS the basis into the LP. */ +/* */ +/* int CClp_getbasis_and_norms (CClp *lp, int *cstat, int *rstat, */ +/* double *dnorm) */ +/* RETURNS the current basis and dual norms - these items should be */ +/* used as a pair, in calls to CClp_loadbasis_and_norms. */ +/* -dnorms should be an array of length at least nrows */ +/* */ +/* int CClp_loadbasis_and_norms (CClp *lp,int *cstat, int *rstat, */ +/* double *dnorm) */ +/* LOADS the basis and dual norms into the LP. (This pair should */ +/* have been obtained by a call to CClp_getbasis_and_norms. */ +/* */ +/* int CClp_x (CClp *lp, double *x) */ +/* RETURNS the current LP solution. */ +/* -x should be an array of length at least ncols */ +/* */ +/* int CClp_rc (CClp *lp, double *rc) */ +/* RETURNS the current reduced costs. */ +/* -rc should be an array of length at least ncols */ +/* */ +/* int CClp_pi_range (CClp *lp, double *pi, int from, int to) */ +/* RETURNS the dual values on the constraints indexed [from, to]. */ +/* -pi should be an array of length at least (to-from+1) */ +/* */ +/* int CClp_objval (CClp *lp, double *obj) */ +/* RETURNS the objective value of the lp. */ +/* */ +/* int CClp_nonzeros (CClp *lp) */ +/* RETURNS the number of nonzeros in the LP. */ +/* */ +/* int CClp_status (CClp *lp, int *status) */ +/* CHECKS whether the current lp is infeasible or whether an optimal */ +/* solution has been found. It returns an error if the LP has not */ +/* not been optimized. */ +/* -lp is the lp */ +/* -status returns 0 if the lp has an optimal solution and 1 if it */ +/* is infeasible. */ +/* */ +/* int CClp_getweight (CClp *lp, int nrows, int *rmatbeg, int *rmatind, */ +/* double *rmatval, double *weight) */ +/* COMPUTES the duals of the steepest edge norms for the n rows */ +/* specified in rmatbeg, rmatind, and rmatval. */ +/* -weight returns the array of weights; the array should be at */ +/* least nrows long */ +/* */ +/* int CClp_dump_lp (CClp *lp, char *fname) */ +/* WRITES the LP to file fname. */ +/* */ +/* int CClp_getgoodlist (CClp *lp, int *goodlist, int *ngood, */ +/* double *downpen, double *uppen) */ +/* RETURNS an array of the column indices corresponding to variables */ +/* that move in both the up and down directions. This is a useful */ +/* list of candidates for strong branching. */ +/* -goodlist, downpen and uppen should be arrays of length at */ +/* least ncols. */ +/* */ +/* int CClp_strongbranch (CClp *lp, int *candidatelist, int ncand, */ +/* double *downpen, double *uppen, int iterations, */ +/* double *upperbound) */ +/* RETURNS estimates of the lp values obtained by setting each of the */ +/* ncand variables listed in candidatelist to 0 and 1. The estimates*/ +/* are obtained by performing iterations pivots of dual simplex */ +/* method. If upperbound is not NULL, then it is used to cutoff the */ +/* dual simplex method. */ +/* -downpen and uppen should be arrays of length at least ncand */ +/* */ +/* int CClp_getfarkasmultipliers (CClp *lp, double *y) */ +/* RETURNS the multipliers for a Farkas' proof after dualopt returns */ +/* with an unbound lp. */ +/* -y should point to an array at least as long as the number of */ +/* rows */ +/* The y[] computed will satisfy the following: */ +/* */ +/* y_i <= 0 for <= constraints */ +/* y_i >= 0 for >= constraints */ +/* */ +/* y'b - sum (y'A_j * u_j: y'A_j > 0) */ +/* - sum (y'A_j * l_j: y'A_j < 0) > 0 */ +/* */ +/* where b is the rhs vector, u_j is the upper bound on variable x_j, */ +/* l_j the lower bound, and A_j the constraint matrix column for x_j. */ +/* */ +/* */ +/* NOTES: */ +/* */ +/* */ +/***************************************************************************/ + + +#include "machdefs.h" +#include "util.h" +#include "macrorus.h" +#include "lp.h" +#include <cplex.h> + +#undef CC_CPLEX_DISPLAY + +#ifdef CC_PROTOTYPE_ANSI +void CClp_init_struct (CClp *lp) +#else +void CClp_init_struct (lp) +CClp *lp; +#endif +{ + lp->cplex_env = (CPXENVptr) NULL; + lp->cplex_lp = (CPXLPptr) NULL; + lp->lp_allocated = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_init (CClp *lp) +#else +int CClp_init (lp) +CClp *lp; +#endif +{ + int rval = 0; + + CClp_init_struct (lp); + + lp->cplex_env = CPXopenCPLEXdevelop (&rval); + if (rval) { + fprintf (stderr, "cplex open failed\n"); goto CLEANUP; + } + +#ifdef CC_CPLEX_DISPLAY + /* the documentation doesn't say what the return value means */ + rval = CPXsetintparam (lp->cplex_env, CPX_PARAM_SCRIND, 1); + if (rval) { + fprintf (stderr, "cplex set SCR_IND failed\n"); goto CLEANUP; + } + + rval = CPXsetintparam (lp->cplex_env, CPX_PARAM_SIMDISPLAY, 1); + if (rval) { + fprintf (stderr, "cplex setitfoind failed\n"); goto CLEANUP; + } +#endif + + rval = CPXsetintparam (lp->cplex_env, CPX_PARAM_ADVIND, 1); + if (rval) { + fprintf (stderr, "cplex setadvind failed\n"); goto CLEANUP; + } + rval = CPXsetintparam (lp->cplex_env, CPX_PARAM_DPRIIND, + CPX_DPRIIND_STEEP); + if (rval) { + fprintf (stderr, "cplex setdpriind failed\n"); goto CLEANUP; + } + rval = CPXsetintparam (lp->cplex_env, CPX_PARAM_PPRIIND, + CPX_PPRIIND_STEEP); + if (rval) { + fprintf (stderr, "cplex setppriind failed\n"); goto CLEANUP; + } + +CLEANUP: + + if (rval) { + CClp_free (lp); + } else { + lp->lp_allocated = 1; + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_free (CClp *lp) +#else +void CClp_free (lp) +CClp *lp; +#endif +{ + if (lp->cplex_env) { + if (lp->cplex_lp) { + CPXfreeprob (lp->cplex_env, &lp->cplex_lp); + } + CPXcloseCPLEX (&lp->cplex_env); + } + lp->lp_allocated = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_loadlp (CClp *lp, char *name, int ncols, int nrows, + int objsense, double *obj, double *rhs, char *sense, + int *matbeg, int *matcnt, + int *matind, double *matval, + double *lb, double *ub) + +#else +int CClp_loadlp (lp, name, ncols, nrows, objsense, obj, rhs, sense, matbeg, + matcnt, matind, matval, lb, ub) +CClp *lp; +char *name; +int ncols, nrows; +int objsense; +double *obj, *rhs; +char *sense; +int *matbeg, *matcnt, *matind; +double *matval, *lb, *ub; +#endif +{ + int rval = 0; + + lp->cplex_lp = CPXcreateprob (lp->cplex_env, &rval, name); + if (!lp->cplex_lp || rval) { + fprintf (stderr, "CPXcreateprob failed\n"); return 1; + } + + rval = CPXcopylp (lp->cplex_env, lp->cplex_lp, ncols, nrows, + objsense, obj, rhs, sense, matbeg, matcnt, + matind, matval, lb, ub, (double *) NULL); + if (rval) { + fprintf (stderr, "CPXcopylp failed\n"); return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_opt (CClp *lp, int method) +#else +int CClp_opt (lp, method) +CClp *lp; +int method; +#endif +{ + int rval = 0; + + switch (method) { + case CClp_METHOD_DUAL: + rval = CClp_dualopt (lp); + break; + /* The purpose of this function is to support calls to other + LP algorithms, such CPXbaropt. However, the current + version of concorde (14 August 1997) does not use this + feature */ + default: + rval = 1; + fprintf (stderr, "Nonexistent method in CClp_opt\n"); + break; + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_dualopt (CClp *lp) +#else +int CClp_dualopt (lp) +CClp *lp; +#endif +{ + int rval; + int solstat; +#ifdef CC_CPLEX_WRITE_DUAL + static int probcnt = 0; + char probname[100]; + + sprintf (probname, "%s.dual%d.sav", lp->lpspace.probname, probcnt); + probcnt++; + printf ("Writing %s\n", probname); + CPXsavwrite (lp->cplex_env, lp->cplex_lp, probname); +#endif + + rval = CPXdualopt (lp->cplex_env, lp->cplex_lp); + if (rval) { + if (rval == CPXERR_PRESLV_INForUNBD) { + int old; + printf ("Cplex presolved failed, switch to simplex\n"); + fflush (stdout); + if (CPXgetintparam (lp->cplex_env, CPX_PARAM_PREIND, &old)) { + fprintf (stderr, "CPXsetintparam failed\n"); + return 1; + } + if (CPXsetintparam (lp->cplex_env, CPX_PARAM_PREIND, CPX_OFF)) { + fprintf (stderr, "CPXsetintparam failed\n"); + return 1; + } + rval = CPXdualopt (lp->cplex_env, lp->cplex_lp); + if (rval) { + fprintf (stderr, "Cplex failed\n"); + return 1; + } + if (CPXsetintparam (lp->cplex_env, CPX_PARAM_PREIND, old)) { + fprintf (stderr, "CPXsetintparam failed\n"); + return 1; + } + } else { + fprintf (stderr, "Cplex failed\n"); + return 1; + } + } + solstat = CPXgetstat (lp->cplex_env, lp->cplex_lp); + if (solstat == CPX_UNBOUNDED) { + printf ("Infeasible in cplex_dualopt\n"); + return 2; + } else if (solstat != CPX_OPTIMAL && solstat != CPX_OPTIMAL_INFEAS) { + fprintf (stderr, "Cplex optimization status %d\n", solstat); + if (solstat == CPX_IT_LIM_FEAS) { + int itlim; + rval = CPXgetintparam (lp->cplex_env, CPX_PARAM_ITLIM, &itlim); + if (!rval) { + printf ("cplex interation limit: %d\n", itlim); + fflush (stdout); + } + return 1; + } + } + return 0; +} + +#define CC_MAX_REFACTORFREQ 150 + +#ifdef CC_PROTOTYPE_ANSI +int CClp_limited_dualopt (CClp *lp, int iterationlim, int *status, + double *objupperlim) +#else +int CClp_limited_dualopt (lp, iterationlim, status, objupperlim) +CClp *lp; +int iterationlim; +int *status; +double *objupperlim; +#endif +{ + int rval = 0; + int sval = 0; + int solstat; + + int got_iterationlim = 0; + int got_presolveind = 0; + int got_objupperlim = 0; + int got_refactorfreq = 0; + + int old_iterationlim; + int old_presolveind; + double old_objupperlim; + int old_refactorfreq; + + rval = CPXgetintparam (lp->cplex_env, CPX_PARAM_ITLIM, &old_iterationlim); + if (rval) { + fprintf (stderr, "CPXgetintparam failed\n"); goto CLEANUP; + } + got_iterationlim = 1; + + rval = CPXgetdblparam (lp->cplex_env, CPX_PARAM_OBJULIM, &old_objupperlim); + if (rval) { + fprintf (stderr, "CPXgetdblparam failed\n"); goto CLEANUP; + } + got_objupperlim = 1; + + rval = CPXgetintparam (lp->cplex_env, CPX_PARAM_PREIND, &old_presolveind); + if (rval) { + fprintf (stderr, "CPXgetintparam failed\n"); goto CLEANUP; + } + got_presolveind = 1; + + rval = CPXgetintparam (lp->cplex_env, CPX_PARAM_REINV, &old_refactorfreq); + if (rval) { + fprintf (stderr, "CPXgetintparam failed\n"); goto CLEANUP; + } + got_refactorfreq = 1; + + rval = CPXsetintparam (lp->cplex_env, CPX_PARAM_ITLIM, iterationlim); + if (rval) { + fprintf (stderr, "CPXsetintparam failed\n"); goto CLEANUP; + } + + if ( iterationlim < CC_MAX_REFACTORFREQ ) { + rval = CPXsetintparam (lp->cplex_env, CPX_PARAM_REINV, iterationlim+1); + if (rval) { + fprintf (stderr, "CPXsetintparam failed\n"); goto CLEANUP; + } + } + + if (objupperlim) { + rval = CPXsetdblparam (lp->cplex_env, CPX_PARAM_OBJULIM, *objupperlim); + if (rval) { + fprintf (stderr, "CPXsetdblparam failed\n"); goto CLEANUP; + } + } + + rval = CPXdualopt (lp->cplex_env, lp->cplex_lp); + if (rval) { + if (rval == CPXERR_PRESLV_INForUNBD) { + printf ("Cplex presolve failed, force simplex\n"); + fflush (stdout); + + if (CPXsetintparam (lp->cplex_env, CPX_PARAM_PREIND, CPX_OFF)) { + fprintf (stderr, "CPXsetintparam failed\n"); goto CLEANUP; + } + rval = CPXdualopt (lp->cplex_env, lp->cplex_lp); + if (rval) { + fprintf (stderr, "Cplex failed\n"); goto CLEANUP; + } + } else { + fprintf (stderr, "Cplex failed\n"); goto CLEANUP; + } + } + solstat = CPXgetstat (lp->cplex_env, lp->cplex_lp); + if (solstat==CPX_IT_LIM_INFEAS) { + rval = CPXsetdblparam (lp->cplex_env, CPX_PARAM_OBJULIM, -1.0E75); + if (rval) { + fprintf (stderr, "CPXsetdblparam failed\n"); goto CLEANUP; + } + /* We could be even more aggressive here and make the iteration + limit infinite, but that approach seems contrary to the + intent of this function. Hence, the repeat test for + CPX_IT_LIM_INFEAS below -- REB, 1 July 97 */ + rval = CPXdualopt (lp->cplex_env, lp->cplex_lp); + if (rval) { + fprintf (stderr, "Cplex failed\n"); goto CLEANUP; + } + } + + if (solstat == CPX_UNBOUNDED) { + printf ("Infeasible in cplex_dualopt\n"); fflush (stdout); + if (status) *status = CClp_INFEASIBLE; + } else if (solstat == CPX_IT_LIM_INFEAS) { + printf ("LP infeasible after the limited number of iterations\n"); + fflush (stdout); + if (status) *status = CClp_UNKNOWN; + } else if (solstat != CPX_OPTIMAL && solstat != CPX_OPTIMAL_INFEAS && + solstat != CPX_IT_LIM_FEAS && solstat != CPX_OBJ_LIM) { + fprintf (stderr, "Cplex optimization status %d\n", solstat); + if (status) *status = CClp_FAILURE; + } else { + if (status) *status = CClp_SUCCESS; + } + +CLEANUP: + + if (got_iterationlim == 1) { + sval = CPXsetintparam (lp->cplex_env, CPX_PARAM_ITLIM, + old_iterationlim); + if (sval) { + fprintf (stderr, "CPXsetintparam failed\n"); + rval = 1; + } + } + + if (got_objupperlim == 1) { + sval = CPXsetdblparam (lp->cplex_env, CPX_PARAM_OBJULIM, + old_objupperlim); + if (sval) { + fprintf (stderr, "CPXsetdblparam failed\n"); + rval = 1; + } + } + + if (got_presolveind == 1) { + sval = CPXsetintparam (lp->cplex_env, CPX_PARAM_PREIND, + old_presolveind); + if (sval) { + fprintf (stderr, "CPXsetintparam failed\n"); + rval = 1; + } + } + + if (got_refactorfreq == 1) { + sval = CPXsetintparam (lp->cplex_env, CPX_PARAM_REINV, + old_refactorfreq); + if (sval) { + fprintf (stderr, "CPXsetintparam failed\n"); + rval = 1; + } + } + + if (rval && status) { + *status = CClp_FAILURE; + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_primalopt (CClp *lp) +#else +int CClp_primalopt (lp) +CClp *lp; +#endif +{ + int rval; + int solstat; +#ifdef CC_CPLEX_WRITE_PRIMAL + static int probcnt = 0; + char probname[100]; + + sprintf (probname, "%s.prim%d.sav", lp->lpspace.probname, probcnt); + probcnt++; + printf ("Writing %s\n", probname); + CPXsavwrite (lp->cplex_env, lp->cplex_lp, probname); +#endif + + rval = CPXprimopt (lp->cplex_env, lp->cplex_lp); + if (rval) { + fprintf (stderr, "Cplex optimize failed\n"); + return 1; + } + solstat = CPXgetstat (lp->cplex_env, lp->cplex_lp); + if (solstat == CPX_INFEASIBLE) { + printf ("Infeasible.\n"); + return 2; + } else if (solstat != CPX_OPTIMAL && solstat != CPX_OPTIMAL_INFEAS) { + fprintf (stderr, "Cplex optimization status %d\n", solstat); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_addrows (CClp *lp, int newrows, int newnz, double *rhs, char *sense, + int *rmatbeg, int *rmatind, double *rmatval) +#else +int CClp_addrows (lp, newrows, newnz, rhs, sense, rmatbeg, rmatind, rmatval) +CClp *lp; +int newrows, newnz; +double *rhs; +char *sense; +int *rmatbeg, *rmatind; +double *rmatval; +#endif +{ + int rval = 0; + + rval = CPXaddrows (lp->cplex_env, lp->cplex_lp, 0, newrows, newnz, + rhs, sense, rmatbeg, rmatind, rmatval, + (char **) NULL, (char **) NULL); + if (rval) fprintf (stderr, "CPXaddrows failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_addcols (CClp *lp, int newcols, int newnz, double *obj, + int *cmatbeg, int *cmatind, double *cmatval, + double *lb, double *ub) +#else +int CClp_addcols (lp, newcols, newnz, obj, cmatbeg, cmatind, cmatval, lb, ub) +CClp *lp; +int newcols, newnz; +double *obj; +int *cmatbeg, *cmatind; +double *cmatval; +double *lb, *ub; +#endif +{ + int rval = 0; + + rval = CPXaddcols (lp->cplex_env, lp->cplex_lp, newcols, newnz, obj, + cmatbeg, cmatind, cmatval, lb, ub, (char **) NULL); + if (rval) fprintf (stderr, "CPXaddcols failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_delete_row (CClp *lp, int i) +#else +int CClp_delete_row (lp, i) +CClp *lp; +int i; +#endif +{ + int rval = 0; + + rval = CPXdelrows (lp->cplex_env, lp->cplex_lp, i, i); + if (rval) fprintf (stderr, "CPXdelrows failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_delete_set_of_rows (CClp *lp, int *delstat) +#else +int CClp_delete_set_of_rows (lp, delstat) +CClp *lp; +int *delstat; +#endif +{ + int rval = 0; + + rval = CPXdelsetrows (lp->cplex_env, lp->cplex_lp, delstat); + if (rval) fprintf (stderr, "CPXdelsetrows failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_delete_column (CClp *lp, int i) +#else +int CClp_delete_column (lp, i) +CClp *lp; +int i; +#endif +{ + int rval = 0; + + rval = CPXdelcols (lp->cplex_env, lp->cplex_lp, i, i); + if (rval) fprintf (stderr, "CPXdelcols failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_delete_set_of_columns (CClp *lp, int *delstat) +#else +int CClp_delete_set_of_columns (lp, delstat) +CClp *lp; +int *delstat; +#endif +{ + int rval = 0; + + rval = CPXdelsetcols (lp->cplex_env, lp->cplex_lp, delstat); + if (rval) fprintf (stderr, "CPXdelsetcols failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_setbnd (CClp *lp, int col, char lower_or_upper, double bnd) +#else +int CClp_setbnd (lp, col, lower_or_upper, bnd) +CClp *lp; +int col; +char lower_or_upper; +double bnd; +#endif +{ + int cindex[1]; + double bd[1]; + char lu[1]; + int rval; + + cindex[0] = col; + lu[0] = lower_or_upper; + bd[0] = bnd; + + rval = CPXchgbds (lp->cplex_env, lp->cplex_lp, 1, cindex, lu, bd); + if (rval) { + fprintf (stderr, "Couldn't set bnd on variable %d in cplex\n", col); + return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_init_basis (CClpbasis *b) +#else +void CClp_init_basis (b) +CClpbasis *b; +#endif +{ + if (b) { + b->cstat = (int *) NULL; + b->rstat = (int *) NULL; + b->dnorm = (double *) NULL; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_free_basis (CClpbasis *b) +#else +void CClp_free_basis (b) +CClpbasis *b; +#endif +{ + if (b) { + CC_IFFREE (b->cstat, int); + CC_IFFREE (b->rstat, int); + CC_IFFREE (b->dnorm, double); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_get_basis_and_norms (CClp *lp, CClpbasis *b) +#else +int CClp_get_basis_and_norms (lp, b) +CClp *lp; +CClpbasis *b; +#endif +{ + int rval = 0; + int ncols, nrows; + + CClp_init_basis (b); + + ncols = CPXgetnumcols (lp->cplex_env, lp->cplex_lp); + if (ncols == 0) { + fprintf (stderr, "No columns in LP\n"); + rval = 1; goto CLEANUP; + } + nrows = CPXgetnumrows (lp->cplex_env, lp->cplex_lp); + if (nrows == 0) { + fprintf (stderr ,"No rows in LP\n"); + rval = 1; goto CLEANUP; + } + + b->cstat = CC_SAFE_MALLOC (ncols, int); + b->rstat = CC_SAFE_MALLOC (nrows, int); + b->dnorm = CC_SAFE_MALLOC (nrows, double); + if (!b->cstat || !b->rstat || !b->dnorm) { + fprintf (stderr, "out of memory in CClp_get_basis_and_norms\n"); + rval = 1; goto CLEANUP; + } + + rval = CPXgetbasednorms (lp->cplex_env, lp->cplex_lp, b->cstat, b->rstat, + b->dnorm); + if (rval) { + fprintf (stderr, "CPXgetbasednorms failed\n"); goto CLEANUP; + } + + return 0; + +CLEANUP: + + CClp_free_basis (b); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_load_basis_and_norms (CClp *lp, CClpbasis *b) +#else +int CClp_load_basis_and_norms (lp, b) +CClp *lp; +CClpbasis *b; +#endif +{ + int rval = 0; + + if (b->cstat && b->rstat && b->dnorm) { + rval = CPXcopybasednorms (lp->cplex_env, lp->cplex_lp, b->cstat, + b->rstat, b->dnorm); + if (rval) { + fprintf (stderr, "CPXcopybasednorms failed\n"); goto CLEANUP; + } + } else if (b->cstat && b->rstat) { + rval = CPXloadbase (lp->cplex_env, lp->cplex_lp, b->cstat, b->rstat); + if (rval) { + fprintf (stderr, "CPXloadbase failed\n"); goto CLEANUP; + } + } else { + printf ("WARNING: No basis or norms in call to load_basis_and_norms\n"); + fflush (stdout); + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_basis (CClp *lp, int *cstat, int *rstat) +#else +int CClp_basis (lp, cstat, rstat) +CClp *lp; +int *cstat; +int *rstat; +#endif +{ + int rval; + + rval = CPXgetbase (lp->cplex_env, lp->cplex_lp, cstat, rstat); + if (rval) { + fprintf (stderr, "CPXgetbase failed\n"); + return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_loadbasis (CClp *lp, int *cstat, int *rstat) +#else +int CClp_loadbasis (lp, cstat, rstat) +CClp *lp; +int *cstat, *rstat; +#endif +{ + int rval; + + rval = CPXloadbase (lp->cplex_env, lp->cplex_lp, cstat, rstat); + if (rval) { + fprintf (stderr, "CPXloadbase failed\n"); + return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_getbasis_and_norms (CClp *lp, int *cstat, int *rstat, double *dnorm) +#else +int CClp_getbasis_and_norms (lp, cstat, rstat, dnorm) +CClp *lp; +int *cstat, *rstat; +double *dnorm; +#endif +{ + int rval; + + rval = CPXgetbasednorms (lp->cplex_env, lp->cplex_lp, cstat, rstat, + dnorm); + if (rval) { + fprintf (stderr, "CPXgetbasednorms failed\n"); + return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_loadbasis_and_norms (CClp *lp, int *cstat, int *rstat, + double *dnorm) +#else +int CClp_loadbasis_and_norms (lp, cstat, rstat, dnorm) +CClp *lp; +int *cstat, *rstat; +double *dnorm; +#endif +{ + int rval; + + rval = CPXcopybasednorms (lp->cplex_env, lp->cplex_lp, cstat, rstat, + dnorm); + if (rval) { + fprintf (stderr, "CPXcopybasednorms failed\n"); + return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_x (CClp *lp, double *x) +#else +int CClp_x (lp, x) +CClp *lp; +double *x; +#endif +{ + int rval = 0; + int ncols; + + ncols = CPXgetnumcols (lp->cplex_env, lp->cplex_lp); + if (ncols == 0) { + fprintf (stderr, "No columns in LP\n"); + return 1; + } + rval = CPXgetx (lp->cplex_env, lp->cplex_lp, x, 0, ncols - 1); + if (rval) { + fprintf (stderr, "CPXgetx failed\n"); + return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_rc (CClp *lp, double *rc) +#else +int CClp_rc (lp, rc) +CClp *lp; +double *rc; +#endif +{ + int rval = 0; + int ncols; + + ncols = CPXgetnumcols (lp->cplex_env, lp->cplex_lp); + if (ncols == 0) { + fprintf (stderr, "No columns in LP\n"); return 1; + } + rval = CPXgetdj (lp->cplex_env, lp->cplex_lp, rc, 0, ncols - 1); + if (rval) { + fprintf (stderr, "CPXgetdj failed\n"); return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_pi_range (CClp *lp, double *pi, int from, int to) +#else +int CClp_pi_range (lp, pi, from, to) +CClp *lp; +double *pi; +int from, to; +#endif +{ + int rval = 0; + + rval = CPXgetpi (lp->cplex_env, lp->cplex_lp, pi, from, to); + if (rval) { + fprintf (stderr, "CPXgetpi failed\n"); return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_objval (CClp *lp, double *obj) +#else +int CClp_objval (lp, obj) +CClp *lp; +double *obj; +#endif +{ + int rval; + + rval = CPXgetobjval (lp->cplex_env, lp->cplex_lp, obj); + if (rval) { + fprintf (stderr, "CPXgetobjval failed\n"); + return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_nonzeros (CClp *lp) +#else +int CClp_nonzeros (lp) +CClp *lp; +#endif +{ + int k; + + k = CPXgetnumnz (lp->cplex_env, lp->cplex_lp); + printf ("NONZEROS = %d\n", k); fflush (stdout); + return k; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_status (CClp *lp, int *status) +#else +int CClp_status (lp, status) +CClp *lp; +int *status; +#endif +{ + int solmethod, solstat; + + solmethod = CPXgetmethod (lp->cplex_env, lp->cplex_lp); + if (solmethod == CPXALG_PRIMAL || solmethod == CPXALG_DUAL) { + solstat = CPXgetstat (lp->cplex_env, lp->cplex_lp); + if (solstat == CPX_OPTIMAL || solstat == CPX_OPTIMAL_INFEAS) { + *status = 0; + return 0; + } else if (solstat == CPX_UNBOUNDED && solmethod == CPXALG_DUAL) { + *status = 1; + return 0; + } else { + fprintf (stderr, "lp in an unknown state: %d %d\n", + solmethod, solstat); + *status = -1; + return 1; + } + } else { + fprintf (stderr, "lp not solved by usual methods: %d\n", solmethod); + *status = -2; + return 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_getweight (CClp *lp, int nrows, int *rmatbeg, int *rmatind, + double *rmatval, double *weight) +#else +int CClp_getweight (lp, nrows, rmatbeg, rmatind, rmatval, weight) +CClp *lp; +int nrows; +int *rmatbeg; +int *rmatind; +double *rmatval; +double *weight; +#endif +{ + int rval = 0; + + rval = CPXgetweight (lp->cplex_env, lp->cplex_lp, nrows, + rmatbeg, rmatind, rmatval, weight, CPX_DPRIIND_STEEP); + if (rval) { + fprintf (stderr, "CPXgetweight failed\n"); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_dump_lp (CClp *lp, char *fname) +#else +int CClp_dump_lp (lp, fname) +CClp *lp; +char *fname; +#endif +{ + int rval = 0; + + rval = CPXlpwrite (lp->cplex_env, lp->cplex_lp, fname); + if (rval) { + fprintf (stderr, "CPXlpwrite failed\n"); + } + return rval; +} + +#define OURCPLEXZERO (1.0E-10) +#define OURCPLEX_INTTOL (0.0001) + +#ifdef CC_PROTOTYPE_ANSI +int CClp_getgoodlist (CClp *lp, int *goodlist, int *goodlen_p, + double *downpen, double *uppen) +#else +int CClp_getgoodlist (lp, goodlist, goodlen_p, downpen, uppen) +CClp *lp; +int *goodlist; +int *goodlen_p; +double *downpen; +double *uppen; +#endif +{ + int rval = 0; + int ncols, i, k; + int *cstat = (int *) NULL; + double *x = (double *) NULL; + + /* Call CPXdualopt and verify optimality */ + + if ( CPXdualopt (lp->cplex_env, lp->cplex_lp) ) { + fprintf (stderr, "CPXdualopt failed\n"); + rval = 1; goto CLEANUP; + } + + ncols = CPXgetnumcols (lp->cplex_env, lp->cplex_lp); + if ( ncols == 0 ) { + fprintf (stderr, "No columns in LP\n"); + rval = 1; goto CLEANUP; + } + + x = CC_SAFE_MALLOC (ncols, double); + if (x == (double *) NULL) { + fprintf (stderr, "out of memory in branch_getgoodlist\n"); + rval = 1; goto CLEANUP; + } + if (CPXgetx (lp->cplex_env, lp->cplex_lp, x, 0, ncols-1)) { + fprintf (stderr, "CPXgetx failed\n"); + rval = 1; goto CLEANUP; + } + + cstat = CC_SAFE_MALLOC (ncols, int); + if ( cstat == (int *) NULL ) { + fprintf (stderr, "Out of memory\n"); + rval = 1; goto CLEANUP; + } + + /* Get basis */ + + if ( CPXgetbase (lp->cplex_env, lp->cplex_lp, cstat, (int *) NULL) ) { + fprintf (stderr, "CPXgetbase failed\n"); + rval = 1; goto CLEANUP; + } + + /* Make initial goodlist and goodlen */ + + *goodlen_p = 0; + for (i = 0; i < ncols; i++) { + if ( cstat[i] == 1 ) { + goodlist[(*goodlen_p)++] = i; + } + } + + /* Call CPXmdleave */ + + if ( CPXmdleave (lp->cplex_env, lp->cplex_lp, goodlist, *goodlen_p, + downpen, uppen)) { + fprintf (stderr, "CPXmdleave failed\n"); + rval = 1; goto CLEANUP; + } + + /* Keep only the nondegenerate ones */ + + k = *goodlen_p; + *goodlen_p = 0; + for (i = 0; i < k; i++) { + if ( CC_OURABS (downpen[i]) > OURCPLEXZERO && + CC_OURABS (uppen[i]) > OURCPLEXZERO && + x[goodlist[i]] >= OURCPLEX_INTTOL && + x[goodlist[i]] <= 1 - OURCPLEX_INTTOL ) { + goodlist[*goodlen_p] = goodlist[i]; + downpen[*goodlen_p] = x[goodlist[i]] * downpen[i]; + uppen[*goodlen_p] = (1.0 - x[goodlist[i]]) * uppen[i]; + (*goodlen_p)++; + } + } + +CLEANUP: + + CC_IFFREE (cstat, int); + CC_IFFREE (x, double); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_strongbranch (CClp *lp, int *candidatelist, int ncand, + double *downpen, double *uppen, int iterations, + double *upperbound) +#else +int CClp_strongbranch (lp, candidatelist, ncand, downpen, uppen, iterations, + upperbound) +CClp *lp; +int *candidatelist; +int ncand; +double *downpen; +double *uppen; +int iterations; +double *upperbound; +#endif +{ + double oldupperbound; + int rval = 0; + int sval = 0; + + if (upperbound) { + rval = CPXgetdblparam (lp->cplex_env, CPX_PARAM_OBJULIM, + &oldupperbound); + if (rval) { + fprintf (stderr, "CPXgetdblparam failed\n"); return rval; + } + rval = CPXsetdblparam (lp->cplex_env, CPX_PARAM_OBJULIM, + *upperbound); + if (rval) { + fprintf (stderr, "CPXsetdblparam failed\n"); return rval; + } + } + + rval = CPXstrongbranch (lp->cplex_env, lp->cplex_lp, candidatelist, + ncand, downpen, uppen, iterations); + if (rval) { + fprintf (stderr, "CPXstrongbranch failed\n"); + if (upperbound) { + sval = CPXsetdblparam (lp->cplex_env, CPX_PARAM_OBJULIM, + oldupperbound); + if (sval) { + fprintf (stderr, + "CPXsetdblparam failed with return code %d\n", + sval); + } + } + return rval; + } + + if (upperbound) { + rval = CPXsetdblparam (lp->cplex_env, CPX_PARAM_OBJULIM, + oldupperbound); + if (rval) { + fprintf (stderr, "CPXsetdblparam failed\n"); return rval; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_getfarkasmultipliers (CClp *lp, double *y) +#else +int CClp_getfarkasmultipliers (lp, y) +CClp *lp; +double *y; +#endif +{ + int rval = 0; + + int i = 0, nrows, idiv, jdiv; + double val, lb, ub; + int *bhead = (int *) NULL; + char *sense = (char *) NULL; + + if ( lp->cplex_env == (struct cpxenv *) NULL || + lp->cplex_lp == (struct cpxlp *) NULL) { + rval = 1; fprintf (stderr, "env object or lp object is NULL\n"); + goto CLEANUP; + } + + if ( CPXgetmethod (lp->cplex_env, lp->cplex_lp) != CPXALG_DUAL || + CPXgetstat (lp->cplex_env, lp->cplex_lp ) != CPX_UNBOUNDED ) { + rval = 1; fprintf (stderr, "Incorrect solution type\n"); + goto CLEANUP; + } + + if ( CPXgetijdiv (lp->cplex_env, lp->cplex_lp, &idiv, &jdiv) ) { + rval = 1; fprintf (stderr, "CPXgetijdiv failed\n"); + goto CLEANUP; + } + + if ( (jdiv == -1 && idiv == -1) || + (jdiv != -1 && idiv != -1) ) { + rval = 1; fprintf (stderr, "CPLEX returned illegal indices\n"); + goto CLEANUP; + } + + nrows = CPXgetnumrows (lp->cplex_env, lp->cplex_lp); + if ( nrows == 0 ) { + rval = 1; fprintf (stderr, "lp->cplex_lp has no rows\n"); + goto CLEANUP; + } + + bhead = CC_SAFE_MALLOC (nrows, int); + sense = CC_SAFE_MALLOC (nrows, char); + if ( bhead == (int *) NULL || + sense == (char *) NULL ) { + rval = -1; fprintf (stderr, "Out of memory\n"); + goto CLEANUP; + } + + if ( CPXgetbhead (lp->cplex_env, lp->cplex_lp, bhead, NULL) ) { + rval = 1; fprintf (stderr, "CPXgetbhead failed\n"); + goto CLEANUP; + } + + if ( CPXgetsense (lp->cplex_env, lp->cplex_lp, sense, 0, nrows-1) ) { + rval = 1; fprintf (stderr, "CPXgetsense failed\n"); + goto CLEANUP; + } + + if ( jdiv >= 0 ) { + for (i = 0; i < nrows; i++) { + if ( bhead[i] == jdiv ) break; + } + if ( i == nrows ) { + rval = 1; fprintf (stderr, "Basis index not found\n"); + goto CLEANUP; + } + if ( CPXgetx (lp->cplex_env, lp->cplex_lp, &val, jdiv, jdiv) ) { + rval = 1; fprintf (stderr, "CPXgetx failed\n"); + goto CLEANUP; + } + if ( CPXgetlb (lp->cplex_env, lp->cplex_lp, &lb, jdiv, jdiv) ) { + rval = 1; fprintf (stderr, "CPXgetlb failed\n"); + goto CLEANUP; + } + if ( CPXgetub (lp->cplex_env, lp->cplex_lp, &ub, jdiv, jdiv) ) { + rval = 1; fprintf (stderr, "CPXgetub failed\n"); + goto CLEANUP; + } + } else { + for (i = 0; i < nrows; i++) { + if ( bhead[i] == -idiv-1 ) break; + } + if ( i == nrows ) { + rval = 1; fprintf (stderr, "Basis index not found\n"); + goto CLEANUP; + } + if ( CPXgetslack (lp->cplex_env, lp->cplex_lp, &val, idiv, idiv) ) { + rval = 1; fprintf (stderr, "CPXgetslack failed\n"); + goto CLEANUP; + } + lb = 0.0; + if ( sense[idiv] == 'E' ) ub = 0.0; + else ub = INFBOUND; + if ( sense[idiv] == 'G' ) val *= -1.0; + } + + if ( CPXbinvrow (lp->cplex_env, lp->cplex_lp, i, y) ) { + rval = 1; fprintf (stderr, "CPXbinvrow failed\n"); + goto CLEANUP; + } + + if ( val < lb ) { + for (i = 0; i < nrows; i++) y[i] *= -1.0; + } + + for (i = 0; i < nrows; i++) { + if ( sense[i] == 'L' && y[i] > 0.0 ) y[i] = 0.0; + if ( sense[i] == 'G' && y[i] < 0.0 ) y[i] = 0.0; + } + +CLEANUP: + + CC_IFFREE (bhead, int); + CC_IFFREE (sense, char); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_pivotin (CClp *lp, int i) +#else +void CClp_pivotin (lp, i) +CClp *lp; +int i; +#endif +{ + int locali = i; + + if ( CPXpivotin (lp->cplex_env, lp->cplex_lp, &locali, 1) ) { + fprintf (stderr, "CPXpivotin failed, continuing anyway\n"); + } +} + diff --git a/contrib/blossom/concorde97/LP/lpsolve.c b/contrib/blossom/concorde97/LP/lpsolve.c new file mode 100644 index 0000000000000000000000000000000000000000..374ede332c091796ac0f9ccb02650769a8abaf24 --- /dev/null +++ b/contrib/blossom/concorde97/LP/lpsolve.c @@ -0,0 +1,797 @@ +/***************************************************************************/ +/* */ +/* Interface Routines to an LP Solver */ +/* */ +/* */ +/* */ +/* NOTE: These are just dummy routines. To make use of the LP-based */ +/* portion of concorde you will need to write an interface between these */ +/* routines and an LP solve. To use the CPLEX 4.1 library, the code in */ +/* lpcplex.c can be used instead of this file. */ +/* */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: April 17, 1997 */ +/* June 19, 1997 (bico, REB) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void CClp_init_struct (CClp *lp) */ +/* INITIALIZES the fields of the LP structure to NULL. */ +/* */ +/* int CClp_init (CClp *lp) */ +/* INITIALIZES the LP. */ +/* */ +/* void CClp_free (CClp *lp) */ +/* FREES the LP (but not pointer to the LP). */ +/* */ +/* int CClp_loadlp (CClp *lp, char *name, int ncols, int nrows, */ +/* int objsense, double *obj, double *rhs, char *sense, */ +/* int *matbeg, int *matcnt, */ +/* int *matind, double *matval, */ +/* double *lb, double *ub) */ +/* LOADS the data into the LP. The memory is used by the LP solver, */ +/* and thus should not be freed until after a call to CClp_free. */ +/* -name attaches a name to the LP (it can be used by the LP solver */ +/* in io routines) */ +/* -ncols and nrows give the number of columns and rows in the LP */ +/* -objsense should be -1 for minimize and 1 for maximize */ +/* -obj and rhs are arrays giving the objective function and rhs */ +/* -sense is an array specifying 'L', 'E', or 'G' for each of the */ +/* rows */ +/* -matbeg, matcnt, matind, and matval give the coefficients of */ +/* the contraint matrix in column by column order. matbeg gives */ +/* gives the index of the start of each column; matcnt gives the */ +/* number of coefficients in each column; matind gives the indices */ +/* of the rows where the coefficients are located in the contraint */ +/* matrix (so for column j, the indices are given in matcnt[j] */ +/* locations starting at matind[matbeg[j]]; and matval gives the */ +/* actual coefficients (organized like matind). */ +/* -lb and ub are arrays giving the upper and lower bounds of */ +/* the variables. */ +/* */ +/* int CClp_opt (CClp *lp, int method) */ +/* CALLS designated LP solution method. */ +/* */ +/* int CClp_dualopt (CClp *lp) */ +/* CALLS the dual simplex method. */ +/* */ +/* int CClp_limited_dualopt (CClp *lp, int lim, double *upperbound, */ +/* int *status) */ +/* CALLS the dual simplex method with a limit on the number of pivots.*/ +/* -upperbound it is used to cutoff the dual simplex method (when */ +/* the objective value reaches upperbound); it can be NULL */ +/* -status returns the status of the optimization (it can be NULL) */ +/* */ +/* void CClp_pivotin (CClp *lp, int i) */ +/* Puts slack/artificial on row i into the resident basis */ +/* If there is no resident basis, the call fails */ +/* */ +/* int CClp_primalopt (CClp *lp) */ +/* CALLS the primal simplex method. */ +/* */ +/* int CClp_addrows (CClp *lp, int newrows, int newnz, double *rhs, */ +/* char *sense, int *rmatbeg, int *rmatind, double *rmatval) */ +/* ADDS the rows to the LP. */ +/* -newrows is the number of rows to be added */ +/* -newnz is the number of nonzero coefficients in the new rows */ +/* -rhs is an array of the rhs values for the new rows */ +/* -sense is 'L', 'E', or 'G' for each of the new rows */ +/* -rmatbeg, rmatind, and rmatval give the coefficients of the */ +/* new rows in sparse format. The arrays can be freed after the */ +/* call. */ +/* */ +/* int CClp_addcols (CClp *lp, int newcols, int newnz, double *obj, */ +/* int *cmatbeg, int *cmatind, double *cmatval, */ +/* double *lb, double *ub) */ +/* ADDS the columns to the LP. */ +/* */ +/* int CClp_delete_row (CClp *lp, int i) */ +/* DELETES row i of the LP. */ +/* */ +/* int CClp_delete_set_of_rows (CClp *lp, int *delstat) */ +/* DELETES the rows corresponding to 1 entries in delstat. */ +/* -delstat is a 0/1 array having an entry for each row */ +/* */ +/* int CClp_delete_column (CClp *lp, int i) */ +/* DELETES column i from the LP. */ +/* */ +/* int CClp_delete_set_of_columns (CClp *lp, int *delstat) */ +/* DELETES the columns corresponding to the 1 entries in delstat. */ +/* -delstat is a 0/1 array having an entry for each column */ +/* */ +/* int CClp_setbnd (CClp *lp, int col, char lower_or_upper, double bnd) */ +/* SETS the bound on the variable index by col. */ +/* -lower_or_upper should be either 'L' or 'U' */ +/* */ +/* void CClp_init_basis (CClpbasis *b) */ +/* INITIALIZES the fields of the basis structure. */ +/* */ +/* void CClp_free_basis (CClpbasis *b) */ +/* FREEs the basis structure. */ +/* */ +/* int CClp_get_basis_and_norms (CClp *lp, CClpbasis *b) */ +/* RETURNS the current basis and dual norms. */ +/* Note: The arrays are allocated by this function are should be */ +/* freed by a call to CC_lp_free_basis (). */ +/* */ +/* int CClp_load_basis_and_norms (CClp *lp, CClpbasis *b) */ +/* LOADS the basis and norm int the LP. */ +/* Note: If the norms field is not set, then just the basis is loaded.*/ +/* */ +/* int CClp_basis (CClp *lp, int *cstat, int *rstat) */ +/* RETURNS the current basis. cstat or rstat can by NULL. */ +/* -cstat should be an array of length at least ncols */ +/* -rstat should be an array of length at least nrows */ +/* */ +/* int CClp_loadbasis (CClp *lp, int *cstat, int *rstat) */ +/* LOADS the basis into the LP. */ +/* */ +/* int CClp_getbasis_and_norms (CClp *lp, int *cstat, int *rstat, */ +/* double *dnorm) */ +/* RETURNS the current basis and dual norms - these items should be */ +/* used as a pair, in calls to CClp_loadbasis_and_norms. */ +/* -dnorms should be an array of length at least nrows */ +/* */ +/* int CClp_loadbasis_and_norms (CClp *lp,int *cstat, int *rstat, */ +/* double *dnorm) */ +/* LOADS the basis and dual norms into the LP. (This pair should */ +/* have been obtained by a call to CClp_getbasis_and_norms. */ +/* */ +/* int CClp_x (CClp *lp, double *x) */ +/* RETURNS the current LP solution. */ +/* -x should be an array of length at least ncols */ +/* */ +/* int CClp_rc (CClp *lp, double *rc) */ +/* RETURNS the current reduced costs. */ +/* -rc should be an array of length at least ncols */ +/* */ +/* int CClp_pi_range (CClp *lp, double *pi, int from, int to) */ +/* RETURNS the dual values on the constraints indexed [from, to]. */ +/* -pi should be an array of length at least (to-from+1) */ +/* */ +/* int CClp_objval (CClp *lp, double *obj) */ +/* RETURNS the objective value of the lp. */ +/* */ +/* int CClp_nonzeros (CClp *lp) */ +/* RETURNS the number of nonzeros in the LP. */ +/* */ +/* int CClp_status (CClp *lp, int *status) */ +/* CHECKS whether the current lp is infeasible or whether an optimal */ +/* solution has been found. It returns an error if the LP has not */ +/* not been optimized. */ +/* -lp is the lp */ +/* -status returns 0 if the lp has an optimal solution and 1 if it */ +/* is infeasible. */ +/* */ +/* int CClp_getweight (CClp *lp, int nrows, int *rmatbeg, int *rmatind, */ +/* double *rmatval, double *weight) */ +/* COMPUTES the duals of the steepest edge norms for the n rows */ +/* specified in rmatbeg, rmatind, and rmatval. */ +/* -weight returns the array of weights; the array should be at */ +/* least nrows long */ +/* */ +/* int CClp_dump_lp (CClp *lp, char *fname) */ +/* WRITES the LP to file fname. */ +/* */ +/* int CClp_getgoodlist (CClp *lp, int *goodlist, int *ngood, */ +/* double *downpen, double *uppen) */ +/* RETURNS an array of the column indices corresponding to variables */ +/* that move in both the up and down directions. This is a useful */ +/* list of candidates for strong branching. */ +/* -goodlist, downpen and uppen should be arrays of length at */ +/* least ncols. */ +/* */ +/* int CClp_strongbranch (CClp *lp, int *candidatelist, int ncand, */ +/* double *downpen, double *uppen, int iterations, */ +/* double *upperbound) */ +/* RETURNS estimates of the lp values obtained by setting each of the */ +/* ncand variables listed in candidatelist to 0 and 1. The estimates*/ +/* are obtained by performing iterations pivots of dual simplex */ +/* method. If upperbound is not NULL, then it is used to cutoff the */ +/* dual simplex method. */ +/* -downpen and uppen should be arrays of length at least ncand */ +/* */ +/* int CClp_getfarkasmultipliers (CClp *lp, double *y) */ +/* RETURNS the multipliers for a Farkas' proof after dualopt returns */ +/* with an unbound lp. */ +/* -y should point to an array at least as long as the number of */ +/* rows */ +/* The y[] computed will satisfy the following: */ +/* */ +/* y_i <= 0 for <= constraints */ +/* y_i >= 0 for >= constraints */ +/* */ +/* y'b - sum (y'A_j * u_j: y'A_j > 0) */ +/* - sum (y'A_j * l_j: y'A_j < 0) > 0 */ +/* */ +/* where b is the rhs vector, u_j is the upper bound on variable x_j, */ +/* l_j the lower bound, and A_j the constraint matrix column for x_j. */ +/* */ +/* */ +/* NOTES: */ +/* */ +/* */ +/***************************************************************************/ + + +#include "machdefs.h" +#include "util.h" +#include "macrorus.h" +#include "lp.h" + + +#ifdef CC_PROTOTYPE_ANSI + +static void + lp_message (void); + +#else + +static void + lp_message (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +static void lp_message (void) +#else +static void lp_message () +#endif +{ + fprintf (stderr, "need to link an lp solver to use this function\n"); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_init_struct (CClp *lp) +#else +void CClp_init_struct (lp) +CClp *lp; +#endif +{ + if (lp) lp_message (); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_init (CClp *lp) +#else +int CClp_init (lp) +CClp *lp; +#endif +{ + if (lp) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_free (CClp *lp) +#else +void CClp_free (lp) +CClp *lp; +#endif +{ + if (lp) lp_message (); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_loadlp (CClp *lp, char *name, int ncols, int nrows, + int objsense, double *obj, double *rhs, char *sense, + int *matbeg, int *matcnt, + int *matind, double *matval, + double *lb, double *ub) + +#else +int CClp_loadlp (lp, name, ncols, nrows, objsense, obj, rhs, sense, matbeg, + matcnt, matind, matval, lb, ub) +CClp *lp; +char *name; +int ncols, nrows; +int objsense; +double *obj, *rhs; +char *sense; +int *matbeg, *matcnt, *matind; +double *matval, *lb, *ub; +#endif +{ + if (lp || name || ncols || nrows || objsense || obj || rhs || sense + || matbeg || matcnt || matind || matval || lb || ub) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_opt (CClp *lp, int method) +#else +int CClp_opt (lp, method) +CClp *lp; +int method; +#endif +{ + if (lp || method) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_dualopt (CClp *lp) +#else +int CClp_dualopt (lp) +CClp *lp; +#endif +{ + if (lp) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_limited_dualopt (CClp *lp, int iterationlim, int *status, + double *objupperlim) +#else +int CClp_limited_dualopt (lp, iterationlim, status, objupperlim) +CClp *lp; +int iterationlim; +int *status; +double *objupperlim; +#endif +{ + if (lp || iterationlim || status || objupperlim) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_primalopt (CClp *lp) +#else +int CClp_primalopt (lp) +CClp *lp; +#endif +{ + if (lp) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_addrows (CClp *lp, int newrows, int newnz, double *rhs, char *sense, + int *rmatbeg, int *rmatind, double *rmatval) +#else +int CClp_addrows (lp, newrows, newnz, rhs, sense, rmatbeg, rmatind, rmatval) +CClp *lp; +int newrows, newnz; +double *rhs; +char *sense; +int *rmatbeg, *rmatind; +double *rmatval; +#endif +{ + if (lp || newrows || newnz || rhs || sense || rmatbeg || rmatind + || rmatval) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_addcols (CClp *lp, int newcols, int newnz, double *obj, + int *cmatbeg, int *cmatind, double *cmatval, + double *lb, double *ub) +#else +int CClp_addcols (lp, newcols, newnz, obj, cmatbeg, cmatind, cmatval, lb, ub) +CClp *lp; +int newcols, newnz; +double *obj; +int *cmatbeg, *cmatind; +double *cmatval; +double *lb, *ub; +#endif +{ + if (lp || newcols || newnz || obj || cmatbeg || cmatind || cmatval + || lb || ub) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_delete_row (CClp *lp, int i) +#else +int CClp_delete_row (lp, i) +CClp *lp; +int i; +#endif +{ + if (lp || i) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_delete_set_of_rows (CClp *lp, int *delstat) +#else +int CClp_delete_set_of_rows (lp, delstat) +CClp *lp; +int *delstat; +#endif +{ + if (lp || delstat) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_delete_column (CClp *lp, int i) +#else +int CClp_delete_column (lp, i) +CClp *lp; +int i; +#endif +{ + if (lp || i) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_delete_set_of_columns (CClp *lp, int *delstat) +#else +int CClp_delete_set_of_columns (lp, delstat) +CClp *lp; +int *delstat; +#endif +{ + if (lp || delstat) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_setbnd (CClp *lp, int col, char lower_or_upper, double bnd) +#else +int CClp_setbnd (lp, col, lower_or_upper, bnd) +CClp *lp; +int col; +char lower_or_upper; +double bnd; +#endif +{ + if (lp || col || lower_or_upper || bnd) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_init_basis (CClpbasis *b) +#else +void CClp_init_basis (b) +CClpbasis *b; +#endif +{ + if (b) lp_message (); +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_free_basis (CClpbasis *b) +#else +void CClp_free_basis (b) +CClpbasis *b; +#endif +{ + if (b) lp_message (); +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_get_basis_and_norms (CClp *lp, CClpbasis *b) +#else +int CClp_get_basis_and_norms (lp, b) +CClp *lp; +CClpbasis *b; +#endif +{ + if (lp || b) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_load_basis_and_norms (CClp *lp, CClpbasis *b) +#else +int CClp_load_basis_and_norms (lp, b) +CClp *lp; +CClpbasis *b; +#endif +{ + if (lp || b) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_basis (CClp *lp, int *cstat, int *rstat) +#else +int CClp_basis (lp, cstat, rstat) +CClp *lp; +int *cstat; +int *rstat; +#endif +{ + if (lp || cstat || rstat) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_loadbasis (CClp *lp, int *cstat, int *rstat) +#else +int CClp_loadbasis (lp, cstat, rstat) +CClp *lp; +int *cstat, *rstat; +#endif +{ + if (lp || cstat || rstat) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_getbasis_and_norms (CClp *lp, int *cstat, int *rstat, double *dnorm) +#else +int CClp_getbasis_and_norms (lp, cstat, rstat, dnorm) +CClp *lp; +int *cstat, *rstat; +double *dnorm; +#endif +{ + if (lp || cstat || rstat || dnorm) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_loadbasis_and_norms (CClp *lp, int *cstat, int *rstat, + double *dnorm) +#else +int CClp_loadbasis_and_norms (lp, cstat, rstat, dnorm) +CClp *lp; +int *cstat, *rstat; +double *dnorm; +#endif +{ + if (lp || cstat || rstat || dnorm) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_x (CClp *lp, double *x) +#else +int CClp_x (lp, x) +CClp *lp; +double *x; +#endif +{ + if (lp || x) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_rc (CClp *lp, double *rc) +#else +int CClp_rc (lp, rc) +CClp *lp; +double *rc; +#endif +{ + if (lp || rc) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_pi_range (CClp *lp, double *pi, int from, int to) +#else +int CClp_pi_range (lp, pi, from, to) +CClp *lp; +double *pi; +int from, to; +#endif +{ + if (lp || pi || from || to) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_objval (CClp *lp, double *obj) +#else +int CClp_objval (lp, obj) +CClp *lp; +double *obj; +#endif +{ + if (lp || obj) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_nonzeros (CClp *lp) +#else +int CClp_nonzeros (lp) +CClp *lp; +#endif +{ + if (lp) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_status (CClp *lp, int *status) +#else +int CClp_status (lp, status) +CClp *lp; +int *status; +#endif +{ + if (lp || status) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_getweight (CClp *lp, int nrows, int *rmatbeg, int *rmatind, + double *rmatval, double *weight) +#else +int CClp_getweight (lp, nrows, rmatbeg, rmatind, rmatval, weight) +CClp *lp; +int nrows; +int *rmatbeg; +int *rmatind; +double *rmatval; +double *weight; +#endif +{ + if (lp || nrows || rmatbeg || rmatind || rmatval || weight) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_dump_lp (CClp *lp, char *fname) +#else +int CClp_dump_lp (lp, fname) +CClp *lp; +char *fname; +#endif +{ + if (lp || fname ) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_getgoodlist (CClp *lp, int *goodlist, int *goodlen_p, + double *downpen, double *uppen) +#else +int CClp_getgoodlist (lp, goodlist, goodlen_p, downpen, uppen) +CClp *lp; +int *goodlist; +int *goodlen_p; +double *downpen; +double *uppen; +#endif +{ + if (lp || goodlist || goodlen_p || downpen || uppen) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_strongbranch (CClp *lp, int *candidatelist, int ncand, + double *downpen, double *uppen, int iterations, double *upperbound) +#else +int CClp_strongbranch (lp, candidatelist, ncand, downpen, uppen, iterations, + upperbound) +CClp *lp; +int *candidatelist; +int ncand; +double *downpen; +double *uppen; +int iterations; +double *upperbound; +#endif +{ + if (lp || candidatelist || ncand || downpen || uppen || iterations + || upperbound) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CClp_getfarkasmultipliers (CClp *lp, double *y) +#else +int CClp_getfarkasmultipliers (lp, y) +CClp *lp; +double *y; +#endif +{ + if (lp || y) { + lp_message (); return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CClp_pivotin (CClp *lp, int i) +#else +void CClp_pivotin (lp, i) +CClp *lp; +int i; +#endif +{ + if (lp || i) lp_message (); +} diff --git a/contrib/blossom/concorde97/Makefile b/contrib/blossom/concorde97/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ea06d1ee1c798d704f5221ce8311e01c0dbf34bc --- /dev/null +++ b/contrib/blossom/concorde97/Makefile @@ -0,0 +1,29 @@ +SHELL=/bin/sh + +DIRS=BIGGUY CUT EDGEGEN FMATCH KDTREE LINKERN LP TSP UTIL XSTUFF + +.PHONY: top +top: concorde.h concorde.a + +all: concorde.h concorde.a + for i in $(DIRS); do $(MAKE) -C $$i $@; done + +.PHONY: concorde.a +concorde.a: + for i in $(DIRS); do $(MAKE) -C $$i concorde.a; done + +INC_LIST=INCLUDE/util.h INCLUDE/bigguy.h INCLUDE/lp.h \ + INCLUDE/kdtree.h INCLUDE/cut.h INCLUDE/edgegen.h \ + INCLUDE/tsp.h INCLUDE/Xstuff.h INCLUDE/fmatch.h \ + INCLUDE/linkern.h INCLUDE/macrorus.h + +concorde.h: INCLUDE/prefix.h $(INC_LIST) Makefile + cat INCLUDE/prefix.h > concorde.h + cat $(INC_LIST) | grep -v '#include' >> concorde.h + +clean: + -rm -f *.o concorde.h concorde.a + for i in $(DIRS); do $(MAKE) -C $$i $@; done + +%: + for i in $(DIRS); do $(MAKE) -C $$i $@; done diff --git a/contrib/blossom/concorde97/Makefile.conf b/contrib/blossom/concorde97/Makefile.conf new file mode 100644 index 0000000000000000000000000000000000000000..c77a920327da3d5ec1e54531843c7d96899ad73e --- /dev/null +++ b/contrib/blossom/concorde97/Makefile.conf @@ -0,0 +1,242 @@ +### This file contains some compilation configuration options. +### The bottom half of this file contains several predefined configurations. +### A predefined configuration can be selected by using using a definition +### "SYS=sysname" at the top of this file, where sysname is the name used +### in this file to describe the configuration. +### +### Or, you can create your own configuration by modifying the default values +### after the comment "DEFAULT VALUES BEGIN HERE" +### +### Note that if you are using cplex, you will have to modify the cplex +### variables even if you use a predefined configuration. +### +### The predefined systems are (the os and compiler versions given are the +### ones on which the configuration has been tested): +### +### vendor/processor o/s compiler configuration name +### ------------------- -------- -------- ------------------ +### DEC Alpha Digital Unix 4.0A cc ALPHA +### DEC Alpha Digital Unix 4.0a gcc 2.7.2.1 ALPHA_GCC +### DEC Alpha Linux/Alpha 2.0.27 gcc ALPHA_LINUX +### Intel x86-compatible Solaris/x86 2.5 gcc 2.7.2.1 INTEL_SOLARIS +### Intel x86-compatible Solaris/x86 2.5 cc 3.0.1 INTEL_SOLARIS_CC +### *Intel x86-compatible Linux/x86 1.2.13 gcc 2.7.2 INTEL_LINUX +### **Intel x86-compatible FreeBSD gcc INTEL_BSD +### IBM RS6000 AIX 4.2.1 cc RS6000 +### IBM RS6000 AIX 4.2.1 gcc 2.7.2 RS6000_GCC +### IBM RS6000 AIX 3.2.5 cc RS6000 +### IBM RS6000 AIX 3.2.5 gcc 2.7.2 RS6000_GCC +### Silicon Graphics IRIX 5.3 cc SILICON +### Silicon Graphics IRIX 5.3 gcc 2.7.2.2 SILICON_GCC +### Sun UltraSparc Solaris 2.5.1 gcc 2.7.2.1 SPARC +### Sun UltraSparc Solaris 2.5.1 cc 4.0,p42 SPARC_CC +### *Sun Sparc Solaris 2.5.1 gcc 2.7.2.1 SPARC +### *Sun Sparc Solaris 2.5.1 cc 4.2 SPARC_CC +### *Sun Sparc SunOS 4.1.3_U1 acc 3.0.1 SUNOS +### *Sun Sparc SunOS 4.1.3_U1 gcc 2.7.2 SUNOS_GCC +### *Sun Sparc SunOS 4.1.3_U1 cc SUNOS_CC +### + +### Uncomment and modify this line to specify a predefined configuration +# SYS=SILICON + +### CC is the name of the C compiler +CC=gcc -m32 + +### OPTFLAGS are optimization flags to the compiler +OPTFLAGS=-O + +### COMFLAGS are flags to be passed to the compiler, in addition to +### the OPTFLAGS. Flags which turn on additional warnings are recommended. +COMFLAGS= + +### LOADFLAGS are flags to be passed to the linker, in addition to +### the OPTFLAGS +LOADFLAGS= + +### RANLIB is the name of a program which creates index information in +### a library archive. Some systems (for example, IRIX), don't require +### ranlib. In this case, set RANLIB=/bin/true. +RANLIB=ranlib +# RANLIB=/bin/true + +### OBJNAME is the extension used for the compiled files output by the +### compiler and read by the linker. It is almost always o. +OBJNAME=o + +### CCSYSNAME is the name of the system in INCLUDE/config.h. +### CCSYS_STANDARD is good on several systems with an ANSI C compiler, +### and CCSYS_STANDARD_KNR is good on a few with an older, K&R C compiler. +CCSYSNAME=CCSYS_STANDARD + +############################################################ +### +### the following are only necessary if you are using CPLEX. +### +############################################################ + +### CPLEX_LIB is the name (and location) of your cplex library +# CPLEX_LIB=/usr/cplex/libcplex.a + +### CPLEX_INCLUDE_DIR is the location of your cplex.h +# CPLEX_INCLUDE_DIR=/usr/cplex/ + +########################################################################## +### +### PREDEFINED CONFIGURATIONS START HERE +### +########################################################################## + +### ALPHA: a DEC Alpha running Digital Unix with cc +ifeq ($(SYS),ALPHA) +OPTFLAGS=-tune host -O4 +COMFLAGS=-std1 -warnprotos -portable +CC=cc +CCSYSNAME=CCSYS_STANDARD +endif + +### ALPHA_GCC: a DEC Alpha running Digital Unix with gcc +ifeq ($(SYS),ALPHA_GCC) +OPTFLAGS=-O3 +COMFLAGS=-ansi -pedantic -Wall -Wshadow -W -Wtraditional -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wnested-externs +CC=gcc +CCSYSNAME=CCSYS_STANDARD +endif + +### ALPHA_LINUX: a DEC Alpha running Linux with gcc +ifeq ($(SYS),ALPHA_LINUX) +OPTFLAGS=-O3 +# -pedantic -Wtraditional -Wmissing-prototypes -Wmissing-declarations +# generate many warnings for header files +COMFLAGS=-ansi -Wall -Wshadow -W -W -Wstrict-prototypes -Wpointer-arith -Wnested-externs +CC=gcc +CCSYSNAME=CCSYS_STANDARD +endif + +### INTEL_BSD: an Intel x86-compatible running FreeBSD with gcc +ifeq ($(SYS),INTEL_BSD) +OPTFLAGS=-O3 +COMFLAGS=-ansi -pedantic -Wall -Wshadow -W -Wtraditional -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wnested-externs +CC=gcc +CCSYSNAME=CCSYS_STANDARD +endif + +### INTEL_LINUX: an Intel x86-compatible running Linux with gcc +ifeq ($(SYS),INTEL_LINUX) +OPTFLAGS=-O3 +COMFLAGS=-ansi -pedantic -Wall -Wshadow -W -Wtraditional -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wnested-externs +CC=gcc +CCSYSNAME=CCSYS_STANDARD +endif + +### INTEL_SOLARIS: an Intel x86-compatible running Solaris with gcc +ifeq ($(SYS),INTEL_SOLARIS) +OPTFLAGS=-O3 +COMFLAGS=-ansi -pedantic -Wall -Wshadow -W -Wtraditional -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wnested-externs +CC=gcc +CCSYSNAME=CCSYS_STANDARD +endif + +### INTEL_SOLARIS_CC: a SUN Sparc running Solaris with cc +ifeq ($(SYS),INTEL_SOLARIS_CC) +OPTFLAGS=-xO2 +COMFLAGS=-fd -v -Xc +CC=cc +CCSYSNAME=CCSYS_STANDARD +endif + +### RS6000: an IBM RS6000 running AIX with cc +ifeq ($(SYS),RS6000) +OPTFLAGS=-O +CC=cc +COMFLAGS=-D_POSIX_SOURCE -qlanglvl=ansi +CCSYSNAME=CCSYS_STANDARD +endif + +### RS6000_GCC: an IBM RS6000 running AIX with gcc +ifeq ($(SYS),RS6000_GCC) +OPTFLAGS=-O3 +COMFLAGS=-ansi -pedantic -Wall -Wshadow -W -Wtraditional -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wnested-externs +CC=gcc +CCSYSNAME=CCSYS_STANDARD +endif + +### SILICON: A Silicon Graphics running IRIX with cc +ifeq ($(SYS),SILICON) +OPTFLAGS=-O2 +COMFLAGS=-ansi -fullwarn +CC=cc +RANLIB=/bin/true +CCSYSNAME=CCSYS_STANDARD +endif + +### SILICON_GCC: A Silicon Graphics running IRIX with gcc +ifeq ($(SYS),SILICON_GCC) +OPTFLAGS=-O3 +COMFLAGS=-ansi -pedantic -Wall -Wshadow -W -Wtraditional -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wnested-externs +CC=gcc +RANLIB=/bin/true +CCSYSNAME=CCSYS_STANDARD +endif + +### SPARC: a SUN Sparc running Solaris with gcc +ifeq ($(SYS),SPARC) +OPTFLAGS=-O3 +COMFLAGS=-ansi -pedantic -Wall -Wshadow -W -Wtraditional -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wnested-externs +CC=gcc +CCSYSNAME=CCSYS_STANDARD +endif + +### SPARC_CC: a SUN Sparc running Solaris with cc +ifeq ($(SYS),SPARC_CC) +OPTFLAGS=-xO2 +COMFLAGS=-fd -v -Xc +CC=cc +CCSYSNAME=CCSYS_STANDARD +endif + +### SUNOS: A Sun Sparc running SunOS with acc +ifeq ($(SYS),SUNOS) +OPTFLAGS=-O2 -fast +CC=/usr/lang/acc +COMFLAGS=-Xc +CCSYSNAME=CCSYS_STANDARD +endif + +### SUNOS_CC: A Sun Sparc running SunOS with cc +ifeq ($(SYS),SUNOS_CC) +OPTFLAGS=-O2 +CC=cc +CCSYSNAME=CCSYS_STANDARD_KNR +endif + +### SUNOS_GCC: a SUN Sparc running SunOS with gcc +ifeq ($(SYS),SUNOS_GCC) +OPTFLAGS=-O3 +COMFLAGS=-ansi -pedantic -Wall -Wshadow -W -Wtraditional -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wnested-externs +CC=gcc +CCSYSNAME=CCSYS_SUNOS_GCC +endif + +########################################################################## +### +### PREDEFINED CONFIGURATIONS END HERE +### +########################################################################## + +ifeq ($(CCSYSNAME),) +CCSYSFLAG=-DCCSYS_UNKNOWN +else +CCSYSFLAG=-D$(CCSYSNAME) +endif + +ifeq ($(CPLEX_INCLUDE_DIR),) +CPLEX_INCFLAG= +else +CPLEX_INCFLAG=-I$(CPLEX_INCLUDE_DIR) +endif + +CFLAGS=$(CCSYSFLAG) -I$(INCLUDE) $(CPLEX_INCFLAG) $(COMFLAGS) $(OPTFLAGS) +LDFLAGS=$(OPTFLAGS) $(LOADFLAGS) + +o=$(OBJNAME) diff --git a/contrib/blossom/concorde97/TSP/Makefile b/contrib/blossom/concorde97/TSP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..557c732a81abc1b7fb715f1518a645b74cc6e6b7 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/Makefile @@ -0,0 +1,91 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=tsp.a +LIBSRCS=prob_io.c tsp_lp.c qsparse.c cliqhash.c generate.c edgemap.c \ + ex_price.c cutcall.c tighten.c cutpool.c branch.c control.c \ + cliqwork.c teething.c bcontrol.c xtour.c +ALLSRCS=concorde.c poolcat.c $(LIBSRCS) +LIBS=$(ROOT)/LINKERN/linkern.a $(ROOT)/EDGEGEN/edgegen.a \ + $(ROOT)/KDTREE/kdtree.a $(ROOT)/FMATCH/fmatch.a \ + $(ROOT)/XSTUFF/Xstuff.a $(ROOT)/UTIL/util.a \ + $(ROOT)/BIGGUY/bigguy.a $(ROOT)/CUT/cut.a \ + $(ROOT)/LP/lp.a + +all: concorde poolcat $(LIB) + +concorde: concorde.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ $(CPLEX_LIB) -lm + +poolcat: poolcat.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ $(CPLEX_LIB) -lm + +clean: + -rm -f *.$o $(LIB) concorde poolcat + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +bcontrol.$o: bcontrol.c $(I)/machdefs.h $(I)/util.h $(I)/edgegen.h \ + $(I)/tsp.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h +branch.$o: branch.c $(I)/machdefs.h $(I)/util.h $(I)/macrorus.h \ + $(I)/tsp.h $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h \ + $(I)/cut.h $(I)/kdtree.h +cliqhash.$o: cliqhash.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h +cliqwork.$o: cliqwork.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h +concorde.$o: concorde.c $(I)/machdefs.h $(I)/util.h $(I)/edgegen.h \ + $(I)/tsp.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h $(I)/linkern.h $(I)/macrorus.h +control.$o: control.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h $(I)/Xstuff.h +cutcall.$o: cutcall.c $(I)/machdefs.h $(I)/macrorus.h $(I)/util.h \ + $(I)/tsp.h $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h \ + $(I)/cut.h $(I)/kdtree.h +cutpool.$o: cutpool.c $(I)/machdefs.h $(I)/util.h $(I)/macrorus.h \ + $(I)/tsp.h $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h \ + $(I)/cut.h $(I)/kdtree.h +edgemap.$o: edgemap.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h $(I)/macrorus.h +ex_price.$o: ex_price.c $(I)/machdefs.h $(I)/util.h $(I)/macrorus.h \ + $(I)/bigguy.h $(I)/tsp.h $(I)/edgegen.h $(I)/lp.h \ + $(I)/cut.h $(I)/kdtree.h +generate.$o: generate.c $(I)/machdefs.h $(I)/util.h $(I)/macrorus.h \ + $(I)/tsp.h $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h \ + $(I)/cut.h $(I)/kdtree.h +poolcat.$o: poolcat.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h +prob_io.$o: prob_io.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h +qsparse.$o: qsparse.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h +teething.$o: teething.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h +tighten.$o: tighten.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h +tsp_lp.$o: tsp_lp.c $(I)/machdefs.h $(I)/util.h $(I)/macrorus.h \ + $(I)/fmatch.h $(I)/edgegen.h $(I)/linkern.h $(I)/tsp.h \ + $(I)/bigguy.h $(I)/lp.h $(I)/cut.h $(I)/kdtree.h +xtour.$o: xtour.c $(I)/machdefs.h $(I)/util.h $(I)/edgegen.h \ + $(I)/linkern.h $(I)/tsp.h $(I)/bigguy.h $(I)/lp.h \ + $(I)/cut.h $(I)/kdtree.h diff --git a/contrib/blossom/concorde97/TSP/bcontrol.c b/contrib/blossom/concorde97/TSP/bcontrol.c new file mode 100644 index 0000000000000000000000000000000000000000..6fce5b7edb878ba864fad713da07241a29190536 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/bcontrol.c @@ -0,0 +1,713 @@ +/***************************************************************************/ +/* */ +/* THE CONTROLLER FOR BRANCHING RUNS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: July 21, 1997 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_init_cutselect (CCtsp_lp *lp, CCtsp_cutselect *s) */ +/* INITIALIZES the cut selctions */ +/* Note: The lp should be solved before this call. */ +/* */ +/* int CCtsp_cutting_loop (CCtsp_lp *lp, CCtsp_cutselect *sel, */ +/* int savelp) */ +/* CALLS the cutting plane and pricing routines. */ +/* -sel should be set with the desired cut selection. */ +/* -savelp should be set to a nonzero value to write the lps to after */ +/* rounds of cuts */ +/* Note: It returns a 2 if the lp becomes infeasible */ +/* */ +/* NOTES: */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "edgegen.h" +#include "tsp.h" + +typedef struct tsp_bbnode { + int id; + double lowerbound; + int status; + int workstatus; + struct tsp_bbnode *prev; + struct tsp_bbnode *next; + struct tsp_bbnode *parent; + struct tsp_bbnode *child0; + struct tsp_bbnode *child1; +} tsp_bbnode; + +#define BB_NEEDS_CUTTING (1) +#define BB_NEEDS_BRANCHING (2) +#define BB_DONE (3) +#define BB_IDLE (1) +#define BB_WORKING (2) + + +CC_PTR_ALLOC_ROUTINE (tsp_bbnode, tsp_bbnode_alloc, tsp_bbnode_chunklist, + tsp_bbnode_freelist) +CC_PTR_FREE_WORLD_ROUTINE (tsp_bbnode, tsp_bbnode_free_world, + tsp_bbnode_chunklist, tsp_bbnode_freelist) +CC_PTR_LEAKS_ROUTINE (tsp_bbnode, tsp_bbnode_check_leaks, + tsp_bbnode_chunklist, tsp_bbnode_freelist, id, int) +CC_PTR_FREE_ROUTINE (tsp_bbnode, tsp_bbnode_free, tsp_bbnode_freelist) + + +#ifdef CC_PROTOTYPE_ANSI + +static void + init_bbnode (tsp_bbnode *bbnode), + insert_bbnode (tsp_bbnode **firstbbnode, tsp_bbnode *bbnode), + delete_bbnode (tsp_bbnode **firstbbnode, tsp_bbnode *bbnode), + free_tree (tsp_bbnode **bbnode); + +static int + add_children (tsp_bbnode **firstbbnode, tsp_bbnode *parent, + int id0, int id1, double val0, double val1, int prune0, int prune1); + +static tsp_bbnode + *select_bbnode (tsp_bbnode *firstbbnode); + +#else + +static void + init_bbnode (), + insert_bbnode (), + delete_bbnode (), + free_tree (); + +static int + add_children (); + +static tsp_bbnode + *select_bbnode (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +static void init_bbnode (tsp_bbnode *bbnode) +#else +static void init_bbnode (bbnode) +tsp_bbnode *bbnode; +#endif +{ + bbnode->id = 0; + bbnode->lowerbound = 0.0; + bbnode->status = BB_NEEDS_CUTTING; + bbnode->workstatus = BB_IDLE; + bbnode->prev = (tsp_bbnode *) NULL; + bbnode->next = (tsp_bbnode *) NULL; + bbnode->parent = (tsp_bbnode *) NULL; + bbnode->child0 = (tsp_bbnode *) NULL; + bbnode->child1 = (tsp_bbnode *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_bfs_brancher (char *probname, int id, double lowerbound, + CCtsp_cutselect *sel, double *upbound, int *bbcount, int usecliques, + CCdatagroup *dat, int *ptour, CCtsp_lpcuts *pool, int ncount, + int *besttour) +#else +int CCtsp_bfs_brancher (probname, id, lowerbound, sel, upbound, bbcount, + usecliques, dat, ptour, pool, ncount, besttour) +char *probname; +int id; +double lowerbound; +CCtsp_cutselect *sel; +double *upbound; +int *bbcount; +int usecliques; +CCdatagroup *dat; +int *ptour; +CCtsp_lpcuts *pool; +int ncount; +int *besttour; +#endif +{ + int rval = 0; + int max_id = 0; + int id0, id1, prune, prune0, prune1, foundtour, count = 0; + double val0, val1, val; + CCtsp_branchobj *b = (CCtsp_branchobj *) NULL; + tsp_bbnode *bbnode = (tsp_bbnode *) NULL; + tsp_bbnode *firstbbnode = (tsp_bbnode *) NULL; + tsp_bbnode *rootbbnode = (tsp_bbnode *) NULL; + + *bbcount = 0; + + if (max_id < id) max_id = id; + rootbbnode = tsp_bbnode_alloc (); + if (!rootbbnode) { + fprintf (stderr, "Failed to allocate root node\n"); + rval = 1; goto CLEANUP; + } + + init_bbnode (rootbbnode); + rootbbnode->id = id; + rootbbnode->lowerbound = lowerbound; + firstbbnode = rootbbnode; + *bbcount = 1; + + while (firstbbnode) { + bbnode = select_bbnode (firstbbnode); + if (!bbnode) { + fprintf (stderr, "No IDLE bbnodes\n"); + rval = 1; goto CLEANUP; + } + printf ("Task %d: %s on node %d\n", count++, + (bbnode->status == BB_NEEDS_CUTTING ? "Cutting" : "Branching"), + bbnode->id); + fflush (stdout); + + switch (bbnode->status) { + case BB_NEEDS_CUTTING: + bbnode->workstatus = BB_WORKING; + rval = CCtsp_bb_cutting (probname, bbnode->id, ncount, dat, ptour, + upbound, pool, sel, &val, &prune, &foundtour, + besttour); + if (rval) { + fprintf (stderr, "CCtsp_bb_cutting failed\n"); goto CLEANUP; + } + if (foundtour) { + printf ("TOUR FOUND - upperbound is %.2f\n", *upbound); + fflush (stdout); + rval = CCtsp_dumptour (ncount, dat, ptour, probname, besttour); + if (rval) { + fprintf (stderr, "CCtsp_dumptour failed\n"); goto CLEANUP; + } + } + if (prune) { + printf ("BBnode can be pruned: upperbound %.2f\n", *upbound); + fflush (stdout); + delete_bbnode (&firstbbnode, bbnode); + rval = CCtsp_prob_file_delete (probname, bbnode->id); + if (rval) goto CLEANUP; + } else { + bbnode->status = BB_NEEDS_BRANCHING; + bbnode->workstatus = BB_IDLE; + bbnode->lowerbound = val; + } + break; + case BB_NEEDS_BRANCHING: + bbnode->workstatus = BB_WORKING; + rval = CCtsp_bb_find_branch (probname, bbnode->id, ncount, dat, + ptour, upbound, pool, &b, usecliques, &foundtour, + besttour); + if (rval) { + fprintf (stderr, "CCtsp_bb_find_branch failed\n"); goto CLEANUP; + } + if (foundtour) { + printf ("TOUR FOUND - upperbound is %.2f\n", *upbound); + fflush (stdout); + rval = CCtsp_dumptour (ncount, dat, ptour, probname, besttour); + if (rval) { + fprintf (stderr, "CCtsp_dumptour failed\n"); goto CLEANUP; + } + } else { + printf ("Found Branch - split problem into children\n"); + fflush (stdout); + id0 = ++max_id; + id1 = ++max_id; + rval = CCtsp_bb_splitprob (probname, bbnode->id, ncount, dat, + ptour, *upbound, pool, &b[0], id0, id1, &val0, &val1, + &prune0, &prune1); + CCtsp_free_branchobj (&b[0]); + CC_IFFREE (b, CCtsp_branchobj); + if (rval) { + fprintf (stderr, "CCtsp_bb_splitprob failed\n"); + goto CLEANUP; + } + + rval = add_children (&firstbbnode, bbnode, id0, id1, + val0, val1, prune0, prune1); + if (rval) { + fprintf (stderr, "add_children failed\n"); goto CLEANUP; + } + (*bbcount) += 2; + } + delete_bbnode (&firstbbnode, bbnode); + rval = CCtsp_prob_file_delete (probname, bbnode->id); + if (rval) goto CLEANUP; + break; + default: + printf ("Not working bbnode: %d (status %d)\n", bbnode->id, + bbnode->status); + fflush (stdout); + rval = 1; goto CLEANUP; + } + } + +CLEANUP: + + CCtsp_free_branchobj (&b[0]); + CC_IFFREE (b, CCtsp_branchobj); + free_tree (&rootbbnode); + tsp_bbnode_free_world (); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_children (tsp_bbnode **firstbbnode, tsp_bbnode *parent, + int id0, int id1, double val0, double val1, int prune0, int prune1) +#else +static int add_children (firstbbnode, parent, id0, id1, val0, val1, + prune0, prune1) +tsp_bbnode **firstbbnode; +tsp_bbnode *parent; +int id0, id1; +double val0, val1; +int prune0, prune1; +#endif +{ + int rval = 0; + tsp_bbnode *child = (tsp_bbnode *) NULL; + + if (val0 == CCtsp_LP_MAXDOUBLE) { + printf ("Child 0 is infeasible\n"); fflush (stdout); + } else if (prune0) { + printf ("Child 0 is pruned\n"); fflush (stdout); + } else { + child = tsp_bbnode_alloc (); + if (!child) { + fprintf (stderr, "Failed to allocate child 0\n"); + rval = 1; goto CLEANUP; + } + + init_bbnode (child); + child->id = id0; + child->lowerbound = val0; + + parent->child0 = child; + insert_bbnode (firstbbnode, child); + } + + if (val1 == CCtsp_LP_MAXDOUBLE) { + printf ("Child 1 is infeasible\n"); fflush (stdout); + } else if (prune1) { + printf ("Child 1 is pruned\n"); fflush (stdout); + } else { + child = tsp_bbnode_alloc (); + if (!child) { + fprintf (stderr, "Failed to allocate child 0\n"); + rval = 1; goto CLEANUP; + } + + init_bbnode (child); + child->id = id1; + child->lowerbound = val1; + + parent->child1 = child; + insert_bbnode (firstbbnode, child); + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void free_tree (tsp_bbnode **bbnode) +#else +static void free_tree (bbnode) +tsp_bbnode **bbnode; +#endif +{ + if (!(*bbnode)) return; + free_tree (&((*bbnode)->child0)); + free_tree (&((*bbnode)->child1)); + tsp_bbnode_free (*bbnode); + *bbnode = (tsp_bbnode *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static tsp_bbnode *select_bbnode (tsp_bbnode *firstbbnode) +#else +static tsp_bbnode *select_bbnode (firstbbnode) +tsp_bbnode *firstbbnode; +#endif +{ + double bestbound = CCtsp_LP_MAXDOUBLE; + double lowerbound = CCtsp_LP_MAXDOUBLE; + tsp_bbnode *bestbbnode = (tsp_bbnode *) NULL; + tsp_bbnode *b; + int count = 0; + + for (b = firstbbnode; b; b = b->next) { + if (b->lowerbound < lowerbound) { + lowerbound = b->lowerbound; + } + count++; + } + printf ("LOWER BOUND: %f ACTIVE NODES: %d\n", lowerbound, count); + fflush (stdout); + + if (firstbbnode) { + /* Find the best bbnode */ + for (b = firstbbnode; b; b = b->next) { + if (b->workstatus == BB_IDLE && b->lowerbound < bestbound) { + bestbound = b->lowerbound; + bestbbnode = b; + } + } + } + + if (!bestbbnode) { + printf ("No idle bbnodes\n"); fflush (stdout); + } else { + + + printf ("Selected bbnode: id %d lowerbound %.2f\n", + bestbbnode->id, bestbound); + fflush (stdout); + if (count > 1) { + printf ("Remaining active bbnodes:\n"); + fflush (stdout); + for (b = firstbbnode; b; b = b->next) { + if (b->id != bestbbnode->id) { + printf (" id %d lowerbound %.2f\n", b->id, b->lowerbound); + fflush (stdout); + } + } + } + } + + return bestbbnode; +} + +#ifdef CC_PROTOTYPE_ANSI +static void insert_bbnode (tsp_bbnode **firstbbnode, tsp_bbnode *bbnode) +#else +static void insert_bbnode (firstbbnode, bbnode) +tsp_bbnode **firstbbnode, *bbnode; +#endif +{ + if (!bbnode) return; + + bbnode->prev = (tsp_bbnode *) NULL; + bbnode->next = *firstbbnode; + if (*firstbbnode) (*firstbbnode)->prev = bbnode; + *firstbbnode = bbnode; +} + +#ifdef CC_PROTOTYPE_ANSI +static void delete_bbnode (tsp_bbnode **firstbbnode, tsp_bbnode *bbnode) +#else +static void delete_bbnode (firstbbnode, bbnode) +tsp_bbnode **firstbbnode; +tsp_bbnode *bbnode; +#endif +{ + tsp_bbnode *next, *prev; + + if (!bbnode) return; + + bbnode->status = BB_DONE; + bbnode->workstatus = BB_IDLE; + if (*firstbbnode == bbnode) { + *firstbbnode = bbnode->next; + } + prev = bbnode->prev; + next = bbnode->next; + if (prev) prev->next = next; + if (next) next->prev = prev; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_easy_dfs_brancher (CCtsp_lp *lp, CCtsp_cutselect *sel, int depth, + double *upbound, int *bbcount, int usecliques, int *besttour) +#else +int CCtsp_easy_dfs_brancher (lp, sel, depth, upbound, bbcount, usecliques, + besttour) +CCtsp_lp *lp; +CCtsp_cutselect *sel; +int depth; +double *upbound; +int *bbcount; +int usecliques; +int *besttour; +#endif +{ + int rval = 0; + int ngot, prune, i; + int *cyc = (int *) NULL; + double val, bnd; + double oldbound = lp->lowerbound; + CCtsp_branchobj *b = (CCtsp_branchobj *) NULL; + + if (!lp->full_edges_valid) { + fprintf (stderr, "CCtsp_easy_dfs_brancher needs valid extra edges\n"); + rval = 1; goto CLEANUP; + } + + printf ("Node %d\n", *bbcount); fflush (stdout); + (*bbcount)++; + CCtsp_print_branchhistory (lp); + + rval = CCtsp_pricing_loop (lp, &bnd); + if (rval) { + fprintf (stderr, "CCtsp_pricing_loop failed\n"); goto CLEANUP; + } + lp->lowerbound = bnd; + lp->upperbound = *upbound; + + if (lp->lowerbound >= lp->upperbound - 0.9) { + rval = CCtsp_verify_lp_prune (lp, &prune); + if (rval) { + fprintf (stderr, "CCtsp_verify_lp_prune failed\n"); goto CLEANUP; + } + if (prune) { + printf ("PRUNE SEARCH: upperbound = %f\n", *upbound); + fflush (stdout); + rval = 0; goto CLEANUP; + } else { + fprintf (stderr, "exact pricing could not prune the search\n"); + rval = 1; goto CLEANUP; + } + } + + rval = CCtsp_cutting_loop (lp, sel, 0); + if (rval == 2) { + rval = CCtsp_verify_infeasible_lp (lp, &prune); + if (rval) { + fprintf (stderr ,"CCtsp_verify_infeasible_lp failed\n"); + goto CLEANUP; + } + if (prune) { + printf ("PRUNE SEARCH - infeasible LP\n"); fflush (stdout); + rval = 0; goto CLEANUP; + } else { + fprintf (stderr, "exact pricing did not verify an infeasible LP\n"); + rval = 1; goto CLEANUP; + } + } else if (rval) { + fprintf (stderr, "CCtsp_cutting_loop failed\n"); goto CLEANUP; + } + + if (lp->lowerbound < lp->upperbound - 0.9) { + rval = CCtsp_call_x_heuristic (lp, &val, besttour); + if (rval) { + fprintf (stderr, "CCtsp_call_x_heuristic failed\n"); + goto CLEANUP; + } + if (val < lp->upperbound) { + printf ("New upperbound from x-heuristic: %.2f\n", val); + lp->upperbound = val; + *upbound = val; + rval = CCtsp_dumptour (lp->graph.ncount, lp->dat, lp->perm, + lp->name, besttour); + if (rval) { + fprintf (stderr, "CCtsp_dumptour failed\n"); goto CLEANUP; + } + } + } + + if (lp->lowerbound >= lp->upperbound - 0.9) { + rval = CCtsp_verify_lp_prune (lp, &prune); + if (rval) { + fprintf (stderr, "CCtsp_verify_lp_prune failed\n"); goto CLEANUP; + } + if (prune) { + printf ("PRUNE SEARCH: upperbound = %f\n", *upbound); + fflush (stdout); + rval = 0; goto CLEANUP; + } else { + fprintf (stderr, "exact pricing could not prune the search\n"); + rval = 1; goto CLEANUP; + } + } + + oldbound = lp->lowerbound; + printf ("Find branch object ...\n"); fflush (stdout); + rval = CCtsp_find_branch (lp, 1, &ngot, &b, &val, &cyc, usecliques); + if (rval) { + fprintf (stderr, "CCtsp_find_branch failed\n"); + goto CLEANUP; + } + + if (ngot == 0) { + printf ("TOUR FOUND: %.2f\n", val); fflush (stdout); + if (val < *upbound) { + *upbound = val; + lp->upperbound = val; + for (i = 0; i < lp->graph.ncount; i++) { + besttour[i] = cyc[i]; + } + rval = CCtsp_dumptour (lp->graph.ncount, lp->dat, lp->perm, + lp->name, besttour); + if (rval) { + fprintf (stderr, "CCtsp_dumptour failed\n"); goto CLEANUP; + } + } + CC_IFFREE (cyc, int); + rval = CCtsp_verify_lp_prune (lp, &prune); + if (rval) { + fprintf (stderr, "CCtsp_verify_lp_prune failed\n"); + goto CLEANUP; + } + if (prune) { + printf ("with new tour, the node can be pruned\n"); fflush (stdout); + rval = 0; goto CLEANUP; + } else { + fprintf (stderr, "could not verify the pruning\n"); + rval = 1; goto CLEANUP; + } + } + + + /**** Down-Side Branch ****/ + + + if (b[0].ends[0] != -1) { + printf ("Branch: set edge (%d, %d) to 0 (depth %d)\n", + b[0].ends[0], b[0].ends[1], depth); + b[0].rhs = 0; + } else { + printf ("Branch: set clique <= 2 (depth %d)\n", depth); + b[0].rhs = 2; b[0].sense = 'L'; + } + fflush (stdout); + rval = CCtsp_execute_branch (lp, &b[0]); + if (rval) { + fprintf (stderr, "CCtsp_execute_branch failed\n"); + rval = 1; goto CLEANUP; + } + + rval = CCtsp_easy_dfs_brancher (lp, sel, depth + 1, upbound, bbcount, + usecliques, besttour); + if (rval) { + fprintf (stderr, "CCtsp_easy_dfs_brancher failed\n"); goto CLEANUP; + } + rval = CCtsp_execute_unbranch (lp, (CClpbasis *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_execute_unbranch failed\n"); goto CLEANUP; + } + lp->lowerbound = oldbound; + + + /**** Up-Side Branch ****/ + + + if (b[0].ends[0] != -1) { + printf ("Branch: set edge (%d, %d) to 1 (depth %d)\n", + b[0].ends[0], b[0].ends[1], depth); + b[0].rhs = 1; + } else { + printf ("Branch: set clique >= 4 (depth %d)\n", depth); + b[0].rhs = 4; b[0].sense = 'G'; + } + fflush (stdout); + rval = CCtsp_execute_branch (lp, &b[0]); + if (rval) { + fprintf (stderr, "CCtsp_execute_branch failed\n"); goto CLEANUP; + } + + rval = CCtsp_easy_dfs_brancher (lp, sel, depth + 1, upbound, bbcount, + usecliques, besttour); + if (rval) { + fprintf (stderr, "CCtsp_easy_dfs_brancher failed\n"); goto CLEANUP; + } + rval = CCtsp_execute_unbranch (lp, (CClpbasis *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_execute_unbranch failed\n"); goto CLEANUP; + } + lp->lowerbound = oldbound; + + CCtsp_free_branchobj (&b[0]); + CC_IFFREE (b, CCtsp_branchobj); + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_do_interactive_branch (CCtsp_lp *lp) +#else +int CCtsp_do_interactive_branch (lp) +CCtsp_lp *lp; +#endif +{ + int bend0, bend1, ch0, ch1, tbran, nseg, i; + CCtsp_branchobj b; + CCtsp_lpclique *c = (CCtsp_lpclique *) NULL; + int *slist = (int *) NULL; + int rval = 0; + + CCtsp_init_branchobj (&b); + + printf ("Enter the (integer) id's for the two child nodes: "); + fflush (stdout); + scanf ("%d %d", &ch0, &ch1); + + printf ("Enter 0 if edge-branch and 1 if clique-branch: "); + fflush (stdout); + scanf ("%d", &tbran); + + if (!tbran) { + printf ("Enter ends of branching edge (use neg if original): "); + fflush (stdout); + scanf ("%d %d", &bend0, &bend1); + if (bend0 < 0) { + if (bend1 >= 0) { + fprintf (stderr, "both ends must be from the same order\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < lp->graph.ncount; i++) { + if (lp->perm[i] == -bend0) bend0 = i; + if (lp->perm[i] == -bend1) bend1 = i; + } + printf ("Current Names of the Ends: %d %d\n", bend0, bend1); + fflush (stdout); + } + b.ends[0] = bend0; + b.ends[1] = bend1; + b.rhs = 1; + } else { + printf ("Enter the number of segments in clique: "); + fflush (stdout); + scanf ("%d", &nseg); + slist = CC_SAFE_MALLOC (2*nseg, int); + if (!slist) { + fprintf (stderr, "out of memory\n"); + rval = 1; goto CLEANUP; + } + printf ("Enter the ends of the segments: "); + fflush (stdout); + for (i = 0; i < nseg; i++) { + scanf ("%d %d", &slist[2*i], &slist[2*i+1]); + } + c = CC_SAFE_MALLOC (1, CCtsp_lpclique); + if (!c) { + fprintf (stderr, "out of memory\n"); + CC_IFFREE (slist, int); + rval = 1; goto CLEANUP; + } + rval = CCtsp_seglist_to_lpclique (nseg, slist, c); + if (rval) { + fprintf (stderr, "CCtsp_seglist_to_lpclique failed\n"); + goto CLEANUP; + } + CC_IFFREE (slist, int); + b.clique = c; + b.rhs = 4; + b.sense = 'G'; + CCtsp_print_lpclique (b.clique); + } + + rval = CCtsp_splitprob (lp, &b, ch0, ch1); + if (rval) { + fprintf (stderr, "CCtsp_splitprob failed\n"); + goto CLEANUP; + } + + CCtsp_free_branchobj (&b); + +CLEANUP: + + return rval; +} diff --git a/contrib/blossom/concorde97/TSP/branch.c b/contrib/blossom/concorde97/TSP/branch.c new file mode 100644 index 0000000000000000000000000000000000000000..0942b0a6f1bece0abf0b167bcb405500a51bdb7f --- /dev/null +++ b/contrib/blossom/concorde97/TSP/branch.c @@ -0,0 +1,2170 @@ +/***************************************************************************/ +/* */ +/* ROUTINES TO BUILD EXECUTE BRANCHING */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 22, 1997 */ +/* Modified: June 17, 1997 (bix) */ +/* June 27, 1997 (bico) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int CCtsp_find_branch (CCtsp_lp *lp, int nwant, int *ngot, */ +/* CCtsp_branchobj **bobj, double *val, int **tour, */ +/* int usecliques) */ +/* FINDS a set of branching edges and cliques. */ +/* -usecliques should be set to 1 to allow branching on cliques */ +/* -val returns the length of a tour if one is detected. */ +/* -tour returns the tour (it can be NULL) */ +/* */ +/* int CCtsp_find_branch_edge (CCtsp_lp *lp, int *n0, int *n1, */ +/* double *val, int **tour, int branchtype) */ +/* FINDS a branching edge or detects that solution is integral. */ +/* -lp points to an optimized lp. */ +/* -n0, n1 return the edges of the branching edge; n0 is set to -1 */ +/* if the current lp solution is a tour */ +/* -val returns the value the tour if n0 is set to -1 */ +/* -branchtype determines the strategy for choosing the branching */ +/* edge; choices for branchtype are given in tsp.h */ +/* */ +/* int CCtsp_check_integral (CCtsp_lp *lp, double *val, int **cyc, */ +/* int *yesno) */ +/* TESTS if the current x-vector is a tour. */ +/* -yesno is set to 1 if it is a tour and 0 otherwise. */ +/* */ +/* int CCtsp_find_branch_cliques (CCtsp_lp *lp, int nwant, int *ngot, */ +/* CCtsp_lpclique **bcliques, double *bval) */ +/* FINDS branching cliques (it may return ngot == 0) */ +/* -bval will return the stongbranching function evaluation for */ +/* each clique (it can be NULL) */ +/* */ +/* void CCtsp_init_branchobj (CCtsp_branchobj *b) */ +/* INITITALIZES the fields in the CCtsp_branchobj pointed to by b. */ +/* */ +/* void CCtsp_free_branchobj (CCtsp_branchobj *b) */ +/* FREES the fields in the CCtsp_branchobj pointed to by b. */ +/* */ +/* void CCtsp_print_branchhistory (CCtsp_lp *lp) */ +/* PRINT to stdout the branch history of the lp */ +/* */ +/* int CCtsp_execute_branch (CCtsp_lp *lp, CCtsp_branchobj *b) */ +/* SETS the lp to realize the branch described in b */ +/* NOTE: returns 2 if the LP becomes infeasible. */ +/* */ +/* int CCtsp_execute_unbranch (CCtsp_lp *lp, CClpbasis *basis) */ +/* UNDOS the changes to the lp caused by the most recent branch that */ +/* has not yet been unbranched (used in dfs) */ +/* -basis can specify a basis and dual norms to help resolve the LP */ +/* (in can be NULL) */ +/* */ +/* int CCtsp_add_branchhistory_to_lp (CCtsp_lp *lp) */ +/* SETS the lp to realize the branches in branch history */ +/* */ +/* int CCtsp_splitprob (CCtsp_lp *lp, CCtsp_branchobj *b, int child0, */ +/* int child1) */ +/* EXECUTES a branch on the lp and writes to two child lps */ +/* -b contains the branching information (the rhs side value is set */ +/* by this function to give 0 and 1 for edge branches and 2 & 4 for */ +/* clique branches; the sense is set by this function for clique */ +/* branches to realize <= 2 and >= 4) */ +/* -child0 and child1 are the ids of the children */ +/* */ +/* int CCtsp_bb_splitprob (char *probname, int probnum, int ncount, */ +/* CCdatagroup *dat, int *ptour, double initial_ub, */ +/* CCtsp_lpcuts *pool, CCtsp_branchobj *b, int child0, */ +/* int child1, double *val0, double *val1, int *prune0, */ +/* int *prune1) */ +/* CALLS splitprob after reading the lp file and building an lp; this */ +/* function will also price the lp and attempt to verify infeasible */ +/* lps. */ +/* -val0 and val1 return the (priced) lp-bounds for the children; if */ +/* an lp is infeasible then the val is set to CCtsp_LP_MAXDOUBLE and */ +/* the lp is not written. */ +/* -prune0 and prune1 will be set to 1 if the child can be pruned */ +/* (in which case the lp is not written) */ +/* */ +/* int CCtsp_dumptour (int ncount, CCdatagroup *dat, int *perm, */ +/* char *probname, int *tour) */ +/* WRITES the tour file to probname.sol. */ +/* -dat is used to compute the length (it can be NULL) */ +/* -perm is a permutation tour */ +/* -tour gives the tour (perm[tour[i]] with be printed) */ +/* */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "macrorus.h" +#include "tsp.h" +#include "lp.h" +#include "cut.h" + + +#define TSP_BRANCH_STRONG_ALL_CHOICES -1 +#define TSP_BRANCH_STRONG_ITERATIONS 100 +#define TSP_BRANCH_STRONG_CHOICES 50 /* SET TO ALL_CHOICES TO TRY ALL */ + +#define TSP_STRONG_CUT_ITER 100 +#define TSP_STRONG_CUT_CHOICES 50 +#define TSP_STRONG_CUT_CANDIDATES 1000 + +#define TSP_BRANCH_STRONG_FIRST_VAL(v0,v1) \ + ((v0) < (v1) ? (10.0 * (v0) + (v1)) : (10.0 * (v1) + (v0))) + +#define TSP_BRANCH_STRONG_VAL(v0,v1) \ + ((v0) < (v1) ? (25.0 * (v0) + (v1)) : (25.0 * (v1) + (v0))) + +#define TSP_BRANCH_STRONG_CUT_NORM_VAL(v0,v1) \ + ((v0) < (v1) ? (100.0 * (v0) + (v1)) : (100.0 * (v1) + (v0))) + +typedef struct sbitem { + int name; + double val; +} sbitem; + + +#ifdef CC_PROTOTYPE_ANSI + +static int + merge_edge_clique (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_branchobj **bobj, + int ecount, int *elist, double *eval, + int ccount, CCtsp_lpclique *clist, double *cval), + find_strong_branch (CCtsp_lp *lp, int *n0, int *n1), + find_strongbranch_edges (CCtsp_lp *lp, int nwant, int *ngot, int **elist, + double **eval), + find_candidate_edges (CCtsp_lp *lp, int nwant, int *ngot, int **list), + find_all_candidate_edges (CCtsp_lp *lp, int *ngot, int **list), + find_candidate_cliques (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_lpclique **list, int use_getweight), + find_branched_clique (CCtsp_lp *lp, CCtsp_lpclique *c, char sense, int rhs, + int *cutnum), + branch_side (CCtsp_lp *lp, CCtsp_branchobj *b, int side, int child, + double *val, int *prune); + +static void + print_branchobj (CCtsp_branchobj *b), + init_sblist (sbitem *list, int count), + insert_sblist (sbitem *list, double val, int name); + +#else /* CC_PROTOTYPE_ANSI */ + +static int + merge_edge_clique (), + find_strong_branch (), + find_strongbranch_edges (), + find_candidate_edges (), + find_all_candidate_edges (), + find_candidate_cliques (), + find_branched_clique (), + branch_side (); + +static void + print_branchobj (), + init_sblist (), + insert_sblist (); + +#endif /* CC_PROTOTYPE_ANSI */ + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_init_branchobj (CCtsp_branchobj *b) +#else +void CCtsp_init_branchobj (b) +CCtsp_branchobj *b; +#endif +{ + b->depth = 0; + b->rhs = 0; + b->ends[0] = -1; + b->ends[1] = -1; + b->sense = 'X'; + b->clique = (CCtsp_lpclique *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_branchobj (CCtsp_branchobj *b) +#else +void CCtsp_free_branchobj (b) +CCtsp_branchobj *b; +#endif +{ + if (!b) return; + + b->depth = 0; + b->rhs = 0; + b->ends[0] = -1; + b->ends[1] = -1; + b->sense = 'X'; + if (b->clique) { + CCtsp_free_lpclique (b->clique); + CC_FREE (b->clique, CCtsp_lpclique); + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_print_branchhistory (CCtsp_lp *lp) +#else +void CCtsp_print_branchhistory (lp) +CCtsp_lp *lp; +#endif +{ + int j; + printf ("Branch History\n"); fflush (stdout); + if (lp->branchdepth == 0) { + printf (" Root Node\n"); + } else { + for (j = 0; j < lp->branchdepth; j++) { + printf (" "); + print_branchobj (&lp->branchhistory[j]); + } + } + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +static void print_branchobj (CCtsp_branchobj *b) +#else +static void print_branchobj (b) +CCtsp_branchobj *b; +#endif +{ + int i; + + printf ("Depth %d: ", b->depth); + if (b->ends[0] != -1) { + printf ("Edge (%d,%d) set to %d\n", b->ends[0], b->ends[1], b->rhs); + } else { + printf ("Clique "); + for (i = 0; i < b->clique->segcount; i++) { + printf ("%d->%d ", b->clique->nodes[i].lo, b->clique->nodes[i].hi); + } + if (b->sense == 'L') { + printf ("at most %d\n", b->rhs); + } else { + printf ("at least %d\n", b->rhs); + } + } + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_find_branch (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_branchobj **bobj, double *val, int **cyc, int usecliques) +#else +int CCtsp_find_branch (lp, nwant, ngot, bobj, val, cyc, usecliques) +CCtsp_lp *lp; +int nwant; +int *ngot; +CCtsp_branchobj **bobj; +double *val; +int **cyc; +int usecliques; +#endif +{ + int rval = 0; + int egot = 0; + int cgot = 0; + int *elist = (int *) NULL; + CCtsp_lpclique *clist = (CCtsp_lpclique *) NULL; + double *eval = (double *) NULL; + double *cval = (double *) NULL; + int i, n0, n1; + + *ngot = 0; + *bobj = (CCtsp_branchobj *) NULL; + if (cyc) *cyc = (int *) NULL; + + if (nwant <= 0) { + fprintf (stderr, "CCtsp_find_branch called with no nwant\n"); + rval = 1; goto CLEANUP; + } + + rval = CCtsp_find_branch_edge (lp, &n0, &n1, val, cyc, CCtsp_BRANCH_MIDDLE); + if (rval) { + fprintf (stderr, "CCtsp_find_branch failed\n"); goto CLEANUP; + } + + if (n0 == -1 && n1 == -1) { + printf ("Integral solution: %f\n", *val); fflush (stdout); + goto CLEANUP; + } + + rval = find_strongbranch_edges (lp, nwant, &egot, &elist, &eval); + if (rval) { + fprintf (stderr, "find_strongbranch_edges failed\n"); goto CLEANUP; + } + + if (usecliques) { + rval = CCtsp_find_branch_cliques (lp, nwant, &cgot, &clist, &cval); + if (rval) { + fprintf (stderr, "CCtsp_find_branch_cliques failed\n"); + goto CLEANUP; + } + printf ("Cliques found:\n"); fflush (stdout); + for (i = 0; i < cgot; i++) { + CCtsp_print_lpclique (&clist[i]); + } + } + + if (egot + cgot > 0) { + rval = merge_edge_clique (lp, nwant, ngot, bobj, egot, elist, eval, + cgot, clist, cval); + if (rval) { + fprintf (stderr, "merge_edge_clique failed\n"); goto CLEANUP; + } + } else { + CCtsp_branchobj *b; + printf ("found no edges or cliques, use the middle branch edge\n"); + fflush (stdout); + + b = CC_SAFE_MALLOC (1, CCtsp_branchobj); + if (!b) { + fprintf (stderr, "out of memory in CCtsp_find_branch\n"); + rval = 1; goto CLEANUP; + } + CCtsp_init_branchobj (b); + b->ends[0] = n0; + b->ends[1] = n1; + *bobj = b; + *ngot = 1; + } + +CLEANUP: + + CC_IFFREE (elist, int); + for (i = 0; i < cgot; i++) { + CCtsp_free_lpclique (&clist[i]); + } + CC_IFFREE (clist, CCtsp_lpclique); + CC_IFFREE (cval, double); + CC_IFFREE (eval, double); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int merge_edge_clique (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_branchobj **bobj, int ecount, int *elist, double *eval, + int ccount, CCtsp_lpclique *clist, double *cval) +#else +static int merge_edge_clique (lp, nwant, ngot, bobj, ecount, elist, eval, + ccount, clist, cval) +CCtsp_lp *lp; +int nwant; +int *ngot; +CCtsp_branchobj **bobj; +int ecount; +int *elist; +double *eval; +int ccount; +CCtsp_lpclique *clist; +double *cval; +#endif +{ + int rval = 0; + int i, k; + sbitem *slist = (sbitem *) NULL; + CCtsp_branchobj *b; + + *ngot = 0; + *bobj = (CCtsp_branchobj *) NULL; + + if (ecount + ccount == 0) { + fprintf (stderr, "no elements in merge_edge_clique\n"); + rval = 1; goto CLEANUP; + } + + slist = CC_SAFE_MALLOC (nwant + 1, sbitem); + if (!slist) { + fprintf (stderr, "out of memory in merge_edge_clique\n"); + rval = 1; goto CLEANUP; + } + init_sblist (slist, nwant); + + for (i = 0; i < ecount; i++) { + insert_sblist (slist, eval[i], i); + } + for (i = 0; i < ccount; i++) { + insert_sblist (slist, cval[i], i + ecount); + } + + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + k++; + } + } + if (k == 0) { + fprintf (stderr, "nothing appeares in merge_edge_clique\n"); + rval = 1; goto CLEANUP; + } + + *bobj = CC_SAFE_MALLOC (k, CCtsp_branchobj); + if (!(*bobj)) { + fprintf (stderr, "out of memory in merge_edge_clique\n"); + rval = 1; goto CLEANUP; + } + + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + b = &((*bobj)[k]); + CCtsp_init_branchobj (b); + if (slist[i].name < ecount) { + b->ends[0] = lp->graph.edges[elist[slist[i].name]].ends[0]; + b->ends[1] = lp->graph.edges[elist[slist[i].name]].ends[1]; + } else { + b->clique = CC_SAFE_MALLOC (1, CCtsp_lpclique); + if (!b->clique) { + fprintf (stderr, "out of memory in merge_edge_clique\n"); + rval = 1; goto CLEANUP; + } else { + rval = CCtsp_copy_lpclique (&clist[slist[i].name - ecount], + b->clique); + } + if (!b->clique || rval) { + fprintf (stderr, "CCtsp_copy_clique failed\n"); + for (i = 0; i < k; i++) { + if ((*bobj)[i].clique) { + CCtsp_free_lpclique ((*bobj)[i].clique); + CC_IFFREE ((*bobj)[i].clique, CCtsp_lpclique); + } + } + CC_IFFREE (b->clique, CCtsp_lpclique); + CC_FREE (*bobj, CCtsp_branchobj); + goto CLEANUP; + } + } + k++; + } + } + *ngot = k; + +CLEANUP: + + CC_IFFREE (slist, sbitem); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_check_integral (CCtsp_lp *lp, double *val, int **cyc, int *yesno) +#else +int CCtsp_check_integral (lp, val, cyc, yesno) +CCtsp_lp *lp; +double *val; +int **cyc; +int *yesno; +#endif +{ + int rval = 0; + double *x = (double *) NULL; + double eval = 0.0; + int *xlist = (int *) NULL; + int xcount; + int *comps = (int *) NULL; + int *compscount = (int *) NULL; + int ncomp; + int *elist = (int *) NULL; + int ncount = lp->graph.ncount; + int i, j, ecount; + + *yesno = 0; + *val = 0.0; + if (cyc) *cyc = (int *) NULL; + + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, &xcount, + &xlist, &x, (double **) NULL, (double **) NULL, + (double **) NULL); + if (rval) { + fprintf (stderr, "CCtsp_get_lp_result failed\n"); goto CLEANUP; + } + + for (i = 0; i < xcount; i++) { + if (x[i] > 0.5) { + if (1.0 - x[i] > CCtsp_INTTOL) goto CLEANUP; + } else { + if (x[i] > CCtsp_INTTOL) goto CLEANUP; + } + } + + elist = CC_SAFE_MALLOC (2*ncount, int); + if (!elist) { + fprintf (stderr, "out of memory in CCtsp_check_integral\n"); + } + ecount = 0; + + for (i = 0; i < xcount; i++) { + if (x[i] > CCtsp_INTTOL) { + j = CCtsp_find_edge (&lp->graph, xlist[2*i], xlist[2*i+1]); + if (j < 0) { + fprintf (stderr, "x edge not in graph\n"); + rval = 1; goto CLEANUP; + } + eval += ((double) lp->graph.edges[j].len); + elist[2*ecount] = lp->graph.edges[j].ends[0]; + elist[2*ecount+1] = lp->graph.edges[j].ends[1]; + ecount++; + } + } + + rval = CCcut_connect_components (ncount, xcount, xlist, x, + &ncomp, &compscount, &comps); + if (rval) { + fprintf (stderr, "CCcut_connect_components failed\n"); goto CLEANUP; + } + if (ncomp > 1) { + printf ("integral solution not connected\n"); fflush (stdout); + goto CLEANUP; + } + printf ("Integral Solution of Value %.2f\n", *val); fflush (stdout); + + if (cyc) { + *cyc = CC_SAFE_MALLOC (ncount, int); + if (!(*cyc)) { + fprintf (stderr, "out of memory in CCtsp_check_integral\n"); + rval = 1; goto CLEANUP; + } + rval = CCutil_edge_to_cycle (ncount, elist, *cyc); + if (rval) { + fprintf (stderr, "CCutil_edge_to_cycle failed\n"); + CC_FREE (*cyc, int); + goto CLEANUP; + } + } + *yesno = 1; + *val = eval; + + +CLEANUP: + + CC_IFFREE (x, double); + CC_IFFREE (xlist, int); + CC_IFFREE (comps, int); + CC_IFFREE (compscount, int); + CC_IFFREE (elist, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_find_branch_edge (CCtsp_lp *lp, int *n0, int *n1, double *val, + int **cyc, int branchtype) +#else +int CCtsp_find_branch_edge (lp, n0, n1, val, cyc, branchtype) +CCtsp_lp *lp; +int *n0, *n1; +double *val; +int **cyc; +int branchtype; +#endif +{ + int rval = 0; + double *x = (double *) NULL; + int *xlist = (int *) NULL; + int xcount; + double maxdiff = -1.0; + int i, test, besti = 0; + + *n0 = -2; + *n1 = -2; + *val = 0.0; + if (cyc) *cyc = (int *) NULL; + + rval = CCtsp_check_integral (lp, val, cyc, &test); + if (rval) { + fprintf (stderr, "CCtsp_check_integral failed\n"); + goto CLEANUP; + } + if (test) { + printf ("Integral solution detected in CCtsp_find_branch_edge\n"); + fflush (stdout); + *n0 = -1; + *n1 = -1; + goto CLEANUP; + } + + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, &xcount, + &xlist, &x, (double **) NULL, (double **) NULL, + (double **) NULL); + if (rval) { + fprintf (stderr, "CCtsp_get_lp_result failed\n"); goto CLEANUP; + } + + for (i = 0; i < xcount; i++) { + if (x[i] > 0.5) { + if (1.0 - x[i] > maxdiff) { + maxdiff = 1.0 - x[i]; + besti = i; + } + } else { + if (x[i] > maxdiff) { + maxdiff = x[i]; + besti = i; + } + } + } + + switch (branchtype) { + case CCtsp_BRANCH_MIDDLE: + *n0 = xlist[2*besti]; + *n1 = xlist[2*besti+1]; + break; + case CCtsp_BRANCH_STRONG: + rval = find_strong_branch (lp, n0, n1); + if (rval) { + fprintf (stderr, "find_strong_branch failed\n"); + goto CLEANUP; + } + if (*n0 == -1) { + *n0 = xlist[2*besti]; + *n1 = xlist[2*besti+1]; + } + break; + default: + fprintf (stderr, "unknown branchtype\n"); + rval = 1; goto CLEANUP; + } + +CLEANUP: + + CC_IFFREE (x, double); + CC_IFFREE (xlist, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_strong_branch (CCtsp_lp *lp, int *n0, int *n1) +#else +static int find_strong_branch (lp, n0, n1) +CCtsp_lp *lp; +int *n0, *n1; +#endif +{ + int rval = 0; + int *elist = (int *) NULL; + int ngot; + + *n0 = -1; + *n1 = -1; + + rval = find_strongbranch_edges (lp, 1, &ngot, &elist, (double **) NULL); + if (rval) { + fprintf (stderr, "find_strongbranch_edges failed\n"); + goto CLEANUP; + } + + if (ngot == 0) { + printf ("WARNING: nothing came back from find_strongbranch_edges\n"); + goto CLEANUP; + } + + *n0 = lp->graph.edges[elist[0]].ends[0]; + *n1 = lp->graph.edges[elist[0]].ends[1]; + + printf ("STRONG branch edge: %d %d\n", *n0, *n1); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (elist, int); + return rval; +} + + +#ifdef CC_PROTOTYPE_ANSI +static int find_strongbranch_edges (CCtsp_lp *lp, int nwant, int *ngot, + int **elist, double **eval) +#else +static int find_strongbranch_edges (lp, nwant, ngot, elist, eval) +CCtsp_lp *lp; +int nwant; +int *ngot; +int **elist; +double **eval; +#endif +{ + int rval = 0; + int *candlist = (int *) NULL; + int ncand = 0; + int i, k; + double *downpen = (double *) NULL; + double *uppen = (double *) NULL; + double sval; + double szeit; + sbitem *slist = (sbitem *) NULL; + + *ngot = 0; + *elist = (int *) NULL; + if (eval) { + *eval = (double *) NULL; + } + + rval = find_candidate_edges (lp, TSP_BRANCH_STRONG_CHOICES, &ncand, + &candlist); + if (rval) { + fprintf (stderr, "find_candidate_edges failed\n"); + goto CLEANUP; + } + + if (ncand == 0) { + printf ("WARNING: find_candidate edges did not find anything\n"); + goto CLEANUP; + } + + printf ("Run strongbranch with %d candidate edges\n", ncand); + fflush (stdout); + + downpen = CC_SAFE_MALLOC (ncand, double); + uppen = CC_SAFE_MALLOC (ncand, double); + if (!downpen || !uppen) { + fprintf (stderr, "out of memory in find_strongbranch_edges\n"); + rval = 1; goto CLEANUP; + } + + szeit = CCutil_zeit (); + rval = CClp_strongbranch (&lp->lp, candlist, ncand, downpen, uppen, + TSP_BRANCH_STRONG_ITERATIONS, &lp->upperbound); + if (rval) { + fprintf (stderr, "CClp_strongbranch failed\n"); goto CLEANUP; + } + printf ("Strongbranch used %.2f seconds\n", CCutil_zeit () - szeit); + + slist = CC_SAFE_MALLOC (nwant + 1, sbitem); + if (!slist) { + fprintf (stderr, "out of memory in find_strongbranch_edges\n"); + rval = 1; goto CLEANUP; + } + init_sblist (slist, nwant); + + for (i = 0; i < ncand; i++) { + printf ("SB Edge (%d, %d): %.4f %.4f\n", + lp->graph.edges[candlist[i]].ends[0], + lp->graph.edges[candlist[i]].ends[1], + downpen[i], uppen[i]); + fflush (stdout); + sval = TSP_BRANCH_STRONG_VAL (downpen[i], uppen[i]); + insert_sblist (slist, sval, candlist[i]); + } + + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + k++; + } + } + if (k == 0) { + printf ("WARNING: no edges appeared in strongbranch\n"); + goto CLEANUP; + } + + *elist = CC_SAFE_MALLOC (k, int); + if (!(*elist)) { + fprintf (stderr, "out of memory in find_strongbranch_edges\n"); + rval = 1; goto CLEANUP; + } + if (eval) { + *eval = CC_SAFE_MALLOC (k, double); + if (!(*eval)) { + fprintf (stderr, "out of memory in find_strongbranch_edges\n"); + CC_IFFREE (*elist, int); + rval = 1; goto CLEANUP; + } + } + *ngot = k; + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + (*elist)[k] = slist[i].name; + if (eval) { + (*eval)[k] = slist[i].val; + } + k++; + } + } + +CLEANUP: + + CC_IFFREE (slist, sbitem); + CC_IFFREE (candlist, int); + CC_IFFREE (downpen, double); + CC_IFFREE (uppen, double); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_candidate_edges (CCtsp_lp *lp, int nwant, int *ngot, int **list) +#else +static int find_candidate_edges (lp, nwant, ngot, list) +CCtsp_lp *lp; +int nwant; +int *ngot; +int **list; +#endif +{ + int *goodlist = (int *) NULL; + double *downpen = (double *) NULL; + double *uppen = (double *) NULL; + double sval; + int nrows, ngood; + int i, k; + sbitem *slist = (sbitem *) NULL; + int rval = 0; + + *ngot = 0; + *list = (int *) NULL; + + if (nwant == TSP_BRANCH_STRONG_ALL_CHOICES) { + rval = find_all_candidate_edges (lp, ngot, list); + if (rval) { + fprintf (stderr, "find_all_candidate_edges failed\n"); + goto CLEANUP; + } + goto CLEANUP; + } + + slist = CC_SAFE_MALLOC (nwant + 1, sbitem); + if (!slist) { + fprintf (stderr, "out of memory in find_strongbranch\n"); + rval = 1; goto CLEANUP; + } + init_sblist (slist, nwant); + + nrows = lp->graph.ncount + lp->cuts.cutcount; + goodlist = CC_SAFE_MALLOC (nrows, int); + downpen = CC_SAFE_MALLOC (nrows, double); + uppen = CC_SAFE_MALLOC (nrows, double); + if (!goodlist || !downpen || !uppen) { + fprintf (stderr, "out of memory in find_strongbranch\n"); + rval = 1; goto CLEANUP; + } + rval = CClp_getgoodlist (&lp->lp, goodlist, &ngood, downpen, uppen); + if (rval) { + fprintf (stderr, "CClp_getgoodlist failed\n"); goto CLEANUP; + } + printf ("Found %d good edges\n", ngood); fflush (stdout); + + for (i = 0; i < ngood; i++) { + if (downpen[i] > lp->upperbound) downpen[i] = lp->upperbound; + if (uppen[i] > lp->upperbound) uppen[i] = lp->upperbound; + sval = TSP_BRANCH_STRONG_FIRST_VAL (downpen[i], uppen[i]); + insert_sblist (slist, sval, goodlist[i]); + } + + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + k++; + } + } + if (k == 0) { + printf ("WARNING: CClp_getgoodlist returned no edges\n"); + goto CLEANUP; + } + + *list = CC_SAFE_MALLOC (k, int); + if (!(*list)) { + fprintf (stderr, "out of memory in find_candidate list\n"); + rval = 1; goto CLEANUP; + } + *ngot = k; + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + (*list)[k++] = slist[i].name; + } + } + +CLEANUP: + + CC_IFFREE (goodlist, int); + CC_IFFREE (downpen, double); + CC_IFFREE (uppen, double); + CC_IFFREE (slist, sbitem); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_all_candidate_edges (CCtsp_lp *lp, int *ngot, int **list) +#else +static int find_all_candidate_edges (lp, ngot, list) +CCtsp_lp *lp; +int *ngot; +int **list; +#endif +{ + int rval = 0; + double *x = (double *) NULL; + int *xlist = (int *) NULL; + int i, j, xcount, count; + + *ngot = 0; + *list = (int *) NULL; + + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, &xcount, + &xlist, &x, (double **) NULL, (double **) NULL, + (double **) NULL); + if (rval) { + fprintf (stderr, "get_lp_result failed\n"); goto CLEANUP; + } + + count = 0; + for (i = 0; i < xcount; i++) { + if (x[i] >= CCtsp_INTTOL && x[i] <= 1.0 - CCtsp_INTTOL) { + count++; + } + } + + if (!count) { + fprintf (stderr, "WARNING: The solution is integral\n"); + goto CLEANUP; + } + + *list = CC_SAFE_MALLOC (count, int); + if (!(*list)) { + fprintf (stderr, "out of memory in find_all_candidate_edges\n"); + rval = 1; goto CLEANUP; + } + + count = 0; + for (i = 0; i < xcount; i++) { + if (x[i] >= CCtsp_INTTOL && x[i] <= 1.0 - CCtsp_INTTOL) { + j = CCtsp_find_edge (&lp->graph, xlist[2 * i], xlist[2 * i + 1]); + if (j < 0) { + fprintf (stderr, "edge not in lp in find_all_candiate_edges\n"); + CC_IFFREE (*list, int); + rval = 1; goto CLEANUP; + } + (*list)[count++] = j; + } + } + *ngot = count; + +CLEANUP: + + CC_IFFREE (x, double); + CC_IFFREE (xlist, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void init_sblist (sbitem *list, int count) +#else +static void init_sblist (list, count) +sbitem *list; +int count; +#endif +{ + int i; + + for (i = 0; i < count; i++) { + list[i].val = -1.0; + list[i].name = -1; + } + list[count].val = CCtsp_LP_MAXDOUBLE; +} + +#ifdef CC_PROTOTYPE_ANSI +static void insert_sblist (sbitem *list, double val, int name) +#else +static void insert_sblist (list, val, name) +sbitem *list; +double val; +int name; +#endif +{ + int k; + + if (list[0].val < val) { + for (k = 0; list[k+1].val < val; k++) { + list[k].name = list[k + 1].name; + list[k].val = list[k + 1].val; + } + list[k].val = val; + list[k].name = name; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_find_branch_cliques (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_lpclique **bcliques, double **bval) +#else +int CCtsp_find_branch_cliques (lp, nwant, ngot, bcliques, bval) +CCtsp_lp *lp; +int nwant; +int *ngot; +CCtsp_lpclique **bcliques; +double **bval; +#endif +{ + int ccount = 0; + CCtsp_lpclique *cliques = (CCtsp_lpclique *) NULL; + sbitem *slist = (sbitem *) NULL; + int i, k; + int rval = 0; + double up, down, sval, szeit; + double meanval = 0.0; + + *ngot = 0; + *bcliques = (CCtsp_lpclique *) NULL; + if (bval) { + *bval = (double *) NULL; + } + + rval = find_candidate_cliques (lp, TSP_STRONG_CUT_CHOICES, &ccount, + &cliques, 1); + if (rval) { + fprintf (stderr, "find_candidate_cliques failed\n"); goto CLEANUP; + } + printf ("Found %d candidate cliques\n", ccount); fflush (stdout); + + slist = CC_SAFE_MALLOC (nwant + 1, sbitem); + if (!slist) { + fprintf (stderr, "out of memory in find_strongbranch_edges\n"); + rval = 1; goto CLEANUP; + } + init_sblist (slist, nwant); + + + for (i = 0; i < ccount; i++) { + szeit = CCutil_zeit (); + rval = CCtsp_test_cut_branch (lp, &cliques[i], &down, &up); + if (rval) { + fprintf (stderr, "CCtsp_test_cut_branch failed\n"); + goto CLEANUP; + } + printf ("SB CLIQUE %d: %f %f (%.2f seconds)\n", + i, down, up, CCutil_zeit () - szeit); + fflush (stdout); + sval = TSP_BRANCH_STRONG_VAL (down, up); + insert_sblist (slist, sval, i); + meanval += sval; + } + + if (ccount) { + printf ("Average Clique Value: %f\n", meanval / ((double) ccount)); + fflush (stdout); + } + + for (i = nwant - 1; i >= 0; i--) { + if (slist[i].name != -1) { + printf ("Top Clique: %d (%f)\n", slist[i].name, slist[i].val); + fflush (stdout); + break; + } + } + + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + k++; + } + } + if (k == 0) { + printf ("WARNING: no branching cliques were found\n"); + goto CLEANUP; + } + + *bcliques = CC_SAFE_MALLOC (k, CCtsp_lpclique); + if (!(*bcliques)) { + fprintf (stderr, "out of memory in CCtsp_find_branch_cliques\n"); + rval = 1; goto CLEANUP; + } + if (bval) { + *bval = CC_SAFE_MALLOC (k, double); + if (!(*bval)) { + fprintf (stderr, "out of memory in CCtsp_find_branch_cliques\n"); + CC_IFFREE (*bcliques, CCtsp_lpclique); + rval = 1; goto CLEANUP; + } + } + *ngot = k; + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + rval = CCtsp_copy_lpclique (&cliques[slist[i].name], + &(*bcliques)[k]); + if (rval) { + fprintf (stderr, "CCtsp_copy_clique failed\n"); + for (i = 0; i < k; i++) { + CC_IFFREE ((*bcliques)[i].nodes, CCtsp_segment); + } + CC_FREE (*bcliques, CCtsp_lpclique); + goto CLEANUP; + } + if (bval) { + (*bval)[k] = slist[i].val; + } + k++; + } + } + *ngot = k; + + +CLEANUP: + + CC_IFFREE (slist, sbitem); + for (i = 0; i < ccount; i++) { + CC_IFFREE (cliques[i].nodes, CCtsp_segment); + } + CC_IFFREE (cliques, CCtsp_lpclique); + + return 0; +} + +#define TSP_STRONG_GETWEIGHT_BATCH 250 + +#ifdef CC_PROTOTYPE_ANSI +static int find_candidate_cliques (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_lpclique **list, int use_getweight) +#else +static int find_candidate_cliques (lp, nwant, ngot, list, use_getweight) +CCtsp_lp *lp; +int nwant; +int *ngot; +CCtsp_lpclique **list; +int use_getweight; +#endif +{ + int xcount = 0; + double *x = (double *) NULL; + int *xlist = (int *) NULL; + int ccount = 0; + double *cval = (double *) NULL; + CCtsp_lpclique *cliques = (CCtsp_lpclique *) NULL; + double *weights = (double *) NULL; + sbitem *slist = (sbitem *) NULL; + CCtsp_lprow cr; + CCtsp_lpcut_in cu; + int i, k, j, batch, ntry, nzlist; + double down, up, t, sval; + int rval = 0; + + CCtsp_init_lprow (&cr); + + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, &xcount, + &xlist, &x, (double **) NULL, (double **) NULL, + (double **) NULL); + if (rval) { + fprintf (stderr, "CCtsp_get_lp_result failed\n"); goto CLEANUP; + } + + ntry = (use_getweight ? TSP_STRONG_CUT_CANDIDATES : nwant); + + rval = CCtsp_branch_cutpool_cliques (lp->pool, &cliques, &ccount, + lp->graph.ncount, xcount, xlist, x, ntry, &cval); + if (rval) { + fprintf (stderr, "CCtsp_branch_cutpool_cliques failed\n"); + goto CLEANUP; + } + if (ccount == 0) { + fprintf (stderr, "WARNING: no cutpool cliques were found\n"); + goto CLEANUP; + } + + if (use_getweight) { + cu.handlecount = 0; + cu.cliquecount = 1; + cu.next = (CCtsp_lpcut_in *) NULL; + cu.prev = (CCtsp_lpcut_in *) NULL; + cu.rhs = 2; + + weights = CC_SAFE_MALLOC (TSP_STRONG_GETWEIGHT_BATCH, double); + if (!weights) { + fprintf (stderr, "out of memory in find_candidate_cliques\n"); + rval = 1; goto CLEANUP; + } + + slist = CC_SAFE_MALLOC (nwant + 1, sbitem); + if (!slist) { + fprintf (stderr, "out of memory in find_strongbranch_edges\n"); + rval = 1; goto CLEANUP; + } + init_sblist (slist, nwant); + + for (i = 0, batch = 0; i < ccount; i++) { + cu.cliques = &(cliques[i]); + nzlist = CCtsp_lpcut_in_nzlist (&lp->graph, &cu); + rval = CCtsp_add_nzlist_to_lp (lp, nzlist, 2, 'G', &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_nzlist_to_lp failed\n"); + goto CLEANUP; + } + if ((i+1) % TSP_STRONG_GETWEIGHT_BATCH == 0 || i == ccount - 1) { + rval = CCutil_reallocrus_count ((void **) &(cr.begin), + cr.rowcnt + 1, sizeof (int)); + if (rval) { + fprintf (stderr, "out of memory\n"); + goto CLEANUP; + } + cr.begin[cr.rowcnt] = cr.nzcnt; + rval = CClp_getweight (&lp->lp, cr.rowcnt, cr.begin, + cr.indices, cr.entries, weights); + if (rval) { + fprintf (stderr, "CClp_getweight failed\n"); goto CLEANUP; + } + + for (j = 0; j < cr.rowcnt; j++) { + t = cval[j] - 2.0; + down = (t * t) / weights[j]; + t = 4.0 - cval[j]; + up = (t * t) / weights[j]; + sval = TSP_BRANCH_STRONG_CUT_NORM_VAL (down, up); + insert_sblist (slist, sval, batch+j); + } + CCtsp_free_lprow (&cr); + batch = i+1; + } + } + + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + k++; + } + } + if (k == 0) { + printf ("WARNING: no candidate branching cliques were found\n"); + goto CLEANUP; + } + + *list = CC_SAFE_MALLOC (k, CCtsp_lpclique); + if (!(*list)) { + fprintf (stderr, "out of memory in CCtsp_find_branch_cliques\n"); + rval = 1; goto CLEANUP; + } + for (i = 0, k = 0; i < nwant; i++) { + if (slist[i].name != -1) { + rval = CCtsp_copy_lpclique (&cliques[slist[i].name], + &(*list)[k++]); + if (rval) { + fprintf (stderr, "CCtsp_copy_clique failed\n"); + for (i = 0; i < k; i++) { + CC_IFFREE ((*list)[i].nodes, CCtsp_segment); + } + CC_FREE (*list, CCtsp_lpclique); + goto CLEANUP; + } + } + } + *ngot = k; + } else { + *list = cliques; + *ngot = ccount; + } + +CLEANUP: + + CCtsp_free_lprow (&cr); + CC_IFFREE (slist, sbitem); + CC_IFFREE (x, double); + CC_IFFREE (xlist, int); + CC_IFFREE (cval, double); + CC_IFFREE (weights, double); + if (use_getweight) { + for (i = 0; i < ccount; i++) { + CC_IFFREE (cliques[i].nodes, CCtsp_segment); + } + CC_IFFREE (cliques, CCtsp_lpclique); + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_test_cut_branch (CCtsp_lp *lp, CCtsp_lpclique *c, double *down, + double *up) +#else +int CCtsp_test_cut_branch (lp, c, down, up) +CCtsp_lp *lp; +CCtsp_lpclique *c; +double *up, *down; +#endif +{ + CCtsp_lprow cr; + CCtsp_lpcut_in cu; + int nzlist, status; + CClpbasis basis; + int rval = 0; + + *down = -CCtsp_LP_MAXDOUBLE; + *up = -CCtsp_LP_MAXDOUBLE; + CCtsp_init_lprow (&cr); + + cu.handlecount = 0; + cu.cliquecount = 1; + cu.cliques = c; + cu.next = (CCtsp_lpcut_in *) NULL; + cu.prev = (CCtsp_lpcut_in *) NULL; + cu.rhs = 2; + + CClp_init_basis (&basis); + rval = CClp_get_basis_and_norms (&lp->lp, &basis); + if (rval) { + fprintf (stderr, "CClp_get_basis_and_norms failed\n"); goto CLEANUP; + } + + nzlist = CCtsp_lpcut_in_nzlist (&lp->graph, &cu); + rval = CCtsp_add_nzlist_to_lp (lp, nzlist, 2, 'L', &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_nzlist_to_lp failed\n"); goto CLEANUP; + } + rval = CCtsp_add_multiple_rows (lp, &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_multiple_rows failed\n"); goto CLEANUP; + } + rval = CClp_limited_dualopt (&lp->lp, TSP_STRONG_CUT_ITER, + &status, &lp->upperbound); + if (rval) { + fprintf (stderr, "CClp_limited_dualopt failed\n"); goto CLEANUP; + } + if (status == CClp_INFEASIBLE) { + printf ("Down side of cut branch is infeasible\n"); fflush (stdout); + *down = lp->upperbound; + } else if (status == CClp_UNKNOWN) { + printf ("Down side information is not avaiable\n"); fflush (stdout); + *down = lp->lowerbound; + } else { + rval = CClp_objval (&lp->lp, down); + if (rval) { + fprintf (stderr, "CClp_objval failed\n"); goto CLEANUP; + } + } + + rval = CCtsp_delete_cut (lp, lp->cuts.cutcount); + if (rval) { + fprintf (stderr, "CCtsp_delete_cut failed\n"); goto CLEANUP; + } + rval = CClp_load_basis_and_norms (&lp->lp, &basis); + if (rval) { + fprintf (stderr, "CClp_load_basis_and_norms failed\n"); goto CLEANUP; + } + + cr.sense[0] = 'G'; + cr.rhs[0] = 4.0; + rval = CCtsp_add_multiple_rows (lp, &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_multiple_rows failed\n"); goto CLEANUP; + } + rval = CClp_limited_dualopt (&lp->lp, TSP_STRONG_CUT_ITER, &status, + &lp->upperbound); + if (rval) { + fprintf (stderr, "CClp_limited_dualopt failed\n"); goto CLEANUP; + } + if (status == CClp_INFEASIBLE) { + printf ("Up side of cut branch is infeasible\n"); fflush (stdout); + *up = lp->upperbound; + } else if (status == CClp_UNKNOWN) { + printf ("Up side information is not avaiable\n"); fflush (stdout); + *up = lp->lowerbound; + } else { + rval = CClp_objval (&lp->lp, up); + if (rval) { + fprintf (stderr, "CClp_objval failed\n"); goto CLEANUP; + } + } + + rval = CCtsp_delete_cut (lp, lp->cuts.cutcount); + if (rval) { + fprintf (stderr, "CCtsp_delete_cut failed\n"); goto CLEANUP; + } + rval = CClp_load_basis_and_norms (&lp->lp, &basis); + if (rval) { + fprintf (stderr, "CClp_load_basis_and_norms failed\n"); goto CLEANUP; + } + rval = CClp_opt (&lp->lp, CClp_METHOD_DUAL); + if (rval) { + fprintf (stderr, "CClp_opt failed\n"); + } + +CLEANUP: + + CClp_free_basis (&basis); + CCtsp_free_lprow (&cr); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_execute_branch (CCtsp_lp *lp, CCtsp_branchobj *b) +#else +int CCtsp_execute_branch (lp, b) +CCtsp_lp *lp; +CCtsp_branchobj *b; +#endif +{ + int n0 = -1; + int n1 = -1; + CCtsp_lpclique *c = (CCtsp_lpclique *) NULL; + int rval = 0; + int i, j; + + if (!b) { + fprintf (stderr, "CCtsp_execute_branch called without a CCtsp_branchobj\n"); + rval = 1; goto CLEANUP; + } + + if (b->ends[0] != -1) { + n0 = b->ends[0]; + n1 = b->ends[1]; + printf ("Branch Edge (%d,%d), to value %d\n", n0, n1, b->rhs); + fflush (stdout); + + if (n0 >= lp->graph.ncount || n0 < 0 || + n1 >= lp->graph.ncount || n1 < 0) { + fprintf (stderr, "CCtsp_execute_branch has invalid nodes\n"); + rval = 1; goto CLEANUP; + } + + if (n0 > n1) { + CC_SWAP (n0, n1, j); + } + + j = CCtsp_find_edge (&lp->graph, n0, n1); + if (j < 0) { + fprintf (stderr, "branching edge is not in the LP edgeset\n"); + rval = 1; goto CLEANUP; + } + if (lp->graph.edges[j].fixed) { + fprintf (stderr, "branching edge is fixed to 1 in the LP\n"); + rval = 1; goto CLEANUP; + } + if (lp->graph.edges[j].branch) { + fprintf (stderr, "branching edge has already been branched\n"); + rval = 1; goto CLEANUP; + } + + if (b->rhs) { + rval = CClp_setbnd (&lp->lp, j, 'L', 1.0); + if (rval) { + fprintf (stderr, "CClp_setbnd failed\n"); + rval = 1; goto CLEANUP; + } + lp->graph.edges[j].branch = lp->branchdepth + 1; + } else { + rval = CClp_setbnd (&lp->lp, j, 'U', 0.0); + if (rval) { + fprintf (stderr, "CClp_setbnd failed\n"); + rval = 1; goto CLEANUP; + } + lp->graph.edges[j].branch = -(lp->branchdepth + 1); + } + } else { + CCtsp_lprow cr; + CCtsp_lpcut_in d; + + if (!b->clique) { + fprintf (stderr, "CCtsp_branchobj has no edge or clique\n"); + rval = 1; goto CLEANUP; + } + + printf ("Branch Clique "); fflush (stdout); + for (i = 0; i < b->clique->segcount; i++) { + printf ("%d->%d ", b->clique->nodes[i].lo, b->clique->nodes[i].hi); + fflush (stdout); + } + if (b->sense == 'G') { + printf ("to at least %d\n", b->rhs); + } else { + printf ("to at most %d\n", b->rhs); + } + fflush (stdout); + + c = CC_SAFE_MALLOC (1, CCtsp_lpclique); + if (!c) { + fprintf (stderr, "out of memory in CCtsp_execute_branch\n"); + rval = 1; goto CLEANUP; + } + rval = CCtsp_copy_lpclique (b->clique, c); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); + rval = 1; goto CLEANUP; + } + + CCtsp_init_lpcut_in (&d); + d.handlecount = 0; + d.cliquecount = 1; + d.rhs = b->rhs; + d.sense = b->sense; + d.branch = 1; + d.cliques = c; + + CCtsp_init_lprow (&cr); + rval = CCtsp_add_cut (lp, &d, &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_cut failed\n"); + rval = 1; goto CLEANUP; + } + rval = CCtsp_add_multiple_rows (lp, &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_multiple_rows failed\n"); + rval = 1; goto CLEANUP; + } + CCtsp_free_lprow (&cr); + CCtsp_free_lpcut_in (&d); + } + + rval = CClp_dualopt (&lp->lp); + if (rval == 2) { + rval = CCtsp_infeas_recover (lp); + if (rval == 2) { + printf ("Problem is really infeasible (CCtsp_execute_branch)\n"); + goto CLEANUP; + } else if (rval) { + fprintf (stderr, "CCtsp_infeas_recover failed\n"); + rval = 1; goto CLEANUP; + } + } else if (rval) { + fprintf (stderr, "CClp_dualopt failed\n"); + rval = 1; goto CLEANUP; + } + + rval = CCtsp_update_result (lp); + if (rval) { + fprintf (stderr, "CCtsp_update_result failed\n"); + rval = 1; goto CLEANUP; + } + CCtsp_free_bigdual (&lp->exact_dual); + +CLEANUP: + + if (rval == 0 || rval == 2) { + int sval = 0; + sval = CCutil_reallocrus_count ((void **) &(lp->branchhistory), + lp->branchdepth + 1, sizeof (CCtsp_branchobj)); + if (sval) { + fprintf (stderr, "CCutil_reallocrus_count failed\n"); return 1; + } + CCtsp_init_branchobj (&lp->branchhistory[lp->branchdepth]); + lp->branchhistory[lp->branchdepth].depth = lp->branchdepth + 1; + lp->branchhistory[lp->branchdepth].ends[0] = n0; + lp->branchhistory[lp->branchdepth].ends[1] = n1; + lp->branchhistory[lp->branchdepth].rhs = b->rhs; + if (b->clique) { + c = CC_SAFE_MALLOC (1, CCtsp_lpclique); + if (!c) { + fprintf (stderr, "out of memory in CCtsp_execute_branch\n"); + return 1; + } + sval = CCtsp_copy_lpclique (b->clique, c); + if (sval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); return 1; + } + lp->branchhistory[lp->branchdepth].clique = c; + } else { + lp->branchhistory[lp->branchdepth].clique = (CCtsp_lpclique *) NULL; + } + lp->branchhistory[lp->branchdepth].sense = b->sense; + lp->branchdepth++; + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_execute_unbranch (CCtsp_lp *lp, CClpbasis *basis) +#else +int CCtsp_execute_unbranch (lp, basis) +CCtsp_lp *lp; +CClpbasis *basis; +#endif +{ + int rval = 0; + int n0, n1; + int num; + int depth = lp->branchdepth; + CCtsp_branchobj *b; + int j; + + if (depth <= 0) { + fprintf (stderr, "CCtsp_execute_unbranch called at depth 0\n"); + rval = 1; goto CLEANUP; + } + + if (lp->branchhistory[depth - 1].depth != depth) { + fprintf (stderr, "branchhistory is corrupted\n"); + rval = 1; goto CLEANUP; + } + b = &lp->branchhistory[depth - 1]; + + if (lp->branchhistory[depth - 1].ends[0] != -1) { + n0 = b->ends[0]; + n1 = b->ends[1]; + printf ("Unbranch Edge (%d,%d), from value %d\n", n0, n1, b->rhs); + fflush (stdout); + + if (n0 > n1) { + CC_SWAP (n0, n1, j); + } + + j = CCtsp_find_edge (&lp->graph, n0, n1); + if (j < 0) { + fprintf (stderr, "ERROR: unbranching 1-edge is not in LP\n"); + rval = 1; goto CLEANUP; + } + if (b->rhs) { + if (lp->graph.edges[j].branch <= 0) { + fprintf (stderr, "unbranching 1-edge not branched to 1\n"); + rval = 1; goto CLEANUP; + } + rval = CClp_setbnd (&lp->lp, j, 'L', 0.0); + if (rval) { + fprintf (stderr, "CClp_setbnd failed\n"); goto CLEANUP; + } + } else { + if (lp->graph.edges[j].branch >= 0) { + fprintf (stderr, "unbranching 0-edge not branched to 0\n"); + rval = 1; goto CLEANUP; + } + + rval = CClp_setbnd (&lp->lp, j, 'U', 1.0); + if (rval) { + fprintf (stderr, "CClp_setbnd failed\n"); goto CLEANUP; + } + } + lp->graph.edges[j].branch = 0; + } else { + if (!b->clique) { + fprintf (stderr, "branchhistory has no edge or clique\n"); + rval = 1; goto CLEANUP; + } + rval = find_branched_clique (lp, b->clique, b->sense, b->rhs, &num); + if (rval) { + fprintf (stderr, "find_branched_clique failed\n"); + goto CLEANUP; + } + printf ("The unbranching clique is cut %d\n", num); fflush (stdout); + if (lp->cuts.cuts[num].branch == 0) { + fprintf (stderr, "the unbranching clique is not set to branch\n"); + rval = 1; goto CLEANUP; + } + + { + int q; + CCtsp_lpcut *cu = &lp->cuts.cuts[num]; + CCtsp_lpclique *t; + + printf ("Sense: %c RHS: %d Cliques: %d Branch: %d\n", + cu->sense, cu->rhs, cu->cliquecount, cu->branch); + t = &lp->cuts.cliques[cu->cliques[0]]; + printf ("Clique: "); + for (q = 0; q < t->segcount; q++) { + printf ("%d->%d ", t->nodes[q].lo, t->nodes[q].hi); + } + printf ("\n"); fflush (stdout); + } + + if (!basis) { + CClp_pivotin (&lp->lp, lp->graph.ncount + num); + } + rval = CCtsp_delete_cut (lp, num); + if (rval) { + fprintf (stderr, "CCtsp_delete_cut failed\n"); goto CLEANUP; + } + CCtsp_delete_cut_from_cutlist (&lp->cuts, num); + } + + if (basis) { + rval = CClp_load_basis_and_norms (&lp->lp, basis); + if (rval) { + fprintf (stderr, "CClp_load_basis_and_norms failed\n"); + goto CLEANUP; + } + } + + rval = CClp_dualopt (&lp->lp); + if (rval == 2) { + fprintf (stderr, "infeasible lp in CCtsp_execute_unbranch\n"); + goto CLEANUP; + } else if (rval) { + fprintf (stderr, "CClp_dualopt failed\n"); goto CLEANUP; + } + + rval = CCtsp_update_result (lp); + if (rval) { + fprintf (stderr, "CCtsp_update_result failed\n"); goto CLEANUP; + } + CCtsp_free_bigdual (&lp->exact_dual); + +CLEANUP: + + if (!rval) { + CCtsp_free_branchobj (&lp->branchhistory[lp->branchdepth - 1]); + lp->branchdepth--; + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_branchhistory_to_lp (CCtsp_lp *lp) +#else +int CCtsp_add_branchhistory_to_lp (lp) +CCtsp_lp *lp; +#endif +{ + int i, k, num; + int rval = 0; + CCtsp_branchobj *b; + + for (i = 0; i < lp->branchdepth; i++) { + b = &lp->branchhistory[i]; + if (b->ends[0] != -1) { + k = CCtsp_find_edge (&lp->graph, b->ends[0], b->ends[1]); + if (k == -1) { + fprintf (stderr, "edge in branch history is not in LP\n"); + rval = 1; goto CLEANUP; + } + if (lp->graph.edges[k].fixed || lp->graph.edges[k].branch) { + fprintf (stderr, "edge in branch history is fixed/branched\n"); + rval = 1; goto CLEANUP; + } + if (b->rhs) { + rval = CClp_setbnd (&lp->lp, k, 'L', 1.0); + if (rval) { + fprintf (stderr, "CClp_setbnd failed\n"); goto CLEANUP; + } + lp->graph.edges[k].branch = b->depth; + } else { + rval = CClp_setbnd (&lp->lp, k, 'U', 0.0); + if (rval) { + fprintf (stderr, "CClp_setbnd failed\n"); goto CLEANUP; + } + lp->graph.edges[k].branch = -(b->depth); + } + } else { + rval = find_branched_clique (lp, b->clique, b->sense, + b->rhs, &num); + if (rval) { + fprintf (stderr, "find_branch_clique failed\n"); + goto CLEANUP; + } + lp->cuts.cuts[num].branch = 1; + } + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_branched_clique (CCtsp_lp *lp, CCtsp_lpclique *c, char sense, + int rhs, int *cutnum) +#else +static int find_branched_clique (lp, c, sense, rhs, cutnum) +CCtsp_lp *lp; +CCtsp_lpclique *c; +char sense; +int rhs; +int *cutnum; +#endif +{ + int i; + CCtsp_lpcut *cu; + CCtsp_lpcut *cuts = lp->cuts.cuts; + CCtsp_lpclique *cliques = lp->cuts.cliques; + int cutcount = lp->cuts.cutcount; + int diff = 0; + + *cutnum = -1; + + for (i = 0; i < cutcount; i++) { + cu = &cuts[i]; + if (cu->cliquecount == 1 && + cu->sense == sense && cu->rhs == rhs) { + CCtsp_lpclique_compare (&cliques[cu->cliques[0]], c, &diff); + if (!diff) { + *cutnum = i; return 0; + } + } + } + + fprintf (stderr, "did not find branched clique\n"); + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_bb_find_branch (char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double *upperbound, CCtsp_lpcuts *pool, + CCtsp_branchobj **b, int usecliques, int *foundtour, int *besttour) +#else +int CCtsp_bb_find_branch (probname, probnum, ncount, dat, ptour, upperbound, + pool, b, usecliques, foundtour, besttour) +char *probname; +int probnum; +int ncount; +CCdatagroup *dat; +int *ptour; +double *upperbound; +CCtsp_lpcuts *pool; +CCtsp_branchobj **b; +int usecliques; +int *foundtour; +int *besttour; +#endif +{ + int rval = 0; + double tval; + CCtsp_lp *lp = (CCtsp_lp *) NULL; + int *cyc = (int *) NULL; + int i, ngot, test; + + *foundtour = 0; + *b = (CCtsp_branchobj *) NULL; + + rval = CCtsp_bb_init_lp (&lp, probname, probnum, ncount, dat, ptour, + *upperbound, pool); + if (rval) { + fprintf (stderr, "CCtsp_bb_init_lp failed\n"); goto CLEANUP; + } + + rval = CCtsp_find_branch (lp, 1, &ngot, b, &tval, &cyc, usecliques); + if (rval) { + fprintf (stderr, "CCtsp_find_branch failed\n"); + goto CLEANUP; + } + + if (ngot == 0) { + printf ("No branch, found tour of value %.2f\n", tval); + fflush (stdout); + if (tval < lp->upperbound) lp->upperbound = tval; + rval = CCtsp_verify_lp_prune (lp, &test); + if (rval) { + fprintf (stderr, "CCtsp_verify_lp_prune failed\n"); + goto CLEANUP; + } + if (test) { + printf ("verified that LP can now be pruned\n"); fflush (stdout); + *foundtour = 1; + if (tval < *upperbound) { + *upperbound = tval; + if (besttour) { + for (i = 0; i < ncount; i++) { + besttour[i] = cyc[i]; + } + } + } + goto CLEANUP; + } else { + fprintf (stderr, "new tour did not permit exact pruning\n"); + rval = 1; goto CLEANUP; + } + } else { + printf ("found branch\n"); fflush (stdout); + } + + +CLEANUP: + + if (lp) CCtsp_free_tsp_lp_struct (&lp); + CC_IFFREE (cyc, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_bb_splitprob (char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double initial_ub, CCtsp_lpcuts *pool, + CCtsp_branchobj *b, int child0, int child1, double *val0, double *val1, + int *prune0, int *prune1) +#else +int CCtsp_bb_splitprob (probname, probnum, ncount, dat, ptour, initial_ub, + pool, b, child0, child1, val0, val1, prune0, prune1) +char *probname; +int probnum; +int ncount; +CCdatagroup *dat; +int *ptour; +double initial_ub; +CCtsp_lpcuts *pool; +CCtsp_branchobj *b; +int child0, child1; +double *val0, *val1; +int *prune0, *prune1; +#endif +{ + int rval = 0; + CCtsp_lp *lp = (CCtsp_lp *) NULL; + + *val0 = 0.0; + *val1 = 0.0; + *prune0 = 0; + *prune1 = 0; + + rval = CCtsp_bb_init_lp (&lp, probname, probnum, ncount, dat, ptour, + initial_ub, pool); + if (rval) { + fprintf (stderr, "CCtsp_bb_init_lp failed\n"); goto CLEANUP; + } + + rval = branch_side (lp, b, 0, child0, val0, prune0); + if (rval) { + fprintf (stderr, "branch_side failed\n"); goto CLEANUP; + } + + CCtsp_free_tsp_lp_struct (&lp); + rval = CCtsp_bb_init_lp (&lp, probname, probnum, ncount, dat, ptour, + initial_ub, pool); + if (rval) { + fprintf (stderr, "CCtsp_bb_init_lp failed\n"); goto CLEANUP; + } + + rval = branch_side (lp, b, 1, child1, val1, prune1); + if (rval) { + fprintf (stderr, "branch_side failed\n"); goto CLEANUP; + } + + +CLEANUP: + + if (lp) CCtsp_free_tsp_lp_struct (&lp); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int branch_side (CCtsp_lp *lp, CCtsp_branchobj *b, int side, int child, + double *val, int *prune) +#else +static int branch_side (lp, b, side, child, val, prune) +CCtsp_lp *lp; +CCtsp_branchobj *b; +int side; +int child; +double *val; +int *prune; +#endif +{ + int rval = 0; + int oldid = lp->id; + int oldparent = lp->parent_id; + double oldbound = lp->lowerbound; + double newbound; + int test; + + *val = 0.0; + *prune = 0; + + if (b->ends[0] != -1) { + printf ("Creating child %d of LP %d: Set Edge (%d, %d) to %d\n", + side, lp->id, b->ends[0], b->ends[1], side); + if (side == 0) { + b->rhs = 0; + } else { + b->rhs = 1; + } + } else { + if (side == 0) { + printf ("Creating child 0 of LP %d: Set Clique <= 2\n", lp->id); + b->rhs = 2; b->sense = 'L'; + } else { + printf ("Creating child 1 of LP %d: Set Clique >= 4\n", lp->id); + b->rhs = 4; b->sense = 'G'; + } + } + fflush (stdout); + + rval = CCtsp_execute_branch (lp, b); + if (rval && rval != 2) { + fprintf (stderr, "CCtsp_execute_branch failed\n"); goto CLEANUP; + } else if (rval == 2) { + printf ("Branched-LP is infeasible\n"); fflush (stdout); + rval = CCtsp_verify_infeasible_lp (lp, &test); + if (rval) { + fprintf (stderr, "CCtsp_verify_infeasible_lp failed\n"); + goto CLEANUP; + } + if (test) { + printf ("Do not creat child node - infeasible\n"); fflush (stdout); + /* for proof mode, write the infeasible LP here */ + *val = CCtsp_LP_MAXDOUBLE; + *prune = 1; + rval = 0; + } else { + fprintf (stderr, "did not verify an infeasible LP\n"); + rval = 1; goto CLEANUP; + } + } else { + rval = CCtsp_pricing_loop (lp, &newbound); + if (rval) { + fprintf (stderr, "CCtsp_pricing_loop\n"); goto CLEANUP; + } + *val = newbound; + lp->lowerbound = newbound; + + if (lp->lowerbound >= lp->upperbound - 0.9) { + rval = CCtsp_verify_lp_prune (lp, &test); + if (rval) { + fprintf (stderr, "CCtsp_verify_lp_prune failed\n"); + goto CLEANUP; + } + if (test) { + printf ("verified that child can be pruned\n"); fflush (stdout); + *prune = 1; /* for proof mode, write the lp file here */ + } else { + fprintf (stderr, "exact pricing could not prune child\n"); + rval = 1; goto CLEANUP; + } + } else { + lp->parent_id = oldid; + lp->id = child; + rval = CCtsp_write_probfile_id (lp); + if (rval) { + fprintf (stderr, "CCtsp_write_probfile_id failed\n"); + goto CLEANUP; + } + lp->parent_id = oldparent; + lp->id = oldid; + } + lp->lowerbound = oldbound; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_splitprob (CCtsp_lp *lp, CCtsp_branchobj *b, int child0, int child1) +#else +int CCtsp_splitprob (lp, b, child0, child1) +CCtsp_lp *lp; +CCtsp_branchobj *b; +int child0, child1; +#endif +{ + int oldid = lp->id; + int oldparent = lp->parent_id; + CClpbasis basis; + int rval = 0; + + CClp_init_basis (&basis); + rval = CClp_get_basis_and_norms (&lp->lp, &basis); + if (rval) { + fprintf (stderr, "CClp_get_basis_and_norms failed\n"); goto CLEANUP; + } + + lp->parent_id = lp->id; + + if (b->ends[0] != -1) { + b->rhs = 0; + } else { + b->rhs = 2; + b->sense = 'L'; + } + + lp->id = child0; + rval = CCtsp_execute_branch (lp, b); + if (rval == 2) { + rval = 0; + printf ("The down side of the branch was infeasible\n"); + fflush (stdout); + } else if (rval) { + fprintf (stderr, "CCtsp_execute_branch failed\n"); goto CLEANUP; + } + rval = CCtsp_write_probfile_id (lp); + if (rval) { + fprintf (stderr, "CCtsp_write_probfile_id failed\n"); goto CLEANUP; + } + rval = CCtsp_execute_unbranch (lp, &basis); + if (rval) { + fprintf (stderr, "CCtsp_execute_unbranch failed\n"); goto CLEANUP; + } + + if (b->ends[0] != -1) { + b->rhs = 1; + } else { + b->rhs = 4; + b->sense = 'G'; + } + + lp->id = child1; + rval = CCtsp_execute_branch (lp, b); + if (rval == 2) { + rval = 0; + printf ("The up side of the branch was infeasible\n"); + fflush (stdout); + } else if (rval) { + fprintf (stderr, "CCtsp_execute_branch failed\n"); goto CLEANUP; + } + rval = CCtsp_write_probfile_id (lp); + if (rval) { + fprintf (stderr, "CCtsp_write_probfile_id failed\n"); goto CLEANUP; + } + rval = CCtsp_execute_unbranch (lp, &basis); + if (rval) { + fprintf (stderr, "CCtsp_execute_unbranch failed\n"); goto CLEANUP; + } + + +CLEANUP: + + CClp_free_basis (&basis); + lp->parent_id = oldparent; + lp->id = oldid; + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_dumptour (int ncount, CCdatagroup *dat, int *perm, char *probname, + int *tour) +#else +int CCtsp_dumptour (ncount, dat, perm, probname, tour) +int ncount; +CCdatagroup *dat; +int *perm; +char *probname; +int *tour; +#endif +{ + int rval = 0; + int *cyc = (int *) NULL; + int i; + double len = 0.0; + char buf[1024]; + + if (!perm || !tour) { + fprintf (stderr, "bad input for CCtsp_dumptour\n"); + rval = 1; goto CLEANUP; + } + + sprintf (buf, "%s.sol", probname); + cyc = CC_SAFE_MALLOC (ncount, int); + if (!cyc) { + fprintf (stderr, "out of memory in CCtsp_dumptour\n"); + rval = 1; goto CLEANUP; + } + + for (i = 0; i < ncount; i++) { + cyc[i] = 0; + } + for (i = 0; i < ncount; i++) { + cyc[tour[i]] = 1; + } + for (i = 0; i < ncount; i++) { + if (cyc[i] == 0) { + fprintf (stderr, "array is not a tour in CCtsp_dumptour\n"); + rval = 1; goto CLEANUP; + } + } + for (i = 0; i < ncount; i++) { + cyc[i] = perm[tour[i]]; + } + + if (dat) { + for (i = 1; i < ncount; i++) { + len += (double) CCutil_dat_edgelen (tour[i-1], tour[i], dat); + } + len += (double) CCutil_dat_edgelen (tour[ncount-1], tour[0], dat); + printf ("Write tour of length %.2f to %s\n", len, buf); + fflush (stdout); + } else { + printf ("Write tour to %s\n", buf); + fflush (stdout); + } + + rval = CCutil_writecycle (ncount, buf, cyc); + if (rval) { + fprintf (stderr, "writecycle failed\n"); goto CLEANUP; + } + +CLEANUP: + + CC_IFFREE (cyc, int); + return rval; +} diff --git a/contrib/blossom/concorde97/TSP/cliqhash.c b/contrib/blossom/concorde97/TSP/cliqhash.c new file mode 100644 index 0000000000000000000000000000000000000000..b8172ae6fc0022699955ed6ad2696128e2cfd2e9 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/cliqhash.c @@ -0,0 +1,207 @@ +/***************************************************************************/ +/* */ +/* ROUTINES TO HASH CLIQUES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: October 10, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_init_cliquehash (CCtsp_lpcuts *cuts, int size) */ +/* initializes the clique hash storage in cuts. */ +/* int size is an estimate of the number of cliques */ +/* */ +/* int CCtsp_register_clique (CCtsp_lpcuts *cuts, CCtsp_lpclique *c) */ +/* returns an integer index for c, adding c to cuts if necessary */ +/* -1 ==> failure */ +/* */ +/* void CCtsp_free_cliquehash (CCtsp_lpcuts *cuts) */ +/* frees the clique hashtable space */ +/* */ +/* void CCtsp_unregister_clique (CCtsp_lpcuts *cuts, int c) */ +/* deletes a reference to clique c, and deletes the clique if no */ +/* references remain */ +/* */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" + +#ifdef CC_PROTOTYPE_ANSI + +static unsigned int + hashclique (CCtsp_lpclique *c); + +static int + clique_eq (CCtsp_lpclique *c, CCtsp_lpclique *d); + +#else + +static unsigned int + hashclique (); + +static int + clique_eq (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_init_cliquehash (CCtsp_lpcuts *cuts, int size) +#else +int CCtsp_init_cliquehash (cuts, size) +CCtsp_lpcuts *cuts; +int size; +#endif +{ + int i; + + cuts->cliquehashsize = (int) CCutil_nextprime ((unsigned int) size); + cuts->cliquehash = CC_SAFE_MALLOC (cuts->cliquehashsize, int); + if (!cuts->cliquehash) { + cuts->cliquehashsize = 0; + return 1; + } + for (i=0; i<cuts->cliquehashsize; i++) { + cuts->cliquehash[i] = -1; + } + cuts->cliquefree = -1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_cliquehash (CCtsp_lpcuts *cuts) +#else +void CCtsp_free_cliquehash (cuts) +CCtsp_lpcuts *cuts; +#endif +{ + CC_IFFREE (cuts->cliquehash, int); + cuts->cliquehashsize = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static unsigned int hashclique (CCtsp_lpclique *c) +#else +static unsigned int hashclique (c) +CCtsp_lpclique *c; +#endif +{ + unsigned int x = 0; + int i; + + for (i=0; i<c->segcount; i++) { + x = x * 65537 + c->nodes[i].lo * 4099 + c->nodes[i].hi; + } + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static int clique_eq (CCtsp_lpclique *c, CCtsp_lpclique *d) +#else +static int clique_eq (c, d) +CCtsp_lpclique *c; +CCtsp_lpclique *d; +#endif +{ + int i; + + if (c->segcount != d->segcount) return 0; + for (i=0; i<c->segcount; i++) { + if (c->nodes[i].lo != d->nodes[i].lo) return 0; + if (c->nodes[i].hi != d->nodes[i].hi) return 0; + } + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_register_clique (CCtsp_lpcuts *cuts, CCtsp_lpclique *c) +#else +int CCtsp_register_clique (cuts, c) +CCtsp_lpcuts *cuts; +CCtsp_lpclique *c; +#endif +{ + int x = hashclique (c) % cuts->cliquehashsize; + int y = cuts->cliquehash[x]; + CCtsp_segment *new = (CCtsp_segment *) NULL; + int i; + + while (y != -1) { + if (clique_eq (c, &cuts->cliques[y])) { + cuts->cliques[y].refcount++; + return y; + } + y = cuts->cliques[y].hashnext; + } + + new = CC_SAFE_MALLOC (c->segcount, CCtsp_segment); + if (!new) { + fprintf (stderr, "out of memory in register_clique\n"); + return -1; + } + + if (cuts->cliquefree != -1) { + y = cuts->cliquefree; + cuts->cliquefree = cuts->cliques[y].hashnext; + } else { + if (cuts->cliqueend >= cuts->cliquespace) { + if (CCutil_reallocrus_scale ((void **) &cuts->cliques, + &cuts->cliquespace, + cuts->cliqueend + 1, 1.3, sizeof (CCtsp_lpclique))) { + CC_FREE (new, CCtsp_segment); + return -1; + } + } + y = cuts->cliqueend++; + } + cuts->cliques[y].segcount = c->segcount; + for (i=0; i<c->segcount; i++) { + new[i] = c->nodes[i]; + } + cuts->cliques[y].nodes = new; + cuts->cliques[y].refcount = 1; + cuts->cliques[y].hashnext = cuts->cliquehash[x]; + cuts->cliquehash[x] = y; + + return y; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_unregister_clique (CCtsp_lpcuts *cuts, int c) +#else +void CCtsp_unregister_clique (cuts, c) +CCtsp_lpcuts *cuts; +int c; +#endif +{ + int x, y, yprev; + + cuts->cliques[c].refcount--; + if (cuts->cliques[c].refcount) return; + x = hashclique (&cuts->cliques[c]) % cuts->cliquehashsize; + y = cuts->cliquehash[x]; + if (y == c) { + cuts->cliquehash[x] = cuts->cliques[c].hashnext; + } else { + yprev = y; + y = cuts->cliques[y].hashnext; + while (y != c && y != -1) { + yprev = y; + y = cuts->cliques[y].hashnext; + } + if (y == -1) { + fprintf (stderr, "Couldn't find clique to delete from hash\n"); + return; + } + cuts->cliques[yprev].hashnext = cuts->cliques[c].hashnext; + } + CC_FREE (cuts->cliques[c].nodes, CCtsp_segment); + cuts->cliques[c].segcount = -1; + cuts->cliques[c].hashnext = cuts->cliquefree; + cuts->cliquefree = c; +} diff --git a/contrib/blossom/concorde97/TSP/cliqwork.c b/contrib/blossom/concorde97/TSP/cliqwork.c new file mode 100644 index 0000000000000000000000000000000000000000..cc11935e5c96f9b874d9af36ff2f953b31430c27 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/cliqwork.c @@ -0,0 +1,273 @@ +/***************************************************************************/ +/* */ +/* SOME ROUTINES FOR HANDLING CLIQUES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: July 15, 1997 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void CCtsp_mark_clique (CCtsp_lpclique *c, int *marks, int marker) */ +/* MARKS the nodes in clique c */ +/* -marks an array of length at least ncount */ +/* -marker an int that is used to mark the clique entries in marks */ +/* */ +/* void CCtsp_mark_clique_and_neighbors (CCtsp_lpgraph *g, */ +/* CCtsp_lpclique *c, int *marks, int marker) */ +/* MARKS the clique and the neighbors of the clique */ +/* */ +/* void CCtsp_mark_clique_and_neighbors_double (CCtsp_lpgraph *g, */ +/* CCtsp_lpclique *c, double *marks, double marker) */ +/* MARKS the clique and the neighbors of the clique in a double array. */ +/* */ +/* void CCtsp_mark_cut (CCtsp_lpcut_in *c, int *marks, int marker) */ +/* MARKS the nodes in the cut. */ +/* */ +/* void CCtsp_mark_cut_and_neighbors (CCtsp_lpgraph *g, */ +/* CCtsp_lpcut_in *c, int *marks, int marker) */ +/* MARKS the nodes in the cut and their neighbors */ +/* */ +/* void CCtsp_is_clique_marked (CCtsp_lpclique *c, int *marks, */ +/* int marker, int *yes_no) */ +/* CHECKS if a node in the clique is marked with the value marker. */ +/* -yesno returns the result (1 is yes and 0 is no) */ +/* */ +/* void CCtsp_clique_count (CCtsp_lpclique *c, int *count) */ +/* COUNTS the number of nodes in the clique. */ +/* */ +/* int CCtsp_clique_to_array (CCtsp_lpclique *c, int **ar, int *count) */ +/* EXPANDS a clique into an array of integers. */ +/* */ +/* int CCtsp_clique_delta (CCtsp_lpgraph *g, double *x, */ +/* CCtsp_lpclique *c, double *delta) */ +/* COMPUTES the sum of the x-edges in the coboundary of the clique, */ +/* that is, x(delta(c)). */ +/* -delta returns the sum */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" + + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_mark_clique (CCtsp_lpclique *c, int *marks, int marker) +#else +void CCtsp_mark_clique (c, marks, marker) +CCtsp_lpclique *c; +int *marks; +int marker; +#endif +{ + int i, j; + + for (i = 0; i < c->segcount; i++) { + for (j = c->nodes[i].lo; j <= c->nodes[i].hi; j++) { + marks[j] = marker; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_mark_clique_and_neighbors (CCtsp_lpgraph *g, CCtsp_lpclique *c, + int *marks, int marker) +#else +void CCtsp_mark_clique_and_neighbors (g, c, marks, marker) +CCtsp_lpgraph *g; +CCtsp_lpclique *c; +int *marks; +int marker; +#endif +{ + int i, j, k; + + for (i = 0; i < c->segcount; i++) { + for (j = c->nodes[i].lo; j <= c->nodes[i].hi; j++) { + marks[j] = marker; + for (k = 0; k < g->nodes[j].deg; k++) { + marks[g->nodes[j].adj[k].to] = marker; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_mark_cut (CCtsp_lpcut_in *c, int *marks, int marker) +#else +void CCtsp_mark_cut (c, marks, marker) +CCtsp_lpcut_in *c; +int *marks; +int marker; +#endif +{ + int i; + + for (i = 0; i < c->cliquecount; i++) { + CCtsp_mark_clique (&(c->cliques[i]), marks, marker); + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_mark_cut_and_neighbors (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, + int *marks, int marker) +#else +void CCtsp_mark_cut_and_neighbors (g, c, marks, marker) +CCtsp_lpgraph *g; +CCtsp_lpcut_in *c; +int *marks; +int marker; +#endif +{ + int i; + + for (i = 0; i < c->cliquecount; i++) { + CCtsp_mark_clique_and_neighbors (g, &(c->cliques[i]), marks, marker); + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_mark_clique_and_neighbors_double (CCtsp_lpgraph *g, + CCtsp_lpclique *c, double *marks, double marker) +#else +void CCtsp_mark_clique_and_neighbors_double (g, c, marks, marker) +CCtsp_lpgraph *g; +CCtsp_lpclique *c; +double *marks; +double marker; +#endif +{ + int i, j, k; + + for (i = 0; i < c->segcount; i++) { + for (j = c->nodes[i].lo; j <= c->nodes[i].hi; j++) { + marks[j] = marker; + for (k = 0; k < g->nodes[j].deg; k++) { + marks[g->nodes[j].adj[k].to] = marker; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_is_clique_marked (CCtsp_lpclique *c, int *marks, int marker, + int *yes_no) +#else +void CCtsp_is_clique_marked (c, marks, marker, yes_no) +CCtsp_lpclique *c; +int *marks; +int marker; +int *yes_no; +#endif +{ + int i, j; + + for (i = 0; i < c->segcount; i++) { + for (j = c->nodes[i].lo; j <= c->nodes[i].hi; j++) { + if (marks[j] == marker) { + *yes_no = 1; + return; + } + } + } + *yes_no = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_clique_count (CCtsp_lpclique *c, int *count) +#else +void CCtsp_clique_count (c, count) +CCtsp_lpclique *c; +int *count; +#endif +{ + int i; + CCtsp_segment *nodes = c->nodes; + + *count = 0; + for (i = 0; i < c->segcount; i++) { + (*count) += (nodes[i].hi - nodes[i].lo + 1); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_clique_to_array (CCtsp_lpclique *c, int **ar, int *count) +#else +int CCtsp_clique_to_array (c, ar, count) +CCtsp_lpclique *c; +int **ar; +int *count; +#endif +{ + int rval = 0; + int i, j; + int k = 0; + + *ar = (int *) NULL; + + CCtsp_clique_count (c, count); + if (count) { + *ar = CC_SAFE_MALLOC (*count, int); + if (!(*ar)) { + fprintf (stderr, "out of memory in CCtsp_clique_to_array\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < c->segcount; i++) { + for (j = c->nodes[i].lo; j <= c->nodes[i].hi; j++) { + (*ar)[k++] = j; + } + } + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_clique_delta (CCtsp_lpgraph *g, double *x, CCtsp_lpclique *c, + double *delta) +#else +int CCtsp_clique_delta (g, x, c, delta) +CCtsp_lpgraph *g; +double *x; +CCtsp_lpclique *c; +double *delta; +#endif +{ + int rval = 0; + int i, j, k; + int *marks = (int *) NULL; + CCtsp_lpnode *n; + + *delta = 0.0; + + marks = CC_SAFE_MALLOC (g->ncount, int); + if (!marks) { + fprintf (stderr, "out of memory in CCtsp_clique_delta\n"); + rval = 1; goto CLEANUP; + } + + CCtsp_mark_clique_and_neighbors (g, c, marks, 0); + CCtsp_mark_clique (c, marks, 1); + + for (i = 0; i < c->segcount; i++) { + for (j = c->nodes[i].lo; j <= c->nodes[i].hi; j++) { + n = &g->nodes[j]; + for (k = 0; k < n->deg; k++) { + if (!marks[n->adj[k].to]) { + (*delta) += x[n->adj[k].edge]; + } + } + } + } + +CLEANUP: + + CC_IFFREE (marks, int); + return rval; +} diff --git a/contrib/blossom/concorde97/TSP/concorde.c b/contrib/blossom/concorde97/TSP/concorde.c new file mode 100644 index 0000000000000000000000000000000000000000..75a3a4c51608cdda39dc80b80059eb679269c4d4 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/concorde.c @@ -0,0 +1,970 @@ +/***************************************************************************/ +/* */ +/* THE MAIN PROGRAM FOR CONCORDE */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: September 25, 1995 */ +/* */ +/* SEE short decsribtion in usage (). */ +/* */ +/* Link with: */ +/* SEE conmake.grs */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "edgegen.h" +#include "tsp.h" +#include "linkern.h" +#include "bigguy.h" +#include "macrorus.h" + +#define CC_LK_TRY (1) /* number of trials to generate initial tour */ + +static int norm = CC_EUCLIDEAN; +static char *datfname = (char *) NULL; +static char *edgegenfname = (char *) NULL; +static char *probname = (char *) NULL; +static char *probfname = (char *) NULL; +static char *edgefname = (char *) NULL; +static char *fullfname = (char *) NULL; +static char *tourfname = (char *) NULL; +static char *masterfname = (char *) NULL; +static char *poolfname = (char *) NULL; +static char *xfname = (char *) NULL; +static int binary_in = 0; +static int tsplib_in = 0; +static int nnodes_want = 0; +static int seed = 0; +static int just_subtour = 0; +static int valid_edges = 0; +static double initial_ub = CCtsp_LP_MAXDOUBLE; +static int useconsecutiveones = 0; +static int usenecklace = 0; +static int usetighten = 1; +static int dfs_branching = 0; +static int bfs_branching = 0; +static int usebranchcliques = 0; +static int standalone_branch = 0; + + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int ac, char **av); + +static void + usage (char *f); + +static int + parseargs (int ac, char **av), + find_good_tour (int ncount, CCdatagroup *dat, int *perm, double *ub, + int trials), + getedges (CCdatagroup *dat, CCedgegengroup *plan, int ncount, int *ecount, + int **elist, int **elen); + +#else + +int + main (); + +static void + usage (); + +static int + parseargs (), + find_good_tour (), + getedges (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + double szeit; + char dummyname[256]; + int i, ncount; + CCdatagroup dat; + CCdatagroup *mydat = (CCdatagroup *) NULL; + CCtsp_lp *lp = (CCtsp_lp *) NULL; + CCbigguy bound; + CCtsp_cutselect sel; + CCtsp_lpcuts *pool = (CCtsp_lpcuts *) NULL; + int *ptour = (int *) NULL; + int ecount = 0; + int *elist = (int *) NULL; + int *elen = (int *) NULL; + int excount = 0; + int *exlist = (int *) NULL; + int *exlen = (int *) NULL; + int *besttour = (int *) NULL; + int probnum = -1; + int rval = 0; + + for (i=0; i<ac; i++) { + printf ("%s", av[i]); + if (i < ac-1) printf (" "); + } + printf ("\n"); + fflush (stdout); + + szeit = CCutil_zeit (); + seed = (int) CCutil_real_zeit (); + if (parseargs (ac, av)) + return 0; + CCutil_sprand (seed); + printf ("Using random seed %d\n", seed); fflush (stdout); + + if (datfname == (char *) NULL && nnodes_want == 0 && probnum == -1 && + probfname == (char *) NULL && edgefname == (char *) NULL && + masterfname == (char *) NULL) { + usage (av[0]); + return 0; + } + ncount = nnodes_want; + + + /****** Get the ncount and the data set ******/ + + if (masterfname != (char *) NULL) { + if (CCutil_getmaster (masterfname, &ncount, &dat, &ptour)) { + fprintf (stderr, "getmaster failed\n"); + return 1; + } + if (dat.norm != 0) { + mydat = &dat; + } else { + mydat = (CCdatagroup *) NULL; + } + } else { + if (tsplib_in && datfname != (char *) NULL) { + if (CCutil_gettsplib (datfname, &ncount, &dat)) { + fprintf (stderr, "could not read the TSPLIB file\n"); + rval = 1; + goto CLEANUP; + } + norm = dat.norm; + mydat = &dat; + } else if (datfname != (char *) NULL || edgefname == (char *) NULL) { + if (CCutil_getdata (datfname, binary_in, norm, &ncount, &dat)) { + fprintf (stderr, "Could not create data set\n"); + rval = 1; + goto CLEANUP; + } + mydat = &dat; + } else { + /* Look at edge file to get ncount */ + + if (CCutil_getedgelist_n (&ncount, edgefname, &ecount, &elist, + &elen)) { + fprintf (stderr, "Could not read edge set\n"); + rval = 1; + goto CLEANUP; + } + printf ("Number of nodes: %d\n", ncount); + fflush (stdout); + + CC_IFFREE (elist, int); + CC_IFFREE (elen, int); + ecount = 0; + mydat = (CCdatagroup *) NULL; + } + } + + if (ncount < 10) { + fprintf (stderr, "Less than 10 nodes. Who cares.\n"); + rval = 1; + goto CLEANUP; + } + if (mydat) { + if (CCutil_init_dat_edgelen (mydat)) { + fprintf (stderr, "CCutil_init_dat_edgelen failed\n"); + rval = 1; + goto CLEANUP; + } + } + + + /***** Get the permutation tour and permute the data *****/ + + if (!ptour) { + ptour = CC_SAFE_MALLOC (ncount, int); + if (!ptour) { + fprintf (stderr, "out of memory in main\n"); + rval = 1; + goto CLEANUP; + } + + if (tourfname) { + rval = CCutil_getcycle (ncount, tourfname, ptour); + if (rval) { + fprintf (stderr, "getcycle failed\n"); + goto CLEANUP; + } + } else if (mydat) { + double bnd; + if (just_subtour) { + rval = find_good_tour (ncount, mydat, ptour, &bnd, -1); + } else if (initial_ub == CCtsp_LP_MAXDOUBLE) { + rval = find_good_tour (ncount, mydat, ptour, &bnd, CC_LK_TRY); + } else { + printf ("Initial bnd %f given - use short tour run\n", + initial_ub); + fflush (stdout); + rval = find_good_tour (ncount, mydat, ptour, &bnd, 0); + } + if (rval) { + fprintf (stderr, "find_good_tour failed\n"); + goto CLEANUP; + } + } else { + fprintf (stderr, "no way to generate the permutation tour\n"); + rval = 1; + goto CLEANUP; + } + + if (mydat) { + rval = CCutil_datagroup_perm (ncount, mydat, ptour); + if (rval) goto CLEANUP; + } + } + if (mydat) { + double bnd; + + bnd = CCutil_dat_edgelen (ncount - 1, 0, mydat); + for (i = 1; i < ncount; i++) { + bnd += CCutil_dat_edgelen (i-1, i, mydat); + } + if (bnd < initial_ub) { + printf ("Set initial upperbound to %.2f (from tour)\n", bnd); + fflush (stdout); + initial_ub = bnd; + } + } + + + /***** Get the initial edge set *****/ + + if (!probfname) { + if (edgefname) { + int *invperm = (int *) NULL; + + rval = CCutil_getedgelist (ncount, edgefname, &ecount, &elist, + &elen); + if (rval) { + fprintf (stderr, "getedgelist failed\n"); + goto CLEANUP; + } + printf ("Initial edgeset: %d edges (%d nodes)\n", ecount, ncount); + printf ("Rearrange the edges to match the tour order\n"); + fflush (stdout); + + invperm = CC_SAFE_MALLOC (ncount, int); + if (!invperm) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) + invperm[ptour[i]] = i; + for (i = 0; i < 2*ecount; i++) + elist[i] = invperm[elist[i]]; + CC_FREE (invperm, int); + } else if (mydat) { + CCedgegengroup plan; + + if (edgegenfname) { + rval = CCedgegen_read (edgegenfname, &plan); + if (rval) { + fprintf (stderr, "CCedgegen_read failed\n"); + return 1; + } + } else { + CCedgegen_init_edgegengroup (&plan); + if (just_subtour) { + plan.tour.greedy = 1; + plan.f2match_nearest.number = 4; + } else { + plan.linkern.count = 10; + plan.linkern.quadnearest = 2; + plan.linkern.greedy_start = 0; + plan.linkern.nkicks = (ncount / 100) + 1; + } + } + + rval = getedges (mydat, &plan, ncount, &ecount, &elist, &elen); + if (rval) { + fprintf (stderr, "getgraph failed\n"); + goto CLEANUP; + } + } + } + + /***** Get the problem name *****/ + + if (probname == (char *) NULL) { + char *p, *q; + char buf[1024]; + + probname = dummyname; + + if (datfname || masterfname) { + if (datfname) + sprintf (buf, "%s", datfname); + else + sprintf (buf, "%s", masterfname); + p = CCutil_strrchr (buf, '/'); + if (!p) + p = buf; + else + p++; + q = CCutil_strrchr (p, '.'); + if (q) + *q = '\0'; + sprintf (probname, "%s", p); + } else { + sprintf (probname, "%s", "noname"); + } + } + + + /***** Write the master file *****/ + + if (!masterfname) { + char buf[1024]; + + sprintf (buf, "%s.mas", probname); + rval = CCutil_writemaster (buf, ncount, mydat, ptour); + if (rval) { + fprintf (stderr, "writemaster failed\n"); + goto CLEANUP; + } + } + + /***** Get full edges *****/ + + if (fullfname) { + int *invperm = (int *) NULL; + + rval = CCutil_getedgelist (ncount, fullfname, &excount, &exlist, + &exlen); + if (rval) { + fprintf (stderr, "getedgelist failed\n"); + goto CLEANUP; + } + + invperm = CC_SAFE_MALLOC (ncount, int); + if (!invperm) { + fprintf (stderr, "out of memory in main\n"); + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncount; i++) + invperm[ptour[i]] = i; + for (i = 0; i < 2*excount; i++) + exlist[i] = invperm[exlist[i]]; + CC_FREE (invperm, int); + } else { + excount = 0; + } + + /***** Get the initial cutpool *****/ + + rval = CCtsp_init_cutpool (ncount, poolfname, &pool); + if (rval) { + fprintf (stderr, "CCtsp_init_cutpool failed\n"); + goto CLEANUP; + } + + /***** Initialize besttour to represent the permutation tour ****/ + + besttour = CC_SAFE_MALLOC (ncount, int); + if (!besttour) { + fprintf (stderr, "out of memory in allocating best tour\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + besttour[i] = i; + } + + /***** Get the initial LP *****/ + + rval = CCtsp_init_lp (&lp, probname, probnum, probfname, ncount, mydat, + ecount, elist, elen, excount, exlist, exlen, valid_edges, + ptour, initial_ub, pool); + if (rval == 2) { + printf ("CCtsp_init_lp reports an infeasible LP\n"); + rval = CCtsp_exact_price (lp, &bound, 1); + if (rval) { + fprintf (stderr, "CCtsp_exact_price failed\n"); + goto CLEANUP; + } + if (CCbigguy_cmp (bound, CCbigguy_ZERO) < 0) { + printf ("Problem shown to be infeasible\n"); + fflush (stdout); + lp->infeasible = 1; + lp->exact_lowerbound = CCbigguy_MAXBIGGUY; + goto DONE; + } else { + fprintf (stderr, "exact pricing did not verify an infeasible LP\n"); + rval = 1; + goto CLEANUP; + } + } else if (rval) { + fprintf (stderr, "CCtsp_init_lp failed\n"); goto CLEANUP; + } + + ecount = 0; + CC_IFFREE (elist, int); + CC_IFFREE (elen, int); + excount = 0; + CC_IFFREE (exlist, int); + CC_IFFREE (exlen, int); + + if (lp->full_edges_valid) { + if (CCtsp_inspect_full_edges (lp)) { + fprintf (stderr, "full edge set does not contain all LP edges\n"); + rval = 1; goto CLEANUP; + } + } + + if (xfname) { + rval = CCtsp_dump_x (lp, xfname); + if (rval) { + fprintf (stderr, "CCtsp_dump_x failed\n"); + goto CLEANUP; + } + } + + if (standalone_branch) { + rval = CCtsp_do_interactive_branch (lp); + if (rval) { + fprintf (stderr, "CCtsp_do_interactive_branch failed\n"); + goto CLEANUP; + } else { + printf ("completed interative branch\n"); + printf ("Total Running Time: %.2f (seconds)\n", + CCutil_zeit () - szeit); + goto CLEANUP; + } + } + + rval = CCtsp_init_cutselect (lp, &sel); + if (rval) { + fprintf (stderr, "CCtsp_init_cutselect failed\n"); + goto CLEANUP; + } + if (useconsecutiveones) sel.consecutiveones = 1; + if (usenecklace) sel.necklace = 1; + sel.usetighten = usetighten; + + if (just_subtour) { + rval = CCtsp_subtour_loop (lp); + if (rval) { + fprintf (stderr, "CCtsp_subtour_loop failed\n"); + goto CLEANUP; + } + printf ("Bound: %f\n", lp->lowerbound); fflush (stdout); + goto DONE; + } else { + rval = CCtsp_cutting_loop (lp, &sel, 1); + if (rval == 2) { + printf ("CCtsp_cutting_loop reports an infeasible LP\n"); + rval = CCtsp_exact_price (lp, &bound, 1); + if (rval) { + fprintf (stderr, "CCtsp_exact_price failed\n"); + goto CLEANUP; + } + if (CCbigguy_cmp (bound, CCbigguy_ZERO) < 0) { + printf ("Problem shown to be infeasible\n"); + fflush (stdout); + lp->infeasible = 1; + lp->exact_lowerbound = CCbigguy_MAXBIGGUY; + goto DONE; + } else { + fprintf (stderr, "pricing did not verify an infeasible LP\n"); + rval = 1; goto CLEANUP; + } + } else if (rval) { + fprintf (stderr, "cutting_loop failed\n"); + goto CLEANUP; + } + } + + if (mydat) { + double tourval; + rval = CCtsp_call_x_heuristic (lp, &tourval, besttour); + if (rval) { + fprintf (stderr, "CCtsp_call_x_heuristic failed\n"); + goto CLEANUP; + } + if (tourval < lp->upperbound) { + printf ("New upperbound from x-heuristic: %.2f\n", tourval); + lp->upperbound = tourval; + rval = CCtsp_dumptour (ncount, mydat, ptour, probname, besttour); + if (rval) { + fprintf (stderr, "CCtsp_dumptour failed\n"); goto CLEANUP; + } + } + } + + printf ("Final lower bound %f, upper bound %f\n", lp->lowerbound, + lp->upperbound); + fflush (stdout); + + if (lp->graph.ncount < 100000) { + CCbigguy bupper; + rval = CCtsp_exact_price (lp, &bound, 0); + if (rval) { + fprintf (stderr, "CCtsp_exact_price failed\n"); + goto CLEANUP; + } + lp->exact_lowerbound = bound; + printf ("Exact lower bound: %.6f\n", CCbigguy_bigguytod (bound)); + printf ("DIFF: %f\n", lp->lowerbound - CCbigguy_bigguytod (bound)); + fflush (stdout); + + bupper = CCbigguy_dtobigguy (lp->upperbound); + CCbigguy_sub (&bupper, CCbigguy_ONE); + + if (CCbigguy_cmp (lp->exact_lowerbound, bupper) > 0) { + printf ("Optimal Solution: %.2f\n", lp->upperbound); + if (dfs_branching || bfs_branching) { + printf ("Number of bbnodes: %d\n", 0); + } + fflush (stdout); + goto DONE; + } + + rval = CCtsp_eliminate_variables (lp); + if (rval) { + fprintf (stderr, "CCtsp_eliminate_variables failed\n"); + goto CLEANUP; + } + } else { + printf ("During testing, do not exact price large problems\n"); + fflush (stdout); + goto DONE; + } + + if (dfs_branching) { + double upbound = lp->upperbound; + int bbcount = 0; + + rval = CCtsp_easy_dfs_brancher (lp, &sel, 0, &upbound, &bbcount, + usebranchcliques, besttour); + if (rval) { + fprintf (stderr, "CCtsp_easy_dfs_brancher failed\n"); + goto CLEANUP; + } + printf ("Optimal Solution: %.2f\n", upbound); + printf ("Number of bbnodes: %d\n", bbcount); + fflush (stdout); + rval = CCtsp_dumptour (ncount, mydat, ptour, probname, besttour); + if (rval) { + fprintf (stderr, "CCtsp_dumptour failed\n"); goto CLEANUP; + } + } else if (bfs_branching) { + double upbound = lp->upperbound; + double lowbound = lp->lowerbound; + int id = lp->id; + int bbcount = 0; + + rval = CCtsp_write_probfile_id (lp); + if (rval) { + fprintf (stderr, "CCtsp_write_probfile_id failed\n"); + goto CLEANUP; + } + CCtsp_free_tsp_lp_struct (&lp); + + rval = CCtsp_bfs_brancher (probname, id, lowbound, &sel, &upbound, + &bbcount, usebranchcliques, mydat, ptour, + pool, ncount, besttour); + if (rval) { + fprintf (stderr, "CCtsp_bfs_brancher failed\n"); goto CLEANUP; + } + + printf ("Optimal Solution: %.2f\n", upbound); + printf ("Number of bbnodes: %d\n", bbcount); + fflush (stdout); + rval = CCtsp_dumptour (ncount, mydat, ptour, probname, besttour); + if (rval) { + fprintf (stderr, "CCtsp_dumptour failed\n"); goto CLEANUP; + } + } + +DONE: + + printf ("Total Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + + if (!dfs_branching && !bfs_branching) { + CCtsp_print_tighten_info (&lp->tighten_stats); + CClp_nonzeros (&lp->lp); + + rval = CCtsp_write_probfile_sav (lp); + if (rval) { + fprintf (stderr, "CCtsp_write_probfile_sav failed\n"); + goto CLEANUP; + } + } + + if (pool && pool->cutcount) { + char buf[1024]; + printf ("Final Pool: %d cuts\n", pool->cutcount); + fflush (stdout); + + sprintf (buf, "%s.pul", probname); + rval = CCtsp_write_cutpool (ncount, buf, pool); + if (rval) { + fprintf (stderr, "CCtsp_write_cutpool failed\n"); + goto CLEANUP; + } + } + rval = 0; + +CLEANUP: + + CCtsp_free_tsp_lp_struct (&lp); + + if (pool) { + CCtsp_free_cutpool (&pool); + } + + CC_IFFREE (elist, int); + CC_IFFREE (elen, int); + CC_IFFREE (exlist, int); + CC_IFFREE (exlen, int); + CC_IFFREE (ptour, int); + CC_IFFREE (besttour, int); + if (mydat) + CCutil_freedatagroup (ncount, mydat); + if (CCutil_bigchunk_free_world ()) { + fprintf (stderr, "ERROR: CCutil_bigchunk_free_world failed\n"); + return 1; + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_good_tour (int ncount, CCdatagroup *dat, int *perm, double *ub, + int trials) +#else +static int find_good_tour (ncount, dat, perm, ub, trials) +int ncount; +CCdatagroup *dat; +int *perm; +double *ub; +int trials; +#endif +{ + int rval = 0; + CCedgegengroup plan; + int ecount; + int *elist = (int *) NULL; + int tcount; + int *tlist = (int *) NULL; + int *bestcyc = (int *) NULL; + int *cyc = (int *) NULL; + int *tmp; + double val, bestval, szeit; + int kicks; + int i; + + szeit = CCutil_zeit (); + bestval = CCtsp_LP_MAXDOUBLE; + + if (trials == -1) { + kicks = (ncount > 400 ? 100 : ncount/4); + } else { + kicks = (ncount > 1000 ? 500 : ncount/2); + } + + printf ("Finding a good tour for compression: %d\n", trials); + fflush (stdout); + + cyc = CC_SAFE_MALLOC (ncount, int); + bestcyc = CC_SAFE_MALLOC (ncount, int); + if (!cyc || !bestcyc) { + fprintf (stderr, "out of memory in find_good_tour\n"); + rval = 1; goto CLEANUP; + } + + CCedgegen_init_edgegengroup (&plan); + plan.quadnearest = 2; + rval = CCedgegen_edges (&plan, ncount, dat, (double *) NULL, &ecount, + &elist); + if (rval) { + fprintf (stderr, "CCedgegen_edges failed\n"); goto CLEANUP; + } + plan.quadnearest = 0; + + + plan.tour.greedy = 1; + rval = CCedgegen_edges (&plan, ncount, dat, (double *) NULL, &tcount, + &tlist); + if (rval) { + fprintf (stderr, "CCedgegen_edges failed\n"); goto CLEANUP; + } + + if (tcount != ncount) { + fprintf (stderr, "wrong edgeset from edgegen\n"); + rval = 1; goto CLEANUP; + } + + rval = CCutil_edge_to_cycle (ncount, tlist, cyc); + if (rval) { + fprintf (stderr, "CCutil_edge_to_cycle failed\n"); + rval = 1; goto CLEANUP; + } + CC_FREE (tlist, int); + + rval = CClinkern_tour (ncount, dat, ecount, elist, ncount, kicks, + cyc, bestcyc, &bestval, 0, 0.0, 0.0, (char *) NULL); + if (rval) { + fprintf (stderr, "CClinkern_tour failed\n"); goto CLEANUP; + } + + for (i = 0; i < trials; i++) { + rval = CClinkern_tour (ncount, dat, ecount, elist, ncount, kicks, + (int *) NULL, cyc, &val, 0, 0.0, 0.0, (char *) NULL); + if (rval) { + fprintf (stderr, "CClinkern_tour failed\n"); goto CLEANUP; + } + if (val < bestval) { + CC_SWAP (cyc, bestcyc, tmp); + bestval = val; + } + } + + if (trials > 0) { + rval = CClinkern_tour (ncount, dat, ecount, elist, ncount, 2 * kicks, + bestcyc, perm, ub, 0, 0.0, 0.0, (char *) NULL); + if (rval) { + fprintf (stderr, "CClinkern_tour failed\n"); goto CLEANUP; + } + } else { + for (i = 0; i < ncount; i++) { + perm[i] = bestcyc[i]; + } + } + + printf ("Time to find compression tour: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (cyc, int); + CC_IFFREE (bestcyc, int); + CC_IFFREE (elist, int); + CC_IFFREE (tlist, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int getedges (CCdatagroup *dat, CCedgegengroup *plan, int ncount, + int *ecount, int **elist, int **elen) +#else +static int getedges (dat, plan, ncount, ecount, elist, elen) +CCdatagroup *dat; +CCedgegengroup *plan; +int ncount, *ecount, **elist, **elen; +#endif +{ + int i; + + *elist = (int *) NULL; + *elen = (int *) NULL; + + if (dat == (CCdatagroup *) NULL || plan == (CCedgegengroup *) NULL) { + fprintf (stderr, "getedges needs CCdatagroup and CCedgegenplan\n"); + return 1; + } + + if (CCedgegen_edges (plan, ncount, dat, (double *) NULL, ecount, elist)) { + fprintf (stderr, "CCedgegen_edges failed\n"); + return 1; + } + *elen = CC_SAFE_MALLOC(*ecount, int); + if (!(*elen)) { + CC_FREE (*elist, int); + return 1; + } + for (i = 0; i < *ecount; i++) { + (*elen)[i] = + CCutil_dat_edgelen ((*elist)[2*i], (*elist)[(2*i) + 1], dat); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "bBcdD:e:E:fk:lM:n:N:P:s:STt:u:vUX:Y0123456789")) != EOF) + switch (c) { + case 'b': + binary_in = 1; + break; + case 'B': + bfs_branching = 1; + break; + case 'c': + useconsecutiveones = 1; + break; + case 'd': + dfs_branching = 1; + break; + case 'D': + edgegenfname = CCutil_bix_optarg; + break; + case 'e': + edgefname = CCutil_bix_optarg; + break; + case 'E': + fullfname = CCutil_bix_optarg; + break; + case 'f': + usetighten = 0; + break; + case 'k': + nnodes_want = atoi (CCutil_bix_optarg); + break; + case 'l': + usenecklace = 1; + break; + case 'n': + probname = CCutil_bix_optarg; + break; + case 'M': + masterfname = CCutil_bix_optarg; + break; + case 'N': + probfname = CCutil_bix_optarg; + break; + case 'P': + poolfname = CCutil_bix_optarg; + break; + case 's': + seed = atoi (CCutil_bix_optarg); + break; + case 'S': + just_subtour = 1; + break; + case 'T': + tsplib_in = 1; + break; + case 't': + tourfname = CCutil_bix_optarg; + break; + case 'u': + initial_ub = atof (CCutil_bix_optarg); + break; + case 'v': + valid_edges = 1; + break; + case 'U': + usebranchcliques = 1; + break; + case 'X': + xfname = CCutil_bix_optarg; + break; + case 'Y': + standalone_branch = 1; + break; + case '0': + norm = CC_MAXNORM; + break; + case '1': + norm = CC_EUCLIDEAN_CEIL; + break; + case '2': + norm = CC_EUCLIDEAN; + break; + case '3': + norm = CC_EUCLIDEAN_3D; + break; + case '4': + norm = CC_IBM; + break; + case '5': + norm = CC_ATT; + break; + case '6': + norm = CC_GEOGRAPHIC; + break; + case '7': + norm = CC_MATRIXNORM; + break; + case '8': + norm = CC_DSJRANDNORM; + break; + case '9': + norm = CC_CRYSTAL; + break; + case CC_BIX_GETOPT_UNKNOWN: + case '?': + default: + usage (av[0]); + return 1; + } + if (CCutil_bix_optind < ac) { + datfname = av[CCutil_bix_optind++]; + } + + if (CCutil_bix_optind != ac) { + usage (av[0]); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "Usage: %s [-see below-] [dat_file]\n", f); + fprintf (stderr, " -b datfile in integer binary format\n"); + fprintf (stderr, " -B run best-bound branching\n"); + fprintf (stderr, " -c use consecutive ones cuts\n"); + fprintf (stderr, " -d dfs search\n"); + fprintf (stderr, " -D f edgegen file for initial edge set\n"); + fprintf (stderr, " -e f initial edge file\n"); + fprintf (stderr, " -E f full edge file\n"); + fprintf (stderr, " -f don't call tighten for each cut\n"); + fprintf (stderr, " -k # number of nodes for random problem\n"); + fprintf (stderr, " -l use necklace cuts\n"); + fprintf (stderr, " -M f master file\n"); + fprintf (stderr, " -n s problem name (just a name, not a file name)\n"); + fprintf (stderr, " -N f prob file\n"); + fprintf (stderr, " -P f cutpool file\n"); + fprintf (stderr, " -s # random seed\n"); + fprintf (stderr, " -S just solve the subtour polytope\n"); + fprintf (stderr, " -T the dat file is a TSPLIB file\n"); + fprintf (stderr, " -t f tour file (in node node node format)\n"); + fprintf (stderr, " -u v initial upperbound\n"); + fprintf (stderr, " -U permit branching on subtour inequalities\n"); + fprintf (stderr, " -v full list valid (must contain initial list)\n"); + fprintf (stderr, " -(0 1 2 3) price out using (MAX JOHNSON L2 3D) norm\n"); + fprintf (stderr, " -(4 5 6 7 8 9) IBM ATT GEO MATRIX DSJRAND CRYSTAL norm\n"); +} diff --git a/contrib/blossom/concorde97/TSP/control.c b/contrib/blossom/concorde97/TSP/control.c new file mode 100644 index 0000000000000000000000000000000000000000..5819de24940a9b8ab6339b8f403890aa25abfd63 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/control.c @@ -0,0 +1,1175 @@ +/***************************************************************************/ +/* */ +/* THE CONTROLLER FOR CUTTING PLANES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: June 27, 1997 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_init_cutselect (CCtsp_lp *lp, CCtsp_cutselect *s) */ +/* INITIALIZES the cut selctions */ +/* Note: The lp should be solved before this call. */ +/* */ +/* int CCtsp_cutting_loop (CCtsp_lp *lp, CCtsp_cutselect *sel, */ +/* int savelp) */ +/* CALLS the cutting plane and pricing routines. */ +/* -sel should be set with the desired cut selection. */ +/* -savelp should be set to a nonzero value to write the lps to after */ +/* rounds of cuts */ +/* Note: It returns a 2 if the lp becomes infeasible */ +/* */ +/* int CCtsp_subtour_loop (CCtsp_lp *lp) */ +/* CALLS the cutting and pricing to optimize over the subtour polytope.*/ +/* */ +/* int CCtsp_pricing_loop (CCtsp_lp *lp, double *bnd) */ +/* ADDS negative reduced costs edges to lp and returns the current */ +/* lowerbound. */ +/* -bnd can be NULL */ +/* NOTE: The LP must have full_edges_valid. */ +/* */ +/* int CCtsp_call_x_heuristic (CCtsp_lp *lp, double *val, int *outcyc ) */ +/* CALLS the x-greedy LK heuristic with the current LP solution. */ +/* -val returns the length of the tour. */ +/* -outcyc will return the tour in node-node-node format if the */ +/* length of the tour is less than lp->upperbound; the array should */ +/* at least of length ncount (it can be NULL) */ +/* */ +/* int CCtsp_bb_cutting (char *probname, int probnum, int ncount, */ +/* CCdatagroup *dat, int *ptour, double initial_ub, */ +/* CCtsp_lpcuts *pool, CCtsp_cutselect *sel, double *val, */ +/* int *prune, int *foundtour, int *besttour) */ +/* CALLS the cutting loop after reading the lp; writes the result to */ +/* the same prob file; using exact price to verify pruned runs */ +/* -upbound should be passed in as the current bound; if a better */ +/* tour is found then upbound will be updated */ +/* -val returns the lp bound; it is CCtsp_LP_MAXDOUBLE if infeasible */ +/* -prune is set to 1 if bbnode can be pruned */ +/* -foundtour is set to 1 if a better tour is found. */ +/* -besttour (if not NULL) will return a better tour if one is found. */ +/* */ +/* NOTES: */ +/* */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" +#include "Xstuff.h" +#include "bigguy.h" +#include "cut.h" + + +#ifdef CC_PROTOTYPE_ANSI + +static int + call_add_cuts (CCtsp_lp *lp, CCtsp_lpcut_in **cuts, int *cut_added, + int *xcount, int **xlist, double **x, double *val, int tighten), + lp_value (CCtsp_lp *lp, double *val), + lp_x (CCtsp_lp *lp, int *xcount, int **xlist, double **x), + full_edge_check (CCtsp_lp *lp, int *nadded), + sparse_edge_check (CCtsp_lp *lp, CCtsp_edgegenerator *eg, int *nadded, + double *bnd), + bb_cutting_work (CCtsp_lp **lp, char *probname, int probnum, + int ncount, CCdatagroup *dat, int *ptour, double upbound, + CCtsp_lpcuts *pool, CCtsp_cutselect *sel, double *val); + +#else + +static int + call_add_cuts (), + lp_value (), + lp_x (), + full_edge_check (), + sparse_edge_check (), + bb_cutting_work (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_init_cutselect (CCtsp_lp *lp, CCtsp_cutselect *s) +#else +int CCtsp_init_cutselect (lp, s) +CCtsp_lp *lp; +CCtsp_cutselect *s; +#endif +{ + double ub; + int rval = 0; + + s->cutpool = 1; + s->connect = 1; + s->segments = 1; + s->exactsubtour = 1; + s->tighten_lp = 1; + s->decker_lp = 0; + s->teething_lp = 1; + s->tighten_pool = 1; + s->decker_pool = 0; + s->teething_pool = 0; + s->maxchunksize = 0; + s->Xfastcuts = 1; + s->Xexactsubtours = 0; + s->Xslowcuts = 1; + s->consecutiveones = 0; + s->necklace = 0; + s->usetighten = 1; + s->extra_connect = 0; + + rval = CCtsp_get_lp_result (lp, (double *) NULL, &ub, (int *) NULL, + (int **) NULL, (double **) NULL, (double **) NULL, + (double **) NULL, (double **) NULL); + if (rval) { + fprintf (stderr, "CCtsp_get_lp_result failed\n"); goto CLEANUP; + } + + s->nexttol = CCtsp_CUTS_NEXT_TOL * ub; + s->roundtol = CCtsp_CUTS_NEXT_ROUND * ub; + +CLEANUP: + + return rval; +} + +#define LOOP_FULL (25) /* to force a full price after 25 inner loops */ +#define CC_NO_NEAREST (20) /* the initial sparse graph for pricing */ + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_cutting_loop (CCtsp_lp *lp, CCtsp_cutselect *sel, int savelp) +#else +int CCtsp_cutting_loop (lp, sel, savelp) +CCtsp_lp *lp; +CCtsp_cutselect *sel; +int savelp; +#endif +{ + int xcount, cutcount, cutcount_connect, cut_added, edge_added; + int *xlist = (int *) NULL; + int outside = 0; + double newval, oldval, ub; + double *x = (double *) NULL; + CCtsp_lpcut_in *cuts = (CCtsp_lpcut_in *) NULL; + CCtsp_edgegenerator eginside; + int rval = 0; + int loopcount = 0; + double szeit = CCutil_zeit (); + + eginside.ncount = 0; + if (lp->fulladj) { + rval = CCtsp_init_edgegenerator (&eginside, lp->graph.ncount, lp->dat, + lp->fulladj, 0); + if (rval) { + fprintf (stderr, "CCtsp_init_edgegenerator (sparse) failed\n"); + rval = 1; goto CLEANUP; + } + } else if (lp->dat) { + rval = CCtsp_init_edgegenerator (&eginside, lp->graph.ncount, lp->dat, + (CCtsp_genadj *) NULL, CC_NO_NEAREST); + if (rval) { + fprintf (stderr, "CCtsp_init_edgegenerator (sparse) failed\n"); + rval = 1; goto CLEANUP; + } + } + + rval = CCtsp_get_lp_result (lp, (double *) NULL, &ub, (int *) NULL, + (int **) NULL, (double **) NULL, (double **) NULL, + (double **) NULL, (double **) NULL); + if (rval) { + fprintf (stderr, "CCtsp_get_lp_result failed\n"); + rval = 1; goto CLEANUP; + } + + do { + loopcount = 0; + cutcount_connect = 0; + do { + cut_added = 0; + rval = lp_value (lp, &oldval); + if (rval) {rval = 1; goto CLEANUP;} + + newval = oldval; + + rval = lp_x (lp, &xcount, &xlist, &x); + if (rval) {rval = 1; goto CLEANUP;} + + if (sel->cutpool) { + rval = CCtsp_search_cutpool (lp->pool, &cuts, &cutcount, + lp->graph.ncount, xcount, xlist, x); + if (rval) { + fprintf (stderr, "CCtsp_search_cutpool failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d cutpool cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->connect) { + rval = CCtsp_connect_cuts (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + if (rval) { + fprintf (stderr, "CCtsp_connect_cuts failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d connect cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->segments) { + rval = CCtsp_segment_cuts (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + if (rval) { + fprintf (stderr, "CCtsp_segment_cuts failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d segment cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->Xfastcuts) { + rval = Xfastcuts (&cuts, &cutcount, lp->graph.ncount, xcount, + xlist, x); + if (rval) { + fprintf (stderr, "Xfastcuts failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d Xfastcuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->exactsubtour) { + rval = CCtsp_exact_subtours (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + if (rval) { + fprintf (stderr, "CCtsp_exact_subtours failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d exact subtours\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->tighten_lp) { + rval = CCtsp_tighten_lp (&lp->cuts, &lp->tighten_stats, &cuts, + &cutcount, lp->graph.ncount, xcount, xlist, x, + 1.0, 500); + if (rval) { + fprintf (stderr, "CCtsp_tighten_lp failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d tighten_lp cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->teething_lp) { + rval = CCtsp_teething_lp (&lp->cuts, &lp->tighten_stats, + &cuts, &cutcount, lp->graph.ncount, xcount, xlist, x, + 10.0, 500); + if (rval) { + fprintf (stderr, "CCtsp_teething_lp failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d teethed combs\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->Xexactsubtours) { + rval = Xexactsubtours (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + if (rval) { + fprintf (stderr, "Xexactsubtours failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d Xexactsubtours\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->Xslowcuts && newval < oldval + sel->nexttol) { + rval = Xslowcuts (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + if (rval) { + fprintf (stderr, "Xslowcuts failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d Xslowcuts\n", cutcount); fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->tighten_pool && newval < oldval + sel->nexttol) { + rval = CCtsp_tighten_lp (lp->pool, &lp->tighten_stats, &cuts, + &cutcount, lp->graph.ncount, xcount, xlist, x, 0.1, + 1000); + if (rval) { + fprintf (stderr, "CCtsp_tighten_lp failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d tighten pool cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->teething_pool && newval < oldval + sel->nexttol) { + rval = CCtsp_teething_lp (lp->pool, &lp->tighten_stats, + &cuts, &cutcount, lp->graph.ncount, xcount, xlist, x, + 0.5, 1000); + if (rval) { + fprintf (stderr, "CCtsp_teething_lp failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d pool teething combs\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + if (sel->consecutiveones && newval < oldval + sel->nexttol) { + rval = Xconsecutiveones (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x, lp->pool); + if (rval) { + fprintf (stderr, "Xconsecutiveones failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d Xconsecutiveones cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + if (sel->necklace && newval < oldval + sel->nexttol) { + rval = Xnecklacecuts (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x, lp->pool); + if (rval) { + fprintf (stderr, "Xnecklacecuts failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d Xnecklace cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + } + + CC_FREE (xlist, int); + CC_FREE (x, double); + + rval = sparse_edge_check (lp, &eginside, &edge_added, + (double *) NULL); + if (rval) { + fprintf (stderr, "sparse_edge_check failed\n"); + rval = 1; goto CLEANUP; + } + if (savelp) { + rval = CCtsp_write_probfile_sav (lp); + if (rval) { + fprintf (stderr, "CCtsp_write_probfile_sav failed\n"); + rval = 1; goto CLEANUP; + } + } + if (lp->pool) { + char buf[1024]; + printf ("Write Pool: %d cuts\n", lp->pool->cutcount); + fflush (stdout); + sprintf (buf, "%s.pul", lp->name); + rval = CCtsp_write_cutpool (lp->graph.ncount, buf, lp->pool); + if (rval) { + fprintf (stderr, "CCtsp_write_cutpool failed\n"); + rval = 1; goto CLEANUP; + } + } + if (lp->lowerbound >= lp->upperbound - 0.9) { + printf ("Stop cutting, lp bound is within 0.9 of upperbound\n"); + fflush (stdout); + goto CLEANUP; + } + loopcount++; + } while ((newval > oldval + sel->roundtol || edge_added) + && loopcount < LOOP_FULL); + + rval = full_edge_check (lp, &edge_added); + if (rval) { + fprintf (stderr, "full_edge_check failed\n"); + rval = 1; goto CLEANUP; + } + if (savelp) { + rval = CCtsp_write_probfile_sav (lp); + if (rval) { + fprintf (stderr, "CCtsp_write_probfile_sav failed\n"); + rval = 1; goto CLEANUP; + } + } + + if (sel->extra_connect && (!edge_added || loopcount != LOOP_FULL)) { + printf ("Check connectivity before exiting cutting_loop\n"); + fflush (stdout); + + rval = lp_x (lp, &xcount, &xlist, &x); + if (rval) {rval = 1; goto CLEANUP;} + + rval = CCtsp_connect_cuts (&cuts, &cutcount_connect, + lp->graph.ncount, + xcount, xlist, x); + if (rval) { + fprintf (stderr, "CCtsp_connect_cuts failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount_connect) { + printf ("Found %d connect cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, sel->usetighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + } + CC_FREE (xlist, int); + CC_FREE (x, double); + } + outside++; + } while (edge_added || loopcount == LOOP_FULL || cutcount_connect); + +CLEANUP: + + if (rval == 2) { + printf ("LP is infeasible in cutting_loop\n"); + fflush (stdout); + } else if (rval) { + fprintf (stderr, "failure in cutting_loop\n"); + } + printf ("Time in cutting routine: %.2f\n", CCutil_zeit () - szeit); + printf ("Number of outside rounds: %d\n", outside); + fflush (stdout); + + if (eginside.ncount) + CCtsp_free_edgegenerator (&eginside); + CC_IFFREE (xlist, int); + CC_IFFREE (x, double); + + return rval; +} + +#define CC_NO_NEAREST_SUBTOUR 50 +#define CC_SUBTOUR_ROUNDS 5 + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_subtour_loop (CCtsp_lp *lp) +#else +int CCtsp_subtour_loop (lp) +CCtsp_lp *lp; +#endif +{ + int rval = 0; + int xcount, cutcount, cut_added, edge_added; + int outside = 0; + int inside = 0; + int tighten = 0; + double newval; + int *xlist = (int *) NULL; + double *x = (double *) NULL; + CCtsp_lpcut_in *cuts = (CCtsp_lpcut_in *) NULL; + CCtsp_edgegenerator eginside; + double szeit = CCutil_zeit (); + double connect_zeit = 0.0; + double linsub_zeit = 0.0; + double exact_zeit = 0.0; + double tzeit; + + eginside.ncount = 0; + if (lp->fulladj) { + rval = CCtsp_init_edgegenerator (&eginside, lp->graph.ncount, lp->dat, + lp->fulladj, 0); + if (rval) { + fprintf (stderr, "CCtsp_init_edgegenerator (sparse) failed\n"); + rval = 1; goto CLEANUP; + } + } else if (lp->dat) { + rval = CCtsp_init_edgegenerator (&eginside, lp->graph.ncount, lp->dat, + (CCtsp_genadj *) NULL, CC_NO_NEAREST_SUBTOUR); + if (rval) { + fprintf (stderr, "CCtsp_init_edgegenerator (sparse) failed\n"); + rval = 1; goto CLEANUP; + } + } + + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, + (int *) NULL, (int **) NULL, (double **) NULL, (double **) NULL, + (double **) NULL, (double **) NULL); + if (rval) { + fprintf (stderr, "CCtsp_get_lp_result failed\n"); + rval = 1; goto CLEANUP; + } + + do { + do { + cut_added = 0; + + rval = lp_x (lp, &xcount, &xlist, &x); + if (rval) {rval = 1; goto CLEANUP;} + + + /**** Connect Cuts ****/ + + + tzeit = CCutil_zeit (); + rval = CCtsp_connect_cuts (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + connect_zeit += (CCutil_zeit () - tzeit); + if (rval) { + fprintf (stderr, "CCtsp_connect_cuts failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d connect cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, tighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); goto CLEANUP; + } + } + + + /**** Linear Cuts ****/ + + + tzeit = CCutil_zeit (); + rval = CCtsp_segment_cuts (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + if (rval) { + fprintf (stderr, "CCtsp_segment_cuts failed\n"); + rval = 1; goto CLEANUP; + } + linsub_zeit += (CCutil_zeit () - tzeit); + if (rval) { + fprintf (stderr, "CCtsp_segment_cuts failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d segment cuts\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, tighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); goto CLEANUP; + } + } + + + /**** Exact Cuts ****/ + + + tzeit = CCutil_zeit (); + rval = CCtsp_exact_subtours (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + exact_zeit += (CCutil_zeit () - tzeit); + if (rval) { + fprintf (stderr, "CCtsp_exact_subtours failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d exact subtours\n", cutcount); + fflush (stdout); + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, tighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); goto CLEANUP; + } + } + +#if 0 + - this is just to check that the code is finding all cuts + + /**** Old Exact Cuts ****/ + + + if (!cut_added) { + rval = Xexactsubtours (&cuts, &cutcount, lp->graph.ncount, + xcount, xlist, x); + if (rval) { + fprintf (stderr, "Xexactsubtours failed\n"); + rval = 1; goto CLEANUP; + } + if (cutcount) { + printf ("Found %d Xexactsubtours\n", cutcount); + fflush (stdout); + + rval = CCtsp_dump_x (lp, "should.x"); + if (rval) { + fprintf (stderr, "CCtsp_dump_x failed\n"); + goto CLEANUP; + } + + rval = call_add_cuts (lp, &cuts, &cut_added, &xcount, + &xlist, &x, &newval, tighten); + if (rval) { + fprintf (stderr, "call_add_cuts failed\n"); + goto CLEANUP; + } + fprintf (stderr, "SHOULD NOT FIND XEXACTSUBTOURS\n"); + rval = 1; goto CLEANUP; + } + } +#endif + + CC_FREE (xlist, int); + CC_FREE (x, double); + + if (!cut_added || (inside % CC_SUBTOUR_ROUNDS) == 0) { + rval = sparse_edge_check (lp, &eginside, &edge_added, + (double *) NULL); + if (rval) { + fprintf (stderr, "sparse_edge_check failed\n"); + rval = 1; goto CLEANUP; + } + } + inside++; + } while (edge_added || cut_added); + + rval = full_edge_check (lp, &edge_added); + if (rval) { + fprintf (stderr, "full_edge_check failed\n"); + rval = 1; goto CLEANUP; + } + outside++; + + } while (edge_added); + +CLEANUP: + + if (rval == 2) { + printf ("LP is infeasible in subtour_loop\n"); + fflush (stdout); + } else if (rval) { + fprintf (stderr, "failure in subtour_loop\n"); + } + printf ("Time in cutting routine: %.2f\n", CCutil_zeit () - szeit); + printf (" Connect cuts: %.2f\n", connect_zeit); + printf (" Linear cuts: %.2f\n", linsub_zeit); + printf (" Exact cuts: %.2f\n", exact_zeit); + + + printf ("Number of outside rounds: %d (%d inside)\n", outside, inside); + fflush (stdout); + + if (eginside.ncount) + CCtsp_free_edgegenerator (&eginside); + CC_IFFREE (xlist, int); + CC_IFFREE (x, double); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int call_add_cuts (CCtsp_lp *lp, CCtsp_lpcut_in **cuts, int *cut_added, + int *xcount, int **xlist, double **x, double *val, int tighten) +#else +static int call_add_cuts (lp, cuts, cut_added, xcount, xlist, x, val, tighten) +CCtsp_lp *lp; +CCtsp_lpcut_in **cuts; +int *cut_added; +int *xcount; +int **xlist; +double **x; +double *val; +int tighten; +#endif +{ + int rval = 0; + + CC_IFFREE (*xlist, int); + CC_IFFREE (*x, double); + + CCtsp_add_cuts_to_queue (lp, cuts); + rval = CCtsp_process_cuts (lp, cut_added, tighten); + if (rval) { + fprintf (stderr, "process_cuts failed\n"); goto CLEANUP; + } + printf ("Added %d cuts (Total %d)\n", *cut_added, lp->cuts.cutcount); + fflush (stdout); + + rval = lp_value (lp, val); + if (rval) { + fprintf (stderr, "lp_value failed\n"); rval = 1; goto CLEANUP; + } + printf ("LP Value: %f\n", *val); fflush (stdout); + + rval = lp_x (lp, xcount, xlist, x); + if (rval) { + fprintf (stderr, "lp_x failed\n"); rval = 1; goto CLEANUP; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int lp_value (CCtsp_lp *lp, double *val) +#else +static int lp_value (lp, val) +CCtsp_lp *lp; +double *val; +#endif +{ + int rval; + + rval = CCtsp_get_lp_result (lp, val, (double *) NULL, (int *) NULL, + (int **) NULL, (double **) NULL, (double **) NULL, + (double **) NULL, (double **) NULL); + if (rval) fprintf (stderr, "CCtsp_get_lp_result failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int lp_x (CCtsp_lp *lp, int *xcount, int **xlist, double **x) +#else +static int lp_x (lp, xcount, xlist, x) +CCtsp_lp *lp; +int *xcount; +int **xlist; +double **x; +#endif +{ + int rval; + + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, xcount, + xlist, x, (double **) NULL, (double **) NULL, + (double **) NULL); + if (rval) fprintf (stderr, "CCtsp_get_lp_result failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_pricing_loop (CCtsp_lp *lp, double *bnd) +#else +int CCtsp_pricing_loop (lp, bnd) +CCtsp_lp *lp; +double *bnd; +#endif +{ + CCtsp_edgegenerator eg; + int nadded; + int rval = 0; + + eg.ncount = 0; + if (!lp->full_edges_valid) { + fprintf (stderr, "CCtsp_pricing_loop called without valid edges\n"); + rval = 1; goto CLEANUP; + } + + + rval = CCtsp_init_edgegenerator (&eg, lp->graph.ncount, lp->dat, + lp->fulladj, 0); + if (rval) { + fprintf (stderr, "CCtsp_init_edgegenerator failed\n"); goto CLEANUP; + } + rval = sparse_edge_check (lp, &eg, &nadded, bnd); + if (rval) { + fprintf (stderr, "sparse_edge_check failed\n"); goto CLEANUP; + } + +CLEANUP: + + if (eg.ncount) { + CCtsp_free_edgegenerator (&eg); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int full_edge_check (CCtsp_lp *lp, int *nadded) +#else +static int full_edge_check (lp, nadded) +CCtsp_lp *lp; +int *nadded; +#endif +{ + int rval; + CCtsp_edgegenerator eg; + double val, penalty; + + if (lp->dat && (!lp->full_edges_valid)) { + rval = CCtsp_init_edgegenerator (&eg, lp->graph.ncount, lp->dat, + (CCtsp_genadj *) NULL, CCtsp_PRICE_COMPLETE_GRAPH); + if (rval) { + fprintf (stderr, "CCtsp_init_edgegenerator failed\n"); return rval; + } + + rval = CCtsp_addbad_variables (lp, &eg, &penalty, nadded, + CCtsp_PRICE_RCTHRESH, CCtsp_PRICE_MAXPENALTY, 0, (int *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_addbad_variables failed\n"); + CCtsp_free_edgegenerator (&eg); + return rval; + } + CCtsp_free_edgegenerator (&eg); + printf ("%d edges added, penalty %f\n", *nadded, penalty); + fflush (stdout); + + rval = lp_value (lp, &val); + if (rval) return rval; + + if (val + penalty > lp->lowerbound) { + printf ("New lower bound: %f\n", val+ penalty); + fflush (stdout); + lp->lowerbound = val + penalty; + } + } else { + *nadded = 0; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int sparse_edge_check (CCtsp_lp *lp, CCtsp_edgegenerator *eg, + int *nadded, double *bnd) +#else +static int sparse_edge_check (lp, eg, nadded, bnd) +CCtsp_lp *lp; +CCtsp_edgegenerator *eg; +int *nadded; +double *bnd; +#endif +{ + double val, penalty; + int rval; + + if (bnd) *bnd = -CCtsp_LP_MAXDOUBLE; + + if (eg->ncount > 0) { + rval = CCtsp_addbad_variables (lp, eg, &penalty, nadded, + CCtsp_PRICE_RCTHRESH, CCtsp_PRICE_MAXPENALTY, 0, (int *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_addbad_variables failed\n"); return rval; + } + + rval = lp_value (lp, &val); + if (rval) { fprintf (stderr, "lp_value failed\n"); return rval; } + + printf ("(SPARSE) %d edges added, penalty %f, val %f\n", + *nadded, penalty, val); + fflush (stdout); + + if (lp->full_edges_valid) { + if (val + penalty > lp->lowerbound) { + printf ("New lower bound: %f\n", val + penalty); + fflush (stdout); + lp->lowerbound = val + penalty; + } + if (bnd) *bnd = val + penalty; + } + } else { + *nadded = 0; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_bb_cutting (char *probname, int probnum, int ncount, CCdatagroup *dat, + int *ptour, double *upbound, CCtsp_lpcuts *pool, CCtsp_cutselect *sel, + double *val, int *prune, int *foundtour, int *besttour) +#else +int CCtsp_bb_cutting (probname, probnum, ncount, dat, ptour, upbound, pool, + sel, val, prune, foundtour, besttour) +char *probname; +int probnum; +int ncount; +CCdatagroup *dat; +int *ptour; +double *upbound; +CCtsp_lpcuts *pool; +CCtsp_cutselect *sel; +double *val; +int *prune; +int *foundtour; +int *besttour; +#endif +{ + int rval = 0; + CCtsp_lp *lp = (CCtsp_lp *) NULL; + double cval, tourval; + int test; + + *val = 0.0; + *prune = 0; + *foundtour = 0; + + rval = bb_cutting_work (&lp, probname, probnum, ncount, dat, ptour, + *upbound, pool, sel, &cval); + if (rval) { + fprintf (stderr, "bb_cutting_work failed\n"); fflush (stdout); + } + + if (cval == CCtsp_LP_MAXDOUBLE) { + rval = CCtsp_verify_infeasible_lp (lp, &test); + if (rval) { + fprintf (stderr, "CCtsp_verify_infeasible_lp failed\n"); + goto CLEANUP; + } + if (test) { + printf ("verified infeasible LP\n"); fflush (stdout); + *val = CCtsp_LP_MAXDOUBLE; + *prune = 1; + /* for proof mode, write the lp file here */ + rval = 0; + } else { + fprintf (stderr, "did not verify an infeasible LP\n"); + rval = 1; goto CLEANUP; + } + } else { + rval = CCtsp_pricing_loop (lp, val); + if (rval) { + fprintf (stderr, "CCtsp_pricing_loop failed\n"); + rval = 1; goto CLEANUP; + } + lp->lowerbound = *val; + if (lp->upperbound < *upbound) *upbound = lp->upperbound; + + if (lp->lowerbound < lp->upperbound - 0.9) { + rval = CCtsp_call_x_heuristic (lp, &tourval, besttour); + if (rval) { + fprintf (stderr, "CCtsp_call_x_heuristic failed\n"); + goto CLEANUP; + } + if (tourval < lp->upperbound) { + printf ("New upperbound from x-heuristic: %.2f\n", tourval); + lp->upperbound = tourval; + *upbound = tourval; + *foundtour = 1; + } + } + + if (lp->lowerbound >= lp->upperbound - 0.9) { + rval = CCtsp_verify_lp_prune (lp, &test); + if (rval) { + fprintf (stderr, "CCtsp_verify_lp_prune failed\n"); + goto CLEANUP; + } + if (test) { + printf ("verified that LP can be pruned\n"); fflush (stdout); + *prune = 1; + /* for proof mode, write the lp file here */ + } else { + fprintf (stderr, "exact pricing could not prune the search\n"); + rval = 1; goto CLEANUP; + } + } else { + rval = CCtsp_write_probfile_id (lp); + if (rval) { + fprintf (stderr, "CCtsp_write_probfile_id failed\n"); + goto CLEANUP; + } + } + } + +CLEANUP: + + if (lp) CCtsp_free_tsp_lp_struct (&lp); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_call_x_heuristic (CCtsp_lp *lp, double *val, int *outcyc) +#else +int CCtsp_call_x_heuristic (lp, val, outcyc) +CCtsp_lp *lp; +double *val; +int *outcyc; +#endif +{ + int rval = 0; + int *cyc = (int *) NULL; + int *xlist = (int *) NULL; + double *x = (double *) NULL; + int ncount = lp->graph.ncount; + int xcount, i; + + *val = CCtsp_LP_MAXDOUBLE; + + if (!lp->dat) goto CLEANUP; + + cyc = CC_SAFE_MALLOC (ncount, int); + if (!cyc) { + fprintf (stderr, "out of memory for cycle\n"); + rval = 1; goto CLEANUP; + } + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, + &xcount, &xlist, &x, (double **) NULL, (double **) NULL, + (double **) NULL); + if (rval) { + fprintf (stderr, "CCtsp_get_lp_result failed\n"); + goto CLEANUP; + } + + rval = CCtsp_x_greedy_tour_lk (lp->dat, ncount, xcount, xlist, x, + cyc, val); + if (rval) { + fprintf (stderr, "CCtsp_x_greedy_tour_lk failed\n"); goto CLEANUP; + } + printf ("x-heuristic lk gives: %.2f\n", *val); + if (*val < lp->upperbound) { + if (outcyc) { + for (i = 0; i < ncount; i++) { + outcyc[i] = cyc[i]; + } + } + } + +CLEANUP: + + CC_IFFREE (cyc, int); + CC_IFFREE (xlist, int); + CC_IFFREE (x, double); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int bb_cutting_work (CCtsp_lp **lp, char *probname, int probnum, + int ncount, CCdatagroup *dat, int *ptour, double initial_ub, + CCtsp_lpcuts *pool, CCtsp_cutselect *sel, double *val) +#else +static int bb_cutting_work (lp, probname, probnum, ncount, dat, ptour, + initial_ub, pool, sel, val) +CCtsp_lp **lp; +char *probname; +int probnum; +int ncount; +CCdatagroup *dat; +int *ptour; +double initial_ub; +CCtsp_lpcuts *pool; +CCtsp_cutselect *sel; +double *val; +#endif +{ + int rval = 0; + + *lp = (CCtsp_lp *) NULL; + *val = 0.0; + + rval = CCtsp_bb_init_lp (lp, probname, probnum, ncount, dat, ptour, + initial_ub, pool); + if (rval == 2) { + printf ("LP is reported to be infeasible\n"); fflush (stdout); + *val = CCtsp_LP_MAXDOUBLE; + rval = 0; goto CLEANUP; + } else if (rval) { + fprintf (stderr, "CCtsp_init_lp failed\n"); goto CLEANUP; + } + + if ((*lp)->lowerbound >= (*lp)->upperbound - 0.9) { + printf ("Do not cut, the lp is within 1.0 of the upperbound\n"); + fflush (stdout); + *val = (*lp)->lowerbound; + goto CLEANUP; + } else { + rval = CCtsp_cutting_loop (*lp, sel, 0); + if (rval == 2) { + printf ("Cut LP is reported to be infeasible\n"); fflush (stdout); + } else if (rval) { + fprintf (stderr, "CCtsp_cutting_loop failed\n"); goto CLEANUP; + } else { + *val = (*lp)->lowerbound; + } + } + +CLEANUP: + + return rval; +} diff --git a/contrib/blossom/concorde97/TSP/cutcall.c b/contrib/blossom/concorde97/TSP/cutcall.c new file mode 100644 index 0000000000000000000000000000000000000000..63f8b25f8a21bdda7f597fd3bd82b238e275d576 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/cutcall.c @@ -0,0 +1,1890 @@ +/***************************************************************************/ +/* */ +/* Interface to the Cutters */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 17, 1997 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_connect_cuts (CCtsp_lpcut_in **cuts, int *cutcount, */ +/* int ncount, int ecount, int *elist, double *x) */ +/* FINDS violated subtour inequalities via connectivity. */ +/* -cuts will return any new cuts found (they will be added to the */ +/* head of the linked list) */ +/* -cutcount will return the number of new cuts added */ +/* -ncount is the number of nodes */ +/* -ecount is the number of edges */ +/* -elist contains the LP edges in node node format */ +/* -x is an LP solution */ +/* */ +/* int CCtsp_segment_cuts (CCtsp_lpcut_in **cuts, int *cutcount, */ +/* int ncount, int ecount, int *elist, double *x) */ +/* FINDS violated subtour inequalities via linsub. */ +/* */ +/* int CCtsp_exact_subtours (CCtsp_lpcut_in **cuts, int *cutcount, */ +/* int ncount, int ecount, int *elist, double *x) */ +/* FINDS violated subtour inequalities via a mincut algorithm. */ +/* */ +/* int CCtsp_tighten_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, */ +/* CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, */ +/* int ecount, int *elist, double *x, double testtol, */ +/* int maxcuts) */ +/* CALLS tighten for each cut in the cuts. */ +/* -stats contains some running statistics of tighten */ +/* -cutsout returns the tightened cuts that are violated (they are */ +/* added to the head of the linked list) */ +/* -cutcount is the number of cuts in cutsout */ +/* -testtol is a tolerance for calling tighten (call only when the */ +/* cut has slack value within testtol) */ +/* -maxcuts is a bound on the number of cuts to be returned */ +/* */ +/* void CCtsp_init_lpcut_in (CCtsp_lpcut_in *c) */ +/* INITIALIZE the fields of the CCtsp_lpcut_in structure */ +/* */ +/* int CCtsp_segment_to_subtour (CCtsp_lpcut_in **cut, int a, int b) */ +/* BUILDS a subtour CCtsp_lpcut_in from an the segment. */ +/* -cut will return the subtour (it will be allocated). */ +/* */ +/* int CCtsp_array_to_subtour (CCtsp_lpcut_in **cut, int *ar, */ +/* int acount) */ +/* BUILDS a subtour CCtsp_lpcut_in from an array. */ +/* -cut will return the subtour (it will be allocated). */ +/* */ +/* void CCtsp_init_lpclique (CCtsp_lpclique *c) */ +/* INITIALIZE the fields of the CCtsp_lpclique structure */ +/* */ +/* int CCtsp_array_to_lpclique (int *ar, int acount, */ +/* CCtsp_lpclique *cliq) */ +/* BUILDS an CCtsp_lpclique represented the nodes in an array. */ +/* -ar is an array of node numbers */ +/* -acount is the length of ar */ +/* -cliq's segcount and nodes will be filled with the compressed */ +/* version of the nodes in ar */ +/* */ +/* int CCtsp_seglist_to_lpclique (int nseg, int *list, */ +/* CCtsp_lpclique *cliq) */ +/* BUILDS the CCtsp_lpclique represented by a list of CCtsp_segments */ +/* (it will sort the CCtsp_segments before it puts them into the */ +/* CCtsp_segment structures) */ +/* -list is an array of CCtsp_segments in lo-hi-lo-hi format */ +/* -clig's segcount and nodes will be filled in (nodes will be */ +/* allocated) */ +/* */ +/* int CCtsp_add_node_to_lpclique (CCtsp_lpclique *cin, */ +/* CCtsp_lpclique *cout, int n) */ +/* ADDS node n to clique cin, and returns the new clique in cout */ +/* */ +/* int CCtsp_delete_node_from_lpclique (CCtsp_lpclique *cin, */ +/* CCtsp_lpclique *cout, int n) */ +/* DELETES node n from clique cin, and returns the new clique in cout */ +/* */ +/* void CCtsp_print_lpcut_in (CCtsp_lpcut_in *c) */ +/* PRINTS the CCtsp_lpcut_in */ +/* */ +/* void CCtsp_print_lpclique (CCtsp_lpclique *c) */ +/* PRINTS the CCtsp_segments in the clique to stdout. */ +/* */ +/* int CCtsp_copy_lpcut_in (CCtsp_lpcut_in *c, */ +/* CCtsp_lpcut_in *new) */ +/* COPIES an CCtsp_lpcut_in */ +/* -c is a pointer to an CCtsp_lpcut_in */ +/* -new returns the copied CCtsp_lpcut */ +/* */ +/* int CCtsp_lpcut_to_lpcut_in (CCtsp_lpcuts *cuts, */ +/* CCtsp_lpcut *c, CCtsp_lpcut_in *new) */ +/* COPIES an CCtsp_lpcut to an CCtsp_lpcut_in */ +/* -cuts is a pointer to the structure holding the set of cuts */ +/* -c is the cut to be copied */ +/* -new returns the copied cut */ +/* */ +/* void CCtsp_lpclique_compare (CCtsp_lpclique *a, */ +/* CCtsp_lpclique *b, int *diff) */ +/* COMPARES two CCtsp_lpcliques. */ +/* -diff is set to 1 if they differ and 0 if they are the same */ +/* Note: Assumes CCtsp_segments are ordered. */ +/* */ +/* int CCtsp_copy_lpclique (CCtsp_lpclique *c, */ +/* CCtsp_lpclique *new) */ +/* COPIES an CCtsp_lpclique */ +/* -c is a pointer to an CCtsp_lpclique */ +/* -new returns the copied clique */ +/* */ +/* int CCtsp_file_cuts (char *cutfile, CCtsp_lpcut_in **cuts, */ +/* int *cutcount, int ncount, int *tour) */ +/* READS a set of cuts from a file; the format of the cuts can be */ +/* found by examining the code */ +/* -cutfile is an asci file with a list of cuts */ +/* -cuts will return any new cuts found (they will be added to the */ +/* head of the linked list) */ +/* -cutcount with return the number of new cuts added */ +/* -ncount is the number of nodes */ +/* -tour the permutation tour (used to map the incoming nodes) */ +/* */ +/* int CCtsp_file_cuts_write (char *cutfile, CCtsp_lpcuts *cuts, */ +/* int *tour) */ +/* WRITES a set of cuts in a text file that can be read by */ +/* tsp_file_cuts */ +/* -cutfile is the name of the file to be written */ +/* -cuts is the set of cuts to be written */ +/* -tour is a permutation tour (used to map the outgoing nodes) */ +/* */ +/* int CCtsp_test_pure_comb (int ncount, CCtsp_lpcut_in *c, int *yes_no,*/ +/* int *handle) */ +/* TEST if the cut is a comb (without flipped teeth or intersections) */ +/* -ncount is the number of nodes in the TSP */ +/* -yes_no will be set to either 0 or 1, with 1 meaning yes */ +/* -handle with return the index of the handle if the cut is a comb */ +/* (handle can be NULL) */ +/* */ +/* int CCtsp_test_pseudocomb (int ncount, CCtsp_lpcut_in *c, int handle,*/ +/* int *yes_no) */ +/* TEST if the cut is a pseudocomb. */ +/* -handle gives the index of the handle of the pseudocomb */ +/* */ +/* int CCtsp_test_teeth_disjoint (int ncount, CCtsp_lpcut_in *c, */ +/* int handle, int *yes_no) */ +/* TEST if the cliques other than handle are pairwise disjoint. */ +/* -yes_no is 1 if disjoint and 0 otherwise. */ +/* */ +/* int CCtsp_find_pure_handle (int ncount, CCtsp_lpcut_in *c, */ +/* int *handle) */ +/* FINDS a clique that is c's handle if c is a comb; the search */ +/* assumes that the teeth are disjoint, so if the comb has */ +/* extra intersections then a tooth may be returned. */ +/* -handle returns the potential handle (it will return -1 if no */ +/* clique is a potential handle) */ +/* */ +/* NOTES: */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "macrorus.h" +#include "util.h" +#include "tsp.h" +#include "cut.h" + +#define X_FLUFF (1e-10) +#undef DUMP_BUILDCUT + +typedef struct exactsub_param { + int cutcount; + CCtsp_lpcut_in *cuts; +} exactsub_param; + +#ifdef CC_PROTOTYPE_ANSI + +static int + add_segment (double val, int a, int b, void *pass_param), + add_exact (double val, int count, int *cutarray, void *pass_param), + work_on_combs_in_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, + int *cutcount, int ncount, int ecount, int *elist, double *x, + double testtol, int maxcuts, + int (*doit_fn) (CCtsp_lpgraph *, double *, CCtsp_lpcut_in *, + CCtsp_lpcut_in **)), + grab_nonzero_x (int ecount, int *elist, double *x, int *new_ecount, + int **new_elist, double **new_x, double tol); + +#else + +static int + add_segment (), + add_exact (), + work_on_combs_in_lp (), + grab_nonzero_x (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_connect_cuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x) +#else +int CCtsp_connect_cuts (cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount, ecount; +int *elist; +double *x; +#endif +{ + int rval; + int i, k, ncomp; + CCtsp_lpcut_in *c = (CCtsp_lpcut_in *) NULL; + int *comps = (int *) NULL; + int *compscount = (int *) NULL; + + *cutcount = 0; + rval = CCcut_connect_components (ncount, ecount, elist, x, &ncomp, + &compscount, &comps); + if (rval) { + fprintf (stderr, "CCcut_connect_components failed\n"); goto CLEANUP; + } + + for (i = 0, k = 0; i < ncomp - 1; k += compscount[i], i++) { + rval = CCtsp_array_to_subtour (&c, comps + k, compscount[i]); + if (rval) { + fprintf (stderr, "CCtsp_array_to_subtour failed\n"); + rval = 1; goto CLEANUP; + } + c->next = *cuts; + *cuts = c; + (*cutcount)++; + } + +CLEANUP: + + CC_IFFREE (comps, int); + CC_IFFREE (compscount, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_segment_cuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x) +#else +int CCtsp_segment_cuts (cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount, ecount; +int *elist; +double *x; +#endif +{ + int rval = 0; + exactsub_param p; + double szeit = CCutil_zeit (); + + *cutcount = 0; + + p.cutcount = 0; + p.cuts = *cuts; + + rval = CCcut_linsub (ncount, ecount, elist, x, 2.0 - 0.0001, + add_segment, (void *) &p); + if (rval) { + fprintf (stderr, "CCcut_linsub failed\n"); goto CLEANUP; + } + + *cutcount = p.cutcount; + *cuts = p.cuts; + + printf ("DONE (found %d segment cuts in %.2f seconds)\n", *cutcount, + CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + return rval; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_exact_subtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x) +#else +int CCtsp_exact_subtours (cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount, ecount; +int *elist; +double *x; +#endif +{ + int rval = 0; + exactsub_param p; + double szeit = CCutil_zeit (); + + + printf ("exact_subtours ... \n"); fflush (stdout); + *cutcount = 0; + rval = CCtsp_connect_cuts (cuts, cutcount, ncount, ecount, elist, x); + if (rval) { + fprintf (stderr, "CCtsp_connect_cuts failed\n"); goto CLEANUP; + } + + if (*cutcount > 0) { + fprintf (stderr, "found connect cuts, do not call exact cut routine\n"); + rval = 0; goto CLEANUP; + } + + p.cutcount = 0; + p.cuts = *cuts; + + rval = CCcut_violated_cuts (ncount, ecount, elist, x, 2.0 - 0.0001, + add_exact, (void *) &p); + if (rval) { + fprintf (stderr, "CCcut_violated_cuts failed\n"); goto CLEANUP; + } + + *cutcount = p.cutcount; + *cuts = p.cuts; + + printf ("DONE (found %d cuts in %.2f seconds)\n", *cutcount, + CCutil_zeit () - szeit); + fflush (stdout); + +#if 0 + - this is just to check the values of the exact cuts + if (*cutcount) { + CCtsp_lpgraph lg; + CCtsp_lpcut_in *c; + double t; + + CCtsp_init_lpgraph_struct (&lg); + + rval = CCtsp_build_lpgraph (&lg, ncount, ecount, elist, (int *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_build_lpgraph failed\n"); goto CLEANUP; + } + rval = CCtsp_build_lpadj (&lg, 0, ecount); + if (rval) { + CCtsp_free_lpgraph (&lg); + fprintf (stderr, "CCtsp_build_lpadj failed\n"); goto CLEANUP; + } + for (c = p.cuts; c; c = c->next) { + t = CCtsp_cutprice (&lg, c, x); + printf ("[%f] ", 2.0 + t); fflush (stdout); + } + printf ("\n"); fflush (stdout); + CCtsp_free_lpgraph (&lg); + } +#endif + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_segment (double val, int a, int b, void *pass_param) +#else +static int add_segment (val, a, b, pass_param) +double val; +int a, b; +void *pass_param; +#endif +{ + int rval = 0; + exactsub_param *p = (exactsub_param *) pass_param; + CCtsp_lpcut_in *c = (CCtsp_lpcut_in *) NULL; + + if (val > 2.0) { + printf ("Warning: Cut of value %f in add_segment\n", val); + fflush (stdout); + goto CLEANUP; + } + + rval = CCtsp_segment_to_subtour (&c, a, b); + if (rval) { + fprintf (stderr, "CCtsp_array_to_subtour failed\n"); + rval = 1; goto CLEANUP; + } + c->next = p->cuts; + p->cuts = c; + p->cutcount++; + +CLEANUP: + + return rval; +} +#ifdef CC_PROTOTYPE_ANSI +static int add_exact (double val, int count, int *cutarray, void *pass_param) +#else +static int add_exact (val, count, cutarray, pass_param) +double val; +int count; +int *cutarray; +void *pass_param; +#endif +{ + int rval = 0; + exactsub_param *p = (exactsub_param *) pass_param; + CCtsp_lpcut_in *c = (CCtsp_lpcut_in *) NULL; + + if (val > 2.0) { + printf ("Warning: Cut of value %f in add_exact\n", val); + fflush (stdout); + goto CLEANUP; + } + + rval = CCtsp_array_to_subtour (&c, cutarray, count); + if (rval) { + fprintf (stderr, "CCtsp_array_to_subtour failed\n"); + rval = 1; goto CLEANUP; + } + c->next = p->cuts; + p->cuts = c; + p->cutcount++; + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_tighten_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts) +#else +int CCtsp_tighten_lp (cuts, stats, cutsout, cutcount, ncount, ecount, elist, x, + testtol, maxcuts) +CCtsp_lpcuts *cuts; +CCtsp_tighten_info *stats; +CCtsp_lpcut_in **cutsout; +int *cutcount; +int ncount, ecount; +int *elist; +double *x; +double testtol; +int maxcuts; +#endif +{ + CCtsp_lpcut_in new, old; + CCtsp_lpcut_in *c; + int i; + int rval = 0; + double improve; + CCtsp_lpgraph lg; + double *newx = (double *) NULL; + int *newelist = (int *) NULL; + int newecount; + CCtsp_lpcut_in **clist = (CCtsp_lpcut_in **) NULL; + double *vlist = (double *) NULL; + double maxviol = 0.0; + int clistsize = 0, vlistsize = 0; + int count = 0; + int *perm = (int *) NULL; + double szeit = CCutil_zeit (); + double *cutval = (double *) NULL; + + *cutcount = 0; + if (!cuts || !cuts->cutcount) return 0; + + + rval = grab_nonzero_x (ecount, elist, x, &newecount, &newelist, &newx, + X_FLUFF); + if (rval) { + fprintf (stderr, "grab_nonzero_x failed\n"); goto CLEANUP; + } + + cutval = CC_SAFE_MALLOC (cuts->cutcount, double); + if (!cutval) { + fprintf (stderr, "out of memory in CCtsp_tighten_lp\n"); + rval = 1; goto CLEANUP; + } + rval = CCtsp_price_cuts (cuts, ncount, newecount, newelist, newx, cutval); + if (rval) { + fprintf (stderr, "CCtsp_price_cuts failed\n"); goto CLEANUP; + } + + CCtsp_init_lpgraph_struct (&lg); + + rval = CCtsp_build_lpgraph (&lg, ncount, newecount, newelist, (int *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_build_lpgraph failed\n"); goto CLEANUP; + } + CC_FREE (newelist, int); + rval = CCtsp_build_lpadj (&lg, 0, newecount); + if (rval) { + fprintf (stderr, "CCtsp_build_lpadj failed\n"); goto CLEANUP; + } + + for (i = 0; i < cuts->cutcount; i++) { + if (cutval[i] < testtol && !cuts->cuts[i].branch) { + rval = CCtsp_lpcut_to_lpcut_in (cuts, &(cuts->cuts[i]), &old); + if (rval) { + fprintf (stderr, "CCtsp_lpcut_to_lpcut_in failed\n"); + goto CLEANUP; + } + rval = CCtsp_tighten_lpcut_in (&lg, &old, newx, &new, stats, + &improve); + if (rval) { + fprintf (stderr, "CCtsp_tighten_lpcut failed\n"); + goto CLEANUP; + } + CCtsp_free_lpcut_in (&old); + + if (improve - cutval[i] > CCtsp_MIN_VIOL) { + c = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!c) { + fprintf (stderr, "out of memory in CCtsp_tighten_lp\n"); + rval = 1; goto CLEANUP; + } + *c = new; + if (count >= clistsize) { + rval = CCutil_reallocrus_scale ((void **) &clist, + &clistsize, + count + 1, 1.3, sizeof (CCtsp_lpcut_in *)); + if (rval) { + fprintf (stderr, "CCutil_reallocrus_scale failed\n"); + rval = 1; goto CLEANUP; + } + } + if (count >= vlistsize) { + rval = CCutil_reallocrus_scale ((void **) &vlist, + &vlistsize, + count + 1, 1.3, sizeof (double)); + if (rval) { + fprintf (stderr, "CCutil_reallocrus_scale failed\n"); + rval = 1; goto CLEANUP; + } + } + clist[count] = c; + vlist[count] = cutval[i] - improve; + count++; + } else { + CCtsp_free_lpcut_in (&new); + } + } + } + + if (count) { + perm = CC_SAFE_MALLOC (count, int); + if (!perm) { + fprintf (stderr, "out of memory in CCtsp_tighten_lp\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < count; i++) { + perm[i] = i; + } + if (count > maxcuts) { + CCutil_rselect (perm, 0, count - 1, maxcuts, vlist); + for (i = maxcuts; i < count; i++) { + CCtsp_free_lpcut_in (clist[perm[i]]); + } + count = maxcuts; + } + for (i = 0; i < count; i++) { + if (vlist[perm[i]] < maxviol) + maxviol = vlist[perm[i]]; + clist[perm[i]]->next = *cutsout; + *cutsout = clist[perm[i]]; + } + } + + *cutcount = count; + printf ("%d tighten cuts, %.5f max violation (%.2f seconds)\n", + count, -maxviol, CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (newelist, int); + CC_IFFREE (newx, double); + CC_IFFREE (clist, CCtsp_lpcut_in *); + CC_IFFREE (vlist, double); + CC_IFFREE (perm, int); + CC_IFFREE (cutval, double); + CCtsp_free_lpgraph (&lg); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_teething_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts) +#else +int CCtsp_teething_lp (cuts, stats, cutsout, cutcount, ncount, ecount, + elist, x, testtol, maxcuts) +CCtsp_lpcuts *cuts; +CCtsp_tighten_info *stats; +CCtsp_lpcut_in **cutsout; +int *cutcount; +int ncount, ecount; +int *elist; +double *x; +double testtol; +int maxcuts; +#endif +{ + int rval = 0; + + rval = work_on_combs_in_lp (cuts, stats, cutsout, cutcount, ncount, ecount, + elist, x, testtol, maxcuts, + CCtsp_teething); + if (rval) { + fprintf (stderr, "work_on_combs_in_lp failed\n"); + goto CLEANUP; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int work_on_combs_in_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts, + int (*doit_fn) (CCtsp_lpgraph *, double *, CCtsp_lpcut_in *, + CCtsp_lpcut_in **)) +#else +static int work_on_combs_in_lp (cuts, stats, cutsout, cutcount, ncount, ecount, + elist, x, testtol, maxcuts, doit_fn) +CCtsp_lpcuts *cuts; +CCtsp_tighten_info *stats; +CCtsp_lpcut_in **cutsout; +int *cutcount; +int ncount, ecount; +int *elist; +double *x; +double testtol; +int maxcuts; +int (*doit_fn) (); +#endif +{ + CCtsp_lpcut_in new, old; + CCtsp_lpcut_in *c = (CCtsp_lpcut_in *) NULL; + CCtsp_lpcut_in *dd = (CCtsp_lpcut_in *) NULL; + int i, test; + int rval = 0; + double improve, newslack; + CCtsp_lpgraph lg; + double *newx = (double *) NULL; + int *newelist = (int *) NULL; + int newecount; + CCtsp_lpcut_in **clist = (CCtsp_lpcut_in **) NULL; + double *vlist = (double *) NULL; + double maxviol = 0.0; + int clistsize = 0, vlistsize = 0; + int count = 0; + int *perm = (int *) NULL; + double *cutval = (double *) NULL; + double szeit = CCutil_zeit (); + + *cutcount = 0; + if (!cuts || !cuts->cutcount) return 0; + + rval = grab_nonzero_x (ecount, elist, x, &newecount, &newelist, &newx, + X_FLUFF); + if (rval) { + fprintf (stderr, "grab_nonzero_x failed\n"); goto CLEANUP; + } + + cutval = CC_SAFE_MALLOC (cuts->cutcount, double); + if (!cutval) { + fprintf (stderr, "out of memory in CCtsp_tighten_lp\n"); + rval = 1; goto CLEANUP; + } + rval = CCtsp_price_cuts (cuts, ncount, newecount, newelist, newx, cutval); + if (rval) { + fprintf (stderr, "CCtsp_price_cuts failed\n"); goto CLEANUP; + } + + CCtsp_init_lpgraph_struct (&lg); + rval = CCtsp_build_lpgraph (&lg, ncount, newecount, newelist, (int *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_build_lpgraph failed\n"); goto CLEANUP; + } + CC_FREE (newelist, int); + rval = CCtsp_build_lpadj (&lg, 0, newecount); + if (rval) { + fprintf (stderr, "CCtsp_build_lpadj failed\n"); goto CLEANUP; + } + + for (i = 0; i < cuts->cutcount; i++) { + if (cuts->cuts[i].branch || cuts->cuts[i].cliquecount % 2 || + cuts->cuts[i].cliquecount < 4 || cutval[i] >= testtol) { + continue; + } + rval = CCtsp_lpcut_to_lpcut_in (cuts, &(cuts->cuts[i]), &old); + if (rval) { + fprintf (stderr, "CCtsp_lpcut_to_lpcut_in failed\n"); goto CLEANUP; + } + rval = CCtsp_test_pure_comb (ncount, &old, &test, (int *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_test_pure_comb failed\n"); + CCtsp_free_lpcut_in (&old); + goto CLEANUP; + } + if (test == 1) { + rval = doit_fn (&lg, newx, &old, &dd); + if (rval) { + fprintf (stderr, "doit_fn failed\n"); goto CLEANUP; + } + CCtsp_free_lpcut_in (&old); + if (dd) { + rval = CCtsp_tighten_lpcut_in (&lg, dd, newx, &new, + stats, &improve); + if (rval) { + fprintf (stderr, "CCtsp_tighten_lpcut failed\n"); + goto CLEANUP; + } + CCtsp_free_lpcut_in (dd); + CC_FREE (dd, CCtsp_lpcut_in); + + newslack = CCtsp_cutprice (&lg, &new, newx); + if (-newslack > CCtsp_MIN_VIOL) { + c = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!c) { + fprintf (stderr, + "out of memory in work_on_combs_in_lp\n"); + CCtsp_free_lpcut_in (&new); + rval = 1; goto CLEANUP; + } + *c = new; + if (count >= clistsize) { + rval = CCutil_reallocrus_scale ((void **) &clist, + &clistsize, count + 1, 1.3, + sizeof (CCtsp_lpcut_in *)); + if (rval) { + fprintf (stderr, + "CCutil_reallocrus_scale failed\n"); + rval = 1; goto CLEANUP; + } + } + if (count >= vlistsize) { + rval = CCutil_reallocrus_scale ((void **) &vlist, + &vlistsize, count + 1, 1.3, + sizeof (double)); + if (rval) { + fprintf (stderr, + "CCutil_reallocrus_scale failed\n"); + rval = 1; goto CLEANUP; + } + } + clist[count] = c; + vlist[count] = newslack; + count++; + } else { + CCtsp_free_lpcut_in (&new); + } + } + } else { + CCtsp_free_lpcut_in (&old); + } + } + + if (count) { + perm = CC_SAFE_MALLOC (count, int); + if (!perm) { + fprintf (stderr, "out of memory in work_on_combs_in_lp\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < count; i++) { + perm[i] = i; + } + if (count > maxcuts) { + CCutil_rselect (perm, 0, count - 1, maxcuts, vlist); + for (i = maxcuts; i < count; i++) { + CCtsp_free_lpcut_in (clist[perm[i]]); + } + count = maxcuts; + } + for (i = 0; i < count; i++) { + if (vlist[perm[i]] < maxviol) + maxviol = vlist[perm[i]]; + clist[perm[i]]->next = *cutsout; + *cutsout = clist[perm[i]]; + } + } + + *cutcount = count; + printf ("%d cuts, %.5f max violation (%.2f seconds)\n", count, -maxviol, + CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (newelist, int); + CC_IFFREE (newx, double); + CC_IFFREE (clist, CCtsp_lpcut_in *); + CC_IFFREE (vlist, double); + CC_IFFREE (perm, int); + CC_IFFREE (cutval, double); + CCtsp_free_lpgraph (&lg); + if (dd) { + CCtsp_free_lpcut_in (dd); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_init_lpcut_in (CCtsp_lpcut_in *c) +#else +void CCtsp_init_lpcut_in (c) +CCtsp_lpcut_in *c; +#endif +{ + if (c) { + c->handlecount = 0; + c->cliquecount = 0; + c->rhs = 0; + c->sense = 'X'; + c->branch = 0; + c->cliques = (CCtsp_lpclique *) NULL; + c->next = (CCtsp_lpcut_in *) NULL; + c->prev = (CCtsp_lpcut_in *) NULL; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_copy_lpcut_in (CCtsp_lpcut_in *c, CCtsp_lpcut_in *new) +#else +int CCtsp_copy_lpcut_in (c, new) +CCtsp_lpcut_in *c; +CCtsp_lpcut_in *new; +#endif +{ + int rval = 0; + int i; + + CCtsp_init_lpcut_in (new); + + new->handlecount = c->handlecount; + new->cliquecount = c->cliquecount; + new->rhs = c->rhs; + new->sense = c->sense; + + if (c->cliquecount) { + new->cliques = CC_SAFE_MALLOC (c->cliquecount, CCtsp_lpclique); + if (!new->cliques) { + fprintf (stderr, "out of memory in CCtsp_copy_lpcut_in\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < c->cliquecount; i++) { + rval = CCtsp_copy_lpclique (&c->cliques[i], &new->cliques[i]); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); + goto CLEANUP; + } + } + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_segment_to_subtour (CCtsp_lpcut_in **cut, int a, int b) +#else +int CCtsp_segment_to_subtour (cut, a, b) +CCtsp_lpcut_in **cut; +int a, b; +#endif +{ + int rval = 0; + int list[2]; + int t; + CCtsp_lpcut_in *c = (CCtsp_lpcut_in *) NULL; + + *cut = (CCtsp_lpcut_in *) NULL; + if (a > b) CC_SWAP (a, b, t); + + c = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!c) { + fprintf (stderr, "out of memory in CCtsp_segment_to_subtour\n"); + rval = 1; goto CLEANUP; + } + CCtsp_init_lpcut_in (c); + + c->cliquecount = 1; + c->handlecount = 0; + c->cliques = CC_SAFE_MALLOC (1, CCtsp_lpclique); + if (!c->cliques) { + fprintf (stderr, "out of memory in CCtsp_segment_to_subtour\n"); + rval = 1; goto CLEANUP; + } + + list[0] = a; + list[1] = b; + rval = CCtsp_seglist_to_lpclique (1, list, &(c->cliques[0])); + if (rval) { + goto CLEANUP; + } + c->rhs = CCtsp_CUTRHS(c); + c->sense = 'G'; + c->branch = 0; + + *cut = c; + +CLEANUP: + + if (rval) { + if (c) { + CCtsp_free_lpcut_in (c); + CC_FREE (c, CCtsp_lpcut_in); + } + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_array_to_subtour (CCtsp_lpcut_in **cut, int *ar, int acount) +#else +int CCtsp_array_to_subtour (cut, ar, acount) +CCtsp_lpcut_in **cut; +int *ar; +int acount; +#endif +{ + int rval = 0; + CCtsp_lpcut_in *c = (CCtsp_lpcut_in *) NULL; + + *cut = (CCtsp_lpcut_in *) NULL; + + c = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!c) { + fprintf (stderr, "out of memory in CCtsp_array_to_subtour\n"); + rval = 1; goto CLEANUP; + } + CCtsp_init_lpcut_in (c); + + c->cliquecount = 1; + c->handlecount = 0; + c->cliques = CC_SAFE_MALLOC (1, CCtsp_lpclique); + if (!c->cliques) { + fprintf (stderr, "out of memory in CCtsp_array_to_subtour\n"); + rval = 1; goto CLEANUP; + } + + rval = CCtsp_array_to_lpclique (ar, acount, &(c->cliques[0])); + if (rval) { + goto CLEANUP; + } + c->rhs = CCtsp_CUTRHS(c); + c->sense = 'G'; + c->branch = 0; + + *cut = c; + +CLEANUP: + + if (rval) { + if (c) { + CCtsp_free_lpcut_in (c); + CC_FREE (c, CCtsp_lpcut_in); + } + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_init_lpclique (CCtsp_lpclique *c) +#else +void CCtsp_init_lpclique (c) +CCtsp_lpclique *c; +#endif +{ + if (c) { + c->segcount = 0; + c->nodes = (CCtsp_segment *) NULL; + c->hashnext = 0; + c->refcount = 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_array_to_lpclique (int *ar, int acount, CCtsp_lpclique *cliq) +#else +int CCtsp_array_to_lpclique (ar, acount, cliq) +int *ar; +int acount; +CCtsp_lpclique *cliq; +#endif +{ + int i, nseg; + + /* Function will alter the order on the array */ + + CCutil_int_array_quicksort (ar, acount); + nseg = 0; + i = 0; + while (i < acount) { + while (i < (acount - 1) && ar[i + 1] == (ar[i] + 1)) + i++; + i++; + nseg++; + } + + cliq->nodes = CC_SAFE_MALLOC (nseg, CCtsp_segment); + if (!cliq->nodes) { + fprintf (stderr, "out of memory in CCtsp_array_to_lpclique\n"); + return 1; + } + cliq->segcount = nseg; + + nseg = 0; + i = 0; + while (i < acount) { + cliq->nodes[nseg].lo = ar[i]; + while (i < (acount - 1) && ar[i + 1] == (ar[i] + 1)) + i++; + cliq->nodes[nseg].hi = ar[i++]; + nseg++; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_seglist_to_lpclique (int nseg, int *list, CCtsp_lpclique *cliq) +#else +int CCtsp_seglist_to_lpclique (nseg, list, cliq) +int nseg; +int *list; +CCtsp_lpclique *cliq; +#endif +{ + int i; + int *perm = (int *) NULL; + int *len = (int *) NULL; + int rval = 0; + + perm = CC_SAFE_MALLOC (nseg, int); + len = CC_SAFE_MALLOC (nseg, int); + if (!perm || !len) { + fprintf (stderr, "out of memory in CCtsp_seglist_to_lpclique\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < nseg; i++) { + perm[i] = i; + len[i] = list[2*i]; + } + CCutil_int_perm_quicksort (perm, len, nseg); + + cliq->nodes = CC_SAFE_MALLOC (nseg, CCtsp_segment); + if (!cliq->nodes) { + fprintf (stderr, "out of memory in CCtsp_seglist_to_lpclique\n"); + rval = 1; goto CLEANUP; + } + cliq->segcount = nseg; + + for (i = 0; i < nseg; i++) { + cliq->nodes[i].lo = list[2*perm[i]]; + cliq->nodes[i].hi = list[2*perm[i]+1]; + } + + nseg = 0; + +CLEANUP: + + CC_IFFREE (perm, int); + CC_IFFREE (len, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_node_to_lpclique (CCtsp_lpclique *cin, CCtsp_lpclique *cout, + int n) +#else +int CCtsp_add_node_to_lpclique (cin, cout, n) +CCtsp_lpclique *cin; +CCtsp_lpclique *cout; +int n; +#endif +{ + int count = 0; + int rval = 0; + int *ar = (int *) NULL; + int i, j; + + CCtsp_init_lpclique (cout); + + for (i = 0; i < cin->segcount; i++) { + count += (cin->nodes[i].hi - cin->nodes[i].lo + 1); + if (cin->nodes[i].lo <= n && n <= cin->nodes[i].hi) { + fprintf (stderr, "node already in clique\n"); + rval = 1; goto CLEANUP; + } + } + + ar = CC_SAFE_MALLOC (count + 1, int); + if (!ar) { + fprintf (stderr, "out of memory in CCtsp_add_node_to_lpclique\n"); + rval = 1; goto CLEANUP; + } + + count = 0; + for (i = 0; i < cin->segcount; i++) { + for (j = cin->nodes[i].lo; j <= cin->nodes[i].hi; j++) { + ar[count++] = j; + } + } + ar[count++] = n; + rval = CCtsp_array_to_lpclique (ar, count, cout); + if (rval) { + fprintf (stderr, "CCtsp_array_to_lpclique failed\n"); goto CLEANUP; + } + +CLEANUP: + + CC_IFFREE (ar, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_delete_node_from_lpclique (CCtsp_lpclique *cin, + CCtsp_lpclique *cout, int n) +#else +int CCtsp_delete_node_from_lpclique (cin, cout, n) +CCtsp_lpclique *cin; +CCtsp_lpclique *cout; +int n; +#endif +{ + int count = 0; + int rval = 0; + int *ar = (int *) NULL; + int i, j, hit = 0; + + CCtsp_init_lpclique (cout); + + for (i = 0; i < cin->segcount; i++) { + count += (cin->nodes[i].hi - cin->nodes[i].lo + 1); + if (cin->nodes[i].lo <= n && n <= cin->nodes[i].hi) { + hit++; + } + } + if (!hit) { + fprintf (stderr, "node is not in clique\n"); + rval = 1; goto CLEANUP; + } + + ar = CC_SAFE_MALLOC (count, int); + if (!ar) { + fprintf (stderr, "out of memory in CCtsp_delete_node_from_lpclique\n"); + rval = 1; goto CLEANUP; + } + + count = 0; + for (i = 0; i < cin->segcount; i++) { + for (j = cin->nodes[i].lo; j <= cin->nodes[i].hi; j++) { + if (j != n) { + ar[count++] = j; + } + } + } + rval = CCtsp_array_to_lpclique (ar, count, cout); + if (rval) { + fprintf (stderr, "CCtsp_array_to_lpclique failed\n"); goto CLEANUP; + } + +CLEANUP: + + CC_IFFREE (ar, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_print_lpcut_in (CCtsp_lpcut_in *c) +#else +void CCtsp_print_lpcut_in (c) +CCtsp_lpcut_in *c; +#endif +{ + int i; + + if (c->cliquecount == 1) { + printf ("Subtour\n"); + printf (" "); + CCtsp_print_lpclique (&(c->cliques[0])); + } else { + if (c->handlecount == 1) { + printf ("Comb\n"); + printf (" Handle\n"); + } else { + printf ("Clique Tree or Wild Thing\n"); + printf (" Handles:\n"); + } + for (i = 0; i < c->handlecount; i++) { + printf (" "); + CCtsp_print_lpclique (&(c->cliques[i])); + } + if (c->cliquecount > c->handlecount) { + printf (" Teeth\n"); + for (; i < c->cliquecount; i++) { + printf (" "); + CCtsp_print_lpclique (&(c->cliques[i])); + } + } + } + printf ("\n"); fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_print_lpclique (CCtsp_lpclique *c) +#else +void CCtsp_print_lpclique (c) +CCtsp_lpclique *c; +#endif +{ + int i; + + if (c->segcount == 0) { + printf ("Empty Clique\n"); fflush (stdout); + } else { + for (i = 0; i < c->segcount; i++) { + printf ("%d->%d ", c->nodes[i].lo, c->nodes[i].hi); + } + printf ("\n"); fflush (stdout); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_lpcut_to_lpcut_in (CCtsp_lpcuts *cuts, CCtsp_lpcut *c, + CCtsp_lpcut_in *new) +#else +int CCtsp_lpcut_to_lpcut_in (cuts, c, new) +CCtsp_lpcuts *cuts; +CCtsp_lpcut *c; +CCtsp_lpcut_in *new; +#endif +{ + int i, k; + CCtsp_lpclique *cl; + int rval = 0; + + new->handlecount = c->handlecount; + new->cliquecount = c->cliquecount; + new->rhs = c->rhs; + new->sense = c->sense; + new->branch = c->branch; + new->next = (CCtsp_lpcut_in *) NULL; + new->prev = (CCtsp_lpcut_in *) NULL; + + new->cliques = CC_SAFE_MALLOC (c->cliquecount, CCtsp_lpclique); + if (!new->cliques) { + fprintf (stderr, "out of memory in CCtsp_lpcut_to_lpcut_in\n"); + return 1; + } + + for (i = 0; i < c->cliquecount; i++) { + cl = &(cuts->cliques[c->cliques[i]]); + rval = CCtsp_copy_lpclique (cl, &new->cliques[i]); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); + for (k = 0; k < i; k++) { + CC_FREE (new->cliques[k].nodes, CCtsp_segment); + } + CC_FREE (new->cliques, CCtsp_lpclique); + return 1; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_copy_lpclique (CCtsp_lpclique *c, CCtsp_lpclique *new) +#else +int CCtsp_copy_lpclique (c, new) +CCtsp_lpclique *c; +CCtsp_lpclique *new; +#endif +{ + int k; + CCtsp_segment *s = (CCtsp_segment *) NULL; + + CCtsp_init_lpclique (new); + if (c->segcount) { + s = CC_SAFE_MALLOC (c->segcount, CCtsp_segment); + if (!s) { + fprintf (stderr, "out of memory in copy_lpclique\n"); + return 1; + } + for (k = 0; k < c->segcount; k++) { + s[k].lo = c->nodes[k].lo; + s[k].hi = c->nodes[k].hi; + } + } + new->segcount = c->segcount; + new->nodes = s; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_lpclique_compare (CCtsp_lpclique *a, CCtsp_lpclique *b, int *diff) +#else +void CCtsp_lpclique_compare (a, b, diff) +CCtsp_lpclique *a, *b; +int *diff; +#endif +{ + int i; + + if (a->segcount != b->segcount) { + *diff = 1; return; + } else { + for (i = 0; i < a->segcount; i++) { + if (a->nodes[i].lo != b->nodes[i].lo) { + *diff = 1; return; + } + if (a->nodes[i].hi != b->nodes[i].hi) { + *diff = 1; return; + } + } + } + *diff = 0; return; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_file_cuts (char *cutfile, CCtsp_lpcut_in **cuts, int *cutcount, + int ncount, int *tour) +#else +int CCtsp_file_cuts (cutfile, cuts, cutcount, ncount, tour) +char *cutfile; +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount; +int *tour; +#endif +{ + FILE *in = (FILE *) NULL; + int *inv = (int *) NULL; + CCtsp_lpcut_in *c; + int i, j, k; + int ncliques, nhandles, size; + int *icliq = (int *) NULL; + int rval = 0; + + *cutcount = 0; + + in = fopen (cutfile, "r"); + if (in == (FILE *) NULL) { + fprintf (stderr, "unable to open %s for reading\n", cutfile); + return 0; + } + + inv = CC_SAFE_MALLOC (ncount, int); + if (!inv) { + fprintf (stderr, "out of memory in CCtsp_file_cuts\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + inv[tour[i]] = i; + } + + while (fscanf (in, "%d", &ncliques) != EOF) { + c = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!c) { + fprintf (stderr, "out of memory in CCtsp_file_cuts\n"); + rval = 1; goto CLEANUP; + } + c->cliquecount = ncliques; + c->cliques = CC_SAFE_MALLOC (ncliques, CCtsp_lpclique); + if (!c->cliques) { + fprintf (stderr, "out of memory in CCtsp_file_cuts\n"); + rval = 1; goto CLEANUP; + } + fscanf (in, "%d", &nhandles); + c->handlecount = nhandles; + for (i = 0; i < ncliques; i++) { + fscanf (in, "%d", &size); + icliq = CC_SAFE_MALLOC (size, int); + if (!icliq) { + fprintf (stderr, "out of memory in CCtsp_file_cuts\n"); + rval = 1; goto CLEANUP; + } + for (j = 0; j < size; j++) { + fscanf (in, "%d", &k); + icliq[j] = inv[k]; + } + rval = CCtsp_array_to_lpclique (icliq, size, &(c->cliques[i])); + if (rval) { + fprintf (stderr, "CCtsp_array_to_lpclique failed\n"); + goto CLEANUP; + } + CC_FREE (icliq, int); + } + fscanf (in, "%d", &(c->rhs)); + c->sense = 'G'; + c->branch = 0; + c->next = *cuts; + *cuts = c; + (*cutcount)++; + } + +CLEANUP: + + CC_IFFREE (inv, int); + fclose (in); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_file_cuts_write (char *cutfile, CCtsp_lpcuts *cuts, int *tour) +#else +int CCtsp_file_cuts_write (cutfile, cuts, tour) +char *cutfile; +CCtsp_lpcuts *cuts; +int *tour; +#endif +{ + FILE *out = (FILE *) NULL; + int i, j, k, p; + int cutcount = cuts->cutcount; + CCtsp_lpcut *c; + CCtsp_lpclique *cl; + int isize; + + out = fopen (cutfile, "w"); + if (out == (FILE *) NULL) { + fprintf (stderr, "unable to open %s for writing\n", cutfile); + return 1; + } + + for (i = 0; i < cutcount; i++) { + c = &cuts->cuts[i]; + if (!c->branch) { + fprintf (out, "%d %d\n", c->cliquecount, c->handlecount); + for (j = 0; j < c->cliquecount; j++) { + cl = &cuts->cliques[c->cliques[j]]; + for (k = 0, isize = 0; k < cl->segcount; k++) { + isize += (cl->nodes[k].hi - cl->nodes[k].lo + 1); + } + fprintf (out, "%d ", isize); + for (k = 0; k < cl->segcount; k++) { + for (p = cl->nodes[k].lo; p <= cl->nodes[k].hi; p++) { + fprintf (out, "%d ", tour[p]); + } + } + fprintf (out, "\n"); + } + fprintf (out, "%d\n", c->rhs); + } + } + + fclose (out); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_buildcut_begin (cutinfo *cuts, int init_cliquecount) +#else +int CCtsp_buildcut_begin (cuts, init_cliquecount) +cutinfo *cuts; +int init_cliquecount; +#endif +{ + cuts->current = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!cuts->current) return -1; + cuts->current->cliquecount = 0; + cuts->current->handlecount = 0; + cuts->current->rhs = 0; + cuts->current->sense = 'G'; + cuts->current->branch = 0; + cuts->current->cliques = CC_SAFE_MALLOC (init_cliquecount, CCtsp_lpclique); + if (!cuts->current->cliques) { + CC_FREE (cuts->current, CCtsp_lpcut_in); + return -1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_buildcut_addclique (cutinfo *cuts, int *arr, int size, int handle) +#else +int CCtsp_buildcut_addclique (cuts, arr, size, handle) +cutinfo *cuts; +int *arr; +int size; +int handle; +#endif +{ + int i; + int *newarr = (int *) NULL; + int newsize; + int rval; + CCtsp_lpcut_in *c = cuts->current; + + if (!c) { + fprintf (stderr, "Trying to add to nonexistent clique\n"); + return -1; + } + + rval = CCcut_SRK_expand (&cuts->expand, arr, size, &newarr, &newsize); + if (rval) { + fprintf (stderr, "CCcut_SRK_expand failed\n"); + CCtsp_buildcut_abort (cuts); + return rval; + } + + rval = CCutil_reallocrus_count ((void **) &(c->cliques), c->cliquecount+1, + sizeof (c->cliques[0])); + if (rval) { + fprintf (stderr, "couldn't realloc cliques\n"); + CC_IFFREE (newarr, int); + CCtsp_buildcut_abort (cuts); + return rval; + } + + if (handle) { + for (i=c->cliquecount; i>c->handlecount; i--) { + c->cliques[i] = c->cliques[i-1]; + } + i = c->handlecount; + c->handlecount++; + } else { + i = c->cliquecount; + } + + rval = CCtsp_array_to_lpclique (newarr, newsize, &(c->cliques[i])); + if (rval) { + fprintf (stderr, "CCtsp_array_to_lpclique failed\n"); + CC_IFFREE (newarr, int); + CCtsp_buildcut_abort (cuts); + return rval; + } + c->cliquecount++; + CC_IFFREE (newarr, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_buildcut_abort (cutinfo *cuts) +#else +void CCtsp_buildcut_abort (cuts) +cutinfo *cuts; +#endif +{ + int i; + CCtsp_lpcut_in *c = cuts->current; + + if (c) { + for (i=0; i<c->cliquecount; i++) { + CC_FREE (c->cliques[i].nodes, CCtsp_segment); + } + CC_FREE (c->cliques, CCtsp_lpclique); + CC_FREE (cuts->current, CCtsp_lpcut_in); + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_buildcut_finish (cutinfo *cuts, int rhs) +#else +void CCtsp_buildcut_finish (cuts, rhs) +cutinfo *cuts; +int rhs; +#endif +{ + CCtsp_lpcut_in *c = cuts->current; + +#ifdef DUMP_BUILDCUT + { + int i, j, k; + printf ("new buildcut (%d %d):", c->cliquecount, c->handlecount); + for (i=0; i<c->cliquecount; i++) { + printf (" ("); + for (j=0; j<c->cliques[i].segcount; j++) { + for (k=c->cliques[i].nodes[j].lo; k<=c->cliques[i].nodes[j].hi; + k++) { + printf ("%d ",k); + } + } + printf (")"); + } + printf (" >= %d\n", rhs); + fflush (stdout); + } +#endif + + c->rhs = rhs; + c->next = *cuts->clist; + (*cuts->clist) = c; + cuts->current = (CCtsp_lpcut_in *) NULL; + (*cuts->cutcount)++; +} + +#ifdef CC_PROTOTYPE_ANSI +static int grab_nonzero_x (int ecount, int *elist, double *x, + int *new_ecount, int **new_elist, double **new_x, double tol) +#else +static int grab_nonzero_x (ecount, elist, x, new_ecount, new_elist, new_x, tol) +int ecount; +int *elist; +double *x; +int *new_ecount; +int **new_elist; +double **new_x; +double tol; +#endif +{ + int i; + int count; + + *new_ecount = 0; + *new_elist = (int *) NULL; + *new_x = (double *) NULL; + + for (i = 0, count = 0; i < ecount; i++) { + if (x[i] > tol) { + count++; + } + } + + *new_elist = CC_SAFE_MALLOC (2*count, int); + *new_x = CC_SAFE_MALLOC (count, double); + if (!(*new_elist) || !(*new_x)) { + fprintf (stderr, "out of memory in grab_nonzero_x\n"); + CC_IFFREE (*new_elist, int); + CC_IFFREE (*new_x, double); + return 1; + } + + for (i = 0, count = 0; i < ecount; i++) { + if (x[i] > tol) { + (*new_elist)[2*count] = elist[2*i]; + (*new_elist)[2*count+1] = elist[2*i+1]; + (*new_x)[count] = x[i]; + count++; + } + } + *new_ecount = count; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_test_pure_comb (int ncount, CCtsp_lpcut_in *c, int *yes_no, + int *handle) +#else +int CCtsp_test_pure_comb (ncount, c, yes_no, handle) +int ncount; +CCtsp_lpcut_in *c; +int *yes_no; +int *handle; +#endif +{ + int rval = 0; + int i, marked, ihandle; + int *marks = (int *) NULL; + + *yes_no = 0; + if (handle) *handle = -1; + + if (c->cliquecount < 4 || c->cliquecount % 2 || + c->sense != 'G') { + goto CLEANUP; + } + + rval = CCtsp_find_pure_handle (ncount, c, &ihandle); + if (rval) { + fprintf (stderr, "CCtsp_find_pure_handle failed\n"); + goto CLEANUP; + } + if (ihandle == -1) goto CLEANUP; + + marks = CC_SAFE_MALLOC (ncount, int); + if (!marks) { + fprintf (stderr, "out of memory in CCtsp_test_pure_comb\n"); + rval = 1; goto CLEANUP; + } + CCtsp_mark_cut (c, marks, 0); + + CCtsp_mark_clique (&c->cliques[ihandle], marks, 1); + for (i = 0; i < c->cliquecount; i++) { + if (i != ihandle) { + CCtsp_is_clique_marked (&c->cliques[i], marks, 1, &marked); + if (!marked) goto CLEANUP; + CCtsp_is_clique_marked (&c->cliques[i], marks, 0, &marked); + if (!marked) goto CLEANUP; + } + } + CCtsp_mark_clique (&c->cliques[ihandle], marks, 0); + + for (i = 0; i < c->cliquecount; i++) { + if (i != ihandle) { + CCtsp_is_clique_marked (&c->cliques[i], marks, 1, &marked); + if (marked) goto CLEANUP; + CCtsp_mark_clique (&c->cliques[i], marks, 1); + } + } + + *yes_no = 1; + if (handle) *handle = ihandle; + +CLEANUP: + + CC_IFFREE (marks, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_test_pseudocomb (int ncount, CCtsp_lpcut_in *c, int handle, + int *yes_no) +#else +int CCtsp_test_pseudocomb (ncount, c, handle, yes_no) +int ncount; +CCtsp_lpcut_in *c; +int handle; +int *yes_no; +#endif +{ + int rval = 0; + int i, k, marked; + int *ends = (int *) NULL; + int *marks = (int *) NULL; + + *yes_no = 0; + if (c->cliquecount <= 1 || c->cliquecount % 2 || c->sense != 'G') { + printf ("bad cliquecount or sense in pseudocomb\n"); fflush (stdout); + goto CLEANUP; + } + + marks = CC_SAFE_MALLOC (ncount, int); + if (!marks) { + fprintf (stderr, "out of memory in CCtsp_test_pseudocomb\n"); + rval = 1; goto CLEANUP; + } + CCtsp_mark_cut (c, marks, 0); + + /* Teeth intersect H and are not contained in H */ + + CCtsp_mark_clique (&c->cliques[handle], marks, 1); + for (i = 0; i < c->cliquecount; i++) { + if (i != handle) { + CCtsp_is_clique_marked (&c->cliques[i], marks, 1, &marked); + if (!marked) goto CLEANUP; + CCtsp_is_clique_marked (&c->cliques[i], marks, 0, &marked); + if (!marked) goto CLEANUP; + } + } + CCtsp_mark_clique (&c->cliques[0], marks, 0); + + /* Big teeth are pairwise disjoint */ + + for (i = 0; i < c->cliquecount; i++) { + if (i != handle) { + CCtsp_clique_count (&c->cliques[i], &k); + if (k >= 3) { + CCtsp_is_clique_marked (&c->cliques[i], marks, 1, &marked); + if (marked) goto CLEANUP; + CCtsp_mark_clique (&c->cliques[i], marks, 1); + } + } + } + for (i = 1; i < c->cliquecount; i++) { + CCtsp_mark_clique (&c->cliques[i], marks, 0); + } + + /* No small tooth is contained in a big tooth */ + + for (i = 0; i < c->cliquecount; i++) { + if (i != handle) { + CCtsp_clique_count (&c->cliques[i], &k); + if (k >= 3) { + CCtsp_mark_clique (&c->cliques[i], marks, i + 1); + } + } + } + for (i = 0; i < c->cliquecount; i++) { + if (i != handle) { + CCtsp_clique_count (&c->cliques[i], &k); + if (k < 3) { + rval = CCtsp_clique_to_array (&c->cliques[i], &ends, &k); + if (rval) { + fprintf (stderr, "CCtsp_clique_to_array failed\n"); + goto CLEANUP; + } + if (ends[0] != 0 && ends[0] == ends[1]) goto CLEANUP; + CC_IFFREE (ends, int); + } + } + } + + + *yes_no = 1; + + +CLEANUP: + + CC_IFFREE (marks, int); + CC_IFFREE (ends, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_test_teeth_disjoint (int ncount, CCtsp_lpcut_in *c, int handle, + int *yes_no) +#else +int CCtsp_test_teeth_disjoint (ncount, c, handle, yes_no) +int ncount; +CCtsp_lpcut_in *c; +int handle; +int *yes_no; +#endif +{ + int rval = 0; + int i, marked; + int *marks = (int *) NULL; + + *yes_no = 0; + + marks = CC_SAFE_MALLOC (ncount, int); + if (!marks) { + fprintf (stderr, "out of memory in CCtsp_teeth_disjoint\n"); + rval = 1; goto CLEANUP; + } + CCtsp_mark_cut (c, marks, 0); + + for (i = 0; i < c->cliquecount; i++) { + if (i != handle) { + CCtsp_is_clique_marked (&c->cliques[i], marks, 1, &marked); + if (marked) goto CLEANUP; + CCtsp_mark_clique (&c->cliques[i], marks, 1); + } + } + + *yes_no = 1; + +CLEANUP: + + CC_IFFREE (marks, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_find_pure_handle (int ncount, CCtsp_lpcut_in *c, int *handle) +#else +int CCtsp_find_pure_handle (ncount, c, handle) +int ncount; +CCtsp_lpcut_in *c; +int *handle; +#endif +{ + int rval = 0; + int *marks = (int *) NULL; + int i, test; + + *handle = -1; + if (c->cliquecount % 2 || c->cliquecount < 4) goto CLEANUP; + + marks = CC_SAFE_MALLOC (ncount, int); + if (!marks) { + fprintf (stderr, "out of memory in CCtsp_pure_find_handle\n"); + rval = 1; goto CLEANUP; + } + CCtsp_mark_cut (c, marks, 0); + + CCtsp_mark_clique (&c->cliques[0], marks, 1); + CCtsp_is_clique_marked (&c->cliques[1], marks, 1, &test); + if (test) { + CCtsp_is_clique_marked (&c->cliques[2], marks, 1, &test); + if (test) { + *handle = 0; goto CLEANUP; + } else { + *handle = 1; goto CLEANUP; + } + } else { + for (i = 2; i < c->cliquecount; i++) { + CCtsp_is_clique_marked (&c->cliques[i], marks, 1, &test); + if (test) { + *handle = i; + goto CLEANUP; + } + } + } + +CLEANUP: + + CC_IFFREE (marks, int); + return rval; +} diff --git a/contrib/blossom/concorde97/TSP/cutpool.c b/contrib/blossom/concorde97/TSP/cutpool.c new file mode 100644 index 0000000000000000000000000000000000000000..9e47ab45626857522270c936c46ed4cc2f06bf46 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/cutpool.c @@ -0,0 +1,1055 @@ +/***************************************************************************/ +/* */ +/* STORING AND SEARCHING THE CUTPOOL */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 19, 1997 */ +/* May 27, 1997 (bico) */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_init_cutpool (int ncount, char *poolfilename, */ +/* CCtsp_lpcuts **pool) */ +/* -ncount is the number of nodes in the problem */ +/* -poolfilename is a file containing an cutpool (it can be NULL) */ +/* -CCtsp_lpcuts will return the pool */ +/* */ +/* int CCtsp_search_cutpool_cliques (CCtsp_lpcuts *pool, */ +/* CCtsp_lpclique **cliques, int *cliquecount, int ncount, */ +/* int ecount, int *elist, double *x, double maxdelta, */ +/* int maxcliques, double **cliquevals) */ +/* RETURNS an array of cliques having x(delta(C)) < maxdelta */ +/* -pool points to a cutpool (or cuts of an lp) */ +/* -cliques will return the array of cliques */ +/* -cliquecount with return the length of the array */ +/* -ncount is the number of nodes in the problem */ +/* -ecount is the number of edges in elist */ +/* -elist is a list of edges in end end format */ +/* -x is an ecount-long array of weights */ +/* -maxdelta is a bound on x(delta(C)) */ +/* -maxcliques is an upperbound on the number of cliques that should */ +/* be returned */ +/* -cliquevals will return the values of x(delta(C)) for the cliques */ +/* (this parameter can be NULL) */ +/* */ +/* void CCtsp_free_cutpool (CCtsp_lpcuts **pool) */ +/* FREES the pool of cuts. */ +/* */ +/* int CCtsp_write_cutpool (int ncount, char *poolfilename, */ +/* CCtsp_lpcuts *pool) */ +/* WRITES pool to poolfilename. */ +/* */ +/* int CCtsp_branch_cutpool_cliques (CCtsp_lpcuts *pool, */ +/* CCtsp_lpclique **cliques, int *cliquecount, int ncount, */ +/* int ecount, int *elist, double *x, int nwant, */ +/* double **cliquevals) */ +/* RETURNS an array of cliques having x(delta(C)) as close to 3.0 as */ +/* possible. */ +/* -the parmeters are like those used by search_cutpool_cliques, */ +/* where nwant is the number of cliques we would like to have in */ +/* the array. */ +/* */ +/* int CCtsp_price_cuts (CCtsp_lpcuts *pool, int ncount, int ecount, */ +/* int *elist, double *x, double *cutval) */ +/* COMPUTES the slack on each cut in the pool */ +/* -ecount, elist, and x give an x-vector */ +/* -cutval returns the array of slack values (it should be passed in */ +/* as an array of length at least pool->cutcount) */ +/* */ +/* NOTES: */ +/* This version does not use the compressed set references. Notes */ +/* on the representation are given in "Chapter 4: The Linear */ +/* Programming Problems". */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "macrorus.h" +#include "tsp.h" + +#define ZERO_EPSILON 0.0000000001 +#define POOL_MAXCUTS 500 +#define POOL_MINVIOL 0.001 + +typedef struct pooledge { + double x; + int to; +} pooledge; + +typedef struct poolnode { + struct pooledge *adj; + int mark; + int deg; +} poolnode; + +#ifdef CC_PROTOTYPE_ANSI + +static int + init_empty_cutpool (int ncount, CCtsp_lpcuts *pool), + cut_eq (void *v_cut1, void *v_cut2, void *u_data), + read_cutpool (int ncount, char *poolfilename, CCtsp_lpcuts *pool), + register_lpcuts (CCtsp_lpcuts *pool), + price_cliques (CCtsp_lpcuts *pool, int ncount, int ecount, int *elist, + double *x, double *cval); + +static unsigned int + cut_hash (void *v_cut, void *u_data); + +static void + sort_cliques (CCtsp_lpcut *c); + +static double + price_clique (poolnode *nlist, CCtsp_lpclique *c, int marker); + +#else + +static int + init_empty_cutpool (), + cut_eq (), + read_cutpool (), + register_lpcuts (), + price_cliques (); + +static unsigned int + cut_hash (); + +static void + sort_cliques (); + +static double + price_clique (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_init_cutpool (int ncount, char *poolfilename, CCtsp_lpcuts **pool) +#else +int CCtsp_init_cutpool (ncount, poolfilename, pool) +int ncount; +char *poolfilename; +CCtsp_lpcuts **pool; +#endif +{ + int rval = 0; + CCtsp_lpcuts *p = (CCtsp_lpcuts *) NULL; + + p = CC_SAFE_MALLOC (1, CCtsp_lpcuts); + if (!p) { + fprintf (stderr, "out of memory in CCtsp_init_cutpool\n"); + return 1; + } + *pool = p; + + p->cutcount = 0; + p->cuts = (CCtsp_lpcut *) NULL; + p->cutspace = 0; + p->cliqueend = 0; + p->cliques = (CCtsp_lpclique *) NULL; + p->cliquespace = 0; + p->cliquehash = (int *) NULL; + p->cuthash = (CCgenhash *) NULL; + + rval = init_empty_cutpool (ncount, p); + if (rval) { + fprintf (stderr, "init_empty_cutpool failed\n"); goto CLEANUP; + } + + if (poolfilename) { + rval = read_cutpool (ncount, poolfilename, p); + if (rval) { + fprintf (stderr, "read_cutpool failed\n"); goto CLEANUP; + } + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_cutpool (CCtsp_lpcuts **pool) +#else +void CCtsp_free_cutpool (pool) +CCtsp_lpcuts **pool; +#endif +{ + int i; + + if (*pool) { + if ((*pool)->cuts) { + for (i = 0; i < (*pool)->cutcount; i++) { + CC_IFFREE ((*pool)->cuts[i].cliques, int); + } + CC_FREE ((*pool)->cuts, CCtsp_lpcut); + } + if ((*pool)->cliques) { + for (i=0; i < (*pool)->cliqueend; i++) { + CC_IFFREE ((*pool)->cliques[i].nodes, CCtsp_segment); + } + CC_FREE ((*pool)->cliques, CCtsp_lpclique); + } + + CCtsp_free_cliquehash (*pool); + + if ((*pool)->cuthash) { + CCutil_genhash_free ((*pool)->cuthash, NULL); + CC_FREE ((*pool)->cuthash, CCgenhash); + } + CC_FREE (*pool, CCtsp_lpcuts); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int init_empty_cutpool (int ncount, CCtsp_lpcuts *pool) +#else +static int init_empty_cutpool (ncount, pool) +int ncount; +CCtsp_lpcuts *pool; +#endif +{ + int rval = 0; + + rval = CCtsp_init_cliquehash (pool, 10 * ncount); + if (rval) { + fprintf (stderr, "CCtsp_init_cliqhash failed\n"); + return rval; + } + + pool->cuthash = CC_SAFE_MALLOC (1, CCgenhash); + if (pool->cuthash == (CCgenhash *) NULL) { + fprintf (stderr, "Out of memory in init_empty_cutpool\n"); + return -1; + } + + rval = CCutil_genhash_init (pool->cuthash, 10 * ncount, cut_eq, + cut_hash, (void *) pool, 1.0, 0.6); + if (rval) { + fprintf (stderr, "CCgenhash_init failed\n"); + return rval; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cut_eq (void *v_cut1, void *v_cut2, void *u_data) +#else +static int cut_eq (v_cut1, v_cut2, u_data) +void *v_cut1; +void *v_cut2; +void *u_data; +#endif +{ + CCtsp_lpcuts *pool = (CCtsp_lpcuts *) u_data; + CCtsp_lpcut *cut1 = pool->cuts + (long) v_cut1; + CCtsp_lpcut *cut2 = pool->cuts + (long) v_cut2; + int i; + + if (cut1->cliquecount != cut2->cliquecount) return 1; + if (cut1->rhs != cut2->rhs) return 1; + if (cut1->sense != cut2->sense) return 1; + for (i=0; i<cut1->cliquecount; i++) { + if (cut1->cliques[i] != cut2->cliques[i]) return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static unsigned int cut_hash (void *v_cut, void *u_data) +#else +static unsigned int cut_hash (v_cut, u_data) +void *v_cut; +void *u_data; +#endif +{ + CCtsp_lpcuts *pool = (CCtsp_lpcuts *) u_data; + CCtsp_lpcut *cut = pool->cuts + (long) v_cut; + unsigned int x = ((unsigned int) cut->rhs) * 257 + + ((unsigned int) cut->sense); + int i; + + for (i=0; i<cut->cliquecount; i++) { + x = x * 4099 + cut->cliques[i]; + } + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static int read_cutpool (int ncount, char *poolfilename, CCtsp_lpcuts *pool) +#else +static int read_cutpool (ncount, poolfilename, pool) +int ncount; +char *poolfilename; +CCtsp_lpcuts *pool; +#endif +{ + CC_SFILE *in; + int n; + int rval = 0; + + if (!poolfilename) { + fprintf (stderr, "pool file name is not set\n"); + return 1; + } + + in = CCutil_sopen (poolfilename, "r"); + if (!in) { + fprintf (stderr, "sopen failed\n"); + return 1; + } + if (CCutil_sread_int (in, (unsigned int *) &n)) { + fprintf (stderr, "CCutil_sread_int failed\n"); + CCutil_sclose (in); + return 1; + } + if (n != ncount) { + fprintf (stderr, "cutpool %s does not have the correct ncount\n", + poolfilename); + CCutil_sclose (in); + return 1; + } + + rval = CCtsp_prob_getcuts ((CCtsp_PROB_FILE *) NULL, in, pool); + if (rval < 0) { + fprintf (stderr, "CCtsp_prob_getcuts failed\n"); + CCutil_sclose (in); + return rval; + } + + rval = register_lpcuts (pool); + if (rval) { + fprintf (stderr, "register_lpcuts failed\n"); + CCutil_sclose (in); + return rval; + } + + CCutil_sclose (in); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_write_cutpool (int ncount, char *poolfilename, CCtsp_lpcuts *pool) +#else +int CCtsp_write_cutpool (ncount, poolfilename, pool) +int ncount; +char *poolfilename; +CCtsp_lpcuts *pool; +#endif +{ + CC_SFILE *out; + int rval = 0; + + if (!poolfilename) { + fprintf (stderr, "pool file name not set\n"); + return 1; + } + + out = CCutil_sopen (poolfilename, "w"); + if (!out) { + fprintf (stderr, "sopen failed\n"); + return 1; + } + if (CCutil_swrite_int (out, (unsigned int) ncount)) { + fprintf (stderr, "CCutil_swrite_int failed\n"); + CCutil_sclose (out); + return 1; + } + + rval = CCtsp_prob_putcuts ((CCtsp_PROB_FILE *) NULL, out, pool); + if (rval) { + fprintf (stderr, "CCtsp_prob_putcuts failed\n"); + CCutil_sclose (out); + return 1; + } + + CCutil_sclose (out); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_search_cutpool (CCtsp_lpcuts *pool, CCtsp_lpcut_in **cuts, + int *cutcount, int ncount, int ecount, int *elist, double *x) +#else +int CCtsp_search_cutpool (pool, cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcuts *pool; +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount, ecount; +int *elist; +double *x; +#endif +{ + int rval = 0; + double *cval = (double *) NULL; + int *ind = (int *) NULL; + int i; + CCtsp_lpcut_in *newc; + double maxviol; + + *cutcount = 0; + *cuts = (CCtsp_lpcut_in *) NULL; + + if (pool->cutcount == 0) return 0; + + cval = CC_SAFE_MALLOC (pool->cutcount, double); + if (!cval) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool\n"); + rval = 1; goto CLEANUP; + } + rval = CCtsp_price_cuts (pool, ncount, ecount, elist, x, cval); + if (rval) { + fprintf (stderr, "CCtsp_price_cuts failed\n"); + goto CLEANUP; + } + + ind = CC_SAFE_MALLOC (pool->cutcount, int); + if (!ind) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool\n"); + rval = 1; goto CLEANUP; + } + + for (i = 0; i < pool->cutcount; i++) { + ind[i] = i; + } + + CCutil_rselect (ind, 0, pool->cutcount - 1, POOL_MAXCUTS, cval); + + maxviol = 0.0; + for (i = 0; i < pool->cutcount && i < POOL_MAXCUTS; i++) { + if (cval[ind[i]] < maxviol) maxviol = cval[ind[i]]; + if (cval[ind[i]] < -POOL_MINVIOL) { + newc = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!newc) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool\n"); + goto CLEANUP; + } + rval = CCtsp_lpcut_to_lpcut_in (pool, &pool->cuts[ind[i]], newc); + if (rval) { + fprintf (stderr, "CCtsp_lpcut_to_lpcut_in failed\n"); + CC_FREE (newc, CCtsp_lpcut_in); + goto CLEANUP; + } + newc->next = *cuts; + *cuts = newc; + (*cutcount)++; + } + } + printf ("%d pool cuts found, max violation %.3f\n", *cutcount, -maxviol); + rval = 0; + +CLEANUP: + + CC_IFFREE (cval, double); + CC_IFFREE (ind, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_search_cutpool_cliques (CCtsp_lpcuts *pool, CCtsp_lpclique **cliques, + int *cliquecount, int ncount, int ecount, int *elist, double *x, + double maxdelta, int maxcliques, double **cliquevals) +#else +int CCtsp_search_cutpool_cliques (pool, cliques, cliquecount, ncount, ecount, + elist, x, maxdelta, maxcliques, cliquevals) +CCtsp_lpcuts *pool; +CCtsp_lpclique **cliques; +int *cliquecount; +int ncount, ecount; +int *elist; +double *x; +double maxdelta; +int maxcliques; +double **cliquevals; +#endif +{ + int rval = 0; + double *cval = (double *) NULL; + int *ind = (int *) NULL; + double upperdelta, lowerdelta; + int i, k; + int ccount = 0; + + *cliquecount = 0; + *cliques = (CCtsp_lpclique *) NULL; + if (cliquevals) { + *cliquevals = (double *) NULL; + } + + if (pool->cutcount == 0) return 0; + + cval = CC_SAFE_MALLOC (pool->cliqueend, double); + if (!cval) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool_cliques\n"); + rval = 1; goto CLEANUP; + } + + rval = price_cliques (pool, ncount, ecount, elist, x, cval); + if (rval) { + fprintf (stderr, "price_cliques failed\n"); + goto CLEANUP; + } + + ind = CC_SAFE_MALLOC (pool->cliqueend, int); + if (!ind) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool_cliques\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < pool->cliqueend; i++) { + ind[i] = i; + } + + CCutil_rselect (ind, 0, pool->cliqueend - 1, maxcliques, cval); + + upperdelta = -1.0; + lowerdelta = maxdelta; + for (i = 0; i < pool->cliqueend && i < maxcliques; i++) { + if (cval[ind[i]] < maxdelta) { + ccount++; + if (cval[ind[i]] < lowerdelta) lowerdelta = cval[ind[i]]; + if (cval[ind[i]] > upperdelta) upperdelta = cval[ind[i]]; + } + } + + if (ccount == 0) { + printf ("Found no nearly tight cliques\n"); fflush (stdout); + goto CLEANUP; + } + + *cliques = CC_SAFE_MALLOC (ccount, CCtsp_lpclique); + if (!(*cliques)) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool_cliques\n"); + rval = 1; goto CLEANUP; + } + if (cliquevals) { + *cliquevals = CC_SAFE_MALLOC (ccount, double); + if (!(*cliquevals)) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool_cliques\n"); + CC_FREE (*cliques, CCtsp_lpclique); + rval = 1; goto CLEANUP; + } + } + + ccount = 0; + for (i = 0; i < pool->cliqueend && i < maxcliques; i++) { + if (cval[ind[i]] < maxdelta) { + rval = CCtsp_copy_lpclique (&(pool->cliques[ind[i]]), + &((*cliques)[ccount])); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); + for (k = 0; k < ccount; k++) { + CC_FREE ((*cliques)[k].nodes, CCtsp_segment); + } + CC_FREE (*cliques, CCtsp_lpclique); + if (cliquevals) { + CC_FREE (*cliquevals, double); + } + goto CLEANUP; + } + if (cliquevals) { + (*cliquevals)[ccount] = cval[ind[i]]; + } + ccount++; + } + } + *cliquecount = ccount; + + printf ("%d nearly tight cliques found, range (%.3f, %.3f)\n", + *cliquecount, lowerdelta, upperdelta); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (cval, double); + CC_IFFREE (ind, int); + return rval; +} + +#define BRANCH_CLIQUE_GOAL 3.00 +#define BRANCH_CLIQUE_TOL 0.99 + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_branch_cutpool_cliques (CCtsp_lpcuts *pool, CCtsp_lpclique **cliques, + int *cliquecount, int ncount, int ecount, int *elist, double *x, + int nwant, double **cliquevals) +#else +int CCtsp_branch_cutpool_cliques (pool, cliques, cliquecount, ncount, ecount, + elist, x, nwant, cliquevals) +CCtsp_lpcuts *pool; +CCtsp_lpclique **cliques; +int *cliquecount; +int ncount, ecount; +int *elist; +double *x; +int nwant; +double **cliquevals; +#endif +{ + int rval = 0; + double *cval = (double *) NULL; + double upperdelta, lowerdelta; + double t; + int i, k; + int ccount = 0; + int *blist = (int *) NULL; + double *bval = (double *) NULL; + + printf ("branch_cutpool_cliques ...\n"); fflush (stdout); + + *cliquecount = 0; + *cliques = (CCtsp_lpclique *) NULL; + if (cliquevals) { + *cliquevals = (double *) NULL; + } + + if (pool->cutcount == 0 || nwant <= 0) return 0; + + blist = CC_SAFE_MALLOC (nwant + 1, int); + bval = CC_SAFE_MALLOC (nwant + 1, double); + cval = CC_SAFE_MALLOC (pool->cliqueend, double); + if (!blist || !bval || !cval) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool_cliques\n"); + rval = 1; goto CLEANUP; + } + + rval = price_cliques (pool, ncount, ecount, elist, x, cval); + if (rval) { + fprintf (stderr, "price_cliques failed\n"); + goto CLEANUP; + } + + for (i = 0; i < nwant; i++) { + blist[i] = -1; + bval[i] = CCtsp_LP_MAXDOUBLE; + } + blist[nwant] = -1; + bval[i] = -1.0; + + for (i = 0; i < pool->cliqueend; i++) { + t = CC_OURABS (BRANCH_CLIQUE_GOAL - cval[i]); + if (t < bval[0] && t < BRANCH_CLIQUE_TOL) { + for (k = 0; t < bval[k+1]; k++) { + blist[k] = blist[k+1]; + bval[k] = bval[k+1]; + } + blist[k] = i; + bval[k] = t; + } + } + + upperdelta = -1.0; + lowerdelta = CCtsp_LP_MAXDOUBLE; + for (i = 0; i < nwant; i++) { + if (blist[i] != -1) { + if (upperdelta < cval[blist[i]]) { + upperdelta = cval[blist[i]]; + } + if (lowerdelta > cval[blist[i]]) { + lowerdelta = cval[blist[i]]; + } + ccount++; + } + } + + if (ccount == 0) { + printf ("Found no nearly tight cliques\n"); fflush (stdout); + goto CLEANUP; + } + + *cliques = CC_SAFE_MALLOC (ccount, CCtsp_lpclique); + if (!(*cliques)) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool_cliques\n"); + rval = 1; goto CLEANUP; + } + if (cliquevals) { + *cliquevals = CC_SAFE_MALLOC (ccount, double); + if (!(*cliquevals)) { + fprintf (stderr, "out of memory in CCtsp_search_cutpool_cliques\n"); + CC_FREE (*cliques, CCtsp_lpclique); + rval = 1; goto CLEANUP; + } + } + + ccount = 0; + for (i = nwant - 1; i >= 0; i--) { + if (blist[i] != -1) { + rval = CCtsp_copy_lpclique (&(pool->cliques[blist[i]]), + &((*cliques)[ccount])); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); + for (k = 0; k < ccount; k++) { + CC_FREE ((*cliques)[k].nodes, CCtsp_segment); + } + CC_FREE (*cliques, CCtsp_lpclique); + if (cliquevals) { + CC_FREE (*cliquevals, double); + } + goto CLEANUP; + } + if (cliquevals) { + (*cliquevals)[ccount] = cval[blist[i]]; + } + ccount++; + } + } + *cliquecount = ccount; + + printf ("%d candidate branching cliques, range (%.3f, %.3f)\n", + *cliquecount, lowerdelta, upperdelta); + fflush (stdout); + + +CLEANUP: + + CC_IFFREE (blist, int); + CC_IFFREE (bval, double); + CC_IFFREE (cval, double); + return rval; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_to_cutpool (CCtsp_lpcuts *pool, CCtsp_lpcuts *cuts, + CCtsp_lpcut *c) +#else +int CCtsp_add_to_cutpool (pool, cuts, c) +CCtsp_lpcuts *pool; +CCtsp_lpcuts *cuts; +CCtsp_lpcut *c; +#endif +{ + int rval = 0; + CCtsp_lpcut_in cin; + int k; + + if (!c || c->cliquecount <= 1) + return 0; + + cin.cliquecount = 0; + cin.cliques = (CCtsp_lpclique *) NULL; + + + rval = CCtsp_lpcut_to_lpcut_in (cuts, c, &cin); + if (rval) { + fprintf (stderr, "CCtsp_lpcut_to_lpcut_in failed\n"); + goto CLEANUP; + } + + rval = CCtsp_add_to_cutpool_lpcut_in (pool, &cin); + if (rval) { + fprintf (stderr, "CCtsp_add_to_cutpool_lpcut_in failed\n"); + goto CLEANUP; + } + +CLEANUP: + + for (k = 0; k < cin.cliquecount; k++) { + CC_IFFREE (cin.cliques[k].nodes, CCtsp_segment); + } + CC_IFFREE (cin.cliques, CCtsp_lpclique); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_to_cutpool_lpcut_in (CCtsp_lpcuts *pool, CCtsp_lpcut_in *cut) +#else +int CCtsp_add_to_cutpool_lpcut_in (pool, cut) +CCtsp_lpcuts *pool; +CCtsp_lpcut_in *cut; +#endif +{ + int rval = 0; + CCtsp_lpcut new; + int cutloc; + unsigned int hval; + + if (!pool) + return 0; + + new.rhs = cut->rhs; + new.branch = cut->branch; + new.sense = cut->sense; + new.modcount = 0; + new.mods = (CCtsp_sparser *) NULL; + new.handlecount = 0; + new.cliquecount = 0; + new.cliques = (int *) NULL; + new.age = 0; + + rval = CCtsp_register_cliques (pool, cut, &new); + if (rval) { + fprintf (stderr, "register_cliques failed\n"); + return rval; + } + + sort_cliques (&new); + + cutloc = CCtsp_add_cut_to_cutlist (pool, &new); + if (cutloc < 0) { + fprintf (stderr, "CCtsp_add_cut_to_cutlist failed\n"); + CCtsp_unregister_cliques (pool, &new); + return cutloc; + } + + hval = CCutil_genhash_hash (pool->cuthash, (void *) ((long) cutloc)); + if (CCutil_genhash_lookup_h (pool->cuthash, hval, + (void *) ((long) cutloc))) { + /* cut was already in pool */ + CCtsp_delete_cut_from_cutlist (pool, cutloc); + return 0; + } + + rval = CCutil_genhash_insert_h (pool->cuthash, hval, (void *) ((long) cutloc), + (void *) ((long) 1)); + if (rval) { + fprintf (stderr, "CCgenhash_insert_h failed\n"); + CCtsp_delete_cut_from_cutlist (pool, cutloc); + return rval; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void sort_cliques (CCtsp_lpcut *c) +#else +static void sort_cliques (c) +CCtsp_lpcut *c; +#endif +{ + CCutil_int_array_quicksort (c->cliques, c->handlecount); + CCutil_int_array_quicksort (c->cliques + c->handlecount, + c->cliquecount - c->handlecount); +} + +#ifdef CC_PROTOTYPE_ANSI +static int register_lpcuts (CCtsp_lpcuts *pool) +#else +static int register_lpcuts (pool) +CCtsp_lpcuts *pool; +#endif +{ + int i; + unsigned int hval; + int rval = 0; + int ndup = 0; + + for (i=0; i<pool->cutcount; i++) { + sort_cliques (&pool->cuts[i]); + hval = CCutil_genhash_hash (pool->cuthash, (void *) ((long) i)); + if (CCutil_genhash_lookup_h (pool->cuthash, hval, + (void *) ((long) i))) { + ndup++; + } else { + rval = CCutil_genhash_insert_h (pool->cuthash, hval, + (void *) ((long) i), + (void *) ((long) 1)); + if (rval) { + fprintf (stderr, "CCgenhash_insert_h failed\n"); + return rval; + } + } + } + if (ndup) { + printf ("%d duplicates detected in pool\n", ndup); + fflush (stdout); + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_display_cutpool (CCtsp_lpcuts *pool) +#else +int CCtsp_display_cutpool (pool) +CCtsp_lpcuts *pool; +#endif +{ + int i, k; + CCtsp_lpcut_in c; + + for (i = 0; i < pool->cutcount; i++) { + if (CCtsp_lpcut_to_lpcut_in (pool, &(pool->cuts[i]), &c)) { + fprintf (stderr, "CCtsp_lpcut_to_lpcut_in failed\n"); + return 1; + } + CCtsp_print_lpcut_in (&c); + for (k = 0; k < c.cliquecount; k++) { + CC_IFFREE (c.cliques[k].nodes, CCtsp_segment); + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_price_cuts (CCtsp_lpcuts *pool, int ncount, int ecount, int *elist, + double *x, double *cutval) +#else +int CCtsp_price_cuts (pool, ncount, ecount, elist, x, cutval) +CCtsp_lpcuts *pool; +int ncount; +int ecount; +int *elist; +double *x; +double *cutval; +#endif +{ + double *cval = (double *) NULL; + int cutcount = pool->cutcount; + int i, j; + CCtsp_lpcut *c; + int rval = 0; + + cval = CC_SAFE_MALLOC (pool->cliqueend, double); + if (!cval) { + fprintf (stderr, "out of memory in CCtsp_price_cuts\n"); + return 1; + } + + rval = price_cliques (pool, ncount, ecount, elist, x, cval); + if (rval) { + fprintf (stderr, "price_cliques failed\n"); + return rval; + } + + for (i = 0, c = pool->cuts; i < cutcount; i++, c++) { + cutval[i] = (double) -(c->rhs); + for (j = 0; j < c->cliquecount; j++) { + cutval[i] += cval[c->cliques[j]]; + } + } + + CC_FREE (cval, double); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int price_cliques (CCtsp_lpcuts *pool, int ncount, int ecount, + int *elist, double *x, double *cval) +#else +static int price_cliques (pool, ncount, ecount, elist, x, cval) +CCtsp_lpcuts *pool; +int ncount; +int ecount; +int *elist; +double *x; +double *cval; +#endif +{ + poolnode *nlist = (poolnode *) NULL; + pooledge *espace = (pooledge *) NULL; + pooledge *p; + char *marks = (char *) NULL; + int marker = 0; + int i, j, a, b, count; + int cend = pool->cliqueend; + int rval = 0; + + nlist = CC_SAFE_MALLOC (ncount, poolnode); + if (!nlist) { + fprintf (stderr, "out of memory in price_cliques\n"); + rval = 1; goto CLEANUP; + } + + for (i = 0; i < ncount; i++) { + nlist[i].mark = 0; + nlist[i].deg = 0; + } + + count = 0; + for (i = 0; i < ecount; i++) { + if (x[i] >= ZERO_EPSILON) { + nlist[elist[2*i]].deg++; + nlist[elist[2*i+1]].deg++; + count++; + } + } + espace = CC_SAFE_MALLOC (2*count, pooledge); + if (!espace) { + fprintf (stderr, "out of memory in price_cliques\n"); + rval = 1; goto CLEANUP; + } + + p = espace; + for (i = 0; i < ncount; i++) { + nlist[i].adj = p; + p += nlist[i].deg; + nlist[i].deg = 0; + } + for (i = 0; i < ecount; i++) { + if (x[i] >= ZERO_EPSILON) { + a = elist[2*i]; + b = elist[2*i+1]; + nlist[a].adj[nlist[a].deg].x = x[i]; + nlist[a].adj[nlist[a].deg++].to = b; + nlist[b].adj[nlist[b].deg].x = x[i]; + nlist[b].adj[nlist[b].deg++].to = a; + } + } + + marks = CC_SAFE_MALLOC (cend, char); + if (!marks) { + fprintf (stderr, "out of memory in price_cliques\n"); + rval = 1; goto CLEANUP; + } + + for (i = 0; i < cend; i++) { + marks[i] = 0; + } + for (i = 0; i < pool->cutcount; i++) { + for (j = 0; j < pool->cuts[i].cliquecount; j++) { + marks[pool->cuts[i].cliques[j]] = 1; + } + } + + for (i = 0; i < cend; i++) { + if (marks[i]) { + marker++; + cval[i] = price_clique (nlist, &(pool->cliques[i]), marker); + } else { + cval[i] = 0.0; + } + } + +CLEANUP: + + CC_IFFREE (nlist, poolnode); + CC_IFFREE (espace, pooledge); + CC_IFFREE (marks, char); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static double price_clique (poolnode *nlist, CCtsp_lpclique *c, int marker) +#else +static double price_clique (nlist, c, marker) +poolnode *nlist; +CCtsp_lpclique *c; +int marker; +#endif +{ + double val = 0.0; + poolnode *n; + int i, j, k; + + for (i = 0; i < c->segcount; i++) { + for (j = c->nodes[i].lo; j <= c->nodes[i].hi; j++) { + nlist[j].mark = marker; + } + } + for (i = 0; i < c->segcount; i++) { + for (j = c->nodes[i].lo; j <= c->nodes[i].hi; j++) { + n = &(nlist[j]); + for (k = 0; k < n->deg; k++) { + if (nlist[n->adj[k].to].mark != marker) { + val += n->adj[k].x; + } + } + } + } + return val; +} diff --git a/contrib/blossom/concorde97/TSP/edgemap.c b/contrib/blossom/concorde97/TSP/edgemap.c new file mode 100644 index 0000000000000000000000000000000000000000..1349bf3e24d2de4b55b249769b654ac8bb333c87 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/edgemap.c @@ -0,0 +1,158 @@ +/***************************************************************************/ +/* */ +/* ROUTINES TO MAP NODE PAIRS TO EDGES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: September 27, 1995 */ +/* */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" +#include "macrorus.h" + +CC_PTR_ALLOC_ROUTINE (CCtsp_edgeinf, edgeinf_alloc, edgeinf_bigchunklist, + edgeinf_freelist) +CC_PTR_FREE_ROUTINE (CCtsp_edgeinf, edgeinf_free, edgeinf_freelist) +CC_PTR_FREE_LIST_ROUTINE(CCtsp_edgeinf, edgeinf_list_free, edgeinf_free) +CC_PTR_FREE_WORLD_ROUTINE (CCtsp_edgeinf, edgeinf_free_world, + edgeinf_bigchunklist, edgeinf_freelist) + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_edgehash_init (CCtsp_edgehash *h, int size) +#else +int CCtsp_edgehash_init (h, size) +CCtsp_edgehash *h; +int size; +#endif +{ + unsigned int i; + + h->size = CCutil_nextprime ((unsigned int) size); + h->mult = (int) sqrt ((double) h->size); + h->table = CC_SAFE_MALLOC ((int) h->size, CCtsp_edgeinf *); + if (!h->table) { + h->size = 0; + return 1; + } + for (i=0; i<h->size; i++) { + h->table[i] = (CCtsp_edgeinf *) NULL; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_edgehash_add (CCtsp_edgehash *h, int end1, int end2, int val) +#else +int CCtsp_edgehash_add (h, end1, end2, val) +CCtsp_edgehash *h; +int end1; +int end2; +int val; +#endif +{ + int t; + unsigned int loc; + CCtsp_edgeinf *e; + + if (h->size == 0) return 1; + e = edgeinf_alloc(); + if (!e) return 1; + + if (end1 > end2) CC_SWAP (end1, end2, t); + loc = (end1 * h->mult + end2) % h->size; + e->ends[0] = end1; + e->ends[1] = end2; + e->val = val; + e->next = h->table[loc]; + h->table[loc] = e; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_edgehash_del (CCtsp_edgehash *h, int end1, int end2) +#else +int CCtsp_edgehash_del (h, end1, end2) +CCtsp_edgehash *h; +int end1; +int end2; +#endif +{ + int t; + CCtsp_edgeinf **prev; + CCtsp_edgeinf *p; + + if (end1 > end2) CC_SWAP (end1, end2, t); + if (h->size == 0) return 1; + + prev = &h->table[(end1 * h->mult + end2) % h->size]; + p = *prev; + while (p) { + if (p->ends[0] == end1 && p->ends[1] == end2) { + *prev = p->next; + edgeinf_free (p); + return 0; + } + prev = &p->next; + p = *prev; + } + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_edgehash_delall (CCtsp_edgehash *h) +#else +void CCtsp_edgehash_delall (h) +CCtsp_edgehash *h; +#endif +{ + unsigned int i; + + for (i=0; i<h->size; i++) { + if (h->table[i]) { + edgeinf_list_free (h->table[i]); + h->table[i] = (CCtsp_edgeinf *) NULL; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_edgehash_find (CCtsp_edgehash *h, int end1, int end2) +#else +int CCtsp_edgehash_find (h, end1, end2) +CCtsp_edgehash *h; +int end1; +int end2; +#endif +{ + int t; + CCtsp_edgeinf *p; + + if (end1 > end2) CC_SWAP (end1, end2, t); + if (h->size == 0) return -1; + + for (p = h->table[(end1 * h->mult + end2) % h->size]; p; p = p->next) { + if (p->ends[0] == end1 && p->ends[1] == end2) { + return p->val; + } + } + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_edgehash_free (CCtsp_edgehash *h) +#else +void CCtsp_edgehash_free (h) +CCtsp_edgehash *h; +#endif +{ + CCtsp_edgehash_delall (h); + CC_FREE (h->table, CCtsp_edgeinf *); + edgeinf_free_world (); + h->size = 0; +} diff --git a/contrib/blossom/concorde97/TSP/ex_price.c b/contrib/blossom/concorde97/TSP/ex_price.c new file mode 100644 index 0000000000000000000000000000000000000000..f0c50aaea51879c49c92e46c5d53beb31624b845 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/ex_price.c @@ -0,0 +1,1196 @@ +/***************************************************************************/ +/* */ +/* ROUTINES TO PRICE EDGES USING BIGGUY ARITHMETIC */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: January 21, 1997 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_exact_price (CCtsp_lp *lp, CCbigguy *bound, int phase1) */ +/* RETURNS a bound that is valid for the entire edge set; the values */ +/* of the dual variables will be stored in lp->exact_dual unless */ +/* the existing lp->exact_dual's cutcount aggrees with the */ +/* cutcount in for lp */ +/* -lp is a pointer to the tsp lp */ +/* -bound returns the LP bound */ +/* -phase1 is either 0 or 1, with 1 indicating that the pricing */ +/* should be to determine a Farkas' lemma bound to prove that the */ +/* LP is infeasbile */ +/* */ +/* int CCtsp_edge_elimination (CCtsp_lp *lp) */ +/* USES the bound information to elimination edges and set edges to 1; */ +/* the remaining edges are placed into lp->fulladj (the old adj */ +/* is freed) and the fixed edges are placed on the list */ +/* lp->fixededges; the dual values are taken from lp->exact_dual */ +/* -lp is a pointer to the tsp lp; lp->exact_lowerbound will be used */ +/* together with lp->upperbound to determine the cutoff to elim */ +/* and fix edges */ +/* NOTE: this function does not alter the LP or lp->graph */ +/* */ +/* int CCtsp_exact_dual (CCtsp_lp *lp, CCtsp_bigdual **d) */ +/* RETURNS the dual values as bigguys (used to store the info used */ +/* to establish the exact lower bound); the values will be */ +/* stored in lp->exact_dual (and the existing values freed) */ +/* -lp is the CCtsp_lp */ +/* */ +/* int CCtsp_verify_infeasible_lp (CCtsp_lp *lp, int *yesno) */ +/* VERIFIES that the lp is infeasible using exact pricing. */ +/* -yesno is set to 1 if the lp is infeasible and 0 otherwise. */ +/* */ +/* int CCtsp_verify_lp_prune (CCtsp_lp *lp, int *yesno) */ +/* VERIFIES that the lp bound is less than the lp upperbound - 1. */ +/* -yesno is set to 1 if bound < upperbound - 1 and 0 otherwise. */ +/* */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "macrorus.h" +#include "bigguy.h" +#include "tsp.h" + +#define BIG_PRICE_GEN 20000 + +typedef struct bigpredge { + int ends[2]; + int len; + CCbigguy rc; +} bigpredge; + +#ifdef CC_PROTOTYPE_ANSI + +static int + big_pricing_duals (CCtsp_lp *lp, CCbigguy *node_pi, CCbigguy *node_piest, + CCbigguy *cut_pi, CCbigguy *clique_pi, CCbigguy *rhs_sum), + big_price_list (CCtsp_lp *lp, int ecount, bigpredge *elist, + CCbigguy *node_pi, CCbigguy *clique_pi), + big_generate_edges (CCtsp_lp *lp, CCbigguy *node_piest, int nwant, + int *gencount, bigpredge *genlist, int *n1, int *n2, + int *finished, CCbigguy cutoff, int phase1), + add_to_inlist (CCtsp_lp *lp, bigpredge *inlist, int *count, int end0, + int end1, int phase1), + add_to_adj (CCtsp_lp *lp, CCtsp_genadj *adj, int end0, int end1, + int *count), + test_edge (int end1, int end2, int len, CCbigguy *node_pi, CCbigguy cutoff); + +#else + +static int + big_pricing_duals (), + big_price_list (), + big_generate_edges (), + add_to_inlist (), + add_to_adj (), + test_edge (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_exact_price (CCtsp_lp *lp, CCbigguy *bound, int phase1) +#else +int CCtsp_exact_price (lp, bound, phase1) +CCtsp_lp *lp; +CCbigguy *bound; +int phase1; +#endif +{ + int incount; + bigpredge *inlist = (bigpredge *) NULL; + CCbigguy penalty, rhs_sum; + CCbigguy *node_pi = (CCbigguy *) NULL; + CCbigguy *node_piest = (CCbigguy *) NULL; + CCbigguy *clique_pi = (CCbigguy *) NULL; + CCbigguy *cut_pi = (CCbigguy *) NULL; + int nbranch = 0; + int n1, n2, i, j, finished; + int rval = 0; + double szeit; + + printf ("exact_price ...\n"); fflush (stdout); + szeit = CCutil_zeit (); + + *bound = CCbigguy_ZERO; + + if (!lp->dat && !lp->full_edges_valid) { + fprintf (stderr, "must have dat file or full edge set\n"); + return 1; + } + + if (phase1) { + printf ("phase 1 pricing\n"); + fflush (stdout); + } + + if (!lp->exact_dual || lp->exact_dual->cutcount != lp->cuts.cutcount) { + printf ("Fetch the bigguy dual variables\n"); + fflush (stdout); + rval = CCtsp_exact_dual (lp); + if (rval) { + fprintf (stderr, "tsp_exact_dual failed\n"); + goto CLEANUP; + } + } + + for (i = 0; i < lp->branchdepth; i++) { + if (lp->branchhistory[i].ends[0] != -1) { + nbranch++; + } + } + + incount = 0; + if (BIG_PRICE_GEN >= lp->nfixededges + nbranch) { + inlist = CC_SAFE_MALLOC (BIG_PRICE_GEN, bigpredge); + } else { + inlist = CC_SAFE_MALLOC (lp->nfixededges + nbranch, bigpredge); + } + node_pi = CC_SAFE_MALLOC (lp->graph.ncount, CCbigguy); + node_piest = CC_SAFE_MALLOC (lp->graph.ncount, CCbigguy); + if (!inlist || !node_pi || !node_piest) { + fprintf (stderr, "out of memory in CCtsp_exact_price\n"); + rval = 1; + goto CLEANUP; + } + + if (lp->cuts.cliqueend) { + clique_pi = CC_SAFE_MALLOC (lp->cuts.cliqueend, CCbigguy); + if (!clique_pi) { + fprintf (stderr, "out of memory in CCtsp_exact_price\n"); + rval = 1; + goto CLEANUP; + } + } + if (lp->cuts.cutcount) { + cut_pi = CC_SAFE_MALLOC (lp->cuts.cutcount, CCbigguy); + if (!cut_pi) { + fprintf (stderr, "out of memory in CCtsp_exact_price\n"); + rval = 1; + goto CLEANUP; + } + } + + rval = big_pricing_duals (lp, node_pi, node_piest, cut_pi, clique_pi, + &rhs_sum); + if (rval) goto CLEANUP; + finished = 0; + n1 = 0; + n2 = (lp->full_edges_valid ? 0 : 1); + penalty = CCbigguy_ZERO; + + while (!finished) { + rval = big_generate_edges (lp, node_pi, BIG_PRICE_GEN, &incount, + inlist, &n1, &n2, &finished, CCbigguy_ZERO, phase1); + if (rval) { + fprintf (stderr, "big_generate_edges failed\n"); + goto CLEANUP; + } + + rval = big_price_list (lp, incount, inlist, node_pi, clique_pi); + if (rval) { + fprintf (stderr, "big_price_list failed\n"); + goto CLEANUP; + } + for (i = 0; i < incount; i++) { + if (CCbigguy_cmp (inlist[i].rc, CCbigguy_ZERO) < 0) { + CCbigguy_add (&penalty, inlist[i].rc); +/* + { + int q; + q = CCtsp_find_edge (&lp->graph, inlist[i].ends[0], + inlist[i].ends[1]); + if (q == -1) { + printf ("YIPES: %f [%d, %d %d]: %f %f\n", + CCbigguytod (inlist[i].rc), inlist[i].ends[0], + inlist[i].ends[1], inlist[i].len, + CCbigguytod (node_pi[inlist[i].ends[0]]), + CCbigguytod (node_pi[inlist[i].ends[1]])); + fflush (stdout); + } + } +*/ + } + } + } + + if (lp->nfixededges + nbranch) { + int end0, end1; + + /* Adjust bound for fixed/branch edges */ + /* If a fixed or a branch=1 edge has positive rc, it can be added */ + /* If a branch=0 edge has negative rc, it should be subtracted */ + /* from the penalty since it was earlier added. */ + + incount = 0; + for (i = 0; i < lp->nfixededges; i++) { + end0 = lp->fixededges[2*i]; + end1 = lp->fixededges[2*i+1]; + rval = add_to_inlist (lp, inlist, &incount, end0, end1, phase1); + if (rval) { + fprintf (stderr, "add_to_inlist failed\n"); + goto CLEANUP; + } + } + for (i = 0; i < lp->branchdepth; i++) { + if (lp->branchhistory[i].ends[0] != -1) { + end0 = lp->branchhistory[i].ends[0]; + end1 = lp->branchhistory[i].ends[1]; + rval = add_to_inlist (lp, inlist, &incount, end0, end1, phase1); + if (rval) { + fprintf (stderr, "add_to_inlist failed\n"); + goto CLEANUP; + } + } + } + + rval = big_price_list (lp, incount, inlist, node_pi, clique_pi); + if (rval) { + fprintf (stderr, "big_price_list failed\n"); + goto CLEANUP; + } + for (i = 0; i < lp->nfixededges; i++) { + if (CCbigguy_cmp (inlist[i].rc, CCbigguy_ZERO) > 0) { + CCbigguy_add (&penalty, inlist[i].rc); + } + } + for (i = lp->nfixededges, j = 0; i < lp->nfixededges+nbranch; i++) { + while (lp->branchhistory[j].ends[0] == -1) + j++; + if (lp->branchhistory[j].rhs == 0) { + if (CCbigguy_cmp (inlist[i].rc, CCbigguy_ZERO) < 0) { + CCbigguy_sub (&penalty, inlist[i].rc); + } + } else { + if (CCbigguy_cmp (inlist[i].rc, CCbigguy_ZERO) > 0) { + CCbigguy_add (&penalty, inlist[i].rc); + } + } + j++; + } + } + + *bound = rhs_sum; + CCbigguy_add (bound, penalty); + + printf ("Exact Price Time: %.2f seconds\n", CCutil_zeit () - szeit); + fflush (stdout); + rval = 0; + +CLEANUP: + + CC_IFFREE (cut_pi, CCbigguy); + CC_IFFREE (clique_pi, CCbigguy); + CC_IFFREE (node_pi, CCbigguy); + CC_IFFREE (node_piest, CCbigguy); + CC_IFFREE (inlist, bigpredge); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_to_inlist (CCtsp_lp *lp, bigpredge *inlist, int *count, + int end0, int end1, int phase1) +#else +static int add_to_inlist (lp, inlist, count, end0, end1, phase1) +CCtsp_lp *lp; +bigpredge *inlist; +int *count; +int end0, end1; +int phase1; +#endif +{ + int rval = 0; + int j; + int len = 0; + CCtsp_genadj *adj = lp->fulladj; + + if (end0 > end1) { + CC_SWAP (end0, end1, j); + } + if (phase1) { + len = 0; + } else { + if (lp->full_edges_valid) { + for (j = 0; j < adj[end0].deg; j++) { + if (adj[end0].list[j].end == end1) { + len = adj[end0].list[j].len; + break; + } + } + if (j == adj[end0].deg) { + fprintf (stderr, "ERROR: fixed edge not in fulladj\n"); + rval = 1; goto CLEANUP; + } + } else { + len = CCutil_dat_edgelen (end0, end1, lp->dat); + } + } + inlist[*count].ends[0] = end0; + inlist[*count].ends[1] = end1; + inlist[*count].len = len; + (*count)++; + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_edge_elimination (CCtsp_lp *lp) +#else +int CCtsp_edge_elimination (lp) +CCtsp_lp *lp; +#endif +{ + int incount; + bigpredge *inlist = (bigpredge *) NULL; + CCbigguy rhs_sum; + CCbigguy *node_pi = (CCbigguy *) NULL; + CCbigguy *node_piest = (CCbigguy *) NULL; + CCbigguy *clique_pi = (CCbigguy *) NULL; + CCbigguy *cut_pi = (CCbigguy *) NULL; + CCtsp_genadj *adj = (CCtsp_genadj *) NULL; + CCtsp_genadjobj *adjspace = (CCtsp_genadjobj *) NULL; + CCtsp_genadjobj *pa; + int i, n1, n2, finished, nremain, nfixed, ek; + int nbranch = 0; + int end0, end1; + int oldnfixed = lp->nfixededges; + int rval = 0; + CCbigguy cutoff, negcutoff; + double szeit; + + /* This code has not been tested after branching (at present, we only */ + /* call edge_elimination at the root LP). */ + + if (CCbigguy_cmp (lp->exact_lowerbound, CCbigguy_MINBIGGUY) == 0) { + fprintf (stderr, "need an exact lowerbound to run elimination\n"); + return 1; + } + if (lp->upperbound == CCtsp_LP_MAXDOUBLE) { + fprintf (stderr, "need an exact upperbound to run elimination\n"); + return 1; + } + if (!lp->exact_dual || lp->exact_dual->cutcount != lp->cuts.cutcount) { + fprintf (stderr, "no exact_dual in big_pricing_duals\n"); + return 1; + } + + szeit = CCutil_zeit (); + + cutoff = CCbigguy_dtobigguy (lp->upperbound); + CCbigguy_sub (&cutoff, lp->exact_lowerbound); + CCbigguy_sub (&cutoff, CCbigguy_ONE); + negcutoff = CCbigguy_ZERO; + CCbigguy_sub (&negcutoff, cutoff); + printf ("Edge Elimination Cutoff: %f\n", CCbigguy_bigguytod (cutoff)); + fflush (stdout); + if (CCbigguy_cmp (cutoff, CCbigguy_ZERO) < 0) { + printf ("Cutoff is less than ZERO, do not eliminate\n"); + fflush (stdout); + return 1; + } + + incount = 0; + inlist = CC_SAFE_MALLOC (BIG_PRICE_GEN, bigpredge); + node_pi = CC_SAFE_MALLOC (lp->graph.ncount, CCbigguy); + node_piest = CC_SAFE_MALLOC (lp->graph.ncount, CCbigguy); + if (!inlist || !node_pi || !node_piest) { + fprintf (stderr, "out of memory in CCtsp_edge_elimination\n"); + rval = 1; goto CLEANUP; + } + if (lp->cuts.cliqueend) { + clique_pi = CC_SAFE_MALLOC (lp->cuts.cliqueend, CCbigguy); + if (!clique_pi) { + fprintf (stderr, "out of memory in CCtsp_edge_elimination\n"); + rval = 1; goto CLEANUP; + } + } + if (lp->cuts.cutcount) { + cut_pi = CC_SAFE_MALLOC (lp->cuts.cutcount, CCbigguy); + if (!cut_pi) { + fprintf (stderr, "out of memory in CCtsp_edge_elimination\n"); + rval = 1; goto CLEANUP; + } + } + + rval = big_pricing_duals (lp, node_pi, node_piest, cut_pi, clique_pi, + &rhs_sum); + if (rval) { + fprintf (stderr, "big_pricing_duals failed\n"); + goto CLEANUP; + } + + adj = CC_SAFE_MALLOC (lp->graph.ncount, CCtsp_genadj); + if (!adj) { + fprintf (stderr, "out of memory in CCtsp_edge_elimination\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < lp->graph.ncount; i++) + adj[i].deg = 0; + + finished = 0; + nremain = 0; + nfixed = 0; + n1 = 0; + n2 = (lp->full_edges_valid ? 0 : 1); + + while (!finished) { + rval = big_generate_edges (lp, node_piest, BIG_PRICE_GEN, &incount, + inlist, &n1, &n2, &finished, cutoff, 0); + if (rval) { + fprintf (stderr, "big_generate_edges failed\n"); + CC_FREE (adj, CCtsp_genadj); + goto CLEANUP; + } + rval = big_price_list (lp, incount, inlist, node_pi, clique_pi); + if (rval) { + fprintf (stderr, "big_price_list failed\n"); + CC_FREE (adj, CCtsp_genadj); + goto CLEANUP; + } + + for (i = 0; i < incount; i++) { + if (CCbigguy_cmp (inlist[i].rc, cutoff) <= 0) { + adj[inlist[i].ends[0]].deg++; + nremain++; + if (CCbigguy_cmp (inlist[i].rc, negcutoff) < 0) { + ek = CCtsp_find_edge (&(lp->graph),inlist[i].ends[0], + inlist[i].ends[1]); + if (ek == -1 || (lp->graph.edges[ek].fixed == 0 && + lp->graph.edges[ek].branch == 0)) { + if (ek == -1) printf ("GONG "); + printf ("[%d, %d] ", inlist[i].ends[0], + inlist[i].ends[1]); + fflush (stdout); + nfixed++; + } + } + } + } + } + + /* leave enough room for the old fixed edges and the branch edges */ + + for (i = 0; i < lp->branchdepth; i++) { + if (lp->branchhistory[i].ends[0] != -1) { + end0 = lp->branchhistory[i].ends[0]; + end1 = lp->branchhistory[i].ends[1]; + if (end0 < end1) + adj[end0].deg++; + else + adj[end1].deg++; + nbranch++; + } + } + for (i = 0; i < lp->nfixededges; i++) { + end0 = lp->fixededges[2*i]; + end1 = lp->fixededges[2*i+1]; + if (end0 < end1) + adj[end0].deg++; + else + adj[end1].deg++; + } + + if (nremain + lp->nfixededges + nbranch) { + adjspace = CC_SAFE_MALLOC (nremain + lp->nfixededges + nbranch, + CCtsp_genadjobj); + if (!adjspace) { + fprintf (stderr, "out of memory in CCtsp_edge_elimination\n"); + CC_FREE (adj, CCtsp_genadj); + rval = 1; + goto CLEANUP; + } + } + if (nfixed) { + rval = CCutil_reallocrus_count ((void **) &(lp->fixededges), + 2 * (lp->nfixededges + nfixed), sizeof (int)); + if (rval) { + fprintf (stderr, "out of memory in CCtsp_edge_elimination\n"); + CC_FREE (adj, CCtsp_genadj); + CC_IFFREE (adjspace, CCtsp_genadjobj); + goto CLEANUP; + } + } + + pa = adjspace; + for (i = 0; i < lp->graph.ncount; i++) { + adj[i].list = pa; + pa += adj[i].deg; + adj[i].deg = 0; + } + + finished = 0; + n1 = 0; + n2 = (lp->full_edges_valid ? 0 : 1); + + while (!finished) { + rval = big_generate_edges (lp, node_piest, BIG_PRICE_GEN, &incount, + inlist, &n1, &n2, &finished, cutoff, 0); + if (rval) { + fprintf (stderr, "big_generate_edges failed\n"); + CC_FREE (adj, CCtsp_genadj); + CC_IFFREE (adjspace, CCtsp_genadjobj); + goto CLEANUP; + } + rval = big_price_list (lp, incount, inlist, node_pi, clique_pi); + if (rval) { + fprintf (stderr, "big_price_list failed\n"); + CC_FREE (adj, CCtsp_genadj); + CC_IFFREE (adjspace, CCtsp_genadjobj); + goto CLEANUP; + } + for (i = 0; i < incount; i++) { + if (CCbigguy_cmp (inlist[i].rc, cutoff) <= 0) { + adj[inlist[i].ends[0]].list[adj[inlist[i].ends[0]].deg].end = + inlist[i].ends[1]; + adj[inlist[i].ends[0]].list[adj[inlist[i].ends[0]].deg].len = + inlist[i].len; + adj[inlist[i].ends[0]].deg++; + if (CCbigguy_cmp (inlist[i].rc, negcutoff) < 0) { + ek = CCtsp_find_edge (&(lp->graph),inlist[i].ends[0], + inlist[i].ends[1]); + if (ek == -1 || (lp->graph.edges[ek].fixed == 0 && + lp->graph.edges[ek].branch == 0)) { + lp->fixededges[2*lp->nfixededges] = inlist[i].ends[0]; + lp->fixededges[2*lp->nfixededges+1] = + inlist[i].ends[1]; + lp->nfixededges++; + } + } + } + } + } + + /* some of the old fixed and branched edges may not have made it into adj */ + + for (i = 0; i < lp->branchdepth; i++) { + if (lp->branchhistory[i].ends[0] != -1) { + end0 = lp->branchhistory[i].ends[0]; + end1 = lp->branchhistory[i].ends[1]; + rval = add_to_adj (lp, adj, end0, end1, &nremain); + if (rval) { + fprintf (stderr, "add_to_adj failed\n"); goto CLEANUP; + } + } + } + for (i = 0; i < oldnfixed; i++) { + end0 = lp->fixededges[2*i]; + end1 = lp->fixededges[2*i+1]; + rval = add_to_adj (lp, adj, end0, end1, &nremain); + if (rval) { + fprintf (stderr, "add_to_adj failed\n"); goto CLEANUP; + } + } + rval = 0; + + CC_IFFREE (lp->fulladjspace, CCtsp_genadjobj); + CC_IFFREE (lp->fulladj, CCtsp_genadj); + lp->fullcount = nremain; + lp->fulladjspace = adjspace; + lp->fulladj = adj; + lp->full_edges_valid = 1; + + printf ("Remaining Edges: %d (with %d new fixed)\n", nremain, nfixed); + printf ("Edge Elimination Time: %.2f seconds\n", CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + CC_IFFREE (cut_pi, CCbigguy); + CC_IFFREE (clique_pi, CCbigguy); + CC_IFFREE (node_pi, CCbigguy); + CC_IFFREE (node_piest, CCbigguy); + CC_IFFREE (inlist, bigpredge); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_to_adj (CCtsp_lp *lp, CCtsp_genadj *adj, int end0, int end1, + int *count) +#else +static int add_to_adj (lp, adj, end0, end1, count) +CCtsp_lp *lp; +CCtsp_genadj *adj; +int end0, end1; +int *count; +#endif +{ + int rval = 0; + int len = 0; + int j, k; + + if (end0 > end1) { + CC_SWAP (end0, end1, k); + } + for (k = 0; k < adj[end0].deg; k++) { + if (adj[end0].list[k].end == end1) + break; + } + if (k == adj[end0].deg) { + if (lp->full_edges_valid) { + for (j = 0; j < lp->fulladj[end0].deg; j++) { + if (lp->fulladj[end0].list[j].end == end1) { + len = lp->fulladj[end0].list[j].len; + break; + } + } + if (j == lp->fulladj[end0].deg) { + fprintf (stderr, "ERROR: fixed/branch edge not in fulladj\n"); + rval = 1; goto CLEANUP; + } + } else { + len = CCutil_dat_edgelen (end0, end1, lp->dat); + } + adj[end0].list[adj[end0].deg].end = end1; + adj[end0].list[adj[end0].deg].len = len; + adj[end0].deg++; + (*count)++; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int big_pricing_duals (CCtsp_lp *lp, CCbigguy *node_pi, + CCbigguy *node_piest, CCbigguy *cut_pi, CCbigguy *clique_pi, + CCbigguy *rhs_sum) +#else +static int big_pricing_duals (lp, node_pi, node_piest, cut_pi, clique_pi, + rhs_sum) +CCtsp_lp *lp; +CCbigguy *node_pi; +CCbigguy *node_piest; +CCbigguy *cut_pi; +CCbigguy *clique_pi; +CCbigguy *rhs_sum; +#endif +{ + CCbigguy x; + int i, j, k; + int rval = 0; + + *rhs_sum = CCbigguy_ZERO; + + if (!lp->exact_dual || lp->exact_dual->cutcount != lp->cuts.cutcount) { + fprintf (stderr, "no exact_dual in big_pricing_duals\n"); + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < lp->graph.ncount; i++) { + node_pi[i] = lp->exact_dual->node_pi[i]; + } + for (i = 0; i < lp->cuts.cutcount; i++) { + cut_pi[i] = lp->exact_dual->cut_pi[i]; + } + + for (i = 0; i < lp->graph.ncount; i++) + CCbigguy_addmult (rhs_sum, node_pi[i], 2); + + for (i = 0; i < lp->cuts.cutcount; i++) { + x = cut_pi[i]; + CCbigguy_addmult (rhs_sum, x, (short) lp->cuts.cuts[i].rhs); + for (j = 0; j < lp->cuts.cuts[i].modcount; j++) { + CCbigguy_addmult (rhs_sum, x, ((short) 2) * + (((short) lp->cuts.cuts[i].mods[j].mult) - ((short) 128))); + } + } + + for (i = 0; i < lp->cuts.cliqueend; i++) { + clique_pi[i] = CCbigguy_ZERO; + } + + for (i = 0; i < lp->cuts.cutcount; i++) { + x = cut_pi[i]; + for (j = 0; j < lp->cuts.cuts[i].modcount; j++) { + CCbigguy_addmult (&(node_pi[lp->cuts.cuts[i].mods[j].node]), x, + ((short) lp->cuts.cuts[i].mods[j].mult) - + ((short) 128)); + } + for (j = 0; j < lp->cuts.cuts[i].cliquecount; j++) { + CCbigguy_add (&(clique_pi[lp->cuts.cuts[i].cliques[j]]), x); + } + } + + for (i = 0; i < lp->graph.ncount; i++) { + node_piest[i] = node_pi[i]; + } + + for (i = 0; i < lp->cuts.cliqueend; i++) { + x = clique_pi[i]; + if (CCbigguy_cmp (x, CCbigguy_ZERO) > 0) { + for (j = 0; j < lp->cuts.cliques[i].segcount; j++) { + for (k = lp->cuts.cliques[i].nodes[j].lo; + k <= lp->cuts.cliques[i].nodes[j].hi; k++) { + CCbigguy_add (&(node_pi[k]), x); + CCbigguy_add (&(node_piest[k]), x); + } + } + } else if (CCbigguy_cmp (x, CCbigguy_ZERO) < 0) { + for (j = 0; j < lp->cuts.cliques[i].segcount; j++) { + for (k = lp->cuts.cliques[i].nodes[j].lo; + k <= lp->cuts.cliques[i].nodes[j].hi; k++) { + CCbigguy_add (&(node_pi[k]), x); + } + } + } + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int big_price_list (CCtsp_lp *lp, int ecount, bigpredge *elist, + CCbigguy *node_pi, CCbigguy *clique_pi) +#else +static int big_price_list (lp, ecount, elist, node_pi, clique_pi) +CCtsp_lp *lp; +int ecount; +bigpredge *elist; +CCbigguy *node_pi; +CCbigguy *clique_pi; +#endif +{ + CCtsp_lpadj *adjspace = (CCtsp_lpadj *) NULL; + CCtsp_lpnode *n = (CCtsp_lpnode *) NULL; + int i, j, k, l; + CCtsp_lpadj *a; + int marker = 0; + CCbigguy x; + int ncount = lp->graph.ncount; + int ccount = lp->cuts.cliqueend; + CCtsp_lpclique *c = lp->cuts.cliques; + + if (ecount == 0) return 0; + + n = CC_SAFE_MALLOC (ncount, CCtsp_lpnode); + adjspace = CC_SAFE_MALLOC (2*ecount, CCtsp_lpadj); + if (!n || !adjspace) { + fprintf (stderr, "out of memory in big_price_list\n"); + CC_IFFREE (n, CCtsp_lpnode); + CC_IFFREE (adjspace, CCtsp_lpadj); + return 1; + } + + for (i = 0; i < ncount; i++) { + n[i].deg = 0; + n[i].mark = 0; + } + for (i = 0; i < ecount; i++) { + elist[i].rc = CCbigguy_itobigguy (elist[i].len); + CCbigguy_sub (&(elist[i].rc), node_pi[elist[i].ends[0]]); + CCbigguy_sub (&(elist[i].rc), node_pi[elist[i].ends[1]]); + n[elist[i].ends[0]].deg++; + n[elist[i].ends[1]].deg++; + } + a = adjspace; + for (i = 0; i < ncount; i++) { + n[i].adj = a; + a += n[i].deg; + n[i].deg = 0; + } + for (i = 0; i < ecount; i++) { + j = elist[i].ends[0]; + n[j].adj[n[j].deg].to = elist[i].ends[1]; + n[j].adj[n[j].deg].edge = i; + n[j].deg++; + j = elist[i].ends[1]; + n[j].adj[n[j].deg].to = elist[i].ends[0]; + n[j].adj[n[j].deg].edge = i; + n[j].deg++; + } + + for (i = 0; i < ccount; i++) { + if (CCbigguy_cmp (clique_pi[i], CCbigguy_ZERO)) { + x = clique_pi[i]; + CCbigguy_add (&x, clique_pi[i]); + marker++; + for (j = 0; j < c[i].segcount; j++) { + for (k = c[i].nodes[j].lo; k <= c[i].nodes[j].hi; k++) { + a = n[k].adj; + for (l = 0; l < n[k].deg; l++) { + if (n[a[l].to].mark == marker) { + CCbigguy_add (&(elist[a[l].edge].rc), x); + } + } + n[k].mark = marker; + } + } + } + } + CC_FREE (n, CCtsp_lpnode); + CC_FREE (adjspace, CCtsp_lpadj); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int big_generate_edges (CCtsp_lp *lp, CCbigguy *node_piest, int nwant, + int *gencount, bigpredge *genlist, int *n1, int *n2, + int *finished, CCbigguy cutoff, int phase1) +#else +static int big_generate_edges (lp, node_piest, nwant, gencount, genlist, + n1, n2, finished, cutoff, phase1) +CCtsp_lp *lp; +CCbigguy *node_piest; +int nwant; +int *gencount; +bigpredge *genlist; +int *n1, *n2; +int *finished; +CCbigguy cutoff; +int phase1; /* Set to nonzero to use phase 1 objective */ +#endif +{ + int i = *n1; + int j = *n2; + int cnt = 0; + int len; + CCtsp_genadj *adj; + CCdatagroup *dat; + int ncount = lp->graph.ncount; + + *gencount = 0; + *finished = 0; + + if (!lp->dat && !lp->full_edges_valid) { + fprintf (stderr, "no source of edges in big_generate_edges\n"); + return 1; + } + + if (i >= ncount) { + *finished = 1; + return 0; + } + + if (lp->full_edges_valid) { + if (!phase1) { + adj = lp->fulladj; + for (; j < adj[i].deg; j++) { + if (test_edge (i, adj[i].list[j].end, adj[i].list[j].len, + node_piest, cutoff)) { + genlist[cnt].ends[0] = i; + genlist[cnt].ends[1] = adj[i].list[j].end; + genlist[cnt].len = adj[i].list[j].len; + cnt++; + if (cnt == nwant) { + *finished = 0; + *gencount = cnt; + *n1 = i; *n2 = j + 1; + return 0; + } + } + } + for (i++; i < ncount; i++) { + for (j = 0; j < adj[i].deg; j++) { + if (test_edge (i, adj[i].list[j].end, adj[i].list[j].len, + node_piest, cutoff)) { + genlist[cnt].ends[0] = i; + genlist[cnt].ends[1] = adj[i].list[j].end; + genlist[cnt].len = adj[i].list[j].len; + cnt++; + if (cnt == nwant) { + *finished = 0; + *gencount = cnt; + *n1 = i; *n2 = j + 1; + return 0; + } + } + } + } + } else { + adj = lp->fulladj; + for (; j < adj[i].deg; j++) { + if (test_edge (i, adj[i].list[j].end, 0, + node_piest, cutoff)) { + genlist[cnt].ends[0] = i; + genlist[cnt].ends[1] = adj[i].list[j].end; + genlist[cnt].len = 0; + cnt++; + if (cnt == nwant) { + *finished = 0; + *gencount = cnt; + *n1 = i; *n2 = j + 1; + return 0; + } + } + } + for (i++; i < ncount; i++) { + for (j = 0; j < adj[i].deg; j++) { + if (test_edge (i, adj[i].list[j].end, 0, + node_piest, cutoff)) { + genlist[cnt].ends[0] = i; + genlist[cnt].ends[1] = adj[i].list[j].end; + genlist[cnt].len = 0; + cnt++; + if (cnt == nwant) { + *finished = 0; + *gencount = cnt; + *n1 = i; *n2 = j + 1; + return 0; + } + } + } + } + } + } else { + if (!phase1) { + dat = lp->dat; + for (; j < ncount; j++) { + len = CCutil_dat_edgelen (i, j, dat); + if (test_edge (i, j, len, node_piest, cutoff)) { + genlist[cnt].ends[0] = i; + genlist[cnt].ends[1] = j; + genlist[cnt].len = len; + cnt++; + if (cnt == nwant) { + *finished = 0; + *gencount = cnt; + *n1 = i; *n2 = j + 1; + return 0; + } + } + } + for (i++; i < ncount; i++) { + for (j = i + 1; j < ncount; j++) { + len = CCutil_dat_edgelen (i, j, dat); + if (test_edge (i, j, len, node_piest, cutoff)) { + genlist[cnt].ends[0] = i; + genlist[cnt].ends[1] = j; + genlist[cnt].len = len; + cnt++; + if (cnt == nwant) { + *finished = 0; + *gencount = cnt; + *n1 = i; *n2 = j + 1; + return 0; + } + } + } + } + } else { + for (; j < ncount; j++) { + if (test_edge (i, j, 0, node_piest, cutoff)) { + genlist[cnt].ends[0] = i; + genlist[cnt].ends[1] = j; + genlist[cnt].len = 0; + cnt++; + if (cnt == nwant) { + *finished = 0; + *gencount = cnt; + *n1 = i; *n2 = j + 1; + return 0; + } + } + } + for (i++; i < ncount; i++) { + for (j = i + 1; j < ncount; j++) { + if (test_edge (i, j, 0, node_piest, cutoff)) { + genlist[cnt].ends[0] = i; + genlist[cnt].ends[1] = j; + genlist[cnt].len = 0; + cnt++; + if (cnt == nwant) { + *finished = 0; + *gencount = cnt; + *n1 = i; *n2 = j + 1; + return 0; + } + } + } + } + } + } + + *n1 = ncount; + *n2 = ncount; + *gencount = cnt; + *finished = 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int test_edge (int end1, int end2, int len, CCbigguy *node_pi, + CCbigguy cutoff) +#else +static int test_edge (end1, end2, len, node_pi, cutoff) +int end1, end2; +int len; +CCbigguy *node_pi; +CCbigguy cutoff; +#endif +{ + CCbigguy rc; + + rc = CCbigguy_itobigguy (len); + CCbigguy_sub (&rc, node_pi[end1]); + CCbigguy_sub (&rc, node_pi[end2]); + if (CCbigguy_cmp (rc, cutoff) <= 0) { + return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_exact_dual (CCtsp_lp *lp) +#else +int CCtsp_exact_dual (lp) +CCtsp_lp *lp; +#endif +{ + int i; + int ncount = lp->graph.ncount; + int cutcount = lp->cuts.cutcount; + double *d_node_pi = (double *) NULL; + double *d_cut_pi = (double *) NULL; + CCtsp_bigdual *d = (CCtsp_bigdual *) NULL; + int rval = 0; + + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, + (int *) NULL, (int **) NULL, (double **) NULL, + (double **) NULL, &d_node_pi, &d_cut_pi); + if (rval) { + fprintf (stderr, "get_lp_result failed\n"); + fflush (stdout); + goto CLEANUP; + } + + d = CC_SAFE_MALLOC (1, CCtsp_bigdual); + if (!(d)) { + fprintf (stderr, "out of memory in CCtsp_exact_dual C\n"); + rval = 1; goto CLEANUP; + } + d->cutcount = cutcount; + d->node_pi = (CCbigguy *) NULL; + d->cut_pi = (CCbigguy *) NULL; + + d->node_pi = CC_SAFE_MALLOC (ncount, CCbigguy); + if (!d->node_pi) { + fprintf (stderr, "out of memory in CCtsp_exact_dual B\n"); + CC_FREE (d, CCtsp_bigdual); + rval = 1; goto CLEANUP; + } + + for (i = 0; i < ncount; i++) { + d->node_pi[i] = CCbigguy_dtobigguy (d_node_pi[i]); + } + + if (cutcount) { + printf ("Request %d bigguys\n", cutcount); fflush (stdout); + d->cut_pi = CC_SAFE_MALLOC (cutcount, CCbigguy); + if (!d->cut_pi) { + fprintf (stderr, "out of memory in CCtsp_exact_dual A\n"); + CC_FREE (d->node_pi, CCbigguy); + CC_FREE (d, CCtsp_bigdual); + rval = 1; goto CLEANUP; + } + for (i = 0; i < lp->cuts.cutcount; i++) { + d->cut_pi[i] = CCbigguy_dtobigguy (d_cut_pi[i]); + } + } + + if (lp->exact_dual) { + CC_IFFREE (lp->exact_dual->node_pi, CCbigguy); + CC_IFFREE (lp->exact_dual->cut_pi, CCbigguy); + CC_FREE (lp->exact_dual, CCtsp_bigdual); + } + lp->exact_dual = d; + + +CLEANUP: + + CC_IFFREE (d_node_pi, double); + CC_IFFREE (d_cut_pi, double); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_bigdual (CCtsp_bigdual **d) +#else +void CCtsp_free_bigdual (d) +CCtsp_bigdual **d; +#endif +{ + if (d) { + if (*d) { + CC_IFFREE ((*d)->node_pi, CCbigguy); + CC_IFFREE ((*d)->cut_pi, CCbigguy); + CC_IFFREE ((*d), CCtsp_bigdual); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_verify_infeasible_lp (CCtsp_lp *lp, int *yesno) +#else +int CCtsp_verify_infeasible_lp (lp, yesno) +CCtsp_lp *lp; +int *yesno; +#endif +{ + int rval = 0; + CCbigguy exactbound; + + *yesno = 0; + rval = CCtsp_exact_price (lp, &exactbound, 1); + if (rval) { + fprintf (stderr, "CCtsp_exact_price_failed\n"); goto CLEANUP; + } + + if (CCbigguy_cmp (exactbound, CCbigguy_ZERO) < 0) { + printf ("Problem is shown to be infeasible\n"); fflush (stdout); + *yesno = 1; + lp->infeasible = 1; lp->lowerbound = CCtsp_LP_MAXDOUBLE; + } else { + printf ("Did not verify an infeasible LP\n"); fflush (stdout); + *yesno = 0; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_verify_lp_prune (CCtsp_lp *lp, int *yesno) +#else +int CCtsp_verify_lp_prune (lp, yesno) +CCtsp_lp *lp; +int *yesno; +#endif +{ + int rval = 0; + CCbigguy exactbound, bnd; + + *yesno = 0; + rval = CCtsp_exact_price (lp, &exactbound, 0); + if (rval) { + fprintf (stderr, "CCtsp_exact_price_failed\n"); goto CLEANUP; + } + printf ("Exact LP bound: %f\n", CCbigguy_bigguytod (exactbound)); + fflush (stdout); + + bnd = CCbigguy_dtobigguy (lp->upperbound); + CCbigguy_sub (&bnd, CCbigguy_ONE); + if (CCbigguy_cmp (exactbound, bnd) > 0) { + printf ("Can prune lp.\n"); fflush (stdout); + *yesno = 1; + lp->exact_lowerbound = exactbound; + } else { + printf ("Cannot prune lp.\n"); fflush (stdout); + *yesno = 0; + } + +CLEANUP: + + return rval; +} diff --git a/contrib/blossom/concorde97/TSP/generate.c b/contrib/blossom/concorde97/TSP/generate.c new file mode 100644 index 0000000000000000000000000000000000000000..c2bdd259e3233c1f0c880568d7f7912a1b8f8598 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/generate.c @@ -0,0 +1,854 @@ +/***************************************************************************/ +/* */ +/* GENERATION OF EDGES FOR THE PRICING ROUTINE */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 10, 1995 */ +/* Last Change: July 10, 1996 (Bico) */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_init_edgegenerator (edgegenerator *eg, int ncount, */ +/* CCdatagroup *dg, CCtsp_genadj *adj, int nneighbors) */ +/* SETS UP the edgegenerator structure. Must be called before calls */ +/* to the other edgegenerator functions. */ +/* -eg must point to an edgegenerator struct. */ +/* -ncount is the number of nodes. */ +/* -dg will not be copied, only the pointer is recorded. */ +/* -adj will be used as the edgelist if it is nonnull (in this case */ +/* dg can be NULL). */ +/* -nneighbors is the number of neighbors that will be considered */ +/* from each node. To consider all edges, this should be set to */ +/* CCtsp_PRICE_COMPLETE_GRAPH. */ +/* void CCtsp_free_edgegenerator (edgegenerator *eg) */ +/* FREES the space used by the structures in eg (but not eg itself). */ +/* int CCtsp_reset_edgegenerator (edgegenerator *eg, double *node_piest)*/ +/* ADDS the pi values to the eg and records the starting position in */ +/* the loop through the edges (so we can determine when we have */ +/* circled through all edges with a single set of pi values). This */ +/* must be called before the first call to generate_edges. */ +/* -eg must have been set up with a call to init_edgegenerator. */ +/* -node_piest is pi values "estimates" on the nodes. */ +/* int CCtsp_generate_edges (CCtsp_edgegenerator *eg, int nwant, */ +/* int *pngot, int *elist, int *elen, int *finished) */ +/* RETURNS a list of edges that have a chance of having negative */ +/* reduced costs in that len(i,j) - pi[i] - pi[j] is negative. If an */ +/* entire pass has been made through the edgeset since the last call */ +/* to reset_edgegenerator, then finished is set to 1 (otherwise 0). */ +/* -eg must have been initialized with a call to init_edgegenerator */ +/* followed by a call to reset_edgegenerator. */ +/* -nwant is the maximum number of edges that should be returned. */ +/* -pngot returns the number of edges found. */ +/* -elist returns the edges in node node format (this must have */ +/* been allocated by the calling routine and should be at least */ +/* 2*nwant long. */ +/* -elen returns the lengths of the edges in elist (this must have */ +/* been allocated by the calling routine and have nwant entries). */ +/* -finished is set to 1 if an entire loop through the edges has */ +/* been made since the last call to reset_edgegenerator. */ +/* int CCtsp_edgelist_to_genadj (int ncount, int ecount, int *elist, */ +/* int *elen, CCtsp_genadj **adj, CCtsp_genadjobj **adjobjspace)*/ +/* RETURNS the genadj struct corresponding the list of edges. */ +/* -ncount is the number of nodes. */ +/* -ecount is the number of edges. */ +/* -elist is the array of edges in end1 end2 format. */ +/* -elen is the array of edge lengths. */ +/* -adj is a pointer to an genadj struct address; upon return it */ +/* will point to the filled in adj struct. */ +/* -adjobjspace will return a pointer to the list of genadjobj's */ +/* used in adj (this can be used to free the objects) */ +/* */ +/* NOTES: */ +/* All (nonvoid) routines return 0 if successful. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "macrorus.h" +#include "tsp.h" +#include "kdtree.h" +#include "edgegen.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + xprice_free (CCtsp_xnorm_pricer *xp); + +static int + xprice_build (int ncount, CCdatagroup *dat, CCtsp_xnorm_pricer *xp), + xprice_reset (CCtsp_xnorm_pricer *xp, double *pi, int currentnode), + xprice_node (CCtsp_xnorm_pricer *xp, int n, int *count, int *nlist); + +#else + +static void + xprice_free (); + +static int + xprice_build (), + xprice_reset (), + xprice_node (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_init_edgegenerator (CCtsp_edgegenerator *eg, int ncount, + CCdatagroup *dg, CCtsp_genadj *adj, int nneighbors) +#else +int CCtsp_init_edgegenerator (eg, ncount, dg, adj, nneighbors) +CCtsp_edgegenerator *eg; +int ncount; +CCdatagroup *dg; +CCtsp_genadj *adj; +int nneighbors; +#endif +{ + int rval; + + printf ("CCtsp_init_edgegenerator (%d)\n", nneighbors); fflush (stdout); + + eg->node_piest = (double *) NULL; + eg->kdtree = (CCkdtree *) NULL; + eg->xnear = (CCxnear *) NULL; + eg->xprice = (CCtsp_xnorm_pricer *) NULL; + eg->supply = (int *) NULL; + eg->adjobjspace = (CCtsp_genadjobj *) NULL; + eg->ncount = ncount; + eg->dg = dg; + eg->adj = adj; + + if (nneighbors == CCtsp_PRICE_COMPLETE_GRAPH) { + eg->nneighbors = CCtsp_PRICE_COMPLETE_GRAPH; + eg->supplyhead = 0; + eg->start = 0; + eg->current = 0; + if (((dg->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) || + ((dg->norm & CC_NORM_BITS) == CC_X_NORM_TYPE)) { + eg->supply = CC_SAFE_MALLOC (ncount, int); + if (!eg->supply) { + fprintf (stderr, "out of memory in init_edgegenerator\n"); + return 1; + } + eg->xprice = CC_SAFE_MALLOC (1, CCtsp_xnorm_pricer); + if (!eg->xprice) { + fprintf (stderr, "out of memory in init_edgegenerator\n"); + return 1; + } + rval = xprice_build (ncount, dg, eg->xprice); + if (rval) { + fprintf (stderr, "xprice_build failed\n"); + CC_FREE (eg->xprice, CCtsp_xnorm_pricer); + return rval; + } + } + } else { + eg->nneighbors = (nneighbors >= ncount - 1 ? ncount - 1 : nneighbors); + eg->start = 0; + eg->current = 0; + + if (adj) { + eg->supplyhead = 0; + eg->supplycount = 0; + } else if (eg->nneighbors <= CCtsp_GEN_USE_ADJ) { + int i, k, ecount; + int *elist = (int *) NULL; + CCtsp_genadjobj *padj; + + eg->supplyhead = 0; + eg->supplycount = 0; + + if ((dg->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + CCkdtree kt; + rval = CCkdtree_build (&kt, ncount, dg, (double *) NULL); + if (rval) { + fprintf (stderr, "CCkdtree_build failed\n"); + return rval; + } + rval = CCkdtree_k_nearest (&kt, ncount, eg->nneighbors, dg, + (double *) NULL, 1, &ecount, &elist); + if (rval) { + fprintf (stderr, "CCkdtree_k_nearest failed\n"); + return rval; + } + CCkdtree_free (&kt); + } else if ((dg->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + rval = CCedgegen_x_k_nearest (ncount, eg->nneighbors, dg, + (double *) NULL, 1, &ecount, &elist); + if (rval) { + fprintf (stderr, "CCedgegen_x_k_nearest failed\n"); + return rval; + } + } else { + rval = CCedgegen_junk_k_nearest (ncount, eg->nneighbors, dg, + (double *) NULL, 1, &ecount, &elist); + if (rval) { + fprintf (stderr, "CCedgegen_junk_k_nearest failed\n"); + return rval; + } + } + eg->adj = CC_SAFE_MALLOC (ncount, CCtsp_genadj); + if (!eg->adj) { + fprintf (stderr, "out of memory in init_edgegenerator\n"); + CC_IFFREE (elist, int); + return 1; + } + for (i = 0; i < ncount; i++) + eg->adj[i].deg = 0; + for (i = 0; i < ecount; i++) { + if (elist[2*i] > elist[2*i + 1]) { + CC_SWAP (elist[2*i], elist[2*i + 1], k); + } + eg->adj[elist[2*i]].deg++; + } + + eg->adjobjspace = CC_SAFE_MALLOC (ecount, CCtsp_genadjobj); + if (!eg->adjobjspace) { + fprintf (stderr, "out of memory in init_edgegenerator\n"); + CC_IFFREE (elist, int); + CC_IFFREE (eg->adj, CCtsp_genadj); + return 1; + } + + padj = eg->adjobjspace; + for (i = 0; i < ncount; i++) { + eg->adj[i].list = padj; + padj += eg->adj[i].deg; + eg->adj[i].deg = 0; + } + for (i = 0; i < ecount; i++) { + k = elist[2*i]; + eg->adj[k].list[eg->adj[k].deg].end = elist[2*i + 1]; + eg->adj[k].list[eg->adj[k].deg].len = + CCutil_dat_edgelen (k, elist[2*i + 1], dg); + eg->adj[k].deg++; + } + CC_IFFREE (elist, int); + } else { + eg->supplycount = 0; + eg->supplyhead = 0; + eg->supply = CC_SAFE_MALLOC (eg->nneighbors, int); + if (!eg->supply) { + fprintf (stderr, "out of memory in init_edgegenerator\n"); + return 1; + } + + if ((dg->norm & CC_NORM_BITS) == CC_KD_NORM_TYPE) { + eg->kdtree = CC_SAFE_MALLOC (1, CCkdtree); + if (!eg->kdtree) { + fprintf (stderr, "out of memory in init_edgegenerator\n"); + CC_FREE (eg->supply, int); + return 1; + } + rval = CCkdtree_build (eg->kdtree, ncount, dg, + (double *) NULL); + if (rval) { + fprintf (stderr, "CCkdtree_build failed\n"); + CC_FREE (eg->kdtree, CCkdtree); + CC_FREE (eg->supply, int); + return rval; + } + } else if ((dg->norm & CC_NORM_BITS) == CC_X_NORM_TYPE) { + eg->xnear = CC_SAFE_MALLOC (1, CCxnear); + if (!eg->xnear) { + fprintf (stderr, "out of memory in init_edgegenerator\n"); + CC_FREE (eg->supply, int); + return 1; + } + rval = CCedgegen_xnear_build (ncount, dg, (double *) NULL, + eg->xnear); + if (rval) { + fprintf (stderr, "CCedgegen_xnear_build failed\n"); + CC_FREE (eg->xnear, CCxnear); + CC_FREE (eg->supply, int); + return rval; + } + } + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_edgegenerator (CCtsp_edgegenerator *eg) +#else +void CCtsp_free_edgegenerator (eg) +CCtsp_edgegenerator *eg; +#endif +{ + printf ("free_edgegenerator\n"); fflush (stdout); + + CC_IFFREE (eg->supply, int); + + if (eg->kdtree) + CCkdtree_free (eg->kdtree); + if (eg->xnear) + CCedgegen_xnear_free (eg->ncount, eg->xnear); + if (eg->xprice) { + xprice_free (eg->xprice); + CC_FREE (eg->xprice, CCtsp_xnorm_pricer); + } + if (eg->adjobjspace) { + CC_FREE (eg->adjobjspace, CCtsp_genadjobj); + CC_IFFREE (eg->adj, CCtsp_genadj); + } + + eg->dg = (CCdatagroup *) NULL; + eg->node_piest = (double *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_reset_edgegenerator (CCtsp_edgegenerator *eg, double *node_piest) +#else +int CCtsp_reset_edgegenerator (eg, node_piest) +CCtsp_edgegenerator *eg; +double *node_piest; +#endif +{ + printf ("reset_edgegenerator\n"); fflush (stdout); + + eg->node_piest = node_piest; + if (eg->nneighbors == CCtsp_PRICE_COMPLETE_GRAPH) { + eg->start = eg->current; + eg->supplyhead = -1; + if (eg->xprice) { + if (xprice_reset (eg->xprice, node_piest, eg->current)) { + fprintf (stderr, "xprice_reset failed\n"); + return 1; + } + eg->supplycount = 0; + } + } else { + eg->start = eg->current; + eg->supplycount = 0; + eg->supplyhead = -1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_generate_edges (CCtsp_edgegenerator *eg, int nwant, int *pngot, + int *elist, int *elen, int *finished) +#else +int CCtsp_generate_edges (eg, nwant, pngot, elist, elen, finished) +CCtsp_edgegenerator *eg; +int nwant; +int *pngot; +int *elist; +int *elen; +int *finished; +#endif +{ + int len, end; + int ngot = 0; + int rval; + + printf ("generate_edges (%d)\n", nwant); fflush (stdout); + + *finished = 0; + *pngot = 0; + if (!eg->node_piest) { + fprintf (stderr, "generate, but no node_piest\n"); + return 1; + } + + if (eg->nneighbors == CCtsp_PRICE_COMPLETE_GRAPH) { + if (eg->xprice) { + int *supply = eg->supply; + int supplyhead = eg->supplyhead; + int supplycount = eg->supplycount; + int current = eg->current; + int realcurrent; + + while (ngot < nwant) { + if (supplyhead == supplycount || supplyhead == -1) { + if (supplyhead != -1) { + current++; + if (current >= eg->ncount) + current = 0; + if (current == eg->start) { + *pngot = ngot; + *finished = 1; + eg->supplyhead = supplyhead; + eg->supplycount = supplycount; + eg->current = current; + return 0; + } + if (current == 0) { + rval = xprice_reset (eg->xprice, eg->node_piest, 0); + if (rval) { + fprintf (stderr, "xprice_reset failed\n"); + return rval; + } + } + } + rval = xprice_node (eg->xprice, current, &supplycount, + supply); + if (rval) { + fprintf (stderr, "xprice_node failed\n"); + return rval; + } + supplyhead = 0; + } + realcurrent = eg->xprice->order[current]; + while (supplyhead < supplycount && ngot < nwant) { + len = CCutil_dat_edgelen (realcurrent, supply[supplyhead], + eg->dg); + if (((double) len) - eg->node_piest[realcurrent] + - eg->node_piest[supply[supplyhead]] < + CCtsp_GEN_PRICE_EPSILON) { + elist[ngot*2] = realcurrent; + elist[ngot*2+1] = supply[supplyhead]; + elen[ngot] = len; + ngot++; + if (ngot % 100000 == 0) { + printf ("Y[%d]", current); + fflush (stdout); + } + } + supplyhead++; + } + } + eg->supplyhead = supplyhead; + eg->supplycount = supplycount; + eg->current = current; + } else { + int supplyhead = eg->supplyhead; + int current = eg->current; + int ncount = eg->ncount; + + while (ngot < nwant) { + if (supplyhead == ncount || supplyhead == -1) { + if (supplyhead != -1) { + current++; + if (current >= ncount) + current = 0; + if (current == eg->start) { + *pngot = ngot; + *finished = 1; + eg->supplyhead = supplyhead; + eg->current = current; + return 0; + } + } + supplyhead = current + 1; + } + if (supplyhead < ncount) { + if (current == 0 && supplyhead == 15) { + printf ("EVALUATE (0,15): \n"); fflush (stdout); + len = CCutil_dat_edgelen (current, supplyhead, eg->dg); + printf (" Length: %d\n", len); + printf (" Estimate: %f\n", + len - eg->node_piest[current] + - eg->node_piest[supplyhead]); + if (len - eg->node_piest[current] - + eg->node_piest[supplyhead] < + CCtsp_GEN_PRICE_EPSILON) { + printf (" TAKE IT\n"); + } else { + printf (" LEAVE IT\n"); + } + fflush (stdout); + } + len = CCutil_dat_edgelen (current, supplyhead, eg->dg); + if (len - eg->node_piest[current] - + eg->node_piest[supplyhead] < + CCtsp_GEN_PRICE_EPSILON) { + elist[ngot*2] = current; + elist[ngot*2+1] = supplyhead; + elen[ngot] = len; + if (current == 0 && supplyhead == 15) { + printf (" GRAB 0 15: %d\n", ngot); + fflush (stdout); + } + ngot++; + } + supplyhead++; + } + } + eg->supplyhead = supplyhead; + eg->current = current; + } + } else if (eg->adj) { + int supplyhead = eg->supplyhead; + int supplycount = eg->supplycount; + int current = eg->current; + CCtsp_genadj *currentadj; + + while (ngot < nwant) { + if (supplyhead == supplycount || supplyhead == -1) { + if (supplyhead != -1) { + current++; + if (current >= eg->ncount) + current = 0; + if (current == eg->start) { + *pngot = ngot; + *finished = 1; + eg->supplyhead = supplyhead; + eg->supplycount = supplycount; + eg->current = current; + return 0; + } + } + supplyhead = 0; + supplycount = eg->adj[current].deg; + } + currentadj = &(eg->adj[current]); + while (supplyhead < supplycount && ngot < nwant) { + end = currentadj->list[supplyhead].end; + len = currentadj->list[supplyhead].len; + if (((double) len) - eg->node_piest[current] - + eg->node_piest[end] < CCtsp_GEN_PRICE_EPSILON) { + elist[ngot*2] = current; + elist[ngot*2+1] = end; + elen[ngot] = len; + ngot++; + } + supplyhead++; + } + } + eg->supplyhead = supplyhead; + eg->supplycount = supplycount; + eg->current = current; + } else { + int *supply = eg->supply; + int supplyhead = eg->supplyhead; + int supplycount = eg->supplycount; + int current = eg->current; + + while (ngot < nwant) { + if (supplyhead == supplycount || supplyhead == -1) { + if (supplyhead != -1) { + current++; + if (current >= eg->ncount) + current = 0; + if (current == eg->start) { + *pngot = ngot; + *finished = 1; + eg->supplyhead = supplyhead; + eg->supplycount = supplycount; + eg->current = current; + return 0; + } + } + if (eg->kdtree) { + rval = CCkdtree_node_k_nearest (eg->kdtree, eg->ncount, + current, eg->nneighbors, eg->dg, (double *) NULL, + supply); + if (rval) { + fprintf (stderr, "CCkdtree_node_k_nearest failed\n"); + return rval; + } + } else if (eg->xnear) { + rval = CCedgegen_x_node_k_nearest (eg->xnear, current, + eg->nneighbors, eg->ncount, supply); + if (rval) { + fprintf (stderr, "CCedgegen_x_node_k_nearest failed\n"); + return 1; + } + } else { + rval = CCedgegen_junk_node_k_nearest (eg->dg, + (double *) NULL, current, eg->nneighbors, + eg->ncount, supply); + if (rval) { + fprintf (stderr, "junk_node_k_nearest failed\n"); + return 1; + } + } + supplyhead = 0; + supplycount = eg->nneighbors; + } + + if (supply[supplyhead] > current) { + len = CCutil_dat_edgelen (current, supply[supplyhead], eg->dg); + if (((double) len) - eg->node_piest[current] - + eg->node_piest[supply[supplyhead]] < + CCtsp_GEN_PRICE_EPSILON) { + elist[ngot*2] = current; + elist[ngot*2+1] = supply[supplyhead]; + elen[ngot] = len; + ngot++; + } + } + supplyhead++; + } + eg->supplyhead = supplyhead; + eg->supplycount = supplycount; + eg->current = current; + } + + *pngot = ngot; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int xprice_build (int ncount, CCdatagroup *dat, CCtsp_xnorm_pricer *xp) +#else +static int xprice_build (ncount, dat, xp) +int ncount; +CCdatagroup *dat; +CCtsp_xnorm_pricer *xp; +#endif +{ + int i; + + printf ("xprice_build\n"); + fflush (stdout); + + xp->pi = (double *) NULL; + xp->order = (int *) NULL; + xp->xminuspi = (CCtsp_xnorm_pricer_val *) NULL; + xp->xminuspi_space = (CCtsp_xnorm_pricer_val *) NULL; + xp->invxminuspi = (int *) NULL; + + if (((dat->norm) & CC_NORM_BITS) != CC_KD_NORM_TYPE && + ((dat->norm) & CC_NORM_BITS) != CC_X_NORM_TYPE) { + fprintf (stderr, "cannot run xprice_build with norm %d\n", dat->norm); + xprice_free (xp); + return 1; + } + + xp->ncount = ncount; + xp->dat = dat; + + xp->pi = CC_SAFE_MALLOC (ncount, double); + if (!xp->pi) { + fprintf (stderr, "out of memory in xprice_build\n"); + xprice_free (xp); + return 1; + } + + xp->order = CC_SAFE_MALLOC (ncount, int); + if (!xp->order) { + fprintf (stderr, "out of memory in xprice_build\n"); + xprice_free (xp); + return 1; + } + for (i = 0; i < ncount; i++) + xp->order[i] = i; + CCutil_double_perm_quicksort (xp->order, dat->x, ncount); + + xp->xminuspi_space = CC_SAFE_MALLOC (ncount + 1, CCtsp_xnorm_pricer_val); + if (!xp->xminuspi_space) { + fprintf (stderr, "out of memory in xprice_build\n"); + xprice_free (xp); + return 1; + } + + xp->invxminuspi = CC_SAFE_MALLOC (ncount, int); + if (!xp->invxminuspi) { + fprintf (stderr, "out of memory in xprice_build\n"); + xprice_free (xp); + return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int xprice_reset (CCtsp_xnorm_pricer *xp, double *pi, int currentnode) +#else +static int xprice_reset (xp, pi, currentnode) +CCtsp_xnorm_pricer *xp; +double *pi; +int currentnode; +#endif +{ + int i; + double *xpi = (double *) NULL; + int *xpiperm = (int *) NULL; + int count = xp->ncount - currentnode; + int rval = 0; + + printf ("xprice_reset (%d)\n", currentnode); + fflush (stdout); + + for (i = 0; i < xp->ncount; i++) + xp->pi[i] = pi[i]; + + xpi = CC_SAFE_MALLOC (count, double); + xpiperm = CC_SAFE_MALLOC (count, int); + if (!xpi || !xpiperm) { + fprintf (stderr, "out of memory in xprice_build\n"); + rval = 1; + goto CLEANUP; + } + + if (xp->dat->norm == CC_GEOGRAPHIC) { + for (i = 0; i < count; i++) { + xpi[i] = + (CC_GEOGRAPHIC_SCALE * xp->dat->x[xp->order[i + currentnode]]) - + pi[xp->order[i + currentnode]]; + xpiperm[i] = i; + } + } else if (xp->dat->norm == CC_ATT) { + for (i = 0; i < count; i++) { + xpi[i] = + (CC_ATT_SCALE * xp->dat->x[xp->order[i + currentnode]]) - + pi[xp->order[i + currentnode]]; + xpiperm[i] = i; + } + } else { + for (i = 0; i < count; i++) { + xpi[i] = xp->dat->x[xp->order[i + currentnode]] - + pi[xp->order[i + currentnode]]; + xpiperm[i] = i; + } + } + + CCutil_double_perm_quicksort (xpiperm, xpi, count); + for (i = 0; i < count; i++) + xp->invxminuspi[xp->order[xpiperm[i] + currentnode]] = i; + + for (i = 1; i < count - 1; i++) { + xp->xminuspi_space[i].val = xpi[xpiperm[i]]; + xp->xminuspi_space[i].index = xp->order[xpiperm[i] + currentnode]; + xp->xminuspi_space[i].next = &(xp->xminuspi_space[i + 1]); + xp->xminuspi_space[i].prev = &(xp->xminuspi_space[i - 1]); + } + xp->xminuspi_space[0].val = xpi[xpiperm[0]]; + xp->xminuspi_space[0].index = xp->order[xpiperm[0] + currentnode]; + xp->xminuspi_space[0].next = &(xp->xminuspi_space[1]); + xp->xminuspi_space[0].prev = (CCtsp_xnorm_pricer_val *) NULL; + xp->xminuspi_space[count - 1].val = xpi[xpiperm[count - 1]]; + xp->xminuspi_space[count - 1].index = + xp->order[xpiperm[count - 1] + currentnode]; + xp->xminuspi_space[count - 1].next = &(xp->xminuspi_space[count]); + xp->xminuspi_space[count - 1].prev = &(xp->xminuspi_space[count - 2]); + xp->xminuspi_space[count].val = 1e30; /* This anchors the linked list */ + xp->xminuspi_space[count].next = (CCtsp_xnorm_pricer_val *) NULL; + xp->xminuspi_space[count].prev = &(xp->xminuspi_space[count - 1]); + xp->xminuspi = xp->xminuspi_space; + +CLEANUP: + + CC_IFFREE (xpi, double); + CC_IFFREE (xpiperm, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int xprice_node (CCtsp_xnorm_pricer *xp, int n, int *count, int *nlist) +#else +static int xprice_node (xp, n, count, nlist) +CCtsp_xnorm_pricer *xp; +int n; +int *count; +int *nlist; +#endif +{ + int k; + double kval; + CCtsp_xnorm_pricer_val *xnp; + double scale; + + if (xp->dat->norm == CC_GEOGRAPHIC) + scale = CC_GEOGRAPHIC_SCALE; + else if (xp->dat->norm == CC_ATT) + scale = CC_ATT_SCALE; + else + scale = 1.0; + + *count = 0; + + k = xp->order[n]; + kval = xp->pi[k] + (scale * xp->dat->x[k]); + + xnp = xp->xminuspi_space + xp->invxminuspi[k]; /* Delete node k */ + if (xnp == xp->xminuspi) + xp->xminuspi = xnp->next; + else + xnp->prev->next = xnp->next; + xnp->next->prev = xnp->prev; + + for (xnp = xp->xminuspi; xnp->val < kval; xnp = xnp->next) + nlist[(*count)++] = xnp->index; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void xprice_free (CCtsp_xnorm_pricer *xp) +#else +static void xprice_free (xp) +CCtsp_xnorm_pricer *xp; +#endif +{ + if (xp->order) + CC_FREE (xp->order, int); + if (xp->pi) + CC_FREE (xp->pi, double); + if (xp->xminuspi_space) + CC_FREE (xp->xminuspi_space, CCtsp_xnorm_pricer_val); + if (xp->invxminuspi) + CC_FREE (xp->invxminuspi, int); + xp->ncount = 0; + xp->dat = (CCdatagroup *) NULL; + xp->xminuspi = (CCtsp_xnorm_pricer_val *) NULL; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_edgelist_to_genadj (int ncount, int ecount, int *elist, int *elen, + CCtsp_genadj **adj, CCtsp_genadjobj **adjobjspace) +#else +int CCtsp_edgelist_to_genadj (ncount, ecount, elist, elen, adj, adjobjspace) +int ncount; +int ecount; +int *elist; +int *elen; +CCtsp_genadj **adj; +CCtsp_genadjobj **adjobjspace; +#endif +{ + int i, k, k1, k2; + CCtsp_genadj *a; + CCtsp_genadjobj *p; + + *adj = CC_SAFE_MALLOC (ncount, CCtsp_genadj); + if (!(*adj)) { + fprintf (stderr, "out of memory in edgelist_to_genadj\n"); + return 1; + } + a = *adj; + + for (i = 0; i < ncount; i++) + a[i].deg = 0; + for (i = 0; i < ecount; i++) { + if (elist[2*i] > elist[2*i + 1]) + a[elist[2*i + 1]].deg++; + else + a[elist[2*i]].deg++; + } + + *adjobjspace = CC_SAFE_MALLOC (ecount, CCtsp_genadjobj); + if (!(*adjobjspace)) { + fprintf (stderr, "out of memory in edgelist_to_genadj\n"); + CC_IFFREE (*adj, CCtsp_genadj); + return 1; + } + + p = *adjobjspace; + for (i = 0; i < ncount; i++) { + a[i].list = p; + p += a[i].deg; + a[i].deg = 0; + } + for (i = 0; i < ecount; i++) { + k1 = elist[2*i]; + k2 = elist[2*i + 1]; + if (k1 > k2) { + CC_SWAP (k1, k2, k); + } + a[k1].list[a[k1].deg].end = k2; + a[k1].list[a[k1].deg].len = elen[i]; + a[k1].deg++; + } + + return 0; +} diff --git a/contrib/blossom/concorde97/TSP/poolcat.c b/contrib/blossom/concorde97/TSP/poolcat.c new file mode 100644 index 0000000000000000000000000000000000000000..ea343e08b6c7667c5adaf98663d7d2a70b2d74ba --- /dev/null +++ b/contrib/blossom/concorde97/TSP/poolcat.c @@ -0,0 +1,288 @@ +/***************************************************************************/ +/* */ +/* MERGE CUTPOOLS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: May 2, 1997 */ +/* */ +/* SEE short decsribtion in usage (). */ +/* */ +/* Link with: */ +/* SEE Makefile */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" + +static int seed = 0; + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int ac, char **av); + +static void + usage (char *f); + +#else + +int + main (); + +static void + usage (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + double szeit; + int i, k, count; + CCtsp_lpcut_in *c, *cnext; + CCtsp_lpcut_in *cuts = (CCtsp_lpcut_in *) NULL; + CCtsp_lpcuts *pool = (CCtsp_lpcuts *) NULL; + CCtsp_lpcuts *nextpool = (CCtsp_lpcuts *) NULL; + CC_SFILE *in; + int ncount; + int textout, textin; + int *ptour = (int *) NULL; + int *qtour = (int *) NULL; + int *perm = (int *) NULL; + int rval = 0; + + if (ac < 2) { + usage (*av); + return 0; + } + + szeit = CCutil_zeit (); + seed = (int) CCutil_real_zeit (); + CCutil_sprand (seed); + + k = 1; + if (av[k][0] == '-' && av[k][1] == 't') { + CCdatagroup dat; + printf ("Read master ...\n"); + if (CCutil_getmaster (av[k+1], &ncount, &dat, &ptour)) { + fprintf (stderr, "CCutil_getmaster failed\n"); + return 1; + } + CCutil_freedatagroup (ncount, &dat); + textout = 1; + k += 2; + } else { + textout = 0; + } + + if (av[k][0] == '-' && av[k][1] == 's') { + CCdatagroup dat; + printf ("Read master ...\n"); + if (CCutil_getmaster (av[k+1], &ncount, &dat, &qtour)) { + fprintf (stderr, "CCutil_getmaster failed\n"); + return 1; + } + CCutil_freedatagroup (ncount, &dat); + textin = 1; + k += 2; + } else { + textin = 0; + } + + if (av[k][0] == '-' && av[k][1] == 'p') { + FILE *tin = fopen (av[k+1], "r"); + + printf ("Read permutation tour ...\n"); + if (!tin) { + fprintf (stderr, "could not open %s for reading\n", av[k+1]); + rval = 1; goto CLEANUP; + } + + if (fscanf (tin, "%d", &ncount) != 1) { + fprintf (stderr, "perm file in wrong format\n"); + rval = 1; fclose (tin); goto CLEANUP; + } + perm = CC_SAFE_MALLOC (ncount, int); + if (!perm) { + fprintf (stderr, "out of memory in main\n"); + rval = 1; fclose (tin); goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + if (fscanf (tin, "%d", &(perm[i])) != 1) { + fprintf (stderr, "perm file in wrong format\n"); + rval = 1; fclose (tin); goto CLEANUP; + } + } + fclose (tin); + k += 2; + } + + if (textin) { + printf ("Number of Nodes: %d\n", ncount); fflush (stdout); + + rval = CCtsp_init_cutpool (ncount, (char *) NULL, &pool); + if (rval) { + fprintf (stderr, "CCtsp_init_cutpool failed\n"); goto CLEANUP; + } + + cuts = (CCtsp_lpcut_in *) NULL; + rval = CCtsp_file_cuts (av[k], &cuts, &count, ncount, qtour); + if (rval) { + fprintf (stderr, "CCtsp_file_cuts failed\n"); goto CLEANUP; + } + printf ("File has %d cuts\n", count); fflush (stdout); + for (c = cuts; c; c = cnext) { + cnext = c->next; + rval = CCtsp_add_to_cutpool_lpcut_in (pool, c); + if (rval) { + fprintf (stderr, "CCtsp_add_to_cutpool_lpcut_in failed\n"); + goto CLEANUP; + } + CCtsp_free_lpcut_in (c); + CC_FREE (c, CCtsp_lpcut_in); + } + k++; + } else { + in = CCutil_sopen (av[k], "r"); + if (!in) { + fprintf (stderr, "sopen failed\n"); goto CLEANUP; + } + if (CCutil_sread_int (in, (unsigned int *) &ncount)) { + fprintf (stderr, "CCutil_sread_int failed\n"); + CCutil_sclose (in); + return 1; + } + CCutil_sclose (in); + printf ("Number of Nodes: %d\n", ncount); fflush (stdout); + + rval = CCtsp_init_cutpool (ncount, av[k], &pool); + if (rval) { + fprintf (stderr, "CCtsp_init_cutpool failed\n"); goto CLEANUP; + } + printf ("Initial Pool: %d cuts\n", pool->cutcount); + fflush (stdout); + k++; + } + + for (; k < ac; k++) { + printf ("Adding Pool %s ... ", av[k]); + fflush (stdout); + + if (textin) { + cuts = (CCtsp_lpcut_in *) NULL; + rval = CCtsp_file_cuts (av[k], &cuts, &count, ncount, qtour); + if (rval) { + fprintf (stderr, "CCtsp_file_cuts failed\n"); goto CLEANUP; + } + for (c = cuts; c; c = cnext) { + cnext = c->next; + rval = CCtsp_add_to_cutpool_lpcut_in (pool, c); + if (rval) { + fprintf (stderr, "CCtsp_add_to_cutpool_lpcut_in failed\n"); + goto CLEANUP; + } + CCtsp_free_lpcut_in (c); + CC_FREE (c, CCtsp_lpcut_in); + } + } else { + rval = CCtsp_init_cutpool (ncount, av[k], &nextpool); + if (rval) { + fprintf (stderr, "CCtsp_init_cutpool failed\n"); goto CLEANUP; + } + + for (i = 0; i < nextpool->cutcount; i++) { + rval = CCtsp_add_to_cutpool (pool, nextpool, + &(nextpool->cuts[i])); + if (rval) { + fprintf (stderr, "CCtsp_add_to_cutpool failed\n"); + goto CLEANUP; + } + } + CCtsp_free_cutpool (&nextpool); + } + printf ("%d\n", pool->cutcount); fflush (stdout); + } + + + printf ("Final Pool: %d cuts\n", pool->cutcount); + fflush (stdout); + + if (textout) { + printf ("Write text file ...\n"); fflush (stdout); + if (perm) { + int *pperm = (int *) NULL; + + pperm = CC_SAFE_MALLOC (ncount, int); + if (!pperm) { + fprintf (stderr, "out of memory in main\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + pperm[i] = perm[ptour[i]]; + } + for (i = 0; i < ncount; i++) { + ptour[i] = pperm[i]; + } + CC_FREE (pperm, int); + } + rval = CCtsp_file_cuts_write ("merge.txt", pool, ptour); + if (rval) { + fprintf (stderr, "CCtsp_file_cuts_write failed\n"); + goto CLEANUP; + } + } else { + rval = CCtsp_write_cutpool (ncount, "merge.pul", pool); + if (rval) { + fprintf (stderr, "CCtsp_write_cutpool failed\n"); + goto CLEANUP; + } + } + + printf ("Running Time: %.2f seconds\n", CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + if (pool) { + CCtsp_free_cutpool (&pool); + } + if (nextpool) { + CCtsp_free_cutpool (&nextpool); + } + if (CCutil_bigchunk_free_world ()) { + fprintf (stderr, "ERROR: CCutil_bigchunk_free_world failed\n"); + return 1; + } + CC_IFFREE (ptour, int); + CC_IFFREE (qtour, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "Usage: %s [-t] pool1 pool2 ... \n", f); + fprintf (stderr, " -t f: to write a text file specify a master\n"); + fprintf (stderr, " -p f: to permute nodes when writing text\n"); + fprintf (stderr, " -s f: to read text files specify a master\n"); + fprintf (stderr, "Note: merged pool will be written merge.pul (.txt)\n"); + fprintf (stderr, " the master files are used to map the nodes\n"); + fprintf (stderr, " the permuation given by p can be used to\n"); + fprintf (stderr, " handle the different node orders in dat and tsp\n"); +} diff --git a/contrib/blossom/concorde97/TSP/prob_io.c b/contrib/blossom/concorde97/TSP/prob_io.c new file mode 100644 index 0000000000000000000000000000000000000000..dc6ce512a78b9c1779c947c96997445bdfdae672 --- /dev/null +++ b/contrib/blossom/concorde97/TSP/prob_io.c @@ -0,0 +1,1741 @@ +/**************************************************************************/ +/* */ +/* Date: April 19, 1996 (dave) */ +/* August 28, 1996 (bico) */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* CCtsp_PROB_FILE */ +/* *CCtsp_prob_read (char *f, int n), */ +/* *CCtsp_prob_read_name (char *f), */ +/* *CCtsp_prob_write (char *f, int n); */ +/* *CCtsp_prob_write_name (char *fname, char *pname); */ +/* */ +/* int */ +/* CCtsp_prob_file_delete (char *f, int n), */ +/* CCtsp_prob_getname (CCtsp_PROB_FILE *p, char *name), */ +/* CCtsp_prob_getid (CCtsp_PROB_FILE *p, int *id), */ +/* CCtsp_prob_getparent (CCtsp_PROB_FILE *p, int *parent), */ +/* CCtsp_prob_getub (CCtsp_PROB_FILE *p, double *ub), */ +/* CCtsp_prob_getlb (CCtsp_PROB_FILE *p, double *lb), */ +/* CCtsp_prob_getexactlb (CCtsp_PROB_FILE *p, CCbigguy *lb), */ +/* CCtsp_prob_getnnodes (CCtsp_PROB_FILE *p, int *nnodes), */ +/* CCtsp_prob_getchildren (CCtsp_PROB_FILE *p, int *child0, */ +/* int *child1), */ +/* CCtsp_prob_getreal (CCtsp_PROB_FILE *p, int *real), */ +/* CCtsp_prob_getprocessed (CCtsp_PROB_FILE *p, int *processed), */ +/* CCtsp_prob_getinfeasible (CCtsp_PROB_FILE *p, int *infeasible), */ +/* CCtsp_prob_gettour (CCtsp_PROB_FILE *p, int **tour), */ +/* CCtsp_prob_getedges (CCtsp_PROB_FILE *p, int *nedges, int **elist, */ +/* int **elen), */ +/* CCtsp_prob_getcuts (CCtsp_PROB_FILE *p, CCtsp_lp *lp); */ +/* CCtsp_prob_getbasis (CCtsp_PROB_FILE *p, int *ccount, int *rcount, */ +/* int **cstat, int **rstat), */ +/* CCtsp_prob_getnorms (CCtsp_PROB_FILE *p, int *rcount, */ +/* double **dnorm), */ +/* CCtsp_prob_getexactdual (CCtsp_PROB_FILE *p, ncount, */ +/* CCtsp_bigdual **d) */ +/* CCtsp_prob_gethistory (CCtsp_PROB_FILE *p, int *depth, */ +/* CCtsp_branchobj **history) */ +/* CCtsp_prob_rclose (CCtsp_PROB_FILE *p), */ +/* */ +/* CCtsp_prob_putname (CCtsp_PROB_FILE *p, char *name), */ +/* CCtsp_prob_putid (CCtsp_PROB_FILE *p, int id), */ +/* CCtsp_prob_putparent (CCtsp_PROB_FILE *p, int parent), */ +/* CCtsp_prob_putub (CCtsp_PROB_FILE *p, double ub), */ +/* CCtsp_prob_putlb (CCtsp_PROB_FILE *p, double lb), */ +/* CCtsp_prob_putexactlb (CCtsp_PROB_FILE *p, CCbigguy lb), */ +/* CCtsp_prob_putnnodes (CCtsp_PROB_FILE *p, int nnodes), */ +/* CCtsp_prob_putchildren (CCtsp_PROB_FILE *p, int child0, */ +/* int child1), */ +/* CCtsp_prob_putreal (CCtsp_PROB_FILE *p, int real), */ +/* CCtsp_prob_putprocessed (CCtsp_PROB_FILE *p, int processed), */ +/* CCtsp_prob_putinfeasible (CCtsp_PROB_FILE *p, int infeasible), */ +/* CCtsp_prob_puttour (CCtsp_PROB_FILE *p, int *tour), */ +/* CCtsp_prob_putedges (CCtsp_PROB_FILE *p, int ecount, int *elist, */ +/* int *elen); */ +/* CCtsp_prob_putcuts (CCtsp_PROB_FILE *p, CCtsp_lp *lp); */ +/* CCtsp_prob_putbasis (CCtsp_PROB_FILE *p, int ccount, int rcount, */ +/* int *cstat, int *rstat), */ +/* CCtsp_prob_putnorms (CCtsp_PROB_FILE *p, int rcount, double *dnorm)*/ +/* CCtsp_prob_putexact_dual (CCtsp_PROB_FILE *p, */ +/* CCtsp_bigdual *exact_dual) */ +/* CCtsp_prob_puthistory (CCtsp_PROB_FILE *p, int depth, */ +/* CCtsp_branchobj *history) */ +/* CCtsp_prob_wclose (CCtsp_PROB_FILE *p), */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" +#include "bigguy.h" + +#ifdef CC_PROTOTYPE_ANSI + +static int + prob_name (char *buf, int buflen, char *f, int n), + write_header (CCtsp_PROB_FILE *p); + +static void + prob_init (CCtsp_PROB_FILE *p); + +#else + +static int + prob_name (), + write_header (); + +static void + prob_init (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_file_delete (char *f, int n) +#else +int CCtsp_prob_file_delete (f, n) +char *f; +int n; +#endif +{ + char nambuf[1024]; + int sval; + + if (prob_name (nambuf, sizeof (nambuf), f, n)) return 1; + printf ("Delete file: %s\n", nambuf); + fflush (stdout); + sval = CCutil_sdelete_file (nambuf); + if (sval) { + printf ("Prob file %s could not be deleted\n", nambuf); + fflush (stdout); + } + sval = CCutil_sdelete_file_backup (nambuf); + if (!sval) { + printf ("Deleted backup to file: %s\n", nambuf); + fflush (stdout); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +CCtsp_PROB_FILE *CCtsp_prob_read (char *f, int n) +#else +CCtsp_PROB_FILE *CCtsp_prob_read (f, n) +char *f; +int n; +#endif +{ + char nambuf[1024]; + + if (prob_name (nambuf, sizeof (nambuf), f, n)) + return (CCtsp_PROB_FILE *) NULL; + + return CCtsp_prob_read_name (nambuf); +} + +#ifdef CC_PROTOTYPE_ANSI +CCtsp_PROB_FILE *CCtsp_prob_read_name (char *f) +#else +CCtsp_PROB_FILE *CCtsp_prob_read_name (f) +char *f; +#endif +{ + CCtsp_PROB_FILE *p = (CCtsp_PROB_FILE *) NULL; + unsigned char version; + int i; + + printf ("Read File %s\n", f); fflush (stdout); + + p = CC_SAFE_MALLOC (1, CCtsp_PROB_FILE); + if (p == (CCtsp_PROB_FILE *) NULL) goto CLEANUP; + prob_init (p); + + p->f = CCutil_sopen (f, "r"); + if (!p->f) goto CLEANUP; + + if (CCutil_sread_char (p->f, &version)) goto CLEANUP; + for (i = 0; i < CCtsp_PROB_FILE_NAME_LEN; i++) + if (CCutil_sread_char (p->f, (unsigned char *) &p->name[i])) + goto CLEANUP; + + switch (version) { + case 1: + if (CCutil_sread_int (p->f, (unsigned int *) &p->parent)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->id)) + goto CLEANUP; + if (CCutil_sread_double (p->f, &p->ub)) + goto CLEANUP; + if (CCutil_sread_double (p->f, &p->lb)) + goto CLEANUP; + if (CCbigguy_sread (p->f, &p->exactlb)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->nnodes)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->child0)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->child1)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->real)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->processed)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->infeasible)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.dat)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.edge)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.fulladj)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.cut)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.tour)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.basis)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.norms)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.fix)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.exactdual)) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &p->offsets.history)) + goto CLEANUP; + break; + default: + fprintf (stderr, "Unknown problem version %ud\n", version); + goto CLEANUP; + } + return p; + + CLEANUP: + if (p) { + if (p->f) { + CCutil_sclose (p->f); + } + CC_FREE (p, CCtsp_PROB_FILE); + } + return (CCtsp_PROB_FILE *) NULL; +} + + +#ifdef CC_PROTOTYPE_ANSI +CCtsp_PROB_FILE *CCtsp_prob_write (char *f, int n) +#else +CCtsp_PROB_FILE *CCtsp_prob_write (f, n) +char *f; +int n; +#endif +{ + char nambuf[1024]; + + if (prob_name (nambuf, sizeof (nambuf), f, n)) + return (CCtsp_PROB_FILE *) NULL; + + return CCtsp_prob_write_name (nambuf, f); +} + +#ifdef CC_PROTOTYPE_ANSI +CCtsp_PROB_FILE *CCtsp_prob_write_name (char *fname, char *pname) +#else +CCtsp_PROB_FILE *CCtsp_prob_write_name (fname, pname) +char *fname, *pname; +#endif +{ + CCtsp_PROB_FILE *p = (CCtsp_PROB_FILE *) NULL; + int i; + + printf ("Write File %s\n", fname); fflush (stdout); + + p = CC_SAFE_MALLOC (1, CCtsp_PROB_FILE); + if (p == (CCtsp_PROB_FILE *) NULL) goto CLEANUP; + prob_init (p); + for (i = 0; pname[i] && i < CCtsp_PROB_FILE_NAME_LEN - 1; i++) + p->name[i] = pname[i]; + p->name[i] = '\0'; + + p->f = CCutil_sopen (fname, "w"); + if (!p->f) goto CLEANUP; + + if (write_header (p)) { + printf ("write_header failed\n"); + goto CLEANUP; + } + + return p; + +CLEANUP: + if (p) { + if (p->f) { + CCutil_sclose (p->f); + } + CC_FREE (p, CCtsp_PROB_FILE); + } + return (CCtsp_PROB_FILE *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static int write_header (CCtsp_PROB_FILE *p) +#else +static int write_header (p) +CCtsp_PROB_FILE *p; +#endif +{ + int i; + + if (CCutil_srewind (p->f)) return 1; + if (CCutil_swrite_char (p->f, (unsigned char) CCtsp_PROB_IO_VERSION)) return 1; + for (i = 0; i < CCtsp_PROB_FILE_NAME_LEN; i++) { + if (CCutil_swrite_char (p->f, (unsigned char) p->name[i])) return 1; + } + if (CCutil_swrite_int (p->f, (unsigned int) p->parent)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->id)) return 1; + if (CCutil_swrite_double (p->f, p->ub)) return 1; + if (CCutil_swrite_double (p->f, p->lb)) return 1; + if (CCbigguy_swrite (p->f, p->exactlb)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->nnodes)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->child0)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->child1)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->real)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->processed)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->infeasible)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.dat)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.edge)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.fulladj)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.cut)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.tour)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.basis)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.norms)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.fix)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.exactdual)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) p->offsets.history)) return 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int prob_name (char *buf, int buflen, char *f, int n) +#else +static int prob_name (buf, buflen, f, n) +char *buf; +int buflen; +char *f; +int n; +#endif +{ + int l = strlen(f); + int lastslash; + int i; + int d; + + if (l + 5 > buflen || n >= 1000 + 26*36*36 || n < 0) { + fprintf (stderr, "Cannot generate filename for %s node %d\n", + f, n); + return -1; + } + + for (i = 0, lastslash = -1; i < l; i++) { + if (f[i] == '/') lastslash = i; + buf[i] = f[i]; + } + if (l > lastslash + 9) l = lastslash + 9; + for (i = lastslash+1; i < l; i++) { + if (buf[i] == '.') buf[i] = '_'; + } + buf[l++] = '.'; + if (n < 1000) { + d = n/100; + buf[l++] = '0' + ((unsigned char) d); + n -= d*100; + d = n/10; + buf[l++] = '0' + ((unsigned char) d); + n -= d*10; + d = n; + buf[l++] = '0' + ((unsigned char) d); + } else { + n -= 1000; + d = n/1296; + buf[l++] = 'a' + ((unsigned char) d); + n -= d*1296; + d = n/36; + buf[l++] = (d < 10) ? '0'+((unsigned char) d) + : 'a'+((unsigned char) (d-10)); + n -= d*36; + d = n; + buf[l++] = (d < 10) ? '0'+((unsigned char) d) + : 'a'+((unsigned char) (d-10)); + } + buf[l] = '\0'; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void prob_init (CCtsp_PROB_FILE *p) +#else +static void prob_init (p) +CCtsp_PROB_FILE *p; +#endif +{ + int i; + + p->f = (CC_SFILE *) NULL; + for (i = 0; i < CCtsp_PROB_FILE_NAME_LEN; i++) + p->name[i] = '\0'; + p->id = -1; + p->parent = -1; + p->lb = -1.0; + p->ub = -1.0; + p->exactlb = CCbigguy_ZERO; + p->nnodes = -1; + p->child0 = -1; + p->child1 = -1; + p->real = -1; + p->processed = -1; + p->infeasible = -1; + p->offsets.dat = -1; + p->offsets.edge = -1; + p->offsets.fulladj = -1; + p->offsets.cut = -1; + p->offsets.tour = -1; + p->offsets.basis = -1; + p->offsets.norms = -1; + p->offsets.fix = -1; + p->offsets.exactdual = -1; + p->offsets.history = -1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_rclose (CCtsp_PROB_FILE *p) +#else +int CCtsp_prob_rclose (p) +CCtsp_PROB_FILE *p; +#endif +{ + int rval; + + rval = CCutil_sclose (p->f); + + CC_FREE (p, CCtsp_PROB_FILE); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_wclose (CCtsp_PROB_FILE *p) +#else +int CCtsp_prob_wclose (p) +CCtsp_PROB_FILE *p; +#endif +{ + int rval; + + rval = write_header (p); + if (rval) return rval; + + rval = CCutil_sclose (p->f); + + CC_FREE (p, CCtsp_PROB_FILE); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getname (CCtsp_PROB_FILE *p, char *name) +#else +int CCtsp_prob_getname (p, name) +CCtsp_PROB_FILE *p; +char *name; +#endif +{ + int i; + + if (!p) return -1; + + for (i = 0; i < CCtsp_PROB_FILE_NAME_LEN; i++) + name[i] = p->name[i]; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putname (CCtsp_PROB_FILE *p, char *name) +#else +int CCtsp_prob_putname (p, name) +CCtsp_PROB_FILE *p; +char *name; +#endif +{ + int i; + + if (!p) return 1; + + for (i = 0; name[i] && i < CCtsp_PROB_FILE_NAME_LEN - 1; i++) + p->name[i] = name[i]; + for (; i < CCtsp_PROB_FILE_NAME_LEN; i++) + p->name[i] = '\0'; + + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getid (CCtsp_PROB_FILE *p, int *id) +#else +int CCtsp_prob_getid (p, id) +CCtsp_PROB_FILE *p; +int *id; +#endif +{ + if (!p) return -1; + + *id = p->id; + if (*id == -1) { + printf ("Setting -1 ID to 0\n"); fflush (stdout); + *id = 0; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putid (CCtsp_PROB_FILE *p, int id) +#else +int CCtsp_prob_putid (p, id) +CCtsp_PROB_FILE *p; +int id; +#endif +{ + if (!p) return 1; + + p->id = id; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getparent (CCtsp_PROB_FILE *p, int *parent) +#else +int CCtsp_prob_getparent (p, parent) +CCtsp_PROB_FILE *p; +int *parent; +#endif +{ + if (!p) return -1; + + *parent = p->parent; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putparent (CCtsp_PROB_FILE *p, int parent) +#else +int CCtsp_prob_putparent (p, parent) +CCtsp_PROB_FILE *p; +int parent; +#endif +{ + if (!p) return 1; + + p->parent = parent; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getub (CCtsp_PROB_FILE *p, double *ub) +#else +int CCtsp_prob_getub (p, ub) +CCtsp_PROB_FILE *p; +double *ub; +#endif +{ + if (!p) return -1; + + *ub = p->ub; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putub (CCtsp_PROB_FILE *p, double ub) +#else +int CCtsp_prob_putub (p, ub) +CCtsp_PROB_FILE *p; +double ub; +#endif +{ + if (!p) return 1; + + p->ub = ub; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getlb (CCtsp_PROB_FILE *p, double *lb) +#else +int CCtsp_prob_getlb (p, lb) +CCtsp_PROB_FILE *p; +double *lb; +#endif +{ + if (!p) return -1; + + *lb = p->lb; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putlb (CCtsp_PROB_FILE *p, double lb) +#else +int CCtsp_prob_putlb (p, lb) +CCtsp_PROB_FILE *p; +double lb; +#endif +{ + if (!p) return 1; + + p->lb = lb; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getexactlb (CCtsp_PROB_FILE *p, CCbigguy *lb) +#else +int CCtsp_prob_getexactlb (p, lb) +CCtsp_PROB_FILE *p; +CCbigguy *lb; +#endif +{ + if (!p) return -1; + + *lb = p->exactlb; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putexactlb (CCtsp_PROB_FILE *p, CCbigguy lb) +#else +int CCtsp_prob_putexactlb (p, lb) +CCtsp_PROB_FILE *p; +CCbigguy lb; +#endif +{ + if (!p) return 1; + + p->exactlb = lb; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getnnodes (CCtsp_PROB_FILE *p, int *nnodes) +#else +int CCtsp_prob_getnnodes (p, nnodes) +CCtsp_PROB_FILE *p; +int *nnodes; +#endif +{ + if (!p) return -1; + + *nnodes = p->nnodes; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putnnodes (CCtsp_PROB_FILE *p, int nnodes) +#else +int CCtsp_prob_putnnodes (p, nnodes) +CCtsp_PROB_FILE *p; +int nnodes; +#endif +{ + if (!p) return 1; + + p->nnodes = nnodes; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getchildren (CCtsp_PROB_FILE *p, int *child0, int *child1) +#else +int CCtsp_prob_getchildren (p, child0, child1) +CCtsp_PROB_FILE *p; +int *child0, *child1; +#endif +{ + if (!p) return -1; + + *child0 = p->child0; + *child1 = p->child1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putchildren (CCtsp_PROB_FILE *p, int child0, int child1) +#else +int CCtsp_prob_putchildren (p, child0, child1) +CCtsp_PROB_FILE *p; +int child0, child1; +#endif +{ + if (!p) return 1; + + p->child0 = child0; + p->child1 = child1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getreal (CCtsp_PROB_FILE *p, int *real) +#else +int CCtsp_prob_getreal (p, real) +CCtsp_PROB_FILE *p; +int *real; +#endif +{ + if (!p) return -1; + + *real = p->real; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putreal (CCtsp_PROB_FILE *p, int real) +#else +int CCtsp_prob_putreal (p, real) +CCtsp_PROB_FILE *p; +int real; +#endif +{ + if (!p) return 1; + + p->real = real; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getprocessed (CCtsp_PROB_FILE *p, int *processed) +#else +int CCtsp_prob_getprocessed (p, processed) +CCtsp_PROB_FILE *p; +int *processed; +#endif +{ + if (!p) return -1; + + *processed = p->processed; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putprocessed (CCtsp_PROB_FILE *p, int processed) +#else +int CCtsp_prob_putprocessed (p, processed) +CCtsp_PROB_FILE *p; +int processed; +#endif +{ + if (!p) return 1; + + p->processed = processed; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getinfeasible (CCtsp_PROB_FILE *p, int *infeasible) +#else +int CCtsp_prob_getinfeasible (p, infeasible) +CCtsp_PROB_FILE *p; +int *infeasible; +#endif +{ + if (!p) return -1; + + *infeasible = p->infeasible; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putinfeasible (CCtsp_PROB_FILE *p, int infeasible) +#else +int CCtsp_prob_putinfeasible (p, infeasible) +CCtsp_PROB_FILE *p; +int infeasible; +#endif +{ + if (!p) return 1; + + p->infeasible = infeasible; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_puttour (CCtsp_PROB_FILE *p, int *tour) +#else +int CCtsp_prob_puttour (p, tour) +CCtsp_PROB_FILE *p; +int *tour; +#endif +{ + int i; + int ncount; + + if (!p) return 1; + + ncount = p->nnodes; + if (ncount <= 0) { + printf ("nnodes not set in CCtsp_prob_puttour\n"); + return 1; + } + p->offsets.tour = CCutil_stell (p->f); + for (i = 0; i < ncount; i++) { + if (CCutil_swrite_int (p->f, (unsigned int) tour[i])) + return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_gettour (CCtsp_PROB_FILE *p, int **tour) +#else +int CCtsp_prob_gettour (p, tour) +CCtsp_PROB_FILE *p; +int **tour; +#endif +{ + int i; + int ncount; + + if (!p) return -1; + + ncount = p->nnodes; + if (ncount <= 0) { + printf ("nnodes not set in CCtsp_prob_gettour\n"); + return 1; + } + if (p->offsets.tour == -1) { + printf ("No tour in file.\n"); + return 1; + } + if (CCutil_sseek (p->f, p->offsets.tour)) { + printf ("CCutil_sseek failed in CCtsp_prob_gettour\n"); + return -1; + } + + *tour = CC_SAFE_MALLOC (ncount, int); + if (!(*tour)) { + fprintf (stderr, "out of memory in CCtsp_prob_gettour\n"); + return -1; + } + + for (i = 0; i < ncount; i++) { + if (CCutil_sread_int (p->f, (unsigned int *) &((*tour)[i]))) { + CC_FREE (*tour, int); + return -1; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putedges (CCtsp_PROB_FILE *p, int ecount, int *elist, int *elen) +#else +int CCtsp_prob_putedges (p, ecount, elist, elen) +CCtsp_PROB_FILE *p; +int ecount; +int *elist, *elen; +#endif +{ + int i; + + if (!p) return 1; + + p->offsets.edge = CCutil_stell (p->f); + if (CCutil_swrite_int (p->f, (unsigned int) ecount)) + return 1; + for (i = 0; i < 2 * ecount; i++) { + if (CCutil_swrite_int (p->f, (unsigned int) elist[i])) + return 1; + } + for (i = 0; i < ecount; i++) { + if (CCutil_swrite_int (p->f, (unsigned int) elen[i])) + return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getedges (CCtsp_PROB_FILE *p, int *ecount, int **elist, int **elen) +#else +int CCtsp_prob_getedges (p, ecount, elist, elen) +CCtsp_PROB_FILE *p; +int *ecount; +int **elist, **elen; +#endif +{ + int i; + + if (!p) return -1; + + if (p->offsets.edge == -1) { + printf ("No edges in file.\n"); + return 1; + } + if (CCutil_sseek (p->f, p->offsets.edge)) { + printf ("CCutil_sseek failed in CCtsp_prob_getedges\n"); + return -1; + } + if (CCutil_sread_int (p->f, (unsigned int *) ecount)) + return -1; + + *elist = CC_SAFE_MALLOC (2 * (*ecount), int); + *elen = CC_SAFE_MALLOC (*ecount, int); + if (!(*elist) || !(*elen)) { + fprintf (stderr, "out of memory in CCtsp_prob_getedges\n"); + CC_IFFREE (*elist, int); + CC_IFFREE (*elen, int); + return -1; + } + + for (i = 0; i < 2 * (*ecount); i++) { + if (CCutil_sread_int (p->f, (unsigned int *) &((*elist)[i]))) { + CC_FREE (*elist, int); + CC_FREE (*elen, int); + return -1; + } + } + for (i = 0; i < *ecount; i++) { + if (CCutil_sread_int (p->f, (unsigned int *) &((*elen)[i]))) { + CC_FREE (*elist, int); + CC_FREE (*elen, int); + return -1; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putcuts (CCtsp_PROB_FILE *p, CC_SFILE *s, CCtsp_lpcuts *cuts) +#else +int CCtsp_prob_putcuts (p, s, cuts) +CCtsp_PROB_FILE *p; +CC_SFILE *s; +CCtsp_lpcuts *cuts; +#endif +{ + int *marks = (int *) NULL; + int cend = cuts->cliqueend; + int i, j, k; + CC_SFILE *f; + + if (!p && !s) return 1; + + if (p) { + p->offsets.cut = CCutil_stell (p->f); + f = p->f; + } else { + f = s; + } + + if (CCutil_swrite_int (f, (unsigned int) CCtsp_PROB_IO_CUTS_VERSION)) + return 1; + + if (cend) { + marks = CC_SAFE_MALLOC (cend, int); + if (!marks) { + fprintf (stderr, "out of memory in CCtsp_prob_putcut\n"); + return 1; + } + for (i = 0; i < cend; i++) + marks[i] = 0; + + for (i = 0; i < cuts->cutcount; i++) { + for (j = 0; j < cuts->cuts[i].cliquecount; j++) { + marks[cuts->cuts[i].cliques[j]]++; + } + } + for (i = 0, k = 1; i < cend; i++) { /* Start a 1 to avoid 0 as an index */ + if (marks[i]) { + if (marks[i] != cuts->cliques[i].refcount) { + fprintf (stderr, "SCREW UP in refcount for clique %d\n", i); + } + marks[i] = k++; + } + } + + for (i = 0; i < cend; i++) { + if (marks[i]) { + if (CCutil_swrite_int (f, (unsigned int) cuts->cliques[i].segcount)) + return 1; + for (j = 0; j < cuts->cliques[i].segcount; j++) { + if (CCutil_swrite_int (f, + (unsigned int) cuts->cliques[i].nodes[j].lo)) + return 1; + if (CCutil_swrite_int (f, + (unsigned int) cuts->cliques[i].nodes[j].hi)) + return 1; + } + } + } + } + + if (CCutil_swrite_int (f, (unsigned int) -1)) return 1; + + for (i = 0; i < cuts->cutcount; i++) { + if (CCutil_swrite_int (f, (unsigned int) cuts->cuts[i].cliquecount)) + return 1; + if (CCutil_swrite_int (f, (unsigned int) cuts->cuts[i].handlecount)) + return 1; + if (CCutil_swrite_int (f, (unsigned int) cuts->cuts[i].rhs)) + return 1; + if (CCutil_swrite_char (f, (unsigned char) cuts->cuts[i].sense)) + return 1; + + for (j = 0; j < cuts->cuts[i].cliquecount; j++) { + if (CCutil_swrite_int (f, + (unsigned int) marks[cuts->cuts[i].cliques[j]] - 1)) + return 1; + } + if (p) { + if (CCutil_swrite_int (f, (unsigned int) cuts->cuts[i].modcount)) + return 1; + for (j = 0; j < cuts->cuts[i].modcount; j++) { + if (CCutil_swrite_int (f,(unsigned int) cuts->cuts[i].mods[j].node)) + return 1; + if (CCutil_swrite_int (f,(unsigned int) cuts->cuts[i].mods[j].mult)) + return 1; + } + } + } + if (CCutil_swrite_int (f, (unsigned int) -1)) return 1; + + CC_IFFREE (marks, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getcuts (CCtsp_PROB_FILE *p, CC_SFILE *s, CCtsp_lpcuts *cuts) +#else +int CCtsp_prob_getcuts (p, s, cuts) +CCtsp_PROB_FILE *p; +CC_SFILE *s; +CCtsp_lpcuts *cuts; +#endif +{ + int i, j, k, nseg, ncliq, nhand, rhs, cliq, nmod, hi, lo, n, mult; + char sense; + int cliqcount = 0, cutcount = 0; + CCtsp_lpclique c; + CCtsp_lpcut u; + int *hits = (int *) NULL; + int version = 0; + CC_SFILE *f; + + + if (!p && !s) return -1; + + if (p) { + if (p->offsets.cut == -1) { + printf ("No cuts in file.\n"); + return 1; + } + if (CCutil_sseek (p->f, p->offsets.cut)) { + printf ("CCutil_sseek failed in CCtsp_prob_getedges\n"); + return -1; + } + f = p->f; + } else { + f = s; + } + + if (CCutil_sread_int (f, (unsigned int *) &version)) + goto CLEANUP; + + if (version > CCtsp_PROB_IO_CUTS_VERSION_BASE) { + /* an initial version of the cut system did not have a version # */ + printf ("Pre-sense version of files cuts\n"); fflush (stdout); + nseg = version; + version = 0; + } else { + if (CCutil_sread_int (f, (unsigned int *) &nseg)) goto CLEANUP; + } + + while (nseg != -1) { + c.segcount = nseg; + if (nseg == 0) { + fprintf (stderr, "ERROR: Clique with no segs in read_da_cuts\n"); + goto CLEANUP; + } + c.nodes = CC_SAFE_MALLOC (nseg, CCtsp_segment); + if (!c.nodes) { + fprintf (stderr, "out of memory in read_da_cuts\n"); + goto CLEANUP; + } + for (j = 0; j < nseg; j++) { + if (CCutil_sread_int (f, (unsigned int *) &lo)) goto CLEANUP; + if (CCutil_sread_int (f, (unsigned int *) &hi)) goto CLEANUP; + c.nodes[j].lo = lo; + c.nodes[j].hi = hi; + } + k = CCtsp_register_clique (cuts, &c); + CC_FREE (c.nodes, CCtsp_segment); + if (k == -1) { + fprintf (stderr, "CCtsp_register_clique failed\n"); + goto CLEANUP; + } + if (k != cliqcount) { + fprintf (stderr, "clique registration number is out of seq\n"); + cliqcount++; + goto CLEANUP; + } + cliqcount++; + if (CCutil_sread_int (f, (unsigned int *) &nseg)) goto CLEANUP; + } + + + if (cliqcount) { + hits = CC_SAFE_MALLOC (cliqcount, int); + if (!hits) { + fprintf (stderr, "out of memory in read_da_cuts\n"); + goto CLEANUP; + } + for (i = 0; i < cliqcount; i++) + hits[i] = 0; + } + + if (CCutil_sread_int (f, (unsigned int *) &ncliq)) goto CLEANUP; + while (ncliq != -1) { + if (CCutil_sread_int (f, (unsigned int *) &nhand)) goto CLEANUP; + if (CCutil_sread_int (f, (unsigned int *) &rhs)) goto CLEANUP; + if (version <= CCtsp_PROB_IO_CUTS_VERSION_BASE) { + if (CCutil_sread_char (f, (unsigned char *) &sense)) goto CLEANUP; + } else { + sense = 'G'; + } + u.cliquecount = ncliq; + u.handlecount = nhand; + u.rhs = rhs; + u.sense = sense; + u.branch = 0; + u.age = 0; + u.cliques = CC_SAFE_MALLOC (ncliq, int); + if (!u.cliques) { + fprintf (stderr, "out of memory in read_da_cuts\n"); + goto CLEANUP; + } + for (j = 0; j < ncliq; j++) { + if (CCutil_sread_int (f, (unsigned int *) &cliq)) goto CLEANUP; + u.cliques[j] = cliq; + if (hits[cliq]) + cuts->cliques[cliq].refcount++; + else + hits[cliq] = 1; + } + if (p) { + if (CCutil_sread_int (f, (unsigned int *) &nmod)) goto CLEANUP; + u.modcount = nmod; + if (nmod) { + u.mods = CC_SAFE_MALLOC (nmod, CCtsp_sparser); + if (!u.mods) { + fprintf (stderr, "out of memory in read_da_cuts\n"); + CC_FREE (u.cliques, int); + goto CLEANUP; + } + } else { + u.mods = (CCtsp_sparser *) NULL; + } + for (j = 0; j < nmod; j++) { + if (CCutil_sread_int (f, (unsigned int *) &n)) goto CLEANUP; + if (CCutil_sread_int (f, (unsigned int *) &mult)) goto CLEANUP; + u.mods[j].node = (unsigned int) n; + u.mods[j].mult = (unsigned int) mult; + } + } else { + u.mods = (CCtsp_sparser *) NULL; + u.modcount = 0; + } + + k = CCtsp_add_cut_to_cutlist (cuts, &u); + if (k == -1) { + fprintf (stderr, "CCtsp_add_cut_to_cutlist failed\n"); + cutcount++; + goto CLEANUP; + } + if (k != cutcount) { + fprintf (stderr, "cut location is out of seq\n"); + goto CLEANUP; + } + cutcount++; + if (CCutil_sread_int (f, (unsigned int *) &ncliq)) goto CLEANUP; + } + + CC_IFFREE (hits, int); + return 0; + + +CLEANUP: + + if (cutcount) { + for (i = 0; i < cutcount; i++) + CCtsp_delete_cut_from_cutlist (cuts, i); + } else { + for (i = 0; i < cliqcount; i++) + CCtsp_unregister_clique (cuts, i); + } + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putbasis (CCtsp_PROB_FILE *p, int ccount, int rcount, int *cstat, + int *rstat) +#else +int CCtsp_prob_putbasis (p, ccount, rcount, cstat, rstat) +CCtsp_PROB_FILE *p; +int ccount, rcount; +int *cstat, *rstat; +#endif +{ + int i; + + if (!p) return 1; + + p->offsets.basis = CCutil_stell (p->f); + + if (CCutil_swrite_int (p->f, (unsigned int) ccount)) return 1; + if (CCutil_swrite_int (p->f, (unsigned int) rcount)) return 1; + + for (i = 0; i < ccount; i++) { + if (CCutil_swrite_bits (p->f, (unsigned int) cstat[i], 2)) return 1; + } + + for (i = 0; i < rcount; i++) { + if (CCutil_swrite_bits (p->f, (unsigned int) rstat[i], 1)) return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getbasis (CCtsp_PROB_FILE *p, int *ccount, int *rcount, int **cstat, + int **rstat) +#else +int CCtsp_prob_getbasis (p, ccount, rcount, cstat, rstat) +CCtsp_PROB_FILE *p; +int *ccount, *rcount; +int **cstat, **rstat; +#endif +{ + int i; + + *ccount = 0; + *rcount = 0; + *cstat = (int *) NULL; + *rstat = (int *) NULL; + + if (!p) return -1; + + if (p->offsets.basis == -1) { + printf ("No basis in file.\n"); + return 1; + } + if (CCutil_sseek (p->f, p->offsets.basis)) { + printf ("CCutil_sseek failed in CCtsp_prob_getbasis\n"); + return -1; + } + + if (CCutil_sread_int (p->f, (unsigned int *) ccount)) goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) rcount)) goto CLEANUP; + + *cstat = CC_SAFE_MALLOC (*ccount, int); + *rstat = CC_SAFE_MALLOC (*rcount, int); + if (!(*rstat) || !(*cstat)) { + fprintf (stderr, "out of memory in CCtsp_prob_getbasis\n"); + goto CLEANUP; + } + for (i = 0; i < *ccount; i++) { + if (CCutil_sread_bits (p->f, (unsigned int *) &((*cstat)[i]), 2)) goto CLEANUP; + } + for (i = 0; i < *rcount; i++) { + if (CCutil_sread_bits (p->f, (unsigned int *) &((*rstat)[i]), 1)) goto CLEANUP; + } + + return 0; + +CLEANUP: + + CC_IFFREE (*cstat, int); + CC_IFFREE (*rstat, int); + *ccount = 0; + *rcount = 0; + + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putnorms (CCtsp_PROB_FILE *p, int rcount, double *dnorm) +#else +int CCtsp_prob_putnorms (p, rcount, dnorm) +CCtsp_PROB_FILE *p; +int rcount; +double *dnorm; +#endif +{ + int i; + + if (!p) return 1; + + p->offsets.norms = CCutil_stell (p->f); + + if (CCutil_swrite_int (p->f, (unsigned int) rcount)) return 1; + + for (i = 0; i < rcount; i++) { + if (CCutil_swrite_double (p->f, dnorm[i])) return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getnorms (CCtsp_PROB_FILE *p, int *rcount, double **dnorm) +#else +int CCtsp_prob_getnorms (p, rcount, dnorm) +CCtsp_PROB_FILE *p; +int *rcount; +double **dnorm; +#endif +{ + int i; + + *rcount = 0; + *dnorm = (double *) NULL; + + if (!p) return -1; + + if (p->offsets.norms == -1) { + printf ("No norms in file.\n"); + return 1; + } + if (CCutil_sseek (p->f, p->offsets.norms)) { + printf ("CCutil_sseek failed in CCtsp_prob_getnorms\n"); + return -1; + } + + if (CCutil_sread_int (p->f, (unsigned int *) rcount)) goto CLEANUP; + + *dnorm = CC_SAFE_MALLOC (*rcount, double); + if (!(*dnorm)) { + fprintf (stderr, "out of memory in CCtsp_prob_getnorms\n"); + goto CLEANUP; + } + for (i = 0; i < *rcount; i++) { + if (CCutil_sread_double (p->f, &((*dnorm)[i]))) goto CLEANUP; + } + + return 0; + +CLEANUP: + + CC_IFFREE (*dnorm, double); + *rcount = 0; + + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putfulladj (CCtsp_PROB_FILE *p, int ncount, int fullcount, + CCtsp_genadj *adj) +#else +int CCtsp_prob_putfulladj (p, ncount, fullcount, adj) +CCtsp_PROB_FILE *p; +int ncount, fullcount; +CCtsp_genadj *adj; +#endif +{ + int i, j; + + if (!p) return 1; + + p->offsets.fulladj = CCutil_stell (p->f); + + if (CCutil_swrite_int (p->f, (unsigned int) fullcount)) return 1; + for (i = 0; i < ncount; i++) { + if (CCutil_swrite_int (p->f, (unsigned int) adj[i].deg)) return 1; + for (j = 0; j < adj[i].deg; j++) { + if (CCutil_swrite_int (p->f, (unsigned int) adj[i].list[j].end)) + return 1; + if (CCutil_swrite_int (p->f, (unsigned int) adj[i].list[j].len)) + return 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getfulladj (CCtsp_PROB_FILE *p, int ncount, int *fullcount, + CCtsp_genadj **adj, CCtsp_genadjobj **adjspace) +#else +int CCtsp_prob_getfulladj (p, ncount, fullcount, adj, adjspace) +CCtsp_PROB_FILE *p; +int ncount, *fullcount; +CCtsp_genadj **adj; +CCtsp_genadjobj **adjspace; +#endif +{ + int i, j; + CCtsp_genadj *a; + CCtsp_genadjobj *s; + + *fullcount = 0; + *adj = (CCtsp_genadj *) NULL; + *adjspace = (CCtsp_genadjobj *) NULL; + + if (!p || ncount <= 0) return -1; + + if (p->offsets.fulladj == -1) { + printf ("No fulladj in file.\n"); + return 1; + } + if (CCutil_sseek (p->f, p->offsets.fulladj)) { + printf ("CCutil_sseek failed in CCtsp_prob_getfulladj\n"); + return -1; + } + + if (CCutil_sread_int (p->f, (unsigned int *) fullcount)) goto CLEANUP; + + *adjspace = CC_SAFE_MALLOC (*fullcount, CCtsp_genadjobj); + *adj = CC_SAFE_MALLOC (ncount, CCtsp_genadj); + if (!adjspace || !adj) { + fprintf (stderr, "out of memory in CCtsp_prob_getfulladj\n"); + goto CLEANUP; + } + + s = *adjspace; + a = *adj; + for (i = 0; i < ncount; i++) { + a[i].list = s; + if (CCutil_sread_int (p->f, (unsigned int *) &(a[i].deg))) goto CLEANUP; + for (j = 0; j < a[i].deg; j++) { + if (CCutil_sread_int (p->f, (unsigned int *) &(a[i].list[j].end))) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &(a[i].list[j].len))) + goto CLEANUP; + } + s += a[i].deg; + } + + return 0; + +CLEANUP: + + CC_IFFREE (*adjspace, CCtsp_genadjobj); + CC_IFFREE (*adj, CCtsp_genadj); + *fullcount = 0; + + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putfixed (CCtsp_PROB_FILE *p, int ecount, int *elist) +#else +int CCtsp_prob_putfixed (p, ecount, elist) +CCtsp_PROB_FILE *p; +int ecount; +int *elist; +#endif +{ + int i; + + if (!p) return 1; + + p->offsets.fix = CCutil_stell (p->f); + + if (CCutil_swrite_int (p->f, (unsigned int) ecount)) return 1; + + for (i = 0; i < 2*ecount; i++) { + if (CCutil_swrite_int (p->f, (unsigned int) elist[i])) return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getfixed (CCtsp_PROB_FILE *p, int *ecount, int **elist) +#else +int CCtsp_prob_getfixed (p, ecount, elist) +CCtsp_PROB_FILE *p; +int *ecount; +int **elist; +#endif +{ + int i; + + *ecount = 0; + *elist = (int *) NULL; + if (!p) return -1; + + if (p->offsets.fix == -1) { + printf ("No fix in file\n"); + return 1; + } + if (CCutil_sseek (p->f, p->offsets.fix)) { + printf ("CCutil_sseek failed in CCtsp_prob_getfix\n"); + return -1; + } + if (CCutil_sread_int (p->f, (unsigned int *) ecount)) goto CLEANUP; + + if (*ecount) { + *elist = CC_SAFE_MALLOC (2*(*ecount), int); + if (!(*elist)) { + fprintf (stderr, "out of memory in CCtsp_prob_getfixed\n"); + goto CLEANUP; + } + for (i = 0; i < 2*(*ecount); i++) { + if (CCutil_sread_int (p->f, (unsigned int *) (&((*elist)[i])))) + goto CLEANUP; + } + } + + return 0; + +CLEANUP: + + CC_IFFREE (*elist, int); + *ecount = 0; + + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_putexactdual (CCtsp_PROB_FILE *p, CCtsp_bigdual *d, int ncount) +#else +int CCtsp_prob_putexactdual (p, d, ncount) +CCtsp_PROB_FILE *p; +CCtsp_bigdual *d; +int ncount; +#endif +{ + int i; + + if (!p) return 1; + + p->offsets.exactdual = CCutil_stell (p->f); + + if (CCutil_swrite_int (p->f, (unsigned int) d->cutcount)) return 1; + + for (i = 0; i < ncount; i++) { + if (CCbigguy_swrite (p->f, d->node_pi[i])) return 1; + } + for (i = 0; i < d->cutcount; i++) { + if (CCbigguy_swrite (p->f, d->cut_pi[i])) return 1; + } + + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_getexactdual (CCtsp_PROB_FILE *p, int ncount, CCtsp_bigdual **d) +#else +int CCtsp_prob_getexactdual (p, ncount, d) +CCtsp_PROB_FILE *p; +int ncount; +CCtsp_bigdual **d; +#endif +{ + CCtsp_bigdual *rd; + int i; + + *d = (CCtsp_bigdual *) NULL; + + if (!p) return -1; + + if (p->offsets.exactdual == -1) { + printf ("No exactdual in file\n"); + fflush (stdout); + return 1; + } + + *d = CC_SAFE_MALLOC (1, CCtsp_bigdual); + if (!(*d)) { + fprintf (stderr, "out of memory in CCtsp_prob_getexactdual\n"); + goto CLEANUP; + } + rd = *d; + rd->cutcount = 0; + rd->node_pi = (CCbigguy *) NULL; + rd->cut_pi = (CCbigguy *) NULL; + + if (CCutil_sseek (p->f, p->offsets.exactdual)) { + fprintf (stderr, "CCutil_sseek failed in CCtsp_prob_getexactdual\n"); + return -1; + } + if (CCutil_sread_int (p->f, (unsigned int *) &(rd->cutcount))) goto CLEANUP; + + rd->node_pi = CC_SAFE_MALLOC (ncount, CCbigguy); + if (!rd->node_pi) { + fprintf (stderr, "out of memory in CCtsp_prob_getexactdual\n"); + goto CLEANUP; + } + for (i = 0; i < ncount; i++) { + if (CCbigguy_sread (p->f, &(rd->node_pi[i]))) goto CLEANUP; + } + if (rd->cutcount) { + rd->cut_pi = CC_SAFE_MALLOC (rd->cutcount, CCbigguy); + if (!rd->cut_pi) { + fprintf (stderr, "out of memory in CCtsp_prob_getexactdual\n"); + goto CLEANUP; + } + for (i = 0; i < rd->cutcount; i++) { + if (CCbigguy_sread (p->f, &(rd->cut_pi[i]))) goto CLEANUP; + } + } + + return 0; + +CLEANUP: + + if (*d) { + CC_IFFREE ((*d)->node_pi, CCbigguy); + CC_IFFREE ((*d)->cut_pi, CCbigguy); + CC_FREE (*d, CCtsp_bigdual); + } + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_puthistory (CCtsp_PROB_FILE *p, int depth, + CCtsp_branchobj *history) +#else +int CCtsp_prob_puthistory (p, depth, history) +CCtsp_PROB_FILE *p; +int depth; +CCtsp_branchobj *history; +#endif +{ + int i, j; + CCtsp_lpclique *c; + + if (!p) return 1; + + p->offsets.history = CCutil_stell (p->f); + + if (CCutil_swrite_int (p->f, (unsigned int) depth)) return 1; + + for (i = 0; i < depth; i++) { + if (CCutil_swrite_int (p->f, (unsigned int) history[i].depth)) + return 1; + if (CCutil_swrite_int (p->f, (unsigned int) history[i].rhs)) + return 1; + if (CCutil_swrite_int (p->f, (unsigned int) history[i].ends[0])) + return 1; + if (CCutil_swrite_int (p->f, (unsigned int) history[i].ends[1])) + return 1; + if (history[i].clique) { + c = history[i].clique; + if (CCutil_swrite_int (p->f, (unsigned int) c->segcount)) + return 1; + for (j = 0; j < c->segcount; j++) { + if (CCutil_swrite_int (p->f, (unsigned int) c->nodes[j].lo)) + return 1; + if (CCutil_swrite_int (p->f, (unsigned int) c->nodes[j].hi)) + return 1; + } + } else { + if (CCutil_swrite_int (p->f, (unsigned int) 0)) return 1; + } + if (CCutil_swrite_char (p->f, (unsigned char) history[i].sense)) + return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_prob_gethistory (CCtsp_PROB_FILE *p, int *depth, + CCtsp_branchobj **history) +#else +int CCtsp_prob_gethistory (p, depth, history) +CCtsp_PROB_FILE *p; +int *depth; +CCtsp_branchobj **history; +#endif +{ + int i, j, nseg, rval; + CCtsp_lpclique *c = (CCtsp_lpclique *) NULL; + int *slist = (int *) NULL; + + *depth = 0; + *history = (CCtsp_branchobj *) NULL; + if (!p) return -1; + + if (p->offsets.history == -1) { + printf ("No branch history in file\n"); + return 1; + } + if (CCutil_sseek (p->f, p->offsets.history)) { + printf ("CCutil_sseek failed in CCtsp_prob_gethistory\n"); + return -1; + } + if (CCutil_sread_int (p->f, (unsigned int *) depth)) goto CLEANUP; + + if (*depth) { + *history = CC_SAFE_MALLOC (*depth, CCtsp_branchobj); + if (!(*history)) { + fprintf (stderr, "out of memory in CCtsp_prob_gethistory\n"); + goto CLEANUP; + } + for (i = 0; i < (*depth); i++) { + if (CCutil_sread_int (p->f, + (unsigned int *) &((*history)[i].depth))) + goto CLEANUP; + if (CCutil_sread_int (p->f, + (unsigned int *) &((*history)[i].rhs))) + goto CLEANUP; + if (CCutil_sread_int (p->f, + (unsigned int *) &((*history)[i].ends[0]))) + goto CLEANUP; + if (CCutil_sread_int (p->f, + (unsigned int *) &((*history)[i].ends[1]))) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &nseg)) + goto CLEANUP; + if (nseg) { + slist = CC_SAFE_MALLOC (2*nseg, int); + if (!slist) goto CLEANUP; + for (j = 0; j < nseg; j++) { + if (CCutil_sread_int (p->f, (unsigned int *) &slist[2*j])) + goto CLEANUP; + if (CCutil_sread_int (p->f, (unsigned int *) &slist[2*j+1])) + goto CLEANUP; + } + c = CC_SAFE_MALLOC (1, CCtsp_lpclique); + if (!c) goto CLEANUP; + rval = CCtsp_seglist_to_lpclique (nseg, slist, c); + if (rval) { + fprintf (stderr, "CCtsp_seglist_to_lpclique failed\n"); + CC_FREE (c, CCtsp_lpclique); + goto CLEANUP; + } + (*history)[i].clique = c; + } else { + (*history)[i].clique = (CCtsp_lpclique *) NULL; + } + if (CCutil_sread_char (p->f, + (unsigned char *) &((*history)[i].sense))) + return 1; + } + } + + return 0; + +CLEANUP: + + CC_IFFREE (slist, int); + CC_IFFREE (*history, CCtsp_branchobj); + *depth = 0; + + return -1; +} diff --git a/contrib/blossom/concorde97/TSP/qsparse.c b/contrib/blossom/concorde97/TSP/qsparse.c new file mode 100644 index 0000000000000000000000000000000000000000..f6d927d6fe878ef3fe09327baf0b3dc64a9964eb --- /dev/null +++ b/contrib/blossom/concorde97/TSP/qsparse.c @@ -0,0 +1,507 @@ +/***************************************************************************/ +/* */ +/* Function to Reduce the Number of Nonzeros in a Cut by add/sub Stars */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: October 7, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_qsparsify (CCtsp_qsparsegroup **pqs, CCtsp_lpgraph *g, */ +/* int *pnzlist, int scount, CCtsp_sparser **slist, */ +/* int *savedcount) */ +/* -pqs (if *pqs is NULL, then it will be initialized) */ +/* -g (the graph) */ +/* -pnzlist (pointer to an int that is the start of a linked list */ +/* of edges that is a superset of the nonzeros in the cut, it */ +/* returns a pointer to a superset of the nonzeros in the */ +/* sparsified cut. The links are via the coefnext field of */ +/* CCtsp_lpedge, and the coef field gives the actual nonzero */ +/* coefs.) */ +/* -scount (returns the number of CCtsp_sparsers in slist) */ +/* -slist (rturns an array of CCtsp_sparsers) */ +/* -savedcount (returns the number of nonzeros that were saved) */ +/* RETURNS 0 is it worked and 1 if it failed (probably due to running */ +/* out of memory). free_qsparsify will free the allocated memory (it */ +/* is not freed after each call since the mallocs and initialization */ +/* require too much time). */ +/* void CCtsp_free_qsparsify (CCtsp_qsparsegroup **pqs) */ +/* -pqs (will free the queues and arrays in the struct pointed to */ +/* by *pqs, and sets *pqs to NULL) */ +/* */ +/* NOTES: */ +/* This functions uses priorty queues to line up the stars that would */ +/* decrease the number of nonzeros if they were added or subtracted */ +/* there are separate add and subtract queues). */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + queue_add (CCdheap *q, int v, int k), + queue_delete (CCdheap *q, int v), + queue_keychange (CCdheap *q, int v, int k), + add_node(int v, CCtsp_qsparsegroup *qs, CCtsp_lpgraph *g, int *pnzlist), + sub_node(int v, CCtsp_qsparsegroup *qs, CCtsp_lpgraph *g, int *pnzlist), + update_queues (int v, CCtsp_qsparsegroup *qs, CCtsp_lpgraph *g); + +static int + init_qsparsify (CCtsp_qsparsegroup **pqs, int ncount), + queue_max (CCdheap *); + +#else + +static void + queue_add (), + queue_delete (), + queue_keychange (), + add_node(), + sub_node(), + update_queues (); + +static int + init_qsparsify (), + queue_max (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +static int init_qsparsify (CCtsp_qsparsegroup **pqs, int ncount) +#else +static int init_qsparsify (pqs, ncount) +CCtsp_qsparsegroup **pqs; +int ncount; +#endif +{ + int i; + CCtsp_qsparsegroup *qs; + + (*pqs) = CC_SAFE_MALLOC (1, CCtsp_qsparsegroup); + if (!(*pqs)) + return 1; + + qs = *pqs; + qs->add_queue = (CCdheap *) NULL; + qs->sub_queue = (CCdheap *) NULL; + qs->count_m1 = (int *) NULL; + qs->count_non0 = (int *) NULL; + qs->count_1 = (int *) NULL; + qs->on_add_queue = (int *) NULL; + qs->on_sub_queue = (int *) NULL; + qs->mults = (int *) NULL; + + qs->add_queue = CC_SAFE_MALLOC (1, CCdheap); + qs->sub_queue = CC_SAFE_MALLOC (1, CCdheap); + if (!qs->add_queue || !qs->sub_queue) { + CCtsp_free_qsparsify (pqs); + return 1; + } + if (CCutil_dheap_init (qs->add_queue, ncount)) { + CCtsp_free_qsparsify (pqs); + return 1; + } + if (CCutil_dheap_init (qs->sub_queue, ncount)) { + CCtsp_free_qsparsify (pqs); + return 1; + } + + qs->count_m1 = CC_SAFE_MALLOC (ncount, int); + qs->count_non0 = CC_SAFE_MALLOC (ncount, int); + qs->count_1 = CC_SAFE_MALLOC (ncount, int); + qs->on_add_queue = CC_SAFE_MALLOC (ncount, int); + qs->on_sub_queue = CC_SAFE_MALLOC (ncount, int); + qs->mults = CC_SAFE_MALLOC (ncount, int); + if (!qs->count_m1 || !qs->count_non0 || !qs->count_1 || + !qs->on_add_queue || !qs->on_sub_queue || !qs->mults) { + CCtsp_free_qsparsify (pqs); + return 1; + } + + for (i = 0; i < ncount; i++) { + qs->count_m1[i] = 0; + qs->count_non0[i] = 0; + qs->count_1[i] = 0; + qs->on_add_queue[i] = 0; + qs->on_sub_queue[i] = 0; + qs->mults[i] = 0; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_qsparsify (CCtsp_qsparsegroup **pqs) +#else +void CCtsp_free_qsparsify (pqs) +CCtsp_qsparsegroup **pqs; +#endif +{ + if (*pqs != (CCtsp_qsparsegroup *) NULL) { + if ((*pqs)->add_queue) { + CCutil_dheap_free ((*pqs)->add_queue); + CC_FREE ((*pqs)->add_queue, CCdheap); + } + if ((*pqs)->sub_queue) { + CCutil_dheap_free ((*pqs)->sub_queue); + CC_FREE ((*pqs)->sub_queue, CCdheap); + } + CC_IFFREE ((*pqs)->count_m1, int); + CC_IFFREE ((*pqs)->count_non0, int); + CC_IFFREE ((*pqs)->count_1, int); + CC_IFFREE ((*pqs)->on_add_queue, int); + CC_IFFREE ((*pqs)->on_sub_queue, int); + CC_IFFREE ((*pqs)->mults, int); + CC_FREE (*pqs, CCtsp_qsparsegroup); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_qsparsify (CCtsp_qsparsegroup **pqs, CCtsp_lpgraph *g, int *pnzlist, + int *scount, CCtsp_sparser **slist, int *savedcount) +#else +int CCtsp_qsparsify (pqs, g, pnzlist, scount, slist, savedcount) +CCtsp_qsparsegroup **pqs; +CCtsp_lpgraph *g; +int *pnzlist; +int *scount; +CCtsp_sparser **slist; +int *savedcount; +#endif +{ + int i, k, e, t; + int v, w; + CCtsp_qsparsegroup *qs; + int *count_non0, *count_1, *count_m1; + CCtsp_lpedge *edges = g->edges; + CCtsp_lpnode *nodes = g->nodes; + + *scount = 0; + *slist = (CCtsp_sparser *) NULL; + *savedcount = 0; + if (*pnzlist == -1) + return 0; + + if (*pqs == (CCtsp_qsparsegroup *) NULL) { + if (init_qsparsify(pqs, g->ncount)) + return 1; + } + + qs = *pqs; + count_non0 = qs->count_non0; + count_1 = qs->count_1; + count_m1 = qs->count_m1; + + for (e = *pnzlist; e != -1; e = g->edges[e].coefnext) { + if (edges[e].coef) { + count_non0[edges[e].ends[0]]++; + count_non0[edges[e].ends[1]]++; + if (edges[e].coef == 1) { + count_1[edges[e].ends[0]]++; + count_1[edges[e].ends[1]]++; + } else if (edges[e].coef == -1) { + count_m1[edges[e].ends[0]]++; + count_m1[edges[e].ends[1]]++; + } + } + } + + g->nodemarker++; + for (e = *pnzlist; e != -1; e = edges[e].coefnext) { + if (edges[e].coef) { + if (nodes[edges[e].ends[0]].mark != g->nodemarker) { + update_queues(edges[e].ends[0], qs, g); + nodes[edges[e].ends[0]].mark = g->nodemarker; + } + if (nodes[edges[e].ends[1]].mark != g->nodemarker) { + update_queues(edges[e].ends[1], qs, g); + nodes[edges[e].ends[1]].mark = g->nodemarker; + } + } + } + + k = 0; + for (;;) { + v = queue_max (qs->add_queue); + w = queue_max (qs->sub_queue); + if (v == -1 && w == -1) break; + if (w == -1 || (v != -1 && + count_m1[v] - (nodes[v].deg - count_non0[v]) > + count_1[w] - (nodes[w].deg - count_non0[w]))) { + k += (count_m1[v] - (nodes[v].deg - count_non0[v])); + queue_delete (qs->add_queue, v); + qs->on_add_queue[v] = 0; + (qs->mults[v])++; + add_node (v, qs, g, pnzlist); + } else { + k += (count_1[w] - (nodes[w].deg - count_non0[w])); + queue_delete (qs->sub_queue, w); + qs->on_sub_queue[w] = 0; + (qs->mults[w])--; + sub_node (w, qs, g, pnzlist); + } + } + + + g->nodemarker++; + for (e = *pnzlist; e != -1; e = edges[e].coefnext) { + if (qs->mults[edges[e].ends[0]] && + nodes[edges[e].ends[0]].mark != g->nodemarker) { + (*scount)++; + nodes[edges[e].ends[0]].mark = g->nodemarker; + } + if (qs->mults[edges[e].ends[1]] && + nodes[edges[e].ends[1]].mark != g->nodemarker) { + (*scount)++; + nodes[edges[e].ends[1]].mark = g->nodemarker; + } + } + if (*scount) { + *slist = CC_SAFE_MALLOC (*scount, CCtsp_sparser); + if (!(*slist)) { + CCtsp_free_qsparsify (pqs); + *scount = 0; + *savedcount = 0; + return 1; + } + i = 0; + for (e = *pnzlist; e != -1; e = edges[e].coefnext) { + if (qs->mults[edges[e].ends[0]]) { + (*slist)[i].node = (unsigned int) edges[e].ends[0]; + t = qs->mults[edges[e].ends[0]]; + if (t > 0) + (*slist)[i++].mult = (unsigned int) (128 + (t % 128)); + else + (*slist)[i++].mult = (unsigned int) (128 - ((-t) % 128)); + qs->mults[edges[e].ends[0]] = 0; + } + if (qs->mults[edges[e].ends[1]]) { + (*slist)[i].node = (unsigned int) edges[e].ends[1]; + t = qs->mults[edges[e].ends[1]]; + if (t > 0) + (*slist)[i++].mult = (unsigned int) (128 + (t % 128)); + else + (*slist)[i++].mult = (unsigned int) (128 - ((-t) % 128)); + qs->mults[edges[e].ends[1]] = 0; + } + } + } + + + for (e = *pnzlist; e != -1; e = g->edges[e].coefnext) { + qs->count_m1[edges[e].ends[0]] = 0; + qs->count_non0[edges[e].ends[0]] = 0; + qs->count_1[edges[e].ends[0]] = 0; + qs->count_m1[edges[e].ends[1]] = 0; + qs->count_non0[edges[e].ends[1]] = 0; + qs->count_1[edges[e].ends[1]] = 0; + } + + *savedcount = k; + +/* + printf ("sscount = %d savedcount = %d\n", *scount, *savedcount); + fflush (stdout); +*/ + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void queue_add (CCdheap *q, int v, int k) +#else +static void queue_add (q, v, k) +CCdheap *q; +int v; +int k; +#endif +{ + /* adds v to q with key k */ + q->key[v] = -k; /* since dheap code works with min, not max */ + CCutil_dheap_insert (q, v); +} + +#ifdef CC_PROTOTYPE_ANSI +static void queue_delete (CCdheap *q, int v) +#else +static void queue_delete (q, v) +CCdheap *q; +int v; +#endif +{ + /* deletes v from q */ + CCutil_dheap_delete (q, v); +} + +#ifdef CC_PROTOTYPE_ANSI +static void queue_keychange (CCdheap *q, int v, int k) +#else +static void queue_keychange (q, v, k) +CCdheap *q; +int v; +int k; +#endif +{ + /* changes v's key to k on q */ + CCutil_dheap_changekey (q, v, (double) -k); +} + +#ifdef CC_PROTOTYPE_ANSI +static int queue_max (CCdheap *q) +#else +static int queue_max (q) +CCdheap *q; +#endif +{ + /* returns the node on q with the largest key */ + return CCutil_dheap_findmin (q); +} + +#ifdef CC_PROTOTYPE_ANSI +static void add_node (int v, CCtsp_qsparsegroup *qs, CCtsp_lpgraph *g, + int *pnzlist) +#else +static void add_node (v, qs, g, pnzlist) +int v; +CCtsp_qsparsegroup *qs; +CCtsp_lpgraph *g; +int *pnzlist; +#endif +{ + int j, w; + CCtsp_lpnode *lv = &(g->nodes[v]); + CCtsp_lpedge *e; + + for (j = lv->deg - 1; j >= 0; j--) { + e = &(g->edges[lv->adj[j].edge]); + w = lv->adj[j].to; + if (e->coef == 0) { + if (e->coefnext == -2) { + e->coefnext = *pnzlist; + *pnzlist = lv->adj[j].edge; + } + qs->count_non0[v]++; + qs->count_1[v]++; + qs->count_non0[w]++; + qs->count_1[w]++; + update_queues (w, qs, g); + } else if (e->coef == 1) { + qs->count_1[v]--; + qs->count_1[w]--; + update_queues (w, qs, g); + } else if (e->coef == -1) { + qs->count_m1[v]--; + qs->count_non0[v]--; + qs->count_m1[w]--; + qs->count_non0[w]--; + update_queues (w, qs, g); + } else if (e->coef == -2) { + qs->count_m1[v]++; + qs->count_m1[w]++; + update_queues (w, qs, g); + } + e->coef++; + } + update_queues (v, qs, g); +} + +#ifdef CC_PROTOTYPE_ANSI +static void sub_node (int v, CCtsp_qsparsegroup *qs, CCtsp_lpgraph *g, + int *pnzlist) +#else +static void sub_node (v, qs, g, pnzlist) +int v; +CCtsp_qsparsegroup *qs; +CCtsp_lpgraph *g; +int *pnzlist; +#endif +{ + int j, w; + CCtsp_lpnode *lv = &(g->nodes[v]); + CCtsp_lpedge *e; + + for (j = lv->deg - 1; j >= 0; j--) { + e = &(g->edges[lv->adj[j].edge]); + w = lv->adj[j].to; + if (e->coef == 0) { + if (e->coefnext == -2) { + e->coefnext = *pnzlist; + *pnzlist = lv->adj[j].edge; + } + qs->count_non0[v]++; + qs->count_m1[v]++; + qs->count_non0[w]++; + qs->count_m1[w]++; + update_queues (w, qs, g); + } else if (e->coef == -1) { + qs->count_m1[v]--; + qs->count_m1[w]--; + update_queues (w, qs, g); + } else if (e->coef == 1) { + qs->count_1[v]--; + qs->count_non0[v]--; + qs->count_1[w]--; + qs->count_non0[w]--; + update_queues (w, qs, g); + } else if (e->coef == 2) { + qs->count_1[v]++; + qs->count_1[w]++; + update_queues (w, qs, g); + } + e->coef--; + } + update_queues (v, qs, g); +} + +/* update_queues (v, qs, g) should be called whenever some of the counts for + v have changed */ + +#ifdef CC_PROTOTYPE_ANSI +static void update_queues (int v, CCtsp_qsparsegroup *qs, CCtsp_lpgraph *g) +#else +static void update_queues (v, qs, g) +int v; +CCtsp_qsparsegroup *qs; +CCtsp_lpgraph *g; +#endif +{ + if (qs->count_m1[v] - (g->nodes[v].deg - qs->count_non0[v]) > 0) { + if (qs->on_add_queue[v]) { + queue_keychange (qs->add_queue, v, + qs->count_m1[v] - (g->nodes[v].deg - qs->count_non0[v])); + } else { + queue_add (qs->add_queue, v, + qs->count_m1[v] - (g->nodes[v].deg - qs->count_non0[v])); + qs->on_add_queue[v] = 1; + } + } else { + if (qs->on_add_queue[v]) { + queue_delete (qs->add_queue, v); + qs->on_add_queue[v] = 0; + } + } + + if (qs->count_1[v] - (g->nodes[v].deg - qs->count_non0[v]) > 0) { + if (qs->on_sub_queue[v]) { + queue_keychange (qs->sub_queue, v, + qs->count_1[v] - (g->nodes[v].deg - qs->count_non0[v])); + } else { + queue_add (qs->sub_queue, v, + qs->count_1[v] - (g->nodes[v].deg - qs->count_non0[v])); + qs->on_sub_queue[v] = 1; + } + } else { + if (qs->on_sub_queue[v]) { + queue_delete (qs->sub_queue, v); + qs->on_sub_queue[v] = 0; + } + } +} diff --git a/contrib/blossom/concorde97/TSP/teething.c b/contrib/blossom/concorde97/TSP/teething.c new file mode 100644 index 0000000000000000000000000000000000000000..52026861924d49808326f7c0ca2386cd3cc5839b --- /dev/null +++ b/contrib/blossom/concorde97/TSP/teething.c @@ -0,0 +1,800 @@ +/***************************************************************************/ +/* */ +/* Teething Combs */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 13, 1997 */ +/* July 15, 1997 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_teething (CCtsp_lpgraph *g, double *x, */ +/* CCtsp_lpcut_in *cut, CCtsp_lpcut_in **newcut) */ +/* -g is the graph of the active edges in the LP */ +/* -x is an LP solution */ +/* -cut is the base comb */ +/* -newcut returns the comb found after teething */ +/* */ +/* NOTES: */ +/* The new cut may be just a subtour inequality. This code is based */ +/* on the "Teething" section of the tsp notes. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" + +typedef struct intptr { + int this; + struct intptr *next; +} intptr; + +typedef struct Rrecord { + int add0; + int add1; + struct Rrecord *next; +} Rrecord; + + +#ifdef CC_PROTOTYPE_ANSI + +static void + teething_free_world (void), + identify_big_teeth (CCtsp_lpcut_in *cut, int handle, int *nbig, + CCtsp_lpclique **bigteeth); + +static int + optimal_pseudocomb (CCtsp_lpgraph *g, double *x, CCtsp_lpcut_in *c, + int ihandle, CCtsp_lpcut_in *d), + grab_record (Rrecord *r, int parity, intptr **list), + clean_pseudocomb (CCtsp_lpgraph *g, double *x, CCtsp_lpcut_in *c, + CCtsp_lpcut_in *d), + add_to_list (intptr **list, int item), + add_to_record (Rrecord **R, int add0, int add1); + +#else + +static void + teething_free_world (), + identify_big_teeth (); + +static int + optimal_pseudocomb (), + grab_record (), + clean_pseudocomb (), + add_to_list (), + add_to_record (); + +#endif + + +CC_PTR_ALLOC_ROUTINE (intptr, intptralloc, intptrchunklist, intptrfreelist) +CC_PTR_FREE_ROUTINE (intptr, intptrfree, intptrfreelist) +CC_PTR_FREE_LIST_ROUTINE(intptr, intptrfree_list, intptrfree) +CC_PTR_FREE_WORLD_ROUTINE(intptr, intptrfree_world, intptrchunklist, + intptrfreelist) +CC_PTR_LEAKS_ROUTINE (intptr, intptr_check_leaks, intptrchunklist, + intptrfreelist, this, int) +CC_PTR_STATUS_ROUTINE (intptr, intptr_status, intptrchunklist, intptrfreelist) + +CC_PTR_ALLOC_ROUTINE (Rrecord, Rrecordalloc, Rrecordchunklist, Rrecordfreelist) +CC_PTR_FREE_ROUTINE (Rrecord, Rrecordfree, Rrecordfreelist) +CC_PTR_FREE_LIST_ROUTINE(Rrecord, Rrecordfree_list, Rrecordfree) +CC_PTR_FREE_WORLD_ROUTINE( Rrecord, Rrecordfree_world, Rrecordchunklist, + Rrecordfreelist) +CC_PTR_LEAKS_ROUTINE (Rrecord, Rrecord_check_leaks, Rrecordchunklist, + Rrecordfreelist, add0, int) +CC_PTR_STATUS_ROUTINE (Rrecord, Rrecord_status, Rrecordchunklist, + Rrecordfreelist) + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_teething (CCtsp_lpgraph *g, double *x, CCtsp_lpcut_in *cut, + CCtsp_lpcut_in **newcut) +#else +int CCtsp_teething (g, x, cut, newcut) +CCtsp_lpgraph *g; +double *x; +CCtsp_lpcut_in *cut; +CCtsp_lpcut_in **newcut; +#endif +{ + int rval = 0; + CCtsp_lpcut_in pseudo; + CCtsp_lpcut_in general; + int test, ihandle; + +/* + printf ("CCtsp_teething ....\n"); fflush (stdout); + CCtsp_print_lpcut_in (cut); +*/ + + *newcut = (CCtsp_lpcut_in *) NULL; + + if (cut->cliquecount > 1) { + rval = CCtsp_test_pure_comb (g->ncount, cut, &test, &ihandle); + if (rval) { + fprintf (stderr, "CCtsp_test_pure_comb failed\n"); goto CLEANUP; + } + if (test != 1) goto CLEANUP; + } else { + ihandle = 0; + } + + rval = optimal_pseudocomb (g, x, cut, ihandle, &pseudo); + if (rval) { + fprintf (stderr, "optimal_pseudocomb failed\n"); goto CLEANUP; + } + + if (pseudo.cliquecount == 2 || pseudo.cliquecount == 1) { + CCtsp_free_lpcut_in (&pseudo); + goto CLEANUP; + } + rval = CCtsp_test_pseudocomb (g->ncount, &pseudo, 0, &test); + if (rval) { + fprintf (stderr, "CCtsp_test_pseudocomb failed\n"); goto CLEANUP; + } + if (test != 1) { + fprintf (stderr, "Not a pseudocomb\n"); + CCtsp_print_lpcut_in (&pseudo); + rval = 1; goto CLEANUP; + } + + rval = CCtsp_test_teeth_disjoint (g->ncount, &pseudo, 0, &test); + if (rval) { + fprintf (stderr, "CCtsp_test_teeth_disjoint failed\n"); goto CLEANUP; + } + + if (!test) { + rval = clean_pseudocomb (g, x, &pseudo, &general); + CCtsp_free_lpcut_in (&pseudo); + if (rval) { + fprintf (stderr, "clean_pseudocomb failed\n"); + goto CLEANUP; + } + if (general.cliquecount <= 2) { + CCtsp_free_lpcut_in (&general); + goto CLEANUP; + } + } + + + *newcut = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!(*newcut)) { + fprintf (stderr, "out or memory in CCtsp_teething\n"); + rval = 1; goto CLEANUP; + } + + if (test) { + **newcut = pseudo; + } else { + **newcut = general; + } + + rval = CCtsp_test_pure_comb (g->ncount, *newcut, &test, (int *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_test_pure_comb failed\n"); + CCtsp_print_lpcut_in (&general); + goto CLEANUP; + } + +CLEANUP: + + teething_free_world (); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int optimal_pseudocomb (CCtsp_lpgraph *g, double *x, CCtsp_lpcut_in *c, + int ihandle, CCtsp_lpcut_in *d) +#else +static int optimal_pseudocomb (g, x, c, ihandle, d) +CCtsp_lpgraph *g; +double *x; +CCtsp_lpcut_in *c; +int ihandle; +CCtsp_lpcut_in *d; +#endif +{ + int rval = 0; + CCtsp_lpclique **bigteeth = (CCtsp_lpclique **) NULL; + int *hhit = (int *) NULL; + int *thit = (int *) NULL; + int *grab0 = (int *) NULL; + int *grab1 = (int *) NULL; + int *usebig = (int *) NULL; + double *ro0 = (double *) NULL; + double *ro1 = (double *) NULL; + intptr *newteeth = (intptr *) NULL; + Rrecord **R = (Rrecord **) NULL; + int nbig, i, j, si, sj, u, v, e; + int ncount = g->ncount; + CCtsp_lpclique *cliques = c->cliques; + CCtsp_lpclique *handle; + int add0, add1, parity; + double nu0, nu1, delta; + intptr *ip; + int ends[2]; + + CCtsp_init_lpcut_in (d); + + handle = &cliques[ihandle]; + + bigteeth = CC_SAFE_MALLOC (c->cliquecount, CCtsp_lpclique *); + hhit = CC_SAFE_MALLOC (ncount, int); + thit = CC_SAFE_MALLOC (ncount, int); + if (!bigteeth || !hhit || !thit) { + fprintf (stderr, "out of memory in optimal_pseudocombn"); + rval = 1; goto CLEANUP; + } + + identify_big_teeth (c, ihandle, &nbig, bigteeth); + + ro0 = CC_SAFE_MALLOC (nbig + 1, double); + ro1 = CC_SAFE_MALLOC (nbig + 1, double); + grab0 = CC_SAFE_MALLOC (nbig + 1, int); + grab1 = CC_SAFE_MALLOC (nbig + 1, int); + usebig = CC_SAFE_MALLOC (nbig + 1, int); + if (!ro0 || !ro1 || !grab0 || !grab1 || !usebig) { + fprintf (stderr, "out of memory in optimal_pseudocomb\n"); + rval = 1; goto CLEANUP; + } + R = CC_SAFE_MALLOC (nbig + 1, Rrecord *); + if (!R) { + fprintf (stderr, "out of memory in optimal_pseudocomb\n"); + rval = 1; goto CLEANUP; + } + for (i = 0; i <= nbig; i++) { + R[i] = (Rrecord *) NULL; + ro0[i] = 0.0; + ro1[i] = CCtsp_LP_MAXDOUBLE; + } + + CCtsp_mark_cut_and_neighbors (g, c, hhit, 0); + CCtsp_mark_cut_and_neighbors (g, c, thit, 0); + CCtsp_mark_clique (handle, hhit, 1); + for (i = 1; i <= nbig; i++) { + CCtsp_mark_clique (bigteeth[i], thit, i); + } + + for (si = 0; si < handle->segcount; si++) { + for (u = handle->nodes[si].lo; u <= handle->nodes[si].hi; u++) { + for (sj = 0; sj < g->nodes[u].deg; sj++) { + v = g->nodes[u].adj[sj].to; + e = g->nodes[u].adj[sj].edge; + if (hhit[v] != 1 && x[e] > 0.0) { + if (thit[v] != 0 && thit[v] == thit[u]) { + i = thit[v]; + } else { + i = 0; + } + nu0 = ro0[i]; + nu1 = ro1[i]; + if (nu1 + (1.0 - 2.0*x[e]) < nu0) { + ro0[i] = nu1 + (1.0 - 2.0*x[e]); + add0 = e; + } else { + add0 = -1; + } + if (nu0 + (1.0 - 2.0*x[e]) < nu1) { + ro1[i] = nu0 + (1.0 - 2.0*x[e]); + add1 = e; + } else { + add1 = -1; + } + if (add0 != -1 || add1 != -1) { + rval = add_to_record (&R[i], add0, add1); + if (rval) { + fprintf (stderr, "add_to_record failed\n"); + goto CLEANUP; + } + } + } + } + } + } + + for (i = 1; i <= nbig; i++) { + rval = CCtsp_clique_delta (g, x, bigteeth[i], &delta); + if (rval) { + fprintf (stderr, "CCtsp_clique_delta failed\n"); goto CLEANUP; + } + if (delta - 3.0 < ro1[i]) { + ro1[i] = delta - 3.0; + usebig[i] = 1; + } else { + usebig[i] = 0; + } + nu0 = ro0[0]; + nu1 = ro1[0]; + if (nu1 + ro1[i] < nu0 + ro0[i]) { + ro0[0] = nu1 + ro1[i]; + grab0[i] = 1; + } else { + ro0[0] = nu0 + ro0[i]; + grab0[i] = 0; + } + if (nu0 + ro1[i] < nu1 + ro0[i]) { + ro1[0] = nu0 + ro1[i]; + grab1[i] = 1; + } else { + ro1[0] = nu1 + ro0[i]; + grab1[i] = 0; + } + } + + parity = 1; + for (i = nbig; i > 0; i--) { + if (parity) { + if (grab1[i]) { + if (usebig[i]) { + rval = add_to_list (&newteeth, -i); + if (rval) goto CLEANUP; + } else { + rval = grab_record (R[i], 1, &newteeth); + if (rval) goto CLEANUP; + } + parity = 0; + } else { + rval = grab_record (R[i], 0, &newteeth); + if (rval) goto CLEANUP; + parity = 1; + } + } else { + if (grab0[i]) { + if (usebig) { + rval = add_to_list (&newteeth, -i); + if (rval) goto CLEANUP; + } else { + rval = grab_record (R[i], 1, &newteeth); + if (rval) goto CLEANUP; + } + parity = 1; + } else { + rval = grab_record (R[i], 0, &newteeth); + if (rval) goto CLEANUP; + parity = 0; + } + } + } + rval = grab_record (R[0], parity, &newteeth); + if (rval) goto CLEANUP; + + d->cliquecount = 1; + for (ip = newteeth; ip; ip = ip->next) { + d->cliquecount++; + } + d->cliques = CC_SAFE_MALLOC (d->cliquecount, CCtsp_lpclique); + if (!d->cliques) { + fprintf (stderr, "out of memory in optimal_pseudocombs\n"); + rval = 1; goto CLEANUP; + } + + rval = CCtsp_copy_lpclique (handle, &d->cliques[0]); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); + CC_FREE (d->cliques, CCtsp_lpclique); + goto CLEANUP; + } + for (i = 1, ip = newteeth; ip; ip = ip->next, i++) { + if (ip->this < 0) { + rval = CCtsp_copy_lpclique (bigteeth[-ip->this], &d->cliques[i]); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); + for (j = 0; j < i; j++) { + CCtsp_free_lpclique (&d->cliques[j]); + } + CC_FREE (d->cliques, CCtsp_lpclique); + goto CLEANUP; + } + } else { + ends[0] = g->edges[ip->this].ends[0]; + ends[1] = g->edges[ip->this].ends[1]; + rval = CCtsp_array_to_lpclique (ends, 2, &d->cliques[i]); + if (rval) { + fprintf (stderr, "CCtsp_array_to_lpclique failed\n"); + for (j = 0; j < i; j++) { + CCtsp_free_lpclique (&d->cliques[j]); + } + CC_FREE (d->cliques, CCtsp_lpclique); + goto CLEANUP; + } + } + } + + d->sense = 'G'; + d->rhs = 3 * d->cliquecount - 2; + +CLEANUP: + + CC_IFFREE (bigteeth, CCtsp_lpclique *); + CC_IFFREE (hhit, int); + CC_IFFREE (thit, int); + if (R) { + for (i = 0; i <= nbig; i++) { + Rrecordfree_list (R[i]); + } + CC_FREE (R, Rrecord *); + } + intptrfree_list (newteeth); + CC_IFFREE (ro0, double); + CC_IFFREE (ro1, double); + CC_IFFREE (grab0, int); + CC_IFFREE (grab1, int); + CC_IFFREE (usebig, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int grab_record (Rrecord *r, int parity, intptr **list) +#else +static int grab_record (r, parity, list) +Rrecord *r; +int parity; +intptr **list; +#endif +{ + int rval = 0; + + while (r) { + if (parity) { + if (r->add1 != -1) { + rval = add_to_list (list, r->add1); + if (rval) goto CLEANUP; + parity = 0; + } + } else { + if (r->add0 != -1) { + rval = add_to_list (list, r->add0); + if (rval) goto CLEANUP; + parity = 1; + } + } + r = r->next; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int clean_pseudocomb (CCtsp_lpgraph *g, double *x, CCtsp_lpcut_in *c, + CCtsp_lpcut_in *d) +#else +static int clean_pseudocomb (g, x, c, d) +CCtsp_lpgraph *g; +double *x; +CCtsp_lpcut_in *c; +CCtsp_lpcut_in *d; +#endif +{ + int rval = 0; + int *hmarks = (int *) NULL; + int *activeteeth = (int *) NULL; + int *cardteeth = (int *) NULL; + int *harray = (int *) NULL; + intptr **inteeth = (intptr **) NULL; + intptr *hlist = (intptr *) NULL; + int ccount = c->cliquecount; + CCtsp_lpclique *handle = &c->cliques[0]; + CCtsp_lpclique *cl; + int i, j, k, si, ismarked, cnt, big, ibig, ismall, hcnt; + double delta, smalldelta; + intptr *ip; + + CCtsp_init_lpcut_in (d); + + hmarks = CC_SAFE_MALLOC (g->ncount, int); + activeteeth = CC_SAFE_MALLOC (ccount, int); + cardteeth = CC_SAFE_MALLOC (ccount, int); + if (!hmarks || !activeteeth || !cardteeth) { + fprintf (stderr, "out of memory in clean_pseudocomb\n"); + rval = 1; goto CLEANUP; + } + + CCtsp_mark_cut (c, hmarks, 0); + CCtsp_mark_clique (handle, hmarks, 1); + for (i = 1; i < ccount; i++) { + activeteeth[i] = 1; + CCtsp_clique_count (&c->cliques[i], &cardteeth[i]); + } + + inteeth = CC_SAFE_MALLOC (g->ncount, intptr *); + if (!inteeth) { + fprintf (stderr, "out of memory in clean_pseudocomb\n"); + rval = 1; goto CLEANUP; + } + for (i = 1; i < ccount; i++) { + cl = &c->cliques[i]; + for (j = 0; j < cl->segcount; j++) { + for (k = cl->nodes[j].lo; k <= cl->nodes[j].hi; k++) { + inteeth[k] = (intptr *) NULL; + } + } + } + for (i = 0; i < handle->segcount; i++) { + for (j = handle->nodes[i].lo; j <= handle->nodes[i].hi; j++) { + inteeth[j] = (intptr *) NULL; + } + } + + for (i = 1; i < ccount; i++) { + cl = &c->cliques[i]; + for (j = 0; j < cl->segcount; j++) { + for (k = cl->nodes[j].lo; k <= cl->nodes[j].hi; k++) { + add_to_list (&inteeth[k], i); + } + } + } + for (i = 1; i < ccount; i++) { + if (!activeteeth[i]) continue; + cl = &c->cliques[i]; + for (j = 0; j < cl->segcount; j++) { + for (k = cl->nodes[j].lo; k <= cl->nodes[j].hi; k++) { + if (!hmarks[k]) { + cnt = 0; + big = 0; + ibig = -1; + for (ip = inteeth[k]; ip; ip = ip->next) { + if (activeteeth[ip->this]) { + cnt++; + if (cardteeth[ip->this] > big) { + big = cardteeth[ip->this]; + ibig = ip->this; + } + } + } + if (cnt > 1) { + CCtsp_mark_clique (&c->cliques[ibig], hmarks, 1); + for (si = 1; si < ccount; si++) { + if (activeteeth[si]) { + CCtsp_is_clique_marked (&c->cliques[si], + hmarks, 0, &ismarked); + activeteeth[si] = ismarked; + } + } + } + } + } + } + } + for (i = 0; i < handle->segcount; i++) { + for (j = handle->nodes[i].lo; j <= handle->nodes[i].hi; j++) { + if (hmarks[j]) { + cnt = 0; + big = 0; + ibig = -1; + for (ip = inteeth[j]; ip; ip = ip->next) { + if (activeteeth[ip->this]) { + cnt++; + if (cardteeth[ip->this] > big) { + big = cardteeth[ip->this]; + ibig = ip->this; + } + } + } + if (cnt > 1) { + CCtsp_mark_clique (&c->cliques[ibig], hmarks, 0); + for (si = 1; si < ccount; si++) { + if (activeteeth[si]) { + CCtsp_is_clique_marked (&c->cliques[si], + hmarks, 1, &ismarked); + activeteeth[si] = ismarked; + } + } + } + } + } + } + + for (i = 0, hcnt = 0; i < ccount; i++) { + cl = &c->cliques[i]; + for (j = 0; j < cl->segcount; j++) { + for (k = cl->nodes[j].lo; k <= cl->nodes[j].hi; k++) { + if (hmarks[k] == 1) { + rval = add_to_list (&hlist, k); + if (rval) goto CLEANUP; + hmarks[k] = 2; + hcnt++; + } + } + } + } + + if (!hcnt) { + printf ("WARNING: generalized comb gets and empty handle\n"); + fflush (stdout); + goto CLEANUP; + } + harray = CC_SAFE_MALLOC (hcnt, int); + if (!harray) { + fprintf (stderr, "out of memory in clean_pseudocomb\n"); + rval = 1; goto CLEANUP; + } + for (ip = hlist, hcnt = 0; ip; ip = ip->next) { + harray[hcnt++] = ip->this; + } + + cnt = 0; + for (i = 1; i < ccount; i++) { + if (activeteeth[i]) cnt++; + } + if (!cnt) { + printf ("WARNING: generalized comb gets no teeth\n"); + fflush (stdout); + goto CLEANUP; + } + + if (cnt % 2 == 0) { + smalldelta = CCtsp_LP_MAXDOUBLE; + ismall = -1; + for (i = 1; i < ccount; i++) { + if (activeteeth[i]) { + rval = CCtsp_clique_delta (g, x, &c->cliques[i], &delta); + if (rval) { + fprintf (stderr, "CCtsp_clique_delta failed\n"); + goto CLEANUP; + } + if (delta < smalldelta) { + smalldelta = delta; + ismall = i; + } + } + } + activeteeth[ismall] = 0; + cnt--; + } + cnt++; + + d->cliques = CC_SAFE_MALLOC (cnt, CCtsp_lpclique); + if (!d->cliques) { + fprintf (stderr, "out of memory in clean_pseudocomb\n"); + rval = 1; goto CLEANUP; + } + rval = CCtsp_array_to_lpclique (harray, hcnt, &d->cliques[0]); + if (rval) { + fprintf (stderr, "CCtsp_array_to_lpclique failed\n"); + CC_FREE (d->cliques, CCtsp_lpclique); + goto CLEANUP; + } + for (i = 1, cnt = 1; i < ccount; i++) { + if (activeteeth[i]) { + rval = CCtsp_copy_lpclique (&c->cliques[i], &d->cliques[cnt++]); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpclique failed\n"); + for (j = 0; j < cnt; j++) { + CCtsp_free_lpclique (&d->cliques[j]); + } + CC_FREE (d->cliques, CCtsp_lpclique); + goto CLEANUP; + } + } + } + d->cliquecount = cnt; + d->rhs = 3 * d->cliquecount - 2; + d->sense = 'G'; + +CLEANUP: + + CC_IFFREE (hmarks, int); + CC_IFFREE (activeteeth, int); + CC_IFFREE (cardteeth, int); + CC_IFFREE (harray, int); + if (inteeth) { + for (i = 1; i < ccount; i++) { + cl = &c->cliques[i]; + for (j = 0; j < cl->segcount; j++) { + for (k = cl->nodes[j].lo; k <= cl->nodes[j].hi; k++) { + if (inteeth[k]) { + intptrfree_list (inteeth[k]); + inteeth[k] = (intptr *) NULL; + } + } + } + } + CC_FREE (inteeth, intptr *); + } + intptrfree_list (hlist); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void teething_free_world (void) +#else +static void teething_free_world () +#endif +{ + int total, onlist; + + if (intptr_status (&total, &onlist)) { + printf ("Active Teething Intptrs: %d\n", total - onlist); + fflush (stdout); + } else { + if (intptr_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding intptrs in teething\n", + total - onlist); + } + intptrfree_world (); + } + + if (Rrecord_status (&total, &onlist)) { + printf ("Active Teething Rrecords: %d\n", total - onlist); + fflush (stdout); + } else { + if (Rrecord_check_leaks (&total, &onlist)) { + fprintf (stderr, "WARNING: %d outstanding Rrecords in teething\n", + total - onlist); + } + Rrecordfree_world (); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void identify_big_teeth (CCtsp_lpcut_in *cut, int handle, int *nbig, + CCtsp_lpclique **bigteeth) +#else +static void identify_big_teeth (cut, handle, nbig, bigteeth) +CCtsp_lpcut_in *cut; +int handle; +int *nbig; +CCtsp_lpclique **bigteeth; +#endif +{ + int i, k; + + /* teeth filled into positions 1 through nbig */ + + *nbig = 0; + for (i = 0; i < cut->cliquecount; i++) { + if (i != handle) { + CCtsp_clique_count (&(cut->cliques[i]), &k); + if (k >= 3) { + bigteeth[++(*nbig)] = &(cut->cliques[i]); + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_to_list (intptr **list, int item) +#else +static int add_to_list (list, item) +intptr **list; +int item; +#endif +{ + intptr *ip; + + ip = intptralloc (); + if (!ip) { fprintf (stderr, "intptralloc failed\n"); return 1; } + ip->this = item; + ip->next = *list; + *list = ip; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_to_record (Rrecord **R, int add0, int add1) +#else +static int add_to_record (R, add0, add1) +Rrecord **R; +int add0, add1; +#endif +{ + Rrecord *p; + + p = Rrecordalloc (); + if (!p) { fprintf (stderr, "Rrecordalloc failed\n"); return 1; } + p->add0 = add0; + p->add1 = add1; + p->next = *R; + *R = p; + return 0; +} diff --git a/contrib/blossom/concorde97/TSP/tighten.c b/contrib/blossom/concorde97/TSP/tighten.c new file mode 100644 index 0000000000000000000000000000000000000000..5062cefc11b155b0c66aa9fb46018ffb606380ca --- /dev/null +++ b/contrib/blossom/concorde97/TSP/tighten.c @@ -0,0 +1,878 @@ +#include "machdefs.h" +#include "util.h" +#include "tsp.h" + +#undef USE_INLINES +#undef TIGHTEN_NOTIEADD +#undef NOTIGHTEN + +#define EPS (1e-6) + +typedef struct tighten_node { + struct tighten_node *next; /* to maintain atomlist */ + struct tighten_node *prev; + struct tighten_node **atomlist; /* alpha(v) */ + struct qu_elem *moves; /* size ncliques */ + struct tighten_node *next_initialized; /* to maintain initialized_nodes */ +} tighten_node; + +typedef struct qu_elem { + double delta; + tighten_node *v; /* node to move */ + int i; /* clique to adjust */ + int chi; /* 0==outside, last del tied */ + /* 1==inside, 2 otherwise */ + int queue_handle; +} qu_elem; + +typedef union atomfind { + union atomfind *child[2]; + tighten_node *nodelist; /* A(I) in writeup */ + union atomfind *next; /* for freelist */ +} atomfind; + +typedef struct tighten_graph { + CCtsp_lpgraph *g; + struct tighten_node *nodes; + double *x; + int ncliques; + int nhandles; + int rhs; + + atomfind *atomtree; + tighten_node *initialized_nodes; /* Vstar in writeup */ + CCpriority queue; +} tighten_graph; + +#define NODE_IN_SINGLETON(v) ((v)->atomlist && (*((v)->atomlist)) \ + && (!(*((v)->atomlist))->next)) + +#ifdef CC_PROTOTYPE_ANSI + +static void + add_to_atom (tighten_node *v), + delete_from_atom (tighten_node *v), + cleanup_atomfinder (atomfind *tree, int depth), + cleanup_graph (tighten_graph *tg); + +static int + update_queue (CCpriority *q, qu_elem *qe), + initialize_graph (CCtsp_lpgraph *g, double *x, tighten_graph *tg), + initialize_lpcut_in (tighten_graph *tg, CCtsp_lpcut_in *c), + initialize_lpcut (tighten_graph *tg, CCtsp_lpclique *cliques, + CCtsp_lpcut *c), + initialize_node (tighten_graph *tg, tighten_node *v, int add_atom), + process_qu_elem (tighten_graph *tg, qu_elem *q), + process_qu_elem_atom (tighten_graph *tg, tighten_node *v), + process_qu_elem_delta (tighten_graph *tg, qu_elem *q), + collect_new_cut (tighten_graph *tg, CCtsp_lpcut_in *cout), + tighten_cut (tighten_graph *tg, CCtsp_tighten_info *stats, + double *pimprove); + +static tighten_node + **find_atomlist (tighten_graph *tg, tighten_node *v, int add); + +#ifndef USE_INLINES +static double + qu_elem_key (qu_elem *q); +static int + qu_elem_is_active (qu_elem *q); +#endif + +#else /* CC_PROTOTYPE_ANSI */ + +static void + add_to_atom (), + delete_from_atom (), + cleanup_atomfinder (), + cleanup_graph (); + +static int + update_queue (), + initialize_graph (), + initialize_lpcut_in (), + initialize_lpcut (), + initialize_node (), + process_qu_elem (), + process_qu_elem_atom (), + process_qu_elem_delta (), + collect_new_cut (), + tighten_cut (); + +static tighten_node + **find_atomlist (); + +#ifndef USE_INLINES +static double + qu_elem_key (); +static int + qu_elem_is_active (); +#endif + +#endif /* CC_PROTOTYPE_ANSI */ + +CC_PTR_ALLOC_ROUTINE (atomfind, atomfind_alloc, chunklist, atomfind_freelist) +CC_PTR_FREE_ROUTINE (atomfind, atomfind_free, atomfind_freelist) +CC_PTR_FREE_WORLD_ROUTINE (atomfind, atomfind_freeworld, chunklist, + atomfind_freelist) +CC_PTR_LEAKS_ROUTINE (atomfind, atomfind_leaks, chunklist, atomfind_freelist, + child[1], atomfind *) + +#ifdef USE_INLINES + +#define qu_elem_key(q) (((q)->delta > EPS) ? (-(3.0 + (q)->delta)) \ + : (-((q)->chi + (q)->delta))) +#ifdef TIGHTEN_NOTIEADD +#define qu_elem_is_active(q) ((!NODE_IN_SINGLETON((q)->v)) \ + && ((q)->delta > EPS \ + || ((q)->delta >= 0.0 && (q)->chi == 1))) +#else +#define qu_elem_is_active(q) ((!NODE_IN_SINGLETON((q)->v)) \ + && ((q)->delta > EPS \ + || ((q)->delta >= 0.0 && (q)->chi > 0))) +#endif + +#else /* USE_INLINES */ + +#ifdef CC_PROTOTYPE_ANSI +static double qu_elem_key (qu_elem *q) +#else +static double qu_elem_key (q) +qu_elem *q; +#endif +{ + double key; + + if (q->delta > EPS) { + key = 3.0 + q->delta; + } else { + key = q->chi + q->delta; + } + return -key; +} + +#ifdef CC_PROTOTYPE_ANSI +static int qu_elem_is_active (qu_elem *q) +#else +static int qu_elem_is_active (q) +qu_elem *q; +#endif +{ +#ifdef TIGHTEN_NOTIEADD + return ((!NODE_IN_SINGLETON(q->v)) + && ((q->delta > EPS) + || ((q)->delta >= 0.0 && (q)->chi == 1))); +#else + return ((!NODE_IN_SINGLETON(q->v)) + && ((q->delta > EPS) + || ((q)->delta >= 0.0 && (q)->chi > 0))); +#endif +} + +#endif + +#ifdef CC_PROTOTYPE_ANSI +static void add_to_atom (tighten_node *v) +#else +static void add_to_atom (v) +tighten_node *v; +#endif +{ + if (v->atomlist) { + v->next = *(v->atomlist); + if (v->next) v->next->prev = v; + v->prev = (tighten_node *) NULL; + *(v->atomlist) = v; + } else { + v->next = (tighten_node *) NULL; + v->prev = (tighten_node *) NULL; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void delete_from_atom (tighten_node *v) +#else +static void delete_from_atom (v) +tighten_node *v; +#endif +{ + if (v->next) v->next->prev = v->prev; + if (v->prev) v->prev->next = v->next; + else if (v->atomlist) *(v->atomlist) = v->next; +} + +#ifdef CC_PROTOTYPE_ANSI +static int update_queue (CCpriority *q, qu_elem *qe) +#else +static int update_queue (q, qe) +CCpriority *q; +qu_elem *qe; +#endif +{ + double newkey; + int handle; + + if (qu_elem_is_active (qe)) { + newkey = qu_elem_key (qe); + if (qe->queue_handle >= 0) { + CCutil_priority_changekey (q, qe->queue_handle, newkey); + } else { + handle = CCutil_priority_insert (q, (void *) qe, newkey); + if (handle < 0) { + return handle; + } + qe->queue_handle = handle; + } + } else { + if (qe->queue_handle >= 0) { + CCutil_priority_delete (q, qe->queue_handle); + qe->queue_handle = -1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static tighten_node **find_atomlist (tighten_graph *tg, tighten_node *v, + int add) +#else +static tighten_node **find_atomlist (tg, v, add) +tighten_graph *tg; +tighten_node *v; +int add; +#endif +{ + atomfind *f = tg->atomtree; + atomfind **pf = &(tg->atomtree); + int i; + int dir; + + for (i=0; i<tg->ncliques; i++) { + if (!f) { + if (add) { + (*pf) = f = atomfind_alloc(); + if (!f) return (tighten_node **) NULL; + f->child[0] = (atomfind *) NULL; + f->child[1] = (atomfind *) NULL; + } else { + return (tighten_node **) NULL; + } + } + + dir = v->moves[i].chi & 1; + pf = &(f->child[dir]); + f = f->child[dir]; + } + if (!f) { + if (add) { + (*pf) = f = atomfind_alloc(); + if (!f) return (tighten_node **) NULL; + f->nodelist = (tighten_node *) NULL; + } else { + return (tighten_node **) NULL; + } + } + + return &(f->nodelist); +} + +#ifdef CC_PROTOTYPE_ANSI +static void cleanup_atomfinder (atomfind *tree, int depth) +#else +static void cleanup_atomfinder (tree, depth) +atomfind *tree; +int depth; +#endif +{ + if (depth > 0) { + if (tree->child[0]) { + cleanup_atomfinder (tree->child[0], depth-1); + } + if (tree->child[1]) { + cleanup_atomfinder (tree->child[1], depth-1); + } + } + atomfind_free (tree); +} + +#ifdef CC_PROTOTYPE_ANSI +static int initialize_graph (CCtsp_lpgraph *g, double *x, tighten_graph *tg) +#else +static int initialize_graph (g, x, tg) +CCtsp_lpgraph *g; +double *x; +tighten_graph *tg; +#endif +{ + int rval; + + tg->g = g; + tg->x = x; + + tg->nodes = (tighten_node *) CC_SAFE_MALLOC (g->ncount, tighten_node); + if (!tg->nodes) return -1; + + rval = CCutil_priority_init (&tg->queue, 1000); + if (rval) { + CC_FREE (tg->nodes, tighten_node); + return rval; + } + + tg->initialized_nodes = (tighten_node *) NULL; + tg->atomtree = (atomfind *) NULL; + tg->ncliques = 0; + g->nodemarker++; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int initialize_lpcut_in (tighten_graph *tg, CCtsp_lpcut_in *c) +#else +static int initialize_lpcut_in (tg, c) +tighten_graph *tg; +CCtsp_lpcut_in *c; +#endif +{ + int i,j,k,l,m; + CCtsp_lpgraph *g = tg->g; + CCtsp_lpclique *cl; + tighten_node *v; + int rval; + + tg->ncliques = c->cliquecount; + tg->nhandles = c->handlecount; + tg->rhs = c->rhs; + for (i=0; i<tg->ncliques; i++) { + cl = &(c->cliques[i]); + for (j=0; j<cl->segcount; j++) { + for (k=cl->nodes[j].lo; k<=cl->nodes[j].hi; k++) { + if (g->nodes[k].mark < g->nodemarker) { + rval = initialize_node (tg, &(tg->nodes[k]), 0); + if (rval) return rval; + } + tg->nodes[k].moves[i].chi = 1; + for (l=0; l<g->nodes[k].deg; l++) { + m = g->nodes[k].adj[l].to; + if (g->nodes[m].mark < g->nodemarker) { + rval = initialize_node (tg, &(tg->nodes[m]), 0); + if (rval) return rval; + } + } + } + } + } + + for (v = tg->initialized_nodes; v; v = v->next_initialized) { + v->atomlist = find_atomlist (tg, v, 1); + if (!v->atomlist) { + return -1; + } + add_to_atom (v); + } + + for (v = tg->initialized_nodes; v; v = v->next_initialized) { + k = v - tg->nodes; + for (l=0; l<g->nodes[k].deg; l++) { + m = g->nodes[k].adj[l].to; + if (g->nodes[m].mark == g->nodemarker) { + for (i=0; i<tg->ncliques; i++) { + if (v->moves[i].chi != tg->nodes[m].moves[i].chi) { + v->moves[i].delta += tg->x[g->nodes[k].adj[l].edge]; + } + } + } + } + for (i=0; i<tg->ncliques; i++) { + rval = update_queue (&tg->queue, &v->moves[i]); + if (rval) return rval; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int initialize_lpcut (tighten_graph *tg, CCtsp_lpclique *cliques, + CCtsp_lpcut *c) +#else +static int initialize_lpcut (tg, cliques, c) +tighten_graph *tg; +CCtsp_lpclique *cliques; +CCtsp_lpcut *c; +#endif +{ + int i,j,k,l,m; + CCtsp_lpgraph *g = tg->g; + CCtsp_lpclique *cl; + tighten_node *v; + int rval; + + tg->ncliques = c->cliquecount; + tg->nhandles = c->handlecount; + tg->rhs = c->rhs; + for (i=0; i<tg->ncliques; i++) { + cl = &cliques[c->cliques[i]]; + for (j=0; j<cl->segcount; j++) { + for (k=cl->nodes[j].lo; k<=cl->nodes[j].hi; k++) { + if (g->nodes[k].mark < g->nodemarker) { + rval = initialize_node (tg, &(tg->nodes[k]), 0); + if (rval) return rval; + } + tg->nodes[k].moves[i].chi = 1; + for (l=0; l<g->nodes[k].deg; l++) { + m = g->nodes[k].adj[l].to; + if (g->nodes[m].mark < g->nodemarker) { + rval = initialize_node (tg, &(tg->nodes[m]), 0); + if (rval) return rval; + } + } + } + } + } + + for (v = tg->initialized_nodes; v; v = v->next_initialized) { + v->atomlist = find_atomlist (tg, v, 1); + if (!v->atomlist) { + return -1; + } + add_to_atom (v); + } + + for (v = tg->initialized_nodes; v; v = v->next_initialized) { + k = v - tg->nodes; + for (l=0; l<g->nodes[k].deg; l++) { + m = g->nodes[k].adj[l].to; + if (g->nodes[m].mark == g->nodemarker) { + for (i=0; i<tg->ncliques; i++) { + if (v->moves[i].chi != tg->nodes[m].moves[i].chi) { + v->moves[i].delta += tg->x[g->nodes[k].adj[l].edge]; + } + } + } + } + for (i=0; i<tg->ncliques; i++) { + rval = update_queue (&tg->queue, &v->moves[i]); + if (rval) return rval; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int initialize_node (tighten_graph *tg, tighten_node *v, int add_atom) +#else +static int initialize_node (tg, v, add_atom) +tighten_graph *tg; +tighten_node *v; +int add_atom; +#endif +{ + int i; + + v->moves = CC_SAFE_MALLOC (tg->ncliques, qu_elem); + if (!v->moves) return -1; + + for (i=0; i<tg->ncliques; i++) { + v->moves[i].v = v; + v->moves[i].i = i; + v->moves[i].delta = -1.0; + v->moves[i].chi = 2; + v->moves[i].queue_handle = -1; + } + if (add_atom) { + v->atomlist = find_atomlist (tg, v, 0); + if (v->atomlist) { + add_to_atom (v); + } + } else { + v->atomlist = (tighten_node **) NULL; + } + + v->next_initialized = tg->initialized_nodes; + tg->initialized_nodes = v; + + tg->g->nodes[v - tg->nodes].mark = tg->g->nodemarker; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int process_qu_elem (tighten_graph *tg, qu_elem *q) +#else +static int process_qu_elem (tg, q) +tighten_graph *tg; +qu_elem *q; +#endif +{ + int rval; + + if (q->chi == 1) { + if (q->delta <= EPS) { + q->chi = 0; + } else { + q->chi = 2; + } + } else { + q->chi = 1; + } + rval = process_qu_elem_atom (tg, q->v); + if (rval) return rval; + rval = process_qu_elem_delta (tg, q); + if (rval) return rval; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int process_qu_elem_atom (tighten_graph *tg, tighten_node *v) +#else +static int process_qu_elem_atom (tg, v) +tighten_graph *tg; +tighten_node *v; +#endif +{ + tighten_node *w; + int j; + int rval; + + if (v->atomlist) { + delete_from_atom (v); + + if (NODE_IN_SINGLETON(v)) { + w = *(v->atomlist); + for (j=0; j<tg->ncliques; j++) { + rval = update_queue (&tg->queue, &w->moves[j]); + if (rval) return rval; + } + } + } + + /* chi was updated before the call */ + v->atomlist = find_atomlist (tg, v, 0); + + if (v->atomlist) { + w = *(v->atomlist); + + add_to_atom (v); + + if (w->next == (tighten_node *) NULL) { + /* v->atomlist was the singleton w */ + for (j=0; j<tg->ncliques; j++) { + rval = update_queue (&tg->queue, &w->moves[j]); + if (rval) return rval; + } + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int process_qu_elem_delta (tighten_graph *tg, qu_elem *q) +#else +static int process_qu_elem_delta (tg, q) +tighten_graph *tg; +qu_elem *q; +#endif +{ + tighten_node *v = q->v; + int i = q->i; + tighten_node *w; + int j; + CCtsp_lpgraph *g = tg->g; + int nv = v - tg->nodes; + int nw; + int e; + int rval; + + v->moves[i].delta = -v->moves[i].delta; + rval = update_queue (&tg->queue, &v->moves[i]); + if (rval) return rval; + + for (j=0; j<g->nodes[nv].deg; j++) { + nw = g->nodes[nv].adj[j].to; + e = g->nodes[nv].adj[j].edge; + w = &tg->nodes[nw]; + if (g->nodes[nw].mark < g->nodemarker) { + rval = initialize_node (tg, w, 1); + if (rval) return rval; + } + + if ((v->moves[i].chi & 1) == (w->moves[i].chi & 1)) { + w->moves[i].delta -= tg->x[e]; + } else { + w->moves[i].delta += tg->x[e]; + } + rval = update_queue (&tg->queue, &w->moves[i]); + if (rval) return rval; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void cleanup_graph (tighten_graph *tg) +#else +static void cleanup_graph (tg) +tighten_graph *tg; +#endif +{ + tighten_node *v, *vnext; + + for (v = tg->initialized_nodes; v; v = vnext) { + vnext = v->next_initialized; + CC_FREE (v->moves, qu_elem); + } + cleanup_atomfinder (tg->atomtree, tg->ncliques); + +#if 0 + { + int total, onlist, leak; + if ((leak = atomfind_leaks(&total, &onlist))) { + fprintf (stderr, "TIGHTEN leaked %d atomfind's (total %d onlist %d)\n", + leak, total, onlist); + } + } +#endif + + atomfind_freeworld(); + + CCutil_priority_free (&tg->queue); + + CC_FREE (tg->nodes, tighten_node); +} + +#ifdef CC_PROTOTYPE_ANSI +static int collect_lpclique (tighten_graph *tg, int cnum, CCtsp_lpclique *c) +#else +static int collect_lpclique (tg, cnum, c) +tighten_graph *tg; +int cnum; +CCtsp_lpclique *c; +#endif +{ + tighten_node *v; + int cnt; + int *arr; + int rval; + + cnt = 0; + for (v = tg->initialized_nodes; v; v = v->next_initialized) { + if (v->moves[cnum].chi == 1) cnt++; + } + arr = CC_SAFE_MALLOC (cnt, int); + if (!arr) return -1; + + cnt = 0; + for (v = tg->initialized_nodes; v; v = v->next_initialized) { + if (v->moves[cnum].chi == 1) { + arr[cnt++] = v - tg->nodes; + } + } + + rval = CCtsp_array_to_lpclique (arr, cnt, c); + CC_FREE (arr, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int collect_new_cut (tighten_graph *tg, CCtsp_lpcut_in *cout) +#else +static int collect_new_cut (tg, cout) +tighten_graph *tg; +CCtsp_lpcut_in *cout; +#endif +{ + int i, j; + int rval; + + cout->handlecount = tg->nhandles; + cout->cliquecount = tg->ncliques; + cout->rhs = tg->rhs; + cout->cliques = CC_SAFE_MALLOC (tg->ncliques, CCtsp_lpclique); + if (!cout->cliques) { + return -1; + } + + for (i=0; i<tg->ncliques; i++) { + rval = collect_lpclique (tg, i, &(cout->cliques[i])); + if (rval) { + for (j=0; j<i; j++) { + CC_FREE (cout->cliques[i].nodes, CCtsp_segment); + } + CC_FREE (cout->cliques, CCtsp_lpclique); + return rval; + } + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int tighten_cut (tighten_graph *tg, CCtsp_tighten_info *stats, + double *pimprove) +#else +static int tighten_cut (tg, stats, pimprove) +tighten_graph *tg; +CCtsp_tighten_info *stats; +double *pimprove; +#endif +{ + qu_elem *q; + int rval; + double improve = 0.0; + + while ((q = (qu_elem *) CCutil_priority_deletemin (&tg->queue, + (double *) NULL))) { + if (q->v->moves[q->i].chi == 1) { + stats->ndel++; + stats->del_delta += q->delta; + if (q->delta <= EPS) stats->ndel_tied++; + } else { + stats->nadd++; + stats->add_delta += q->delta; + if (q->delta <= EPS) stats->nadd_tied++; + } + improve += q->delta; + q->queue_handle = -1; + rval = process_qu_elem (tg, q); + if (rval) return rval; + } + if (pimprove) *pimprove = improve; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_tighten_lpcut_in (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, double *x, + CCtsp_lpcut_in *cout, CCtsp_tighten_info *stats, double *pimprove) +#else +int CCtsp_tighten_lpcut_in (g, c, x, cout, stats, pimprove) +CCtsp_lpgraph *g; +CCtsp_lpcut_in *c; +double *x; +CCtsp_lpcut_in *cout; +CCtsp_tighten_info *stats; +double *pimprove; +#endif +{ + tighten_graph tg; + int rval = 0; + double szeit = CCutil_zeit (); + + if (c->branch != 0) { + fprintf (stderr, "try to tighten a branch cut\n"); return 1; + } + if (c->sense != 'G') { + fprintf (stderr, "try to tighten a <= cut\n"); return 1; + } + + rval = initialize_graph (g, x, &tg); + if (rval) return rval; + + rval = initialize_lpcut_in (&tg, c); + if (rval) goto CLEANUP; + +#ifndef NOTIGHTEN + rval = tighten_cut (&tg, stats, pimprove); + if (rval) goto CLEANUP; +#endif + + rval = collect_new_cut (&tg, cout); + if (rval) goto CLEANUP; + + cout->branch = c->branch; + cout->sense = c->sense; + +CLEANUP: + + stats->ncall++; + if (rval) stats->nfail++; + stats->time += CCutil_zeit () - szeit; + cleanup_graph (&tg); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_tighten_lpcut (CCtsp_lpgraph *g, CCtsp_lpclique *cliques, + CCtsp_lpcut *c, double *x, CCtsp_lpcut_in *cout, + CCtsp_tighten_info *stats, double *pimprove) +#else +int CCtsp_tighten_lpcut (g, cliques, c, x, cout, stats, pimprove) +CCtsp_lpgraph *g; +CCtsp_lpclique *cliques; +CCtsp_lpcut *c; +double *x; +CCtsp_lpcut_in *cout; +CCtsp_tighten_info *stats; +double *pimprove; +#endif +{ + tighten_graph tg; + int rval = 0; + double szeit = CCutil_zeit (); + + if (c->branch != 0) { + fprintf (stderr, "try to tighten a branch cut\n"); return 1; + } + if (c->sense != 'G') { + fprintf (stderr, "try to tighten a <= cut\n"); return 1; + } + + rval = initialize_graph (g, x, &tg); + if (rval) return rval; + + rval = initialize_lpcut (&tg, cliques, c); + if (rval) goto CLEANUP; + + rval = tighten_cut (&tg, stats, pimprove); + if (rval) goto CLEANUP; + + rval = collect_new_cut (&tg, cout); + if (rval) goto CLEANUP; + + cout->branch = c->branch; + cout->sense = c->sense; + +CLEANUP: + + stats->ncall++; + if (rval) stats->nfail++; + stats->time += CCutil_zeit () - szeit; + cleanup_graph (&tg); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_init_tighten_info (CCtsp_tighten_info *stats) +#else +void CCtsp_init_tighten_info (stats) +CCtsp_tighten_info *stats; +#endif +{ + stats->ncall = 0; + stats->nfail = 0; + stats->nadd = 0; + stats->nadd_tied = 0; + stats->ndel = 0; + stats->ndel_tied = 0; + stats->add_delta = 0.0; + stats->del_delta = 0.0; + stats->time = 0.0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_print_tighten_info (CCtsp_tighten_info *stats) +#else +void CCtsp_print_tighten_info (stats) +CCtsp_tighten_info *stats; +#endif +{ + printf ("TIGHTEN STATS: %d calls (%d failed), %.2f improvement, %.2f seconds\n", + stats->ncall, stats->nfail, stats->add_delta + stats->del_delta, + stats->time); + printf (" %d adds, %d tied, %.2f improvement\n", + stats->nadd, stats->nadd_tied, stats->add_delta); + printf (" %d dels, %d tied, %.2f improvement\n", + stats->ndel, stats->ndel_tied, stats->del_delta); + fflush (stdout); +} diff --git a/contrib/blossom/concorde97/TSP/tsp_lp.c b/contrib/blossom/concorde97/TSP/tsp_lp.c new file mode 100644 index 0000000000000000000000000000000000000000..af143474e78ee126513fb82ce3fb86b153929cca --- /dev/null +++ b/contrib/blossom/concorde97/TSP/tsp_lp.c @@ -0,0 +1,3691 @@ +/***************************************************************************/ +/* */ +/* ROUTINES TO BUILD LPS AND CALL THE LP SOLVER */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: September 26, 1995 */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* void CCtsp_init_tsp_lp_struct (CCtsp_lp *lp) */ +/* INITIALIZES the CCtsp_lp struture with NULL values */ +/* */ +/* int CCtsp_init_lp (CCtsp_lp **lp, char *probname, int probnum, */ +/* char *probfilename, int ncount, CCdatagroup *dat, int ecount, */ +/* int *elist, int *elen, int excount, int *exlist, int *exlen, */ +/* int exvalid, int *ptour, double initial_ub, */ +/* CCtsp_lpcuts *pool) */ +/* BUILDS/READS the problem, and loads it into the LP solver. If */ +/* probnum < 0, init_lp will build an initial problem according to */ +/* edgegengroup; otherwise it will read the problem from disk. If */ +/* the problem is read from disk, then the elist is ignored. */ +/* -lp is a handle to the tsp lp (filled in by init_lp) */ +/* -probname is the name for the problem */ +/* -probnum is the number for the problem */ +/* -ncount is the number of nodes */ +/* -dat is a handle on the complete graph */ +/* -plan says how to generate an initial edgeset */ +/* -ecount, elist, elen specify an initial edge set (they can be */ +/* 0, NULL, NULL); if a prob is read from a file, then this list */ +/* is ignored */ +/* -excount, exlist, exlen specify an full edge set (they can be */ +/* 0, NULL, NULL); if the probfile already has an full edge set, */ +/* then this values are ignored. */ +/* -exvalid indicates whether or not the edges specified in exlist */ +/* are a valid complete set of edges (0 no, 1 yes) */ +/* -pool is a pointer to a cutpool (can be NULL) */ +/* NOTE: If init_lp returns 2, then the LP is infeasible (even after */ +/* considering the full edge set). */ +/* */ +/* int CCtsp_bb_init_lp (CCtsp_lp **lp, char *probname, int probnum, */ +/* int ncount, CCdatagroup *dat, int *ptour, double initial_ub, */ +/* CCtsp_lpcuts *pool) */ +/* SHORT form of CCtsp_init_lp for use in the branch and bound. */ +/* */ +/* int CCtsp_get_lp_result (CCtsp_lp *lp, double *lb, double *ub, */ +/* int *ecount, int **elist, double **x, double **rc, */ +/* double **node_pi, double **cut_pi) */ +/* RETURNS a copy of the values cached in lp->result. However, it */ +/* allows a single point of locking for the threaded version. Any */ +/* return argument can be NULL. */ +/* -lp is a pointer to the tsp lp */ +/* -obj returns the location for the current objective value */ +/* -ecount returns the location for the number of nonzero edges */ +/* -elist returns the location for the nonzero edges in end1 end2 */ +/* format */ +/* -x returns location for the edge values */ +/* -rc returns location for the edge values */ +/* -node_pi returns the values on the degree constraints */ +/* -cut_pi returns the dual values on the cuts */ +/* NOTE: node_pi and cut_pi go to the LP to fetch the results. */ +/* */ +/* int CCtsp_add_cut (CCtsp_lp *lp, CCtsp_lpcut_in *d, CCtsp_lprow *cr) */ +/* ADDS cut d to the lp structure and to cr (a call to */ +/* CCtsp_add_multiple will put the cut into the lp solver) */ +/* */ +/* int CCtsp_add_multiple_rows (CCtsp_lp *lp, CCtsp_lprow *cr) */ +/* HANDS the cuts in cr to the lp solver. */ +/* */ +/* void CCtsp_add_cuts_to_queue (CCtsp_lp *lp, CCtsp_lpcut_in **clist) */ +/* ADDS clist to the queue of cuts to be processed by the lp solver; */ +/* clist will be set to NULL */ +/* -lp is a pointer to the tsp lp */ +/* -clist is the head of a NULL terminated linked list of cuts */ +/* */ +/* int CCtsp_add_cut_to_cutlist (CCtsp_lpcuts *cuts, CCtsp_lpcut *c) */ +/* */ +/* void CCtsp_delete_cut_from_cutlist (CCtsp_lpcuts *cuts, int ind) */ +/* */ +/* int CCtsp_process_cuts (CCtsp_lp *lp, int *pnadded, int tighten) */ +/* -lp is a pointer to the tsp lp */ +/* -pnadded returns the location for the number of cuts added */ +/* -tighten is a flag to indicate whether or not the tighten routine */ +/* should be called for each cut before it is added to the LP */ +/* NOTE: process_cuts runs through all the cuts in the queue; */ +/* process_cuts also calls add_to_cutpool(). If process_cuts */ +/* returns 2, then the LP is infeasible, even after considering the */ +/* full edge set. */ +/* */ +/* int CCtsp_addbad_variables (CCtsp_lp *lp, struct edgegenerator *eg, */ +/* double *ppenalty, int *pnadded, double rcthresh, */ +/* double maxpenalty, int phase1, int *feasible) */ +/* ADDS negative reduced cost edges to the LP; if phase1 is nonzero */ +/* then the added edges attempt to make a feasible LP (in this */ +/* case the eg variable is ignored and the edges are taked either */ +/* from fulladj (if they are valid) or from dat) */ +/* -lp is a pointer to the tsp lp */ +/* -eg is a generator for the edges to check */ +/* -ppenalty is the penalty from the last pass of pricing */ +/* -pnadded is the number of negative reduced cost edges added */ +/* -rcthresh is the threshold on the reduced cost of edges to be */ +/* added (it should be something <= 0.0) */ +/* -maxpenalty is the maximum sum of penalties that is permitted */ +/* before the rounds of pricing stop */ +/* -phase1 should be 0 for normal column generation, and nonzero */ +/* to try to fix an infeasible LP */ +/* -feasible can be NULL, otherwise it is set to 1 if phase 1 */ +/* gets to a feasible LP and 0 if the LP really is infeasible */ +/* */ +/* int CCtsp_eliminate_variables (CCtsp_lp *lp) */ +/* SETS edges to 0 or 1 if possible, based on reduced costs */ +/* -lp is a pointer to the tsp lp */ +/* */ +/* double CCtsp_cutprice (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, */ +/* double *x) */ +/* RETURNS the slack of cut c */ +/* -g is a pointer to an CCtsp_lpgraph that matches the vector x */ +/* */ +/* int CCtsp_add_vars_to_lp (CCtsp_lp *lp, CCtsp_predge *prlist, int n) */ +/* ADDS the columns to the lp. */ +/* -n the number of edges listed in prlist */ +/* */ +/* int CCtsp_update_result (CCtsp_lp *lp) */ +/* UPDATES the solution information in the lp structure */ +/* */ +/* int CCtsp_infeas_recover (CCtsp_lp *lp) */ +/* TRIES to add columns to lp to regain feasibiblity */ +/* NOTE: Returns 2 if the full lp is infeasible */ +/* */ +/* int CCtsp_build_lpgraph (CCtsp_lpgraph *g, int ncount, */ +/* int ecount, int *elist, int *elen) */ +/* BUILDS the node and edge lists for the CCtsp_lpgraph pointed by g. */ +/* -elen contains the edge lengths (it can be NULL, in which case */ +/* the lengths are set to 0). */ +/* */ +/* int CCtsp_build_lpadj (CCtsp_lpgraph *g, int estart, int eend) */ +/* BUILDS the incidence list for the graph *g */ +/* -estart is the index of the first edge to include in the list */ +/* -eend is the index of the last edge + 1 */ +/* */ +/* void CCtsp_init_lpgraph_struct (CCtsp_lpgraph *g) */ +/* INITIALIZES the CCtsp_lpgraph struct pointed to by g. */ +/* */ +/* void CCtsp_free_lpgraph (CCtsp_lpgraph *g) */ +/* FREES the fields in the CCtsp_lpgraph pointed to by g. */ +/* */ +/* void CCtsp_free_lpcut_in (CCtsp_lpcut_in *c) */ +/* FREES the fields in the CCtsp_lpcut pointed to by c. */ +/* */ +/* CCtsp_free_lpclique (CCtsp_lpclique *c) */ +/* FREES the fields in the CCtsp_lpclique pointed to by c. */ +/* */ +/* int CCtsp_register_cliques (CCtsp_lpcuts *cuts, CCtsp_lpcut_in *c, */ +/* CCtsp_lpcut *new) */ +/* BUILDS the references to the cliques in c into the cut strucure */ +/* pointed to by cuts and creates an array of the indices of the */ +/* the cliques in CCtsp_lpcut new */ +/* -cuts is the structure holding the set of cuts */ +/* -c describes the cut to be added to the structure */ +/* -new returns the array of clique indices */ +/* */ +/* void CCtsp_unregister_cliques (CCtsp_lpcuts *cuts, CCtsp_lpcut *c) */ +/* REMOVES the references to the cliques in cut c (and deletes the */ +/* cliques if they have no more references) and frees the array */ +/* of clique indices in c */ +/* -cuts is the structure holding the set of cuts */ +/* -c is the cut containing the cliques to be removed */ +/* */ +/* int CCtsp_inspect_full_edges (CCtsp_lp *lp) */ +/* CHECKS that full edge set contains the current LP edge set; it */ +/* returns 0 if it is okay and 1 if some edge is not present */ +/* -lp is the CCtsp_lp */ +/* */ +/* int CCtsp_read_probfile (CCtsp_lp *lp, char *fname, int ncount) */ +/* READS a tsp file and loads the results into lp */ +/* -lp is an initialized lp (via a call to init_tsp_lp_struct; the */ +/* results are returned in this struct */ +/* -fname is the tsp file */ +/* -ncount is the number of nodes; it is used as a check to see if */ +/* if the tsp file matches */ +/* */ +/* int CCtsp_read_probfile_id (CCtsp_lp *lp, char *fname, int id, */ +/* int ncount) */ +/* READS a tsp file and loads the results into lp, where the filename */ +/* is obtained by using the id. */ +/* */ +/* int CCtsp_dump_x (CCtsp_lp *lp, char *fname) */ +/* WRITES the lp solution to fname. */ +/* Note: The vector contains the original node names. */ +/* */ +/* */ +/***************************************************************************/ + +/* +Known TODO: +espace +make sure all seg loops are <= +change CCtsp_lpadj strategy - graph always complete graph, except for + build_lp_cols + +Remark: + Sparified cut is viewed as cut + CCtsp_sparser*stars (ie, a positive value + in the CCtsp_sparser means that the cut in the lp is the original cut + the + star for that node +*/ + + +#include "machdefs.h" +#include "util.h" +#include "macrorus.h" +#include "fmatch.h" +#include "edgegen.h" +#include "linkern.h" +#include "tsp.h" +#include "lp.h" +#include "bigguy.h" +#include "cut.h" + +/* + parameters for addbad_variables. Addbad generates edges (x,y) with + len(x,y) - pi_ub[x] - pi_ub[y] < 0 in chunks of PRICE_GEN, computes + rc for that chunk, and adds those with rc(x,y) < CCtsp_PRICE_RCTHRESH to the + pool. This continues until the pool contains more than PRICE_POOL edges, + at which point the worst PRICE_ADD edges are added to the lp, new reduced + are computed for the pool, and only edges with rc(x,y) < + CCtsp_PRICE_RCTHRESH are retained. This overall process continues until + the total penalty for a full pass through the edges without adding any is + < CCtsp_PRICE_MAXPENALTY. +*/ + +/* Some of these should probably depend on the problem size */ + +#define REALLOC_FACTOR 1.25 +#define PRICE_GEN 20000 +#define PRICE_GEN_FACTOR 3 +#define PRICE_POOL 1000 /* 10000 */ +#define PRICE_ADD 100 + +#ifdef CC_PROTOTYPE_ANSI + +static int + first_lp (CCtsp_lp *lp, char *probname, int ncount, int ecount, int *elist, + int *elen), + find_edge_full (CCtsp_lp *lp, int from, int to), + load_lp (CCtsp_lp *lp), + build_lp_cols (CCtsp_lpgraph *g, CCtsp_lpcuts *cuts, int estart, int eend, + int *pnzcnt, double **pobj, int **pmatbeg, int **pmatcnt, + int **pmatind, double **pmatval, double **plb, double **pub), + tsp_lpcut_nzlist (CCtsp_lpgraph *g, CCtsp_lpcut *c, + CCtsp_lpclique *cliques), + checkout_cut (CCtsp_lp *lp, CCtsp_lpcut_in *c, double *x, CCtsp_lprow *cr, + int tighten), + verify_lpcut_in (CCtsp_lpgraph *g, CCtsp_lpcut_in *d), + update_newcuts (CCtsp_lp *lp), + phase1_test_edge (int end1, int end2, double *node_piest), + phase1_generate_edges (CCtsp_lp *lp, double *node_piest, int nwant, + int *ngot, int *genlist, int *genlen, int start, int *ni, int *nj, + int *finished), + pricing_duals (CCtsp_lp *lp, double *node_pi, + double *node_piest, double *cut_pi, double *clique_pi), + price_list (CCtsp_lp *lp, int ecount, CCtsp_predge *elist, + double *node_pi, double *clique_pi, int phase1), + age_cuts (CCtsp_lp *lp, int *ndeleted), + age_edges (CCtsp_lp *lp, int *ndeleted), + get_pi (CCtsp_lp *lp, double *node_pi, double *cut_pi), + addrow_to_list (int nzcnt, double drhs, char sense, + int *rmatind, double *rmatval, CCtsp_lprow *cr), + lp_addcols (CCtsp_lp *lp, int ncols, int nzcnt, + double *obj, int *matbeg, int *matind, double *matval, + double *lb, double *ub), + lp_delete_cut_set (CCtsp_lp *lp, int *del), + lp_delete_var_set (CCtsp_lp *lp, int *del), + write_probfile (CCtsp_lp *lp, int saveit), + read_probfile (CCtsp_lp *lp, CCtsp_PROB_FILE *p, int ncount); + +static void + tsp_lpcut_nonzero_work (CCtsp_lpgraph *g, CCtsp_lpclique *c, int *pnzlist), + tsp_lpcut_nonzero_modify (CCtsp_lpgraph *g, int modcount, + CCtsp_sparser *mods, int *pnzlist), + clear_nzlist (CCtsp_lpgraph *g, int nzlist), + pr_select (int nsel, int n, CCtsp_predge *list), + add_cut_to_queue (CCtsp_lp *lp, CCtsp_lpcut_in *c); + +#else /* CC_PROTOTYPE_ANSI */ + +static int + first_lp (), + find_edge_full (), + load_lp (), + build_lp_cols (), + tsp_lpcut_nzlist (), + checkout_cut (), + verify_lpcut_in (), + update_newcuts (), + phase1_test_edge (), + phase1_generate_edges (), + pricing_duals (), + price_list (), + age_cuts (), + age_edges (), + get_pi (), + addrow_to_list (), + lp_addcols (), + lp_delete_cut_set (), + lp_delete_var_set (), + write_probfile (), + read_probfile (); + +static void + tsp_lpcut_nonzero_work (), + tsp_lpcut_nonzero_modify (), + clear_nzlist (), + pr_select (), + add_cut_to_queue (); + +#endif /* CC_PROTOTYPE_ANSI */ + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_bb_init_lp (CCtsp_lp **lp, char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double initial_ub, CCtsp_lpcuts *pool) +#else +int CCtsp_bb_init_lp (lp, probname, probnum, ncount, dat, ptour, initial_ub, + pool) +CCtsp_lp **lp; +char *probname; +int probnum; +int ncount; +CCdatagroup *dat; +int *ptour; +double initial_ub; +CCtsp_lpcuts *pool; +#endif +{ + return CCtsp_init_lp (lp, probname, probnum, (char *) NULL, + ncount, dat, + 0, (int *) NULL, (int *) NULL, /* elist */ + 0, (int *) NULL, (int *) NULL, 0, /* exlist */ + ptour, initial_ub, pool); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_init_lp (CCtsp_lp **lp, char *probname, int probnum, + char *probfilename, int ncount, CCdatagroup *dat, + int ecount, int *elist, int *elen, int excount, + int *exlist, int *exlen, int exvalid, int *ptour, + double initial_ub, CCtsp_lpcuts *pool) +#else +int CCtsp_init_lp (lp, probname, probnum, probfilename, ncount, dat, ecount, + elist, elen, excount, exlist, exlen, exvalid, ptour, + initial_ub, pool) +CCtsp_lp **lp; +char *probname; +int probnum; +char *probfilename; +int ncount; +CCdatagroup *dat; +int ecount; +int *elist, *elen; +int excount; +int *exlist, *exlen; +int exvalid; +int *ptour; +double initial_ub; +CCtsp_lpcuts *pool; +#endif +{ + int rval = 0; + double tet; + + if (!ptour) { + fprintf (stderr, "must have a permutation tour in CCtsp_init_lp\n"); + rval = 1; goto CLEANUP; + } + + *lp = CC_SAFE_MALLOC (1, CCtsp_lp); + if ( !(*lp) ) { + rval = 1; goto CLEANUP; + } + + CCtsp_init_tsp_lp_struct (*lp); + (*lp)->perm = ptour; + (*lp)->dat = dat; + (*lp)->pool = pool; + + if (probfilename) { + rval = CCtsp_read_probfile (*lp, probfilename, ncount); + CCtsp_free_bigdual (&((*lp)->exact_dual)); + } else if (probnum != -1) { + rval = CCtsp_read_probfile_id (*lp, probname, probnum, ncount); + CCtsp_free_bigdual (&((*lp)->exact_dual)); + } else { + rval = first_lp (*lp, probname, ncount, ecount, elist, elen); + } + if (rval) { + fprintf (stderr, "CCtsp_read_probfile or first_lp failed\n"); + CCtsp_free_tsp_lp_struct (lp); + rval = 1; goto CLEANUP; + } + + if ((*lp)->fullcount == 0) { + if (excount) { + rval = CCtsp_edgelist_to_genadj (ncount, excount, exlist, exlen, + &((*lp)->fulladj), &((*lp)->fulladjspace)); + if (rval) { + fprintf (stderr, "CCtsp_edgelist_to_genadj failed\n"); + CCtsp_free_tsp_lp_struct (lp); + rval = 1; goto CLEANUP; + } + (*lp)->fullcount = excount; + if (exvalid) + (*lp)->full_edges_valid = 1; + } + } + + if (initial_ub < (*lp)->upperbound) { + printf ("Setting upperbound to the initial bound: %.2f\n", initial_ub); + fflush (stdout); + (*lp)->upperbound = initial_ub; + } + + rval = CClp_init (&((*lp)->lp)); + if (rval) { + fprintf (stderr, "CClp_init failed\n"); + CCtsp_free_tsp_lp_struct (lp); + rval = 1; goto CLEANUP; + } + + rval = load_lp (*lp); + if (rval) { + fprintf (stderr, "load_lp failed\n"); + CCtsp_free_tsp_lp_struct (lp); + rval = 1; goto CLEANUP; + } + + if ((*lp)->basis) { + CClp_free_basis ((*lp)->basis); + CC_FREE ((*lp)->basis, CClpbasis); + } + + (*lp)->edge_life = CCtsp_EDGE_LIFE; + (*lp)->cut_life = CCtsp_CUT_LIFE; + + rval = CCtsp_add_branchhistory_to_lp (*lp); + if (rval) { + fprintf (stderr, "CCtsp_add_branchhistory_to_lp failed\n"); + rval = 1; goto CLEANUP; + } + + tet = CCutil_zeit (); + rval = CClp_opt (&((*lp)->lp), CClp_METHOD_DUAL); + printf ("Dual opt returned after %.2f seconds\n", CCutil_zeit () - tet); + fflush (stdout); + if (rval == 2) { + fprintf (stderr, "Initial lp infeasible\n"); + goto CLEANUP; + } else if (rval) { + fprintf (stderr, "CClp_opt failed\n"); + rval = 1; goto CLEANUP; + } + + rval = CCtsp_update_result (*lp); + if (rval) { + fprintf (stderr, "CCtsp_update_result failed\n"); + rval = 1; goto CLEANUP; + } + +CLEANUP: + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int first_lp (CCtsp_lp *lp, char *probname, int ncount, + int ecount, int *elist, int *elen) +#else +static int first_lp (lp, probname, ncount, ecount, elist, elen) +CCtsp_lp *lp; +char *probname; +int ncount; +int ecount; +int *elist, *elen; +#endif +{ + double v, szeit; + int *basis = (int *) NULL; + int *match = (int *) NULL; + int rval = 0; + int i; + int e; + CClpbasis *b = (CClpbasis *) NULL; + + + szeit = CCutil_zeit (); + + rval = CCtsp_init_cliquehash (&lp->cuts, 2*ncount); + if (rval) goto CLEANUP; + rval = CCtsp_build_lpgraph (&lp->graph, ncount, ecount, elist, elen); + if (rval) goto CLEANUP; + rval = CCtsp_build_lpadj (&lp->graph, 0, ecount); + if (rval) goto CLEANUP; + + lp->name = CC_SAFE_MALLOC (strlen (probname)+1, char); + if (!lp->name) { + rval = 1; + goto CLEANUP; + } + strcpy (lp->name, probname); + + lp->id = 0; + lp->parent_id = -1; + lp->full_edges_valid = 0; + + basis = CC_SAFE_MALLOC (2 * ncount, int); + if (!basis) { + rval = 1; + goto CLEANUP; + } + match = CC_SAFE_MALLOC ((6 * ncount) + 1, int); + if (!match) { + rval = 1; + goto CLEANUP; + } + + rval = CCfmatch_fractional_2match (ncount, ecount, elist, elen, + (CCdatagroup *) NULL, &v, match, (int *) NULL, basis, 1); + if (rval) { + fprintf (stderr, "Fractional matching routine failed\n"); + CC_FREE (basis, int); + CC_FREE (match, int); + return 0; + } + + b = CC_SAFE_MALLOC (1, CClpbasis); + if (!b) { + fprintf (stderr, "out of memory in first_lp\n"); + rval = 1; goto CLEANUP; + } + CClp_init_basis (b); + + b->cstat = CC_SAFE_MALLOC (ecount, int); + b->rstat = CC_SAFE_MALLOC (ncount, int); + if (!b->cstat || !b->rstat) { + fprintf (stderr, "out of memory in first_lp\n"); + rval = 1; goto CLEANUP; + } + + for (i=0; i<ecount; i++) b->cstat[i] = 0; + for (i=0; i<ncount; i++) b->rstat[i] = 0; + + for (i = 0; i < ncount; i++) { + e = CCtsp_find_edge (&lp->graph, basis[2*i], basis[2*i+1]); + if (e < 0) { + fprintf (stderr, "Basis contains edge %d,%d not in edgelist\n", + basis[2*i],basis[2*i+1]); + } else { + b->cstat[e] = 1; + } + } + + for (i=0; i <= 6*ncount && match[i] > -1; i += 3) { + e = CCtsp_find_edge (&lp->graph, match[i], match[i+1]); + if (e < 0) { + fprintf (stderr, "Matching contains edge %d,%d not in edgelist\n", + match[i], match[i+1]); + } else { + if (b->cstat[e] == 0) { + if (match[i+2] == 1) { + fprintf (stderr, "Edge at 0.5 not in basis\n"); + } + b->cstat[e] = 2; + } + } + } + + CC_FREE (basis, int); + CC_FREE (match, int); + lp->basis = b; + + printf ("Total Time for first_lp: %.2f (seconds)\n", + CCutil_zeit () - szeit); + + return 0; + +CLEANUP: + + CC_IFFREE (basis, int); + CC_IFFREE (match, int); + if (b) { + CClp_free_basis (b); + CC_FREE (b, CClpbasis); + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_build_lpgraph (CCtsp_lpgraph *g, int ncount, int ecount, + int *elist, int *elen) +#else +int CCtsp_build_lpgraph (g, ncount, ecount, elist, elen) +CCtsp_lpgraph *g; +int ncount; +int ecount; +int *elist; +int *elen; +#endif +{ + int i; + CCtsp_lpnode *n; + CCtsp_lpedge *e; + + g->ncount = ncount; + g->ecount = ecount; + g->nodes = CC_SAFE_MALLOC (ncount, CCtsp_lpnode); + if (!g->nodes) { + return 1; + } + g->edges = CC_SAFE_MALLOC (ecount, CCtsp_lpedge); + if (!g->edges) { + CC_FREE (g->nodes, CCtsp_lpnode); + return 1; + } + g->espace = ecount; + n = g->nodes; + e = g->edges; + + for (i = 0; i < ncount; i++) { + n[i].mark = 0; + } + for (i=0; i<ecount; i++) { + if (elist[2*i] < elist[2*i+1]) { + e[i].ends[0] = elist[2*i]; + e[i].ends[1] = elist[2*i+1]; + } else { + e[i].ends[0] = elist[2*i+1]; + e[i].ends[1] = elist[2*i]; + } + e[i].fixed = 0; + e[i].branch = 0; + e[i].age = 0; + if (elen) { + e[i].len = elen[i]; + } else { + e[i].len = 0; + } + e[i].coefnext = -2; + e[i].coef = 0; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_build_lpadj (CCtsp_lpgraph *g, int estart, int eend) +#else +int CCtsp_build_lpadj (g, estart, eend) +CCtsp_lpgraph *g; +int estart; +int eend; +#endif +{ + CCtsp_lpadj *a; + CCtsp_lpnode *n = g->nodes; + CCtsp_lpedge *e = g->edges; + int i, j; + + if (g->adjspace) { + if (g->adjstart == estart && g->adjend == eend) { + return 0; + } else { + CC_FREE (g->adjspace, CCtsp_lpadj); + } + } + + if (estart >= eend) { + g->adjstart = estart; + g->adjend = eend; + for (i=0; i<g->ncount; i++) { + n[i].deg = 0; + n[i].adj = (CCtsp_lpadj *) NULL; + } + return 0; + } + + g->adjspace = CC_SAFE_MALLOC ((eend - estart)*2, CCtsp_lpadj); + if (!g->adjspace) { + return 1; + } + a = g->adjspace; + for (i=0; i<g->ncount; i++) { + n[i].deg = 0; + } + for (i=estart; i<eend; i++) { + n[e[i].ends[0]].deg++; + n[e[i].ends[1]].deg++; + } + for (i=0; i<g->ncount; i++) { + n[i].adj = a; + a += n[i].deg; + n[i].deg = 0; + } + for (i=estart; i<eend; i++) { + j = e[i].ends[0]; + a = &n[j].adj[n[j].deg]; + a->to = e[i].ends[1]; + a->edge = i; + n[j].deg++; + j = e[i].ends[1]; + a = &n[j].adj[n[j].deg]; + a->to = e[i].ends[0]; + a->edge = i; + n[j].deg++; + } + g->adjstart = estart; + g->adjend = eend; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_find_edge (CCtsp_lpgraph *g, int from, int to) +#else +int CCtsp_find_edge (g, from, to) +CCtsp_lpgraph *g; +int from; +int to; +#endif +{ + int t; + int i; + CCtsp_lpnode *f; + + if (from > to) { + CC_SWAP (from, to, t); + } + + f = &g->nodes[from]; + for (i=0; i<f->deg; i++) { + if (f->adj[i].to == to) { + return f->adj[i].edge; + } + } + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_edge_full (CCtsp_lp *lp, int from, int to) +#else +static int find_edge_full (lp, from, to) +CCtsp_lp *lp; +int from; +int to; +#endif +{ + int i; + CCtsp_genadjobj *a; + + /* returns 1 if it is there */ + + if (!lp->fulladj) + return 0; + + if (from > to) { + CC_SWAP (from, to, i); + } + + a = lp->fulladj[from].list; + for (i = lp->fulladj[from].deg-1; i >= 0; i--) { + if (a[i].end == to) { + return 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_inspect_full_edges (CCtsp_lp *lp) +#else +int CCtsp_inspect_full_edges (lp) +CCtsp_lp *lp; +#endif +{ + int i; + int ecount = lp->graph.ecount; + CCtsp_lpedge *edges = lp->graph.edges; + + for (i = 0; i < ecount; i++) { + if (find_edge_full (lp, edges[i].ends[0], edges[i].ends[1]) == 0) { + printf ("edge (%d,%d) not in full list\n", + edges[i].ends[0], edges[i].ends[1]); + fflush (stdout); + return 1; + } + } + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_init_tsp_lp_struct (CCtsp_lp *lp) +#else +void CCtsp_init_tsp_lp_struct (lp) +CCtsp_lp *lp; +#endif +{ + CCtsp_init_lpgraph_struct (&(lp->graph)); + + lp->sparsifier = (CCtsp_qsparsegroup *) NULL; + lp->perm = (int *) NULL; + lp->dat = (CCdatagroup *) NULL; + CClp_init_struct (&lp->lp); + + lp->cuts.cutcount = 0; + lp->cuts.cuts = (CCtsp_lpcut *) NULL; + lp->cuts.cutspace = 0; + lp->cuts.cliqueend = 0; + lp->cuts.cliques = (CCtsp_lpclique *) NULL; + lp->cuts.cliquespace = 0; + lp->cuts.cliquehash = (int *) NULL; + lp->cuts.cliquehashsize = 0; + lp->cuts.cuthash = (CCgenhash *) NULL; + + lp->pool = (CCtsp_lpcuts *) NULL; + + lp->fullcount = 0; + lp->fulladj = (CCtsp_genadj *) NULL; + lp->fulladjspace = (CCtsp_genadjobj *) NULL; + lp->fixededges = (int *) NULL; + lp->nfixededges = 0; + lp->name = (char *) NULL; + lp->id = -1; + lp->parent_id = -1; + lp->root = 0; + lp->upperbound = CCtsp_LP_MAXDOUBLE; + lp->lowerbound = -CCtsp_LP_MAXDOUBLE; + lp->exact_lowerbound = CCbigguy_MINBIGGUY; + lp->exact_dual = (CCtsp_bigdual *) NULL; + lp->infeasible = 0; + lp->full_edges_valid = 0; + lp->basis = (CClpbasis *) NULL; + + lp->cutqueue.cliquecount = 0; + lp->cutqueue.handlecount = 0; + lp->cutqueue.cliques = (CCtsp_lpclique *) NULL; + lp->cutqueue.next = &lp->cutqueue; + lp->cutqueue.prev = &lp->cutqueue; + + lp->result.ub = 0.0; + lp->result.lb = 0.0; + lp->result.ecount = 0; + lp->result.elist = (int *) NULL; + lp->result.x = (double *) NULL; + lp->result.rc = (double *) NULL; + + lp->branchhistory = (CCtsp_branchobj *) NULL; + lp->branchdepth = 0; + + CCtsp_init_tighten_info (&lp->tighten_stats); +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_tsp_lp_struct (CCtsp_lp **lp) +#else +void CCtsp_free_tsp_lp_struct (lp) +CCtsp_lp **lp; +#endif +{ + int i; + + if (!(*lp)) return; + + CCtsp_free_lpgraph (&((*lp)->graph)); + + (*lp)->perm = (int *) NULL; /* perm is owned by calling program */ + if ((*lp)->sparsifier) { + CCtsp_free_qsparsify (&((*lp)->sparsifier)); + } + (*lp)->dat = (CCdatagroup *) NULL; /* dat is owned by the calling program */ + if ((*lp)->dat) { + CCutil_freedatagroup ((*lp)->graph.ncount, (*lp)->dat); + CC_FREE ((*lp)->dat, CCdatagroup); + } + if ((*lp)->fulladjspace) { + CC_FREE ((*lp)->fulladjspace, CCtsp_genadjobj); + CC_IFFREE ((*lp)->fulladj, CCtsp_genadj); + } + (*lp)->fullcount = 0; + CC_IFFREE ((*lp)->fixededges, int); + (*lp)->nfixededges = 0; + + if ((*lp)->lp.lp_allocated) { + CClp_free (&((*lp)->lp)); + } + + if ((*lp)->cuts.cuts) { + for (i=0; i<(*lp)->cuts.cutcount; i++) { + CC_FREE ((*lp)->cuts.cuts[i].cliques, int); + CC_IFFREE ((*lp)->cuts.cuts[i].mods, CCtsp_sparser); + } + CC_FREE ((*lp)->cuts.cuts, CCtsp_lpcut); + } + if ((*lp)->cuts.cliques) { + for (i=0; i<(*lp)->cuts.cliqueend; i++) { + CC_IFFREE ((*lp)->cuts.cliques[i].nodes, CCtsp_segment); + } + CC_FREE ((*lp)->cuts.cliques, CCtsp_lpclique); + } + + (*lp)->pool = (CCtsp_lpcuts *) NULL; /* owned by calling routine */ + + if ((*lp)->exact_dual) { + CC_IFFREE ((*lp)->exact_dual->node_pi, CCbigguy); + CC_IFFREE ((*lp)->exact_dual->cut_pi, CCbigguy); + CC_FREE ((*lp)->exact_dual, CCtsp_bigdual); + } + CC_IFFREE ((*lp)->cuts.cliquehash, int); + CC_IFFREE ((*lp)->name, char); + if ((*lp)->basis) { + CClp_free_basis ((*lp)->basis); + CC_FREE ((*lp)->basis, CClpbasis); + } + CC_IFFREE ((*lp)->result.elist, int); + CC_IFFREE ((*lp)->result.x, double); + CC_IFFREE ((*lp)->result.rc, double); + + if ((*lp)->branchhistory) { + for (i = 0; i < (*lp)->branchdepth; i++) { + CCtsp_free_branchobj (&((*lp)->branchhistory[i])); + } + CC_FREE ((*lp)->branchhistory, CCtsp_branchobj); + (*lp)->branchdepth = 0; + } + + CC_IFFREE (*lp, CCtsp_lp); +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_init_lpgraph_struct (CCtsp_lpgraph *g) +#else +void CCtsp_init_lpgraph_struct (g) +CCtsp_lpgraph *g; +#endif +{ + g->ncount = 0; + g->ecount = 0; + g->nodes = (CCtsp_lpnode *) NULL; + g->edges = (CCtsp_lpedge *) NULL; + g->adjspace = (CCtsp_lpadj *) NULL; + g->adjstart = 0; + g->adjend = 0; + g->nodemarker = 0; + g->espace = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_lpgraph (CCtsp_lpgraph *g) +#else +void CCtsp_free_lpgraph (g) +CCtsp_lpgraph *g; +#endif +{ + CC_IFFREE (g->nodes, CCtsp_lpnode); + CC_IFFREE (g->edges, CCtsp_lpedge); + CC_IFFREE (g->adjspace, CCtsp_lpadj); + g->espace = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int load_lp (CCtsp_lp *lp) +#else +static int load_lp (lp) +CCtsp_lp *lp; +#endif +{ + int rval = 0; + int nzcnt; + int i, j; + int xrhs; + double sz = CCutil_zeit (); + + double *obj = (double *) NULL; + double *rhs = (double *) NULL; + char *sense = (char *) NULL; + int *matbeg = (int *) NULL; + int *matcnt = (int *) NULL; + int *matind = (int *) NULL; + double *matval = (double *) NULL; + double *lb = (double *) NULL; + double *ub = (double *) NULL; + + printf ("Loading lp..."); fflush (stdout); + + rhs = CC_SAFE_MALLOC (lp->graph.ncount + lp->cuts.cutcount, double); + sense = CC_SAFE_MALLOC (lp->graph.ncount + lp->cuts.cutcount, char); + if (!rhs || !sense ) { + fprintf (stderr, "not enough memory to load problem\n"); + rval = 1; + goto CLEANUP; + } + + rval = build_lp_cols (&lp->graph, &lp->cuts, 0, lp->graph.ecount, + &nzcnt, &obj, &matbeg, &matcnt, &matind, &matval, + &lb, &ub); + if (rval) goto CLEANUP; + + for (i = 0; i < lp->graph.ncount; i++) { + rhs[i] = 2.0; + sense[i] = 'E'; + } + for (i = 0; i < lp->cuts.cutcount; i++) { + xrhs = lp->cuts.cuts[i].rhs; + for (j = 0; j < lp->cuts.cuts[i].modcount; j++) { + xrhs += 2*(((int) lp->cuts.cuts[i].mods[j].mult)-128); + } + rhs[lp->graph.ncount + i] = xrhs; + sense[lp->graph.ncount + i] = lp->cuts.cuts[i].sense; + } + + rval = CClp_loadlp (&lp->lp, lp->name, lp->graph.ecount, + lp->graph.ncount + lp->cuts.cutcount, 1, + obj, rhs, sense, matbeg, matcnt, matind, matval, + lb, ub); + + if (rval) { + fprintf (stderr, "couldn't load problem\n"); + goto CLEANUP; + } + + if (lp->basis) { + rval = CClp_load_basis_and_norms (&lp->lp, lp->basis); + if (rval) { + fprintf (stderr, "Couln't load basis and norms\n"); + } + } else { + fprintf (stderr, "No basis to load, stumbling on anyway\n"); + } + + printf ("done in %.2f seconds\n", CCutil_zeit () - sz); fflush (stdout); + +CLEANUP: + + CC_IFFREE (obj, double); + CC_IFFREE (rhs, double); + CC_IFFREE (sense, char); + CC_IFFREE (matbeg, int); + CC_IFFREE (matcnt, int); + CC_IFFREE (matind, int); + CC_IFFREE (matval, double); + CC_IFFREE (lb, double); + CC_IFFREE (ub, double); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int build_lp_cols (CCtsp_lpgraph *g, CCtsp_lpcuts *cuts, int estart, int eend, + int *pnzcnt, double **pobj, int **pmatbeg, + int **pmatcnt, int **pmatind, double **pmatval, + double **plb, double **pub) +#else +static int build_lp_cols (g, cuts, estart, eend, pnzcnt, pobj, pmatbeg, + pmatcnt, pmatind, pmatval, plb, pub) +CCtsp_lpgraph *g; +CCtsp_lpcuts *cuts; +int estart; +int eend; +int *pnzcnt; +double **pobj; +int **pmatbeg; +int **pmatcnt; +int **pmatind; +double **pmatval; +double **plb; +double **pub; +#endif +{ + int rval; + int nzcnt; + int ncols = eend - estart; + double *obj = (double *) NULL; + int *matbeg = (int *) NULL; + int *matcnt = (int *) NULL; + int *matind = (int *) NULL; + double *matval = (double *) NULL; + double *lb = (double *) NULL; + double *ub = (double *) NULL; + int i; + int nzlist, nznext; + + if (estart >= eend) { + fprintf (stderr, "No columns for build_lp_cols to build\n"); + return 1; + } + + rval = CCtsp_build_lpadj (g, estart, eend); + if (rval) goto CLEANUP; + + obj = CC_SAFE_MALLOC (ncols, double); + lb = CC_SAFE_MALLOC (ncols, double); + ub = CC_SAFE_MALLOC (ncols, double); + matbeg = CC_SAFE_MALLOC (ncols, int); + matcnt = CC_SAFE_MALLOC (ncols, int); + if (!obj || !lb || !ub || !matbeg || !matcnt) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ncols; i++) { + obj[i] = g->edges[i+estart].len; + if (g->edges[i+estart].fixed || g->edges[i+estart].branch > 0) { + lb[i] = 1.0; + } else { + lb[i] = 0.0; + } + if (g->edges[i+estart].branch < 0) { + ub[i] = 0.0; + } else { + ub[i] = 1.0; + } + matcnt[i] = 2; + } + + for (i=0; i<cuts->cutcount; i++) { + nzlist = tsp_lpcut_nzlist (g, &cuts->cuts[i], cuts->cliques); + while (nzlist != -1) { + nznext = g->edges[nzlist].coefnext; + g->edges[nzlist].coefnext = -2; + if (g->edges[nzlist].coef) { + g->edges[nzlist].coef = 0; + matcnt[nzlist - estart]++; + } + nzlist = nznext; + } + } + + nzcnt = 0; + for (i=0; i<ncols; i++) { + matbeg[i] = nzcnt; + nzcnt += matcnt[i]; + matcnt[i] = 0; + } + matind = CC_SAFE_MALLOC (nzcnt, int); + matval = CC_SAFE_MALLOC (nzcnt, double); + if (!matind || !matval) { + rval = 1; + goto CLEANUP; + } + + for (i=0; i<ncols; i++) { + matval[matbeg[i] + matcnt[i]] = 1.0; + matind[matbeg[i] + matcnt[i]] = g->edges[estart+i].ends[0]; + matcnt[i]++; + matval[matbeg[i] + matcnt[i]] = 1.0; + matind[matbeg[i] + matcnt[i]] = g->edges[estart+i].ends[1]; + matcnt[i]++; + } + + for (i=0; i<cuts->cutcount; i++) { + nzlist = tsp_lpcut_nzlist (g, &cuts->cuts[i], cuts->cliques); + while (nzlist != -1) { + nznext = g->edges[nzlist].coefnext; + g->edges[nzlist].coefnext = -2; + if (g->edges[nzlist].coef) { + matval[matbeg[nzlist-estart] + matcnt[nzlist-estart]] = + g->edges[nzlist].coef; + matind[matbeg[nzlist-estart] + matcnt[nzlist-estart]] = + g->ncount + i; + matcnt[nzlist-estart]++; + g->edges[nzlist].coef = 0; + } + nzlist = nznext; + } + } + + if (pnzcnt) *pnzcnt = nzcnt; + if (pobj) *pobj = obj; + else CC_FREE (obj, double); + if (pmatbeg) *pmatbeg = matbeg; + else CC_FREE (matbeg, int); + if (pmatcnt) *pmatcnt = matcnt; + else CC_FREE (matcnt, int); + if (pmatind) *pmatind = matind; + else CC_FREE (matind, int); + if (pmatval) *pmatval = matval; + else CC_FREE (matval, double); + if (plb) *plb = lb; + else CC_FREE (lb, double); + if (pub) *pub = ub; + else CC_FREE (ub, double); + + return 0; + +CLEANUP: + + CC_IFFREE (obj, double); + CC_IFFREE (matbeg, int); + CC_IFFREE (matcnt, int); + CC_IFFREE (matind, int); + CC_IFFREE (matval, double); + CC_IFFREE (lb, double); + CC_IFFREE (ub, double); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_update_result (CCtsp_lp *lp) +#else +int CCtsp_update_result (lp) +CCtsp_lp *lp; +#endif +{ + CCtsp_lp_result new; + int i; + + if (CClp_objval (&lp->lp, &new.lb)) { + return 1; + } + new.ub = lp->upperbound; + new.elist = CC_SAFE_MALLOC (lp->graph.ecount*2, int); + if (!new.elist) return 1; + new.x = CC_SAFE_MALLOC (lp->graph.ecount, double); + if (!new.x) { + CC_FREE (new.elist, int); + return 1; + } + new.rc = CC_SAFE_MALLOC (lp->graph.ecount, double); + if (!new.rc) { + CC_FREE (new.x, double); + CC_FREE (new.elist, int); + return 1; + } + + if (CClp_x (&lp->lp, new.x)) { + CC_FREE (new.rc, double); + CC_FREE (new.x, double); + CC_FREE (new.elist, int); + return 1; + } + + if (CClp_rc (&lp->lp, new.rc)) { + CC_FREE (new.rc, double); + CC_FREE (new.x, double); + CC_FREE (new.elist, int); + return 1; + } + + new.ecount = lp->graph.ecount; + for (i=0; i<new.ecount; i++) { + new.elist[2*i] = lp->graph.edges[i].ends[0]; + new.elist[2*i+1] = lp->graph.edges[i].ends[1]; + } + + CC_IFFREE (lp->result.elist, int); + CC_IFFREE (lp->result.x, double); + CC_IFFREE (lp->result.rc, double); + + lp->result = new; + + printf ("Optimized, val = %.6f\n", lp->result.lb); + fflush (stdout); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_get_lp_result (CCtsp_lp *lp, double *lb, double *ub, int *ecount, + int **elist, double **x, double **rc, double **node_pi, + double **cut_pi) +#else +int CCtsp_get_lp_result (lp, lb, ub, ecount, elist, x, rc, node_pi, cut_pi) +CCtsp_lp *lp; +double *lb; +double *ub; +int *ecount; +int **elist; +double **x; +double **rc; +double **node_pi; +double **cut_pi; +#endif +{ + int *myelist = (int *) NULL; + double *myx = (double *) NULL; + double *myrc = (double *) NULL; + double *mynode_pi = (double *) NULL; + double *mycut_pi = (double *) NULL; + int i; + int rval = 0; + + if ((elist || x || rc) && lp->result.ecount == 0){ + fprintf (stderr, "lp->result is not initialized\n"); + return 1; + } + + if (elist) { + myelist = CC_SAFE_MALLOC (2*lp->result.ecount, int); + if (!myelist) { + fprintf (stderr, "out of memory in CCtsp_get_lp_result\n"); + rval = 1; + goto CLEANUP; + } + } + if (x) { + myx = CC_SAFE_MALLOC (lp->result.ecount, double); + if (!myx) { + fprintf (stderr, "out of memory in CCtsp_get_lp_result\n"); + rval = 1; + goto CLEANUP; + } + } + if (rc) { + myrc = CC_SAFE_MALLOC (lp->result.ecount, double); + if (!myrc) { + fprintf (stderr, "out of memory in CCtsp_get_lp_result\n"); + rval = 1; + goto CLEANUP; + } + } + if (node_pi) { + mynode_pi = CC_SAFE_MALLOC (lp->graph.ncount, double); + if (!mynode_pi) { + fprintf (stderr, "out of memory in CCtsp_get_lp_result\n"); + rval = 1; + goto CLEANUP; + } + } + if (cut_pi && lp->cuts.cutcount) { + mycut_pi = CC_SAFE_MALLOC (lp->cuts.cutcount, double); + if (!mycut_pi) { + fprintf (stderr, "out of memory in CCtsp_get_lp_result\n"); + rval = 1; + goto CLEANUP; + } + } + + if (elist) { + for (i=0; i<2*lp->result.ecount; i++) { + myelist[i] = lp->result.elist[i]; + } + *elist = myelist; + } + if (x) { + for (i=0; i<lp->result.ecount; i++) { + myx[i] = lp->result.x[i]; + } + *x = myx; + } + if (rc) { + for (i=0; i<lp->result.ecount; i++) { + myrc[i] = lp->result.rc[i]; + } + *rc = myrc; + } + if (node_pi || cut_pi) { + rval = get_pi (lp, mynode_pi, mycut_pi); + if (rval) { + fprintf (stderr, "get_pi failed\n"); + goto CLEANUP; + } + *node_pi = mynode_pi; + *cut_pi = mycut_pi; + } + if (lb) *lb = lp->result.lb; + if (ub) *ub = lp->result.ub; + if (ecount) *ecount = lp->result.ecount; + + return 0; + +CLEANUP: + + CC_IFFREE (myelist, int); + CC_IFFREE (myx, double); + CC_IFFREE (myrc, double); + CC_IFFREE (mynode_pi, double); + CC_IFFREE (mycut_pi, double); + + return rval; +} + + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_add_cuts_to_queue (CCtsp_lp *lp, CCtsp_lpcut_in **clist) +#else +void CCtsp_add_cuts_to_queue (lp, clist) +CCtsp_lp *lp; +CCtsp_lpcut_in **clist; +#endif +{ + CCtsp_lpcut_in *c, *cnext; + + for (c = *clist; c; c = cnext) { + cnext = c->next; + add_cut_to_queue (lp, c); + } + *clist = (CCtsp_lpcut_in *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static void add_cut_to_queue (CCtsp_lp *lp, CCtsp_lpcut_in *c) +#else +static void add_cut_to_queue (lp, c) +CCtsp_lp *lp; +CCtsp_lpcut_in *c; +#endif +{ + assert (c->sense == 'G' || c->branch != 0); + c->next = &lp->cutqueue; + c->prev = lp->cutqueue.prev; + c->next->prev = c; + c->prev->next = c; +} + +#ifdef CC_PROTOTYPE_ANSI +double CCtsp_cutprice (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, double *x) +#else +double CCtsp_cutprice (g, c, x) +CCtsp_lpgraph *g; +CCtsp_lpcut_in *c; +double *x; +#endif +{ + double slack; + int nzlist, nznext; + + slack = (double) -(c->rhs); + + nzlist = CCtsp_lpcut_in_nzlist (g, c); + + while (nzlist != -1) { + nznext = g->edges[nzlist].coefnext; + g->edges[nzlist].coefnext = -2; + slack += g->edges[nzlist].coef * x[nzlist]; + g->edges[nzlist].coef = 0; + nzlist = nznext; + } + return slack; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_lpcut_in_nzlist (CCtsp_lpgraph *g, CCtsp_lpcut_in *c) +#else +int CCtsp_lpcut_in_nzlist (g, c) +CCtsp_lpgraph *g; +CCtsp_lpcut_in *c; +#endif +{ + int nzlist = -1; + int i; + + for (i = 0; i < c->cliquecount; i++) { + tsp_lpcut_nonzero_work (g, &c->cliques[i], &nzlist); + } + return nzlist; +} + +#ifdef CC_PROTOTYPE_ANSI +static int tsp_lpcut_nzlist (CCtsp_lpgraph *g, CCtsp_lpcut *c, + CCtsp_lpclique *cliques) +#else +static int tsp_lpcut_nzlist (g, c, cliques) +CCtsp_lpgraph *g; +CCtsp_lpcut *c; +CCtsp_lpclique *cliques; +#endif +{ + int nzlist = -1; + int i; + + for (i = 0; i < c->cliquecount; i++) { + tsp_lpcut_nonzero_work (g, &cliques[c->cliques[i]], &nzlist); + } + tsp_lpcut_nonzero_modify (g, c->modcount, c->mods, &nzlist); + return nzlist; +} + +#ifdef CC_PROTOTYPE_ANSI +static void tsp_lpcut_nonzero_work (CCtsp_lpgraph *g, CCtsp_lpclique *c, + int *pnzlist) +#else +static void tsp_lpcut_nonzero_work (g, c, pnzlist) +CCtsp_lpgraph *g; +CCtsp_lpclique *c; +int *pnzlist; +#endif +{ + int nzlist = *pnzlist; + int nodemarker; + CCtsp_lpadj *a; + int e; + int j, k, l; + + g->nodemarker++; + nodemarker = g->nodemarker; + + for (j=0; j<c->segcount; j++) { + for (k=c->nodes[j].lo; k<=c->nodes[j].hi; k++) { + g->nodes[k].mark = nodemarker; + } + } + + for (j=0; j<c->segcount; j++) { + for (k=c->nodes[j].lo; k<=c->nodes[j].hi; k++) { + a = g->nodes[k].adj; + for (l=0; l<g->nodes[k].deg; l++) { + if (g->nodes[a[l].to].mark != nodemarker) { + e = a[l].edge; + if (g->edges[e].coefnext == -2) { + g->edges[e].coefnext = nzlist; + nzlist = e; + } + g->edges[e].coef++; + } + } + } + } + *pnzlist = nzlist; +} + +#ifdef CC_PROTOTYPE_ANSI +static void tsp_lpcut_nonzero_modify (CCtsp_lpgraph *g, int modcount, + CCtsp_sparser *mods, int *pnzlist) +#else +static void tsp_lpcut_nonzero_modify (g, modcount, mods, pnzlist) +CCtsp_lpgraph *g; +int modcount; +CCtsp_sparser *mods; +int *pnzlist; +#endif +{ + int nzlist = *pnzlist; + int i,j,k,l; + CCtsp_lpadj *a; + int e; + + for (i=0; i<modcount; i++) { + k = mods[i].node; + j = ((int) mods[i].mult) - 128; + a = g->nodes[k].adj; + for (l=0; l<g->nodes[k].deg; l++) { + e = a[l].edge; + if (g->edges[e].coefnext == -2) { + g->edges[e].coefnext = nzlist; + nzlist = e; + } + g->edges[e].coef += j; + } + } + *pnzlist = nzlist; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_process_cuts (CCtsp_lp *lp, int *pnadded, int tighten) +#else +int CCtsp_process_cuts (lp, pnadded, tighten) +CCtsp_lp *lp; +int *pnadded; +int tighten; +#endif +{ + int nadded = 0; + int addpiece = 0; + CCtsp_lpcut_in *c = (CCtsp_lpcut_in *) NULL; + double *x = (double *) NULL; + int ecount_save; + int rval; + CCtsp_lprow cr; + + *pnadded = 0; + CCtsp_init_lprow (&cr); + ecount_save = lp->graph.ecount; + x = CC_SAFE_MALLOC (ecount_save, double); + if (!x) { + return 1; + } + + rval = CClp_x (&lp->lp, x); + if (rval) { + CC_FREE (x, double); + return rval; + } + + nadded = 0; + addpiece = 0; + while (lp->cutqueue.next != &lp->cutqueue) { + c = lp->cutqueue.next; + c->next->prev = c->prev; + c->prev->next = c->next; + rval = checkout_cut (lp, c, x, &cr, tighten); + if (rval > 1) { + rval = 1; + goto CLEANUP; + } else if (rval == 1) { + nadded++; + addpiece++; + if (cr.rowcnt >= CCtsp_STORE_BATCH) { + if (cr.rowcnt > 0) { + rval = CCtsp_add_multiple_rows (lp, &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_multiple_rows failed\n"); + goto CLEANUP; + } + CCtsp_free_lprow (&cr); + } + } + if (addpiece >= CCtsp_CUT_BATCH) { + if (cr.rowcnt > 0) { + rval = CCtsp_add_multiple_rows (lp, &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_multiple_rows failed\n"); + goto CLEANUP; + } + CCtsp_free_lprow (&cr); + } + rval = update_newcuts (lp); + if (rval == 2) { + printf ("LP is really infeasible (processs_cuts)\n"); + fflush (stdout); + goto CLEANUP; + } else if (rval) { + goto CLEANUP; + } + if (lp->graph.ecount != ecount_save) { + CC_FREE (x, double); + ecount_save = lp->graph.ecount; + x = CC_SAFE_MALLOC (ecount_save, double); + if (!x) { + rval = 1; + goto CLEANUP; + } + } + rval = CClp_x (&lp->lp, x); + if (rval) { + goto CLEANUP; + } + addpiece = 0; + } + } + CCtsp_free_lpcut_in (c); + CC_FREE (c, CCtsp_lpcut_in); + } + if (addpiece > 0) { + if (cr.rowcnt > 0) { + rval = CCtsp_add_multiple_rows (lp, &cr); + if (rval) { + fprintf (stderr, "CCtsp_add_multiple_rows failed\n"); + goto CLEANUP; + } + CCtsp_free_lprow (&cr); + } + rval = update_newcuts (lp); + if (rval == 2) { + printf ("LP is really infeasible (processs_cuts)\n"); + fflush (stdout); + goto CLEANUP; + } else if (rval) { + goto CLEANUP; + } + } + CC_FREE (x, double); + *pnadded = nadded; + + rval = CCtsp_update_result (lp); + if (rval) goto CLEANUP; + + return 0; + +CLEANUP: + + CCtsp_free_lprow (&cr); + if (c) { + CCtsp_free_lpcut_in (c); + CC_FREE (c, CCtsp_lpcut_in); + } + CC_IFFREE (x, double); + *pnadded = nadded; + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_init_lprow (CCtsp_lprow *cr) +#else +void CCtsp_init_lprow (cr) +CCtsp_lprow *cr; +#endif +{ + cr->rowcnt = 0; + cr->nzcnt = 0; + cr->sense = (char *) NULL; + cr->rhs = (double *) NULL; + cr->begin = (int *) NULL; + cr->indexspace = 0; + cr->indices = (int *) NULL; + cr->entryspace = 0; + cr->entries = (double *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_lprow (CCtsp_lprow *cr) +#else +void CCtsp_free_lprow (cr) +CCtsp_lprow *cr; +#endif +{ + if (cr) { + cr->rowcnt = 0; + cr->nzcnt = 0; + CC_IFFREE (cr->sense, char); + CC_IFFREE (cr->rhs, double); + CC_IFFREE (cr->begin, int); + CC_IFFREE (cr->indices, int); + cr->indexspace = 0; + CC_IFFREE (cr->entries, double); + cr->entryspace = 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int checkout_cut (CCtsp_lp *lp, CCtsp_lpcut_in *c, double *x, + CCtsp_lprow *cr, int tighten) +#else +static int checkout_cut (lp, c, x, cr, tighten) +CCtsp_lp *lp; +CCtsp_lpcut_in *c; +double *x; +CCtsp_lprow *cr; +int tighten; +#endif +{ + int rval; + CCtsp_lpcut_in d; + double slack; + CCtsp_lpgraph *g = &lp->graph; + + if (tighten) { + rval = CCtsp_tighten_lpcut_in (g, c, x, &d, &lp->tighten_stats, + (double *) NULL); + if (rval) { + fprintf (stderr, "CCtsp_tighten_lpcut_in failed\n"); + return 2; + } + } else { + rval = CCtsp_copy_lpcut_in (c, &d); + if (rval) { + fprintf (stderr, "CCtsp_copy_lpcut_in failed\n"); + return 2; + } + } + + slack = CCtsp_cutprice (g, &d, x); + if (slack >= -CCtsp_MIN_VIOL) { + CCtsp_free_lpcut_in (&d); + return 0; + } + + rval = verify_lpcut_in (g, &d); + if (rval) { + fprintf (stderr, "Discarding invalid cut\n"); + CCtsp_print_lpcut_in (&d); + CCtsp_free_lpcut_in (&d); + return 2; + } + + rval = CCtsp_add_cut (lp, &d, cr); + if (rval) { + CCtsp_free_lpcut_in (&d); + return 2; + } + CCtsp_free_lpcut_in (&d); + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_lpcut_in (CCtsp_lpcut_in *c) +#else +void CCtsp_free_lpcut_in (c) +CCtsp_lpcut_in *c; +#endif +{ + int i; + + if (c) { + for (i = 0; i < c->cliquecount; i++) { + CCtsp_free_lpclique (&c->cliques[i]); + } + CC_IFFREE (c->cliques, CCtsp_lpclique); + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_free_lpclique (CCtsp_lpclique *c) +#else +void CCtsp_free_lpclique (c) +CCtsp_lpclique *c; +#endif +{ + if (c) { + CC_IFFREE (c->nodes, CCtsp_segment); + c->segcount = 0; + c->hashnext = 0; + c->refcount = 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int verify_lpcut_in (CCtsp_lpgraph *g, CCtsp_lpcut_in *d) +#else +static int verify_lpcut_in (g, d) +CCtsp_lpgraph *g; +CCtsp_lpcut_in *d; +#endif +{ + /* Verify not yet written. */ + + if (!d || !g) return 1; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int update_newcuts (CCtsp_lp *lp) +#else +static int update_newcuts (lp) +CCtsp_lp *lp; +#endif +{ + int rval; + int ndeleted; + + rval = CClp_opt (&lp->lp, CClp_METHOD_DUAL); + if (rval == 2) { + rval = CCtsp_infeas_recover (lp); + if (rval == 2) { + printf ("Problem is really infeasible (update_newcuts)\n"); + return 2; + } else if (rval) { + return 1; + } + } else if (rval) { + fprintf (stderr, "CClp_opt failed\n"); + return 1; + } + rval = age_cuts (lp, &ndeleted); + if (rval) { + fprintf (stderr, "age_cuts failed\n"); + return 1; + } + rval = CClp_opt (&lp->lp, CClp_METHOD_DUAL); + if (rval) { + fprintf (stderr, "CClp_opt failed\n"); + return 1; + } + + ndeleted = 0; + rval = age_edges (lp, &ndeleted); + if (rval) { + fprintf (stderr, "age_edges failed\n"); + return 1; + } + rval = CClp_opt (&lp->lp, CClp_METHOD_DUAL); + if (rval) { + fprintf (stderr, "CClp_opt failed\n"); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_infeas_recover (CCtsp_lp *lp) +#else +int CCtsp_infeas_recover (lp) +CCtsp_lp *lp; +#endif +{ + double penalty; + int nadded, feasible; + int rval; + + printf ("infeas_recover ...\n"); fflush (stdout); + + rval = CCtsp_addbad_variables (lp, (CCtsp_edgegenerator *) NULL, &penalty, + &nadded, CCtsp_PHASE1_RCTHRESH, CCtsp_PHASE1_MAXPENALTY, + 1, &feasible); + if (rval) { + fprintf (stderr, "CCtsp_addbad_variables failed\n"); + return 1; + } + + if (feasible) { + printf ("Recovered a feasible LP\n"); + fflush (stdout); + return 0; + } else { + printf ("Could not recover a feasible LP\n"); + fflush (stdout); + return 2; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_cut (CCtsp_lp *lp, CCtsp_lpcut_in *d, CCtsp_lprow *cr) +#else +int CCtsp_add_cut (lp, d, cr) +CCtsp_lp *lp; +CCtsp_lpcut_in *d; +CCtsp_lprow *cr; +#endif +{ + int nzlist; + CCtsp_lpgraph *g = &lp->graph; + int saved; + CCtsp_lpcut new; + int rval; + int newloc; + int rhs; + int i; + + assert (d->sense == 'G' || d->branch != 0); + + new.rhs = d->rhs; + new.sense = d->sense; + new.branch = d->branch; + new.modcount = 0; + new.mods = (CCtsp_sparser *) NULL; + new.cliquecount = 0; + new.handlecount = 0; + new.cliques = (int *) NULL; + rval = CCtsp_register_cliques (&lp->cuts, d, &new); + if (rval) { + return rval; + } + nzlist = CCtsp_lpcut_in_nzlist (g, d); + rval = CCtsp_qsparsify (&lp->sparsifier, g, &nzlist, &new.modcount, + &new.mods, &saved); + if (rval) { + CCtsp_unregister_cliques (&lp->cuts, &new); + CC_IFFREE (new.mods, CCtsp_sparser); + clear_nzlist (g, nzlist); + return rval; + } + new.age = CCtsp_NEWCUT_AGE; + newloc = CCtsp_add_cut_to_cutlist (&lp->cuts, &new); + if (newloc == -1) { + CCtsp_unregister_cliques (&lp->cuts, &new); + CC_IFFREE (new.mods, CCtsp_sparser); + clear_nzlist (g, nzlist); + return 1; + } + rhs = new.rhs; + for (i=0; i<new.modcount; i++) { + rhs += 2*(((int) new.mods[i].mult) - 128); + } + rval = CCtsp_add_nzlist_to_lp (lp, nzlist, rhs, new.sense, cr); + if (rval) { + fprintf (stderr, "CCtsp_add_nzlist_to_lp failed\n"); + CCtsp_delete_cut_from_cutlist (&lp->cuts, newloc); + return rval; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_register_cliques (CCtsp_lpcuts *cuts, CCtsp_lpcut_in *c, + CCtsp_lpcut *new) +#else +int CCtsp_register_cliques (cuts, c, new) +CCtsp_lpcuts *cuts; +CCtsp_lpcut_in *c; +CCtsp_lpcut *new; +#endif +{ + int i, j; + + new->cliques = CC_SAFE_MALLOC (c->cliquecount, int); + if (!new->cliques) return 1; + new->handlecount = c->handlecount; + new->cliquecount = c->cliquecount; + for (i = 0; i < c->cliquecount; i++) { + new->cliques[i] = CCtsp_register_clique (cuts, &c->cliques[i]); + if (new->cliques[i] == -1) { + for (j=0; j<i; j++) { + CCtsp_unregister_clique (cuts, new->cliques[j]); + } + CC_FREE (new->cliques, int); + return 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_unregister_cliques (CCtsp_lpcuts *cuts, CCtsp_lpcut *c) +#else +void CCtsp_unregister_cliques (cuts, c) +CCtsp_lpcuts *cuts; +CCtsp_lpcut *c; +#endif +{ + int i; + + for (i = 0; i < c->cliquecount; i++) { + CCtsp_unregister_clique (cuts, c->cliques[i]); + } + CC_FREE (c->cliques, int); + c->cliquecount = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_cut_to_cutlist (CCtsp_lpcuts *cuts, CCtsp_lpcut *c) +#else +int CCtsp_add_cut_to_cutlist (cuts, c) +CCtsp_lpcuts *cuts; +CCtsp_lpcut *c; +#endif +{ + if (cuts->cutcount >= cuts->cutspace) { + if (CCutil_reallocrus_scale ((void **) &cuts->cuts, &cuts->cutspace, + cuts->cutcount + 1, 1.3, sizeof (CCtsp_lpcut))) { + return -1; + } + } + cuts->cuts[cuts->cutcount] = *c; + return cuts->cutcount++; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_nzlist_to_lp (CCtsp_lp *lp, int nzlist, int rhs, char sense, + CCtsp_lprow *cr) +#else +int CCtsp_add_nzlist_to_lp (lp, nzlist, rhs, sense, cr) +CCtsp_lp *lp; +int nzlist; +int rhs; +char sense; +CCtsp_lprow *cr; +#endif +{ + int nzcnt; + int i; + CCtsp_lpgraph *g = &lp->graph; + int *rmatind = (int *) NULL; + double *rmatval = (double *) NULL; + double drhs = (double) rhs; + int rval; + + nzcnt = 0; + for (i=nzlist; i != -1; i = g->edges[i].coefnext) { + if (g->edges[i].coef) nzcnt++; + } + + if (nzcnt != 0) { + rmatind = CC_SAFE_MALLOC (nzcnt, int); + if (!rmatind) { + clear_nzlist (g, nzlist); + return 1; + } + rmatval = CC_SAFE_MALLOC (nzcnt, double); + if (!rmatval) { + CC_FREE (rmatind, int); + clear_nzlist (g, nzlist); + return 1; + } + for (nzcnt = 0; nzlist != -1; nzlist = i) { + i = g->edges[nzlist].coefnext; + g->edges[nzlist].coefnext = -2; + if (g->edges[nzlist].coef) { + rmatind[nzcnt] = nzlist; + rmatval[nzcnt] = g->edges[nzlist].coef; + g->edges[nzlist].coef = 0; + nzcnt++; + } + } + } else { + printf ("WARNING: Adding an empty cut to the LP\n"); + fflush (stdout); + } + + rval = addrow_to_list (nzcnt, drhs, sense, rmatind, rmatval, cr); + + CC_FREE (rmatind, int); + CC_FREE (rmatval, double); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCtsp_delete_cut_from_cutlist (CCtsp_lpcuts *cuts, int ind) +#else +void CCtsp_delete_cut_from_cutlist (cuts, ind) +CCtsp_lpcuts *cuts; +int ind; +#endif +{ + int i; + + CCtsp_unregister_cliques (cuts, &cuts->cuts[ind]); + CC_IFFREE (cuts->cuts[ind].mods, CCtsp_sparser); + for (i = ind+1; i < cuts->cutcount; i++) { + cuts->cuts[i-1] = cuts->cuts[i]; + } + cuts->cutcount--; +} + +#ifdef CC_PROTOTYPE_ANSI +static void clear_nzlist (CCtsp_lpgraph *g, int nzlist) +#else +static void clear_nzlist (g, nzlist) +CCtsp_lpgraph *g; +int nzlist; +#endif +{ + int nznext; + + while (nzlist != -1) { + nznext = g->edges[nzlist].coefnext; + g->edges[nzlist].coefnext = -2; + g->edges[nzlist].coef = 0; + nzlist = nznext; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_addbad_variables (CCtsp_lp *lp, struct CCtsp_edgegenerator *eg, + double *ppenalty, int *pnadded, double rcthresh, double maxpenalty, + int phase1, int *feasible) +#else +int CCtsp_addbad_variables (lp, eg, ppenalty, pnadded, rcthresh, maxpenalty, + phase1, feasible) +CCtsp_lp *lp; +struct CCtsp_edgegenerator *eg; +double *ppenalty; +int *pnadded; +double rcthresh, maxpenalty; +int phase1; +int *feasible; +#endif +{ + int nadded; + double penalty; + int finished; + CCtsp_edgehash eh; + int rval; + int *genlist = (int *) NULL; + int *genlen = (int *) NULL; + int gencount; + CCtsp_predge *inlist = (CCtsp_predge *) NULL; + int incount; + CCtsp_predge *prlist = (CCtsp_predge *) NULL; + int prcount; + double *node_pi = (double *) NULL; + double *node_piest = (double *) NULL; + double *clique_pi = (double *) NULL; + double *cut_pi = (double *) NULL; + int i, iend, n; + int start = 0, ni, nj; + int ngen = PRICE_GEN + PRICE_GEN_FACTOR * lp->graph.ncount; + + if (phase1) { + printf ("phase 1 addbad_variables\n"); fflush (stdout); + } + + if (feasible) + *feasible = 0; + + rval = CCtsp_edgehash_init (&eh, (int) (ngen * 1.5)); + if (rval) return rval; + + gencount = 0; + incount = 0; + prcount = 0; + + genlist = CC_SAFE_MALLOC (ngen*2, int); + genlen = CC_SAFE_MALLOC (ngen, int); + inlist = CC_SAFE_MALLOC (ngen, CCtsp_predge); + prlist = CC_SAFE_MALLOC (PRICE_POOL + ngen, CCtsp_predge); + node_pi = CC_SAFE_MALLOC (lp->graph.ncount, double); + node_piest = CC_SAFE_MALLOC (lp->graph.ncount, double); + if (!genlist || !genlen || !inlist || !prlist || !node_pi || !node_piest) { + fprintf (stderr, "out of memory in CCtsp_addbad_variables\n"); + rval = 1; goto CLEANUP; + } + + if (lp->cuts.cliqueend) { + clique_pi = CC_SAFE_MALLOC (lp->cuts.cliqueend, double); + if (!clique_pi) { + fprintf (stderr, "out of memory in CCtsp_addbad_variables\n"); + rval = 1; goto CLEANUP; + } + } + if (lp->cuts.cutcount) { + cut_pi = CC_SAFE_MALLOC (lp->cuts.cutcount, double); + if (!cut_pi) { + fprintf (stderr, "out of memory in CCtsp_addbad_variables\n"); + rval = 1; goto CLEANUP; + } + } + + *pnadded = 0; + rval = pricing_duals (lp, node_pi, node_piest, cut_pi, clique_pi); + if (rval) { + fprintf (stderr, "pricing_duals failed\n"); + goto CLEANUP; + } + if (phase1) { + start = ni = 0; + nj = (lp->full_edges_valid ? 0 : start + 1); + } else { + rval = CCtsp_reset_edgegenerator (eg, node_piest); + if (rval) goto CLEANUP; + } + finished = 0; + nadded = 0; + penalty = 0.0; + while (!finished) { + if (phase1) { + rval = phase1_generate_edges (lp, node_piest, ngen, + &gencount, genlist, genlen, start, &ni, &nj, &finished); + if (rval) { + fprintf (stderr, "phase1_generate_edges failed\n"); + goto CLEANUP; + } + } else { + rval = CCtsp_generate_edges (eg, ngen, &gencount, genlist, genlen, + &finished); + if (rval) { + fprintf (stderr, "CCtsp_generate_edges failed\n"); + goto CLEANUP; + } + } + + for (i = 0, incount = 0; i < gencount; i++) { + if (CCtsp_edgehash_find (&eh, genlist[2*i], genlist[2*i+1]) == -1 + && CCtsp_find_edge (&lp->graph, genlist[2*i], + genlist[2*i+1]) == -1) { + CCtsp_edgehash_add (&eh, genlist[2*i], genlist[2*i+1], 1); + if (genlist[2*i] < genlist[2*i+1]) { + inlist[incount].ends[0] = genlist[2*i]; + inlist[incount].ends[1] = genlist[2*i+1]; + } else { + inlist[incount].ends[0] = genlist[2*i+1]; + inlist[incount].ends[1] = genlist[2*i]; + } + inlist[incount].len = genlen[i]; + incount++; + } + } + rval = price_list (lp, incount, inlist, node_pi, clique_pi, phase1); + if (rval) goto CLEANUP; + for (i=0; i<incount; i++) { + if (inlist[i].rc < 0.0) penalty += inlist[i].rc; + if (inlist[i].rc < rcthresh) { + prlist[prcount++] = inlist[i]; + } else { + rval = CCtsp_edgehash_del (&eh, inlist[i].ends[0], + inlist[i].ends[1]); + if (rval) goto CLEANUP; + } + } + nadded = 0; + while ((!finished && prcount >= PRICE_POOL) || + (finished && penalty < -maxpenalty && prcount > 0)) { + n = PRICE_ADD; + if (n >= prcount) { + n = prcount; + } else { + pr_select (prcount - n, prcount, prlist); + } + printf ("Add %d\n", n); fflush (stdout); + rval = CCtsp_add_vars_to_lp (lp, prlist + prcount - n, n); + if (rval) goto CLEANUP; + nadded += n; + *pnadded += n; + prcount -= n; + rval = CClp_opt (&lp->lp, CClp_METHOD_DUAL); + if (phase1) { + if (rval == 0) { + printf ("LP is now feasible\n"); fflush (stdout); + if (feasible) *feasible = 1; + goto DONE; + } else if (rval != 2) { + fprintf (stderr, "CClp_opt failed\n"); + goto CLEANUP; + } + } else { + if (rval == 2) { + fprintf (stderr, "Adding variables made LP infeasible!\n"); + rval = 1; + goto CLEANUP; + } else if (rval) { + fprintf (stderr, "CClp_opt failed\n"); + goto CLEANUP; + } + } + rval = pricing_duals (lp, node_pi, node_piest, cut_pi, + clique_pi); + if (rval) { + fprintf (stderr, "pricing_duals failed\n"); + goto CLEANUP; + } + rval = price_list (lp, prcount, prlist, node_pi, clique_pi, phase1); + if (rval) { + fprintf (stderr, "price_list failed\n"); + goto CLEANUP; + } + penalty = 0.0; + for (i=0, iend = prcount, prcount = 0; i<iend; i++) { + if (prlist[i].rc < 0.0) penalty += prlist[i].rc; + if (prlist[i].rc < rcthresh && + CCtsp_find_edge (&lp->graph, prlist[i].ends[0], + prlist[i].ends[1]) == -1) { + prlist[prcount++] = prlist[i]; + } + } + } + if (nadded > 0) { + if (phase1) { + start = ni; + nj = (lp->full_edges_valid ? 0 : start + 1); + } else { + rval = CCtsp_reset_edgegenerator (eg, node_piest); + if (rval) goto CLEANUP; + } + finished = 0; + CCtsp_edgehash_delall (&eh); + for (i = 0; i < prcount; i++) { + CCtsp_edgehash_add (&eh, prlist[i].ends[0], + prlist[i].ends[1], 1); + } + } + } + +DONE: + + *ppenalty = penalty; + if (!phase1 || (feasible && *feasible)) + rval = CCtsp_update_result (lp); + +CLEANUP: + + CC_IFFREE (cut_pi, double); + CC_IFFREE (clique_pi, double); + CC_IFFREE (node_piest, double); + CC_IFFREE (node_pi, double); + CC_IFFREE (prlist, CCtsp_predge); + CC_IFFREE (inlist, CCtsp_predge); + CC_IFFREE (genlen, int); + CC_IFFREE (genlist, int); + CCtsp_edgehash_free (&eh); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int phase1_generate_edges (CCtsp_lp *lp, double *node_piest, int nwant, + int *ngot, int *genlist, int *genlen, int start, int *ni, int *nj, + int *finished) +#else +static int phase1_generate_edges (lp, node_piest, nwant, ngot, genlist, genlen, + start, ni, nj, finished) +CCtsp_lp *lp; +double *node_piest; +int nwant; +int *ngot, *genlist, *genlen; +int start; +int *ni, *nj, *finished; +#endif +{ + int i = *ni; + int j = *nj; + CCtsp_genadj *adj; + CCdatagroup *dat; + int cnt = 0; + int ncount = lp->graph.ncount; + + *ngot = 0; + *finished = 0; + + if (!lp->dat && !lp->full_edges_valid) { + fprintf (stderr, "no source of edges to generate\n"); + return 1; + } + + if (i >= ncount) { + i = 0; + j = (lp->full_edges_valid ? 0 : i + 1); + } + + if (lp->full_edges_valid) { + adj = lp->fulladj; + for (; j < adj[i].deg; j++) { + if (phase1_test_edge (i, adj[i].list[j].end, node_piest)) { + genlist[2*cnt] = i; + genlist[2*cnt+1] = adj[i].list[j].end; + genlen[cnt] = adj[i].list[j].len; + cnt++; + if (cnt == nwant) { + goto NOT_FINISHED; + } + } + } + while ((i = (i+1) % ncount) != start) { + for (j = 0; j < adj[i].deg; j++) { + if (phase1_test_edge (i, adj[i].list[j].end, node_piest)) { + genlist[2*cnt] = i; + genlist[2*cnt+1] = adj[i].list[j].end; + genlen[cnt] = adj[i].list[j].len; + cnt++; + if (cnt == nwant) { + goto NOT_FINISHED; + } + } + } + } + } else { + dat = lp->dat; + for (; j < ncount; j++) { + if (phase1_test_edge (i, j, node_piest)) { + genlist[2*cnt] = i; + genlist[2*cnt+1] = j; + genlen[cnt] = CCutil_dat_edgelen (i, j, dat); + cnt++; + if (cnt == nwant) { + goto NOT_FINISHED; + } + } + } + while ((i = (i+1) % ncount) != start) { + for (j = i + 1; j < ncount; j++) { + if (phase1_test_edge (i, j, node_piest)) { + genlist[2*cnt] = i; + genlist[2*cnt+1] = j; + genlen[cnt] = CCutil_dat_edgelen (i, j, dat); + cnt++; + if (cnt == nwant) { + goto NOT_FINISHED; + } + } + } + } + } + + *finished = 1; + return 0; + +NOT_FINISHED: + + *finished = 0; + *ngot = cnt; + *ni = i; *nj = j + 1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int phase1_test_edge (int end1, int end2, double *node_piest) +#else +static int phase1_test_edge (end1, end2, node_piest) +int end1, end2; +double *node_piest; +#endif +{ + return (node_piest[end1] + node_piest[end2] > 0.0); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_eliminate_variables (CCtsp_lp *lp) +#else +int CCtsp_eliminate_variables (lp) +CCtsp_lp *lp; +#endif +{ + int i, j, k; + int rval; + CCbigguy ub; + + /* This function should not create an infeasible LP */ + + if (lp->upperbound == CCtsp_LP_MAXDOUBLE || + CCbigguy_cmp (lp->exact_lowerbound, CCbigguy_MINBIGGUY) == 0) { + printf ("Can't elmininate without upper and lower bounds\n"); + fflush (stdout); + return 0; + } + + ub = CCbigguy_dtobigguy (lp->upperbound - 1.0); + if (CCbigguy_cmp (lp->exact_lowerbound, ub) > 0) { + printf ("No need for elimination, bounds are optimal\n"); + fflush (stdout); + return 0; + } + + assert (lp->infeasible == 0); + + rval = CCtsp_edge_elimination (lp); + if (rval) { + fprintf (stderr, "tsp_edge_elimination failed\n"); + return rval; + } + + assert (lp->infeasible == 0); + + for (i = 0; i < lp->nfixededges; i++) { + k = CCtsp_find_edge (&(lp->graph), lp->fixededges[2*i], + lp->fixededges[2*i+1]); + if (k != -1) { + rval = CClp_setbnd (&lp->lp, k, 'L', 1.0); + lp->graph.edges[k].fixed = 1; + } else { + printf ("WARNING: Fixed edge is not in LP\n"); + fflush (stdout); + } + } + + CC_IFFREE (lp->graph.adjspace, CCtsp_lpadj); + for (i = lp->graph.ecount - 1; i >= 0; i--) { + if (!find_edge_full (lp, lp->graph.edges[i].ends[0], + lp->graph.edges[i].ends[1])) { + if (!lp->graph.edges[i].fixed && !lp->graph.edges[i].branch) { + rval = CClp_delete_column (&lp->lp, i); + if (rval) { + fprintf (stderr, "CClp_delete_column failed\n"); + return rval; + } + lp->graph.edges[i].ends[0] = 0; + lp->graph.edges[i].ends[1] = 0; + } else { + printf ("WARNING: Tried to eliminate a fixed/branch edge\n"); + fflush (stdout); + } + } + } + for (i = 0, j = 0; i < lp->graph.ecount; i++) { + if (lp->graph.edges[i].ends[1] != 0 || + lp->graph.edges[i].ends[0] != 0) { + lp->graph.edges[j] = lp->graph.edges[i]; + j++; + } + } + printf ("Eliminated %d LP edges\n", lp->graph.ecount - j); + fflush (stdout); + + assert (lp->infeasible == 0); + + lp->graph.ecount = j; + rval = CCtsp_build_lpadj (&lp->graph, 0, lp->graph.ecount); + if (rval) { + fprintf (stderr, "CCtsp_build_lpadj failed\n"); + return rval; + } + + rval = CClp_opt (&lp->lp, CClp_METHOD_DUAL); + if (rval == 2) { + fprintf (stderr, "ERROR: edge_elimination created an infeasible LP\n"); + return 1; + } else if (rval) { + fprintf (stderr, "CClp_opt failed\n"); + return rval; + } + rval = CCtsp_update_result (lp); + if (rval) { + fprintf (stderr, "CCtsp_update_result failed\n"); + return rval; + } + + assert (lp->infeasible == 0); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int pricing_duals (CCtsp_lp *lp, double *node_pi, + double *node_piest, double *cut_pi, double *clique_pi) +#else +static int pricing_duals (lp, node_pi, node_piest, cut_pi, clique_pi) +CCtsp_lp *lp; +double *node_pi; +double *node_piest; +double *cut_pi; +double *clique_pi; +#endif +{ + double x; + int i, j, k; + int rval; + + rval = get_pi (lp, node_pi, cut_pi); + if (rval) { + fprintf (stderr, "get_pi failed\n"); + return rval; + } + + for (i = 0; i < lp->cuts.cliqueend; i++) { + clique_pi[i] = 0.0; + } + + for (i = 0; i < lp->cuts.cutcount; i++) { + x = cut_pi[i]; + for (j = 0; j < lp->cuts.cuts[i].modcount; j++) { + node_pi[lp->cuts.cuts[i].mods[j].node] += x * + (((int) lp->cuts.cuts[i].mods[j].mult) - 128); + } + for (j = 0; j < lp->cuts.cuts[i].cliquecount; j++) { + clique_pi[lp->cuts.cuts[i].cliques[j]] += x; + } + } + + for (i = 0; i < lp->graph.ncount; i++) { + node_piest[i] = node_pi[i]; + } + + for (i = 0; i < lp->cuts.cliqueend; i++) { + x = clique_pi[i]; + if (x > 0.0) { + for (j = 0; j < lp->cuts.cliques[i].segcount; j++) { + for (k = lp->cuts.cliques[i].nodes[j].lo; + k <= lp->cuts.cliques[i].nodes[j].hi; k++) { + node_pi[k] += x; + node_piest[k] += x; + } + } + } else if (x < 0.0) { + for (j = 0; j < lp->cuts.cliques[i].segcount; j++) { + for (k = lp->cuts.cliques[i].nodes[j].lo; + k <= lp->cuts.cliques[i].nodes[j].hi; k++) { + node_pi[k] += x; + } + } + } + } + + /* For now, no munching of edges. To do in future, just add + loop here for each edge clique, (if find_edge,)? zero the edge + clique's pi */ + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int price_list (CCtsp_lp *lp, int ecount, CCtsp_predge *elist, + double *node_pi, double *clique_pi, int phase1) +#else +static int price_list (lp, ecount, elist, node_pi, clique_pi, phase1) +CCtsp_lp *lp; +int ecount; +CCtsp_predge *elist; +double *node_pi; +double *clique_pi; +int phase1; +#endif +{ + CCtsp_lpadj *adjspace = (CCtsp_lpadj *) NULL; + CCtsp_lpnode *n = (CCtsp_lpnode *) NULL; + int i, j, k, l; + CCtsp_lpadj *a; + int marker = 0; + double x; + int ncount = lp->graph.ncount; + int ccount = lp->cuts.cliqueend; + CCtsp_lpclique *c = lp->cuts.cliques; + + if (ecount == 0) return 0; + + n = CC_SAFE_MALLOC (ncount, CCtsp_lpnode); + if (!n) return 1; + adjspace = CC_SAFE_MALLOC (2*ecount, CCtsp_lpadj); + if (!adjspace) { + CC_FREE (n, CCtsp_lpnode); + return 1; + } + + for (i = 0; i < ncount; i++) { + n[i].deg = 0; + n[i].mark = 0; + } + for (i = 0; i < ecount; i++) { + if (phase1) { + elist[i].rc = - node_pi[elist[i].ends[0]] + - node_pi[elist[i].ends[1]]; + + } else { + elist[i].rc = elist[i].len + - node_pi[elist[i].ends[0]] + - node_pi[elist[i].ends[1]]; + } + + n[elist[i].ends[0]].deg++; + n[elist[i].ends[1]].deg++; + } + a = adjspace; + for (i = 0; i < ncount; i++) { + n[i].adj = a; + a += n[i].deg; + n[i].deg = 0; + } + for (i=0; i<ecount; i++) { + j = elist[i].ends[0]; + n[j].adj[n[j].deg].to = elist[i].ends[1]; + n[j].adj[n[j].deg].edge = i; + n[j].deg++; + j = elist[i].ends[1]; + n[j].adj[n[j].deg].to = elist[i].ends[0]; + n[j].adj[n[j].deg].edge = i; + n[j].deg++; + } + + for (i = 0; i < ccount; i++) { + if (clique_pi[i]) { + x = clique_pi[i] * 2; + marker++; + for (j = 0; j < c[i].segcount; j++) { + for (k = c[i].nodes[j].lo; k <= c[i].nodes[j].hi; k++) { + a = n[k].adj; + for (l = 0; l < n[k].deg; l++) { + if (n[a[l].to].mark == marker) { + elist[a[l].edge].rc += x; + /* We could test if rc>0, and delete e from adj*/ + } + } + n[k].mark = marker; + } + } + } + } + CC_FREE (n, CCtsp_lpnode); + CC_FREE (adjspace, CCtsp_lpadj); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void pr_select (int nsel, int n, CCtsp_predge *list) +#else +static void pr_select (nsel, n, list) +int nsel; +int n; +CCtsp_predge *list; +#endif +{ + double s1, s2, s3, s; + int i, j, k, l; + CCtsp_predge t; + + s1 = list[n/4].rc; + s2 = list[n/2].rc; + s3 = list[3*n/4].rc; + if (s1 < s2) { + if (s2 < s3) s = s2; + else if (s1 < s3) s = s3; + else s = s1; + } else { + if (s1 < s3) s = s1; + else if (s2 < s3) s = s3; + else s = s2; + } + + /* 0 <= x < i ==> r[i] == s + * i <= x < j ==> r[i] > s + * j <= x <= k ==> r[i] unknown + * k < x <= l ==> r[i] < s + * l < x < n ==> r[i] == s + */ + + i = j = 0; + k = l = n-1; + while (j <= k) { + while (j <= k && list[j].rc >= s) { + if (list[j].rc == s) { + CC_SWAP (list[i], list[j], t); + i++; + } + j++; + } + while (j <= k && list[k].rc <= s) { + if (list[k].rc == s) { + CC_SWAP (list[l], list[k], t); + l--; + } + k--; + } + if (j <= k) { + CC_SWAP (list[j], list[k], t); + j++; + k--; + } + } + while (i > 0) { + i--; + j--; + CC_SWAP (list[i], list[j], t); + } + while (l < n-1) { + k++; + l++; + CC_SWAP (list[k], list[l], t); + } + /* 0 <= x < j ==> r[i] > s + * j <= x <= k ==> r[i] == s + * k < x < n ==> r[i] < s + */ + if (nsel < j) { + pr_select (nsel, j, list); + } else if (nsel > k) { + pr_select (nsel - (k+1), n - (k+1), list + (k+1)); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_vars_to_lp (CCtsp_lp *lp, CCtsp_predge *prlist, int n) +#else +int CCtsp_add_vars_to_lp (lp, prlist, n) +CCtsp_lp *lp; +CCtsp_predge *prlist; +int n; +#endif +{ + int i; + CCtsp_lpedge *e; + int rval; + int nzcnt; + double *obj; + int *matbeg; + int *matind; + double *matval; + double *lb; + double *ub; + + while (lp->graph.ecount + n > lp->graph.espace) { + if (CCutil_reallocrus_scale ((void **) &lp->graph.edges, + &lp->graph.espace, + lp->graph.ecount + n, 1.3, sizeof (CCtsp_lpedge))) { + return 1; + } + } + e = lp->graph.edges + lp->graph.ecount; + for (i = 0; i < n; i++) { + e[i].ends[0] = prlist[i].ends[0]; + e[i].ends[1] = prlist[i].ends[1]; + e[i].fixed = 0; + e[i].branch = 0; + e[i].age = 0; + e[i].len = prlist[i].len; + e[i].coefnext = -2; + e[i].coef = 0; + } + + rval = build_lp_cols (&lp->graph, &lp->cuts, lp->graph.ecount, + lp->graph.ecount + n, &nzcnt, &obj, &matbeg, + (int **) NULL, &matind, &matval, &lb, &ub); + if (rval) return rval; + + rval = lp_addcols (lp, n, nzcnt, obj, matbeg, matind, matval, + lb, ub); + if (rval) goto CLEANUP; + + lp->graph.ecount += n; + rval = CCtsp_build_lpadj (&lp->graph, 0, lp->graph.ecount); + if (rval) goto CLEANUP; + rval = 0; + +CLEANUP: + + CC_IFFREE (obj, double); + CC_IFFREE (matbeg, int); + CC_IFFREE (matind, int); + CC_IFFREE (matval, double); + CC_IFFREE (lb, double); + CC_IFFREE (ub, double); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int age_cuts (CCtsp_lp *lp, int *ndeleted) +#else +static int age_cuts (lp, ndeleted) +CCtsp_lp *lp; +int *ndeleted; +#endif +{ + int *rstat = (int *) NULL; + int *cutstat = (int *) NULL; + int *del = (int *) NULL; + double *cut_pi = (double *) NULL; + int ncount = lp->graph.ncount; + int rval; + int i, j; + + *ndeleted = 0; + + rstat = CC_SAFE_MALLOC (ncount + lp->cuts.cutcount, int); + if (!rstat) { + return 1; + } + rval = CClp_basis (&lp->lp, (int *) NULL, rstat); + if (rval) { + CC_FREE (rstat, int); + return rval; + } + cutstat = rstat + ncount; + if (lp->cuts.cutcount) { + cut_pi = CC_SAFE_MALLOC (lp->cuts.cutcount, double); + if (!cut_pi) { + CC_FREE (rstat, int); + return 1; + } + } + rval = get_pi (lp, (double *) NULL, cut_pi); + if (rval) { + fprintf (stderr, "get_pi failed\n"); + CC_IFFREE (cut_pi, double); + CC_FREE (rstat, int); + return rval; + } + + for (i = lp->cuts.cutcount-1; i >= 0; i--) { + if (lp->cuts.cuts[i].branch == 0) { + if (cut_pi[i]) { + if (lp->cuts.cuts[i].age == CCtsp_NEWCUT_AGE) { + rval = CCtsp_add_to_cutpool (lp->pool, &lp->cuts, + &lp->cuts.cuts[i]); + if (rval) { + fprintf (stderr, "add_to_cutpool failed\n"); + CC_FREE (cut_pi, double); + CC_FREE (rstat, int); + return rval; + } + } + lp->cuts.cuts[i].age = 0; + } else { + if (lp->cuts.cuts[i].age != CCtsp_NEWCUT_AGE) { + lp->cuts.cuts[i].age++; + } + if (cutstat[i] == 1 && + (lp->cuts.cuts[i].age == CCtsp_NEWCUT_AGE || + lp->cuts.cuts[i].age >= lp->cut_life)) { + CCtsp_unregister_cliques (&lp->cuts, &lp->cuts.cuts[i]); + CC_IFFREE (lp->cuts.cuts[i].mods, CCtsp_sparser); + lp->cuts.cuts[i].handlecount = 0; + lp->cuts.cuts[i].cliquecount = 0; + lp->cuts.cuts[i].modcount = 0; + } + } + } + } + CC_FREE (rstat, int); + CC_IFFREE (cut_pi, double); + + del = CC_SAFE_MALLOC (lp->cuts.cutcount, int); + if (!del) { + fprintf (stderr, "out of memory in age_cuts\n"); + return 1; + } + for (i = 0, j = 0; i < lp->cuts.cutcount; i++) { + if (lp->cuts.cuts[i].cliquecount) { + lp->cuts.cuts[j] = lp->cuts.cuts[i]; + j++; + del[i] = 0; + } else { + del[i] = 1; + } + } + if (j < lp->cuts.cutcount) { + rval = lp_delete_cut_set (lp, del); + if (rval) { + fprintf (stderr, "lp_delete_cut_set failed\n"); + CC_FREE (del, int); + return rval; + } + } + CC_FREE (del, int); + + *ndeleted = lp->cuts.cutcount - j; + lp->cuts.cutcount = j; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int age_edges (CCtsp_lp *lp, int *ndeleted) +#else +static int age_edges (lp, ndeleted) +CCtsp_lp *lp; +int *ndeleted; +#endif +{ + int *cstat = (int *) NULL; + int *del = (int *) NULL; + int rval; + int i, j; + + *ndeleted = 0; + + cstat = CC_SAFE_MALLOC (lp->graph.ecount, int); + if (!cstat) { + fprintf (stderr, "out of memory in age_edges\n"); + return 1; + } + rval = CClp_basis (&lp->lp, cstat, (int *) NULL); + if (rval) { + CC_FREE (cstat, int); + return rval; + } + + CC_IFFREE (lp->graph.adjspace, CCtsp_lpadj); + + for (i = lp->graph.ecount-1; i >= 0; i--) { + if (cstat[i] == 0) { + lp->graph.edges[i].age++; + if (lp->graph.edges[i].age >= lp->edge_life && + !lp->graph.edges[i].fixed && !lp->graph.edges[i].branch) { + lp->graph.edges[i].ends[0] = 0; + lp->graph.edges[i].ends[1] = 0; + } + } else { + lp->graph.edges[i].age = 0; + } + } + CC_FREE (cstat, int); + + del = CC_SAFE_MALLOC (lp->graph.ecount, int); + if (!del) { + fprintf (stderr, "out of memory in age_edges\n"); + return 1; + } + for (i = 0, j = 0; i < lp->graph.ecount; i++) { + if (lp->graph.edges[i].ends[1] != 0 || + lp->graph.edges[i].ends[0] != 0) { + lp->graph.edges[j] = lp->graph.edges[i]; + j++; + del[i] = 0; + } else { + del[i] = 1; + } + } + if (j < lp->graph.ecount) { + rval = lp_delete_var_set (lp, del); + if (rval) { + fprintf (stderr, "lp_delete_var_set failed\n"); + CC_FREE (del, int); + return rval; + } + } + CC_FREE (del, int); + + *ndeleted = lp->graph.ecount - j; + lp->graph.ecount = j; + rval = CCtsp_build_lpadj (&lp->graph, 0, lp->graph.ecount); + if (rval) { + fprintf (stderr, "CCtsp_build_lpadj failed\n"); + return rval; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int get_pi (CCtsp_lp *lp, double *node_pi, double *cut_pi) +#else +static int get_pi (lp, node_pi, cut_pi) +CCtsp_lp *lp; +double *node_pi; +double *cut_pi; +#endif +{ + int rval; + + if (node_pi) { + rval = CClp_pi_range (&lp->lp, node_pi, 0, lp->graph.ncount-1); + if (rval) { + fprintf (stderr, "CClp_pi_range failed\n"); + return 1; + } + } + if (cut_pi) { + rval = CClp_pi_range (&lp->lp, cut_pi, lp->graph.ncount, + lp->graph.ncount + lp->cuts.cutcount - 1); + if (rval) { + fprintf (stderr, "CClp_pi_range failed\n"); + return 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_add_multiple_rows (CCtsp_lp *lp, CCtsp_lprow *cr) +#else +int CCtsp_add_multiple_rows (lp, cr) +CCtsp_lp *lp; +CCtsp_lprow *cr; +#endif +{ + int rval = 0; + + if (!cr->rowcnt) + return 0; + + rval = CClp_addrows (&lp->lp, cr->rowcnt, cr->nzcnt, cr->rhs, cr->sense, + cr->begin, cr->indices, cr->entries); + if (rval) { + fprintf (stderr, "Couldn't add rows into LP\n"); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int addrow_to_list (int nzcnt, double drhs, char sense, + int *rmatind, double *rmatval, CCtsp_lprow *cr) +#else +static int addrow_to_list (nzcnt, drhs, sense, rmatind, rmatval, cr) +int nzcnt; +double drhs; +char sense; +int *rmatind; +double *rmatval; +CCtsp_lprow *cr; +#endif +{ + int i, rval; + int *ip; + double *dp; + double rhs = drhs; /* copy to work around problem with sun cc -dalign */ + + rval = CCutil_reallocrus_count ((void **) &(cr->sense), cr->rowcnt + 1, + sizeof (char)); + if (rval) goto CLEANUP; + rval = CCutil_reallocrus_count ((void **) &(cr->rhs), cr->rowcnt + 1, + sizeof (double)); + if (rval) goto CLEANUP; + rval = CCutil_reallocrus_count ((void **) &(cr->begin), cr->rowcnt + 1, + sizeof (int)); + if (rval) goto CLEANUP; + + if (nzcnt + cr->nzcnt > cr->indexspace) { + rval = CCutil_reallocrus_scale ((void **) &(cr->indices), + &(cr->indexspace), nzcnt + cr->nzcnt, 1.3, sizeof (int)); + if (rval) goto CLEANUP; + } + if (nzcnt + cr->nzcnt > cr->entryspace) { + rval = CCutil_reallocrus_scale ((void **) &(cr->entries), + &(cr->entryspace), nzcnt + cr->nzcnt, 1.3, sizeof (double)); + if (rval) goto CLEANUP; + } + + cr->sense[cr->rowcnt] = sense; + cr->rhs[cr->rowcnt] = rhs; + cr->begin[cr->rowcnt] = cr->nzcnt; + cr->rowcnt++; + + ip = cr->indices + cr->nzcnt; + dp = cr->entries + cr->nzcnt; + for (i = 0; i < nzcnt; i++) { + ip[i] = rmatind[i]; + dp[i] = rmatval[i]; + } + cr->nzcnt += nzcnt; + + return 0; + +CLEANUP: + + fprintf (stderr, "out of memory in addrow_to_list\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int lp_addcols (CCtsp_lp *lp, int ncols, int nzcnt, + double *obj, int *matbeg, int *matind, double *matval, + double *lb, double *ub) +#else +static int lp_addcols (lp, ncols, nzcnt, obj, matbeg, matind, matval, lb, ub) +CCtsp_lp *lp; +int ncols; +int nzcnt; +double *obj; +int *matbeg; +int *matind; +double *matval; +double *lb; +double *ub; +#endif +{ + int rval = 0; + + rval = CClp_addcols (&lp->lp, ncols, nzcnt, obj, + matbeg, matind, matval, lb, ub); + if (rval) { + fprintf (stderr, "Couldn't add columns into LP\n"); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_delete_cut (CCtsp_lp *lp, int i) +#else +int CCtsp_delete_cut (lp, i) +CCtsp_lp *lp; +int i; +#endif +{ + int rval = 0; + rval = CClp_delete_row(&lp->lp, lp->graph.ncount + i); + if (rval) fprintf (stderr, "CClp_delete_row failed\n"); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int lp_delete_cut_set (CCtsp_lp *lp, int *del) +#else +static int lp_delete_cut_set (lp, del) +CCtsp_lp *lp; +int *del; +#endif +{ + int i, rval = 0; + int *delstat = (int *) NULL; + int ncount = lp->graph.ncount; + int cutcount = lp->cuts.cutcount; + + delstat = CC_SAFE_MALLOC (ncount + cutcount, int); + if (!delstat) { + fprintf (stderr, "out of memory in lp_delete_cut_set\n"); + return 1; + } + for (i = 0; i < ncount; i++) + delstat[i] = 0; + for (i = 0; i < cutcount; i++) + delstat[i + ncount] = del[i]; + + rval = CClp_delete_set_of_rows (&lp->lp, delstat); + if (rval) { + fprintf (stderr, "CClp_delete_set_of_rows failed\n"); + } + + CC_FREE (delstat, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int lp_delete_var_set (CCtsp_lp *lp, int *del) +#else +static int lp_delete_var_set (lp, del) +CCtsp_lp *lp; +int *del; +#endif +{ + int rval = 0; + + rval = CClp_delete_set_of_columns (&lp->lp, del); + if (rval) { + fprintf (stderr, "CClp_delete_set_of_columns failed\n"); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_write_probfile_sav (CCtsp_lp *lp) +#else +int CCtsp_write_probfile_sav (lp) +CCtsp_lp *lp; +#endif +{ + return write_probfile (lp, 1); +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_write_probfile_id (CCtsp_lp *lp) +#else +int CCtsp_write_probfile_id (lp) +CCtsp_lp *lp; +#endif +{ + return write_probfile (lp, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +static int write_probfile (CCtsp_lp *lp, int saveit) +#else +static int write_probfile (lp, saveit) +CCtsp_lp *lp; +int saveit; /* set to 1 to write to prob.sav */ +#endif +{ + CCtsp_PROB_FILE *p = (CCtsp_PROB_FILE *) NULL; + char fname[1024]; + int len; + + if (!lp) { + fprintf (stderr, "CCtsp_write_probfile called without an lp\n"); + return 1; + } + if (!lp->graph.ecount) { + fprintf (stderr, "CCtsp_write_probfile called with an edgeset\n"); + return 1; + } + + if (saveit) { + len = strlen (lp->name); + if (len + 40 > 1024) { + sprintf (fname, "probfile.sav"); + } else { + sprintf (fname, "%s.sav", lp->name); + } + + p = CCtsp_prob_write_name (fname, lp->name); + if (!p) { + fprintf (stderr, "CCtsp_prob_write_name failed\n"); + return 1; + } + } else { + p = CCtsp_prob_write (lp->name, lp->id); + if (!p) { + fprintf (stderr, "CCtsp_prob_write failed\n"); + return 1; + } + } + + if (CCtsp_prob_putname (p, lp->name)) goto CLEANUP; + if (CCtsp_prob_putid (p, lp->id)) goto CLEANUP; + if (CCtsp_prob_putparent (p, lp->parent_id)) goto CLEANUP; + if (CCtsp_prob_putnnodes (p, lp->graph.ncount)) goto CLEANUP; + if (CCtsp_prob_putub (p, lp->upperbound)) goto CLEANUP; + if (CCtsp_prob_putlb (p, lp->lowerbound)) goto CLEANUP; + if (CCtsp_prob_putexactlb (p, lp->exact_lowerbound)) goto CLEANUP; + if (CCtsp_prob_putinfeasible (p, lp->infeasible)) goto CLEANUP; + + { + int *elist = (int *) NULL; + int *elen = (int *) NULL; + int ecount = lp->graph.ecount; + int i; + + elist = CC_SAFE_MALLOC (2 * ecount, int); + elen = CC_SAFE_MALLOC (ecount, int); + + if (!elist || !elen) { + fprintf (stderr, "out of memory in CCtsp_write_probfile\n"); + CC_IFFREE (elist, int); + CC_IFFREE (elen, int); + goto CLEANUP; + } + + for (i = 0; i < ecount; i++) { + elist[2*i] = lp->graph.edges[i].ends[0]; + elist[2*i + 1] = lp->graph.edges[i].ends[1]; + elen[i] = lp->graph.edges[i].len; + } + + if (CCtsp_prob_putedges (p, ecount, elist, elen)) { + CC_FREE (elist, int); + CC_FREE (elen, int); + goto CLEANUP; + } + CC_FREE (elist, int); + CC_FREE (elen, int); + } + + if (CCtsp_prob_putcuts (p, (CC_SFILE *) NULL, &(lp->cuts))) goto CLEANUP; + + { + CClpbasis b; + int ccount = lp->graph.ecount; + int rcount = lp->graph.ncount + lp->cuts.cutcount; + + CClp_init_basis (&b); + + if (CClp_get_basis_and_norms (&lp->lp, &b)) { + printf ("No basis/norms to add to probfile\n"); + fflush (stdout); + } else { + if (CCtsp_prob_putbasis (p, ccount, rcount, b.cstat, b.rstat)) { + CClp_free_basis (&b); + goto CLEANUP; + } + if (CCtsp_prob_putnorms (p, rcount, b.dnorm)) { + CClp_free_basis (&b); + goto CLEANUP; + } + } + CClp_free_basis (&b); + } + + if (lp->nfixededges > 0) { + if (CCtsp_prob_putfixed (p, lp->nfixededges, lp->fixededges)) { + fprintf (stderr, "CCtsp_prob_putfixed failed\n"); + goto CLEANUP; + } + } + + if (lp->fullcount > 0 && lp->full_edges_valid) { + if (CCtsp_prob_putfulladj (p, lp->graph.ncount, lp->fullcount, + lp->fulladj)) { + fprintf (stderr, "CCtsp_prob_putfulladj failed\n"); + goto CLEANUP; + } + } + + if (lp->exact_dual) { + if (CCtsp_prob_putexactdual (p, lp->exact_dual, lp->graph.ncount)) { + fprintf (stderr, "CCtsp_prob_putexact_dual failed\n"); + goto CLEANUP; + } + } + + if (CCtsp_prob_puthistory (p, lp->branchdepth, lp->branchhistory)) { + fprintf (stderr, "CCtsp_prob_puthistory failed\n"); + goto CLEANUP; + } + + if (CCtsp_prob_wclose (p)) { + fprintf (stderr, "CCtsp_prob_wclose failed\n"); + return 1; + } + + return 0; + +CLEANUP: + + fprintf (stderr, "CCtsp_write_probfile failed\n"); + + if (p) + CCtsp_prob_wclose (p); + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_read_probfile (CCtsp_lp *lp, char *fname, int ncount) +#else +int CCtsp_read_probfile (lp, fname, ncount) +CCtsp_lp *lp; +char *fname; +int ncount; +#endif +{ + CCtsp_PROB_FILE *p = (CCtsp_PROB_FILE *) NULL; + + p = CCtsp_prob_read_name (fname); + if (!p) { + fprintf (stderr, "could not open %s for reading\n", fname); + return 1; + } + + return read_probfile (lp, p, ncount); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_read_probfile_id (CCtsp_lp *lp, char *name, int id, int ncount) +#else +int CCtsp_read_probfile_id (lp, name, id, ncount) +CCtsp_lp *lp; +char *name; +int id; +int ncount; +#endif +{ + CCtsp_PROB_FILE *p = (CCtsp_PROB_FILE *) NULL; + + p = CCtsp_prob_read (name, id); + if (!p) { + fprintf (stderr, "could not open %s for reading\n", name); + return 1; + } + + return read_probfile (lp, p, ncount); +} + +#ifdef CC_PROTOTYPE_ANSI +static int read_probfile (CCtsp_lp *lp, CCtsp_PROB_FILE *p, int ncount) +#else +static int read_probfile (lp, p, ncount) +CCtsp_lp *lp; +CCtsp_PROB_FILE *p; +int ncount; +#endif +{ + int tncount, ecount, ccount, rcount; + int *elist = (int *) NULL; + int *elen = (int *) NULL; + int i, k; + int rval = 0; + CClpbasis *b = (CClpbasis *) NULL; + + rval = CCtsp_init_cliquehash (&lp->cuts, 2*ncount); + if (rval) return rval; + + lp->name = CC_SAFE_MALLOC (CCtsp_PROB_FILE_NAME_LEN, char); + if (!lp->name) { + fprintf (stderr, "out of memory in read_probfile\n"); + rval = 1; + goto CLEANUP; + } + rval = CCtsp_prob_getname (p, lp->name); + if (rval == -1) goto CLEANUP; + printf ("Prob Name: %s\n", lp->name); fflush (stdout); + + rval = CCtsp_prob_getid (p, &(lp->id)); + if (rval == -1) goto CLEANUP; + printf ("Prob ID: %d\n", lp->id); fflush (stdout); + + rval = CCtsp_prob_getparent (p, &(lp->parent_id)); + if (rval == -1) goto CLEANUP; + printf ("Prob Parent ID: %d\n", lp->parent_id); fflush (stdout); + + rval = CCtsp_prob_getub (p, &(lp->upperbound)); + if (rval == -1) goto CLEANUP; + rval = CCtsp_prob_getlb (p, &(lp->lowerbound)); + if (rval == -1) goto CLEANUP; + printf ("Prob Bounds: (%f, %f)\n", lp->lowerbound, lp->upperbound); + fflush (stdout); + + rval = CCtsp_prob_getexactlb (p, &(lp->exact_lowerbound)); + if (rval == -1) goto CLEANUP; + if (CCbigguy_cmp (lp->exact_lowerbound, CCbigguy_MINBIGGUY) != 0) { + printf ("Prob Exact Lowerbound: %f\n", + CCbigguy_bigguytod (lp->exact_lowerbound)); + fflush (stdout); + } + + rval = CCtsp_prob_getinfeasible (p, &(lp->infeasible)); + if (rval == -1) goto CLEANUP; + if (lp->infeasible) { + printf ("Prob stored is tagged as infeasible\n"); + fflush (stdout); + } + + rval = CCtsp_prob_getnnodes (p, &tncount); + if (rval == -1) goto CLEANUP; + if (!rval) { + if (tncount != ncount) { + fprintf (stderr, "node counts differ in probfile and input\n"); + rval = 1; + goto CLEANUP; + } + } + + rval = CCtsp_prob_getcuts (p, (CC_SFILE *) NULL, &(lp->cuts)); + if (rval == -1) goto CLEANUP; + + rval = CCtsp_prob_getedges (p, &ecount, &elist, &elen); + if (rval == -1) goto CLEANUP; + if (!rval) { + rval = CCtsp_build_lpgraph (&lp->graph, ncount, ecount, elist, elen); + if (rval) goto CLEANUP; + rval = CCtsp_build_lpadj (&lp->graph, 0, ecount); + if (rval) goto CLEANUP; + CC_FREE (elist, int); + CC_FREE (elen, int); + } + + rval = CCtsp_prob_getfixed (p, &(lp->nfixededges), &(lp->fixededges)); + if (rval == -1) goto CLEANUP; + if (!rval) { + printf ("Read %d LP fixed edges\n", lp->nfixededges); fflush (stdout); + for (i = 0; i < lp->nfixededges; i++) { + k = CCtsp_find_edge (&(lp->graph), lp->fixededges[2*i], + lp->fixededges[2*i+1]); + if (k != -1) { + lp->graph.edges[k].fixed = 1; + } else { + printf ("WARNING: File want's to fix a non-lp edge\n"); + fflush (stdout); + } + } + } + + b = CC_SAFE_MALLOC (1, CClpbasis); + if (!b) { + fprintf (stderr, "out of memory in read_probfile\n"); + rval = 1; goto CLEANUP; + } + CClp_init_basis (b); + lp->basis = b; + + rval = CCtsp_prob_getbasis (p, &ccount, &rcount, &b->cstat, &b->rstat); + if (rval == -1) goto CLEANUP; + if (!rval) { + if (ccount != lp->graph.ecount) { + fprintf (stderr, "column counts differs in basis probfile\n"); + rval = 1; + goto CLEANUP; + } + if (rcount != lp->graph.ncount + lp->cuts.cutcount) { + fprintf (stderr, "rcount differs in basis probfile\n"); + rval = 1; + goto CLEANUP; + } + } + + rval = CCtsp_prob_getnorms (p, &rcount, &b->dnorm); + if (rval == -1) goto CLEANUP; + if (!rval) { + if (rcount != lp->graph.ncount + lp->cuts.cutcount) { + fprintf (stderr, "rcount differs in norms probfile\n"); + rval = 1; goto CLEANUP; + } + } + + rval = CCtsp_prob_getfulladj (p, ncount, &(lp->fullcount), + &(lp->fulladj), &(lp->fulladjspace)); + if (rval == -1) { + fprintf (stderr, "CCtsp_prob_getfulladj failed\n"); + goto CLEANUP; + } + if (!rval) { + printf ("Read LP full adj\n"); fflush (stdout); + if (lp->fullcount) { + lp->full_edges_valid = 1; + } + } + + rval = CCtsp_prob_getexactdual (p, ncount, &(lp->exact_dual)); + if (rval == -1) { + fprintf (stderr, "CCtsp_prob_getexactdual failed\n"); + goto CLEANUP; + } + if (!rval) { + printf ("Read LP exact dual values\n"); fflush (stdout); + } + + rval = CCtsp_prob_gethistory (p, &lp->branchdepth, &lp->branchhistory); + if (rval == -1) { + fprintf (stderr, "CCtsp_prob_gethistory failed\n"); + goto CLEANUP; + } + if (!rval) { + CCtsp_print_branchhistory (lp); + } + + rval = 0; + + +CLEANUP: + + if (CCtsp_prob_rclose (p)) { + fprintf (stderr, "CCtsp_prob_rclose failed\n"); + return 1; + } + + printf ("Done with read_probfile\n"); fflush (stdout); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_dump_x (CCtsp_lp *lp, char *fname) +#else +int CCtsp_dump_x (lp, fname) +CCtsp_lp *lp; +char *fname; +#endif +{ + int i, xcount; + int nonzero = 0; + int *xlist = (int *) NULL; + double *x = (double *) NULL; + FILE *out; + int rval = 0; + + printf ("Dumping the x vector to %s ... ", fname); fflush (stdout); + + rval = CCtsp_get_lp_result (lp, (double *) NULL, (double *) NULL, &xcount, + &xlist, &x, (double **) NULL, (double **) NULL, (double **) NULL); + if (rval) { + fprintf (stderr, "CCtsp_get_lp_result failed\n"); return rval; + } + + for (i = 0; i < xcount; i++) { + if (x[i] > CCtsp_INTTOL) { + nonzero++; + } + } + + out = fopen (fname, "w"); + if (out == (FILE *) NULL) { + fprintf (stderr, "could not open %s for writing\n", fname); + rval = 1; goto CLEANUP; + } + + fprintf (out, "%d %d\n", lp->graph.ncount, nonzero); + for (i = 0; i < xcount; i++) { + if (x[i] > CCtsp_INTTOL) { + fprintf (out, "%d %d %f\n", lp->perm[xlist[2*i]], + lp->perm[ xlist[2*i+1]], + x[i]); + } + } + fclose (out); + printf ("DONE\n"); fflush (stdout); + +CLEANUP: + + CC_IFFREE (xlist, int); + CC_IFFREE (x, double); + return rval; +} + diff --git a/contrib/blossom/concorde97/TSP/xtour.c b/contrib/blossom/concorde97/TSP/xtour.c new file mode 100644 index 0000000000000000000000000000000000000000..be77224864e183e12383bc49e04c2ab9397119ce --- /dev/null +++ b/contrib/blossom/concorde97/TSP/xtour.c @@ -0,0 +1,234 @@ +/***************************************************************************/ +/* */ +/* ROUTINES FOR CONSTRUCTING TOURS FROM x-VECTORS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: July 21, 1997 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCtsp_x_greedy_tour (CCdatagroup *dat, int ncount, int ecount, */ +/* int *elist, double *x, int *cyc, double *val) */ +/* FINDS a tour by adding in edges by nonincreasing x-value. */ +/* -cyc should be an array of length at least ncount */ +/* -val returns the length of the tour */ +/* */ +/* int CCtsp_x_greedy_tour_lk (CCdatagroup *dat, int ncount, int ecount,*/ +/* int *elist, double *x, int *cyc, double *val) */ +/* FINDS the x-greedy tour then calls a short LK. */ +/* */ +/* NOTES: */ +/* */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "edgegen.h" +#include "linkern.h" +#include "tsp.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + update_tail (int *tail, int a, int b); + +#else + +static void + update_tail (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_x_greedy_tour_lk (CCdatagroup *dat, int ncount, int ecount, + int *elist, double *x, int *cyc, double *val) +#else +int CCtsp_x_greedy_tour_lk (dat, ncount, ecount, elist, x, cyc, val) +CCdatagroup *dat; +int ncount, ecount; +int *elist; +double *x; +int *cyc; +double *val; +#endif +{ + int rval = 0; + int *gcyc = (int *) NULL; + int *tlist = (int *) NULL; + int tcount; + double gval; + CCedgegengroup plan; + + *val = 1e30; + if (!dat) { + fprintf (stderr, "no dat in CCtsp_x_greedy_tour_lk\n"); + rval = 1; goto CLEANUP; + } + + gcyc = CC_SAFE_MALLOC (ncount, int); + if (!gcyc) { + fprintf (stderr, "out of memory in CCtsp_x_greedy_tour_lk\n"); + rval = 1; goto CLEANUP; + } + + rval = CCtsp_x_greedy_tour (dat, ncount, ecount, elist, x, gcyc, + &gval); + if (rval) { + fprintf (stderr, "CCtsp_x_greedy_tour failed\n"); goto CLEANUP; + } + + CCedgegen_init_edgegengroup (&plan); + plan.quadnearest = 2; + + rval = CCedgegen_edges (&plan, ncount, dat, (double *) NULL, &tcount, + &tlist); + if (rval) { + fprintf (stderr, "CCedgegen_edges failed\n"); goto CLEANUP; + } + + rval = CClinkern_tour (ncount, dat, tcount, tlist, ncount, + ncount > 1000 ? 500 : ncount/2, gcyc, cyc, val, 0, 0.0, + 0.0, (char *) NULL); + if (rval) { + fprintf (stderr, "CClinkern_tour failed\n"); goto CLEANUP; + } + +CLEANUP: + + CC_IFFREE (tlist, int); + CC_IFFREE (gcyc, int); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCtsp_x_greedy_tour (CCdatagroup *dat, int ncount, int ecount, int *elist, + double *x, int *cyc, double *val) +#else +int CCtsp_x_greedy_tour (dat, ncount, ecount, elist, x, cyc, val) +CCdatagroup *dat; +int ncount, ecount; +int *elist; +double *x; +int *cyc; +double *val; +#endif +{ + int rval = 0; + int tcount = 0; + int i, a, b; + double szeit = CCutil_zeit (); + double len; + int *perm = (int *) NULL; + int *tail = (int *) NULL; + int *tcyc = (int *) NULL; + char *degree = (char *) NULL; + + printf ("CCtsp_x_greedy_tour ...\n"); fflush (stdout); + + *val = 1e30; + if (!dat) { + fprintf (stderr, "no dat in CCtsp_x_greedy_tour\n"); + rval = 1; goto CLEANUP; + } + + perm = CC_SAFE_MALLOC (ecount, int); + degree = CC_SAFE_MALLOC (ncount, char); + tail = CC_SAFE_MALLOC (ncount, int); + tcyc = CC_SAFE_MALLOC (2 * ncount, int); + if (!perm || !degree || !tail || !tcyc) { + fprintf (stderr, "out of memory in CCtsp_x_greedy_tour\n"); + rval = 1; goto CLEANUP; + } + + for (i = 0; i < ncount; i++) { + degree[i] = 0; + tail[i] = -1; + } + for (i = 0; i < ecount; i++) { + perm[i] = i; + } + + CCutil_double_perm_quicksort (perm, x, ecount); + len = 0; + for (i = ecount - 1; i >= 0; i--) { + a = elist[2*perm[i]]; + b = elist[(2*perm[i]) + 1]; + if (degree[a] != 2 && degree[b] != 2 && tail[a] != b) { + /* add (a, b) to the tour */ + tcyc[tcount++] = a; + tcyc[tcount++] = b; + len += (double) CCutil_dat_edgelen (a, b, dat); + degree[a]++; + degree[b]++; + update_tail (tail, a, b); + } + } + + printf ("%d edges in x-tour\n", tcount / 2); fflush (stdout); + a = 0; + b = 0; + while (tcount < (2*ncount - 2)) { + for (; degree[a] == 2; a++); + for (b = a + 1; degree[b] == 2 || tail[a] == b; b++); + tcyc[tcount++] = a; + tcyc[tcount++] = b; + degree[a]++; + degree[b]++; + update_tail (tail, a, b); + len += (double) CCutil_dat_edgelen (a, b, dat); + } + + if (tcount < 2*ncount) { + for (a = 0; degree[a] != 1; a++); + for (b = a + 1; degree[b] != 1; b++); + tcyc[tcount++] = a; + tcyc[tcount++] = b; + len += (double) CCutil_dat_edgelen (a, b, dat); + } + + printf ("tour length: %.2f (%.2f seconds)\n", len, CCutil_zeit () - szeit); + fflush (stdout); + *val = len; + + rval = CCutil_edge_to_cycle (ncount, tcyc, cyc); + if (rval) { + fprintf (stderr, "CCutil_edge_to_cycle failed\n"); + goto CLEANUP; + } + +CLEANUP: + + CC_IFFREE (perm, int); + CC_IFFREE (tail, int); + CC_IFFREE (tcyc, int); + CC_IFFREE (degree, char); + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void update_tail (int *tail, int a, int b) +#else +static void update_tail (tail, a, b) +int *tail; +int a, b; +#endif +{ + if (tail[a] == -1) { + if (tail[b] == -1) { + tail[a] = b; + tail[b] = a; + } else { + tail[a] = tail[b]; + tail[tail[b]] = a; + } + } else if (tail[b] == -1) { + tail[tail[a]] = b; + tail[b] = tail[a]; + } else { + tail[tail[a]] = tail[b]; + tail[tail[b]] = tail[a]; + } +} diff --git a/contrib/blossom/concorde97/UTIL/Makefile b/contrib/blossom/concorde97/UTIL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eafa97131db72be6209dff6d7329b82c7fd7ae53 --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/Makefile @@ -0,0 +1,40 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=util.a +LIBSRCS=allocrus.c bgetopt.c dheaps_i.c edg2cyc.c edgelen.c fastread.c \ + getdata.c safe_io.c sortrus.c urandom.c util.c zeit.c \ + genhash.c priority.c +ALLSRCS=$(LIBSRCS) + +all: $(LIB) + +clean: + -rm -f *.$o $(LIB) + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +allocrus.$o: allocrus.c $(I)/machdefs.h $(I)/util.h +bgetopt.$o: bgetopt.c $(I)/machdefs.h $(I)/util.h +dheaps_i.$o: dheaps_i.c $(I)/machdefs.h $(I)/util.h +edg2cyc.$o: edg2cyc.c $(I)/machdefs.h $(I)/util.h +edgelen.$o: edgelen.c $(I)/machdefs.h $(I)/util.h +fastread.$o: fastread.c $(I)/machdefs.h $(I)/util.h +genhash.$o: genhash.c $(I)/machdefs.h $(I)/util.h +getdata.$o: getdata.c $(I)/machdefs.h $(I)/util.h +priority.$o: priority.c $(I)/machdefs.h $(I)/util.h +safe_io.$o: safe_io.c $(I)/machdefs.h $(I)/util.h +sortrus.$o: sortrus.c $(I)/machdefs.h $(I)/util.h +urandom.$o: urandom.c $(I)/machdefs.h $(I)/util.h +util.$o: util.c $(I)/machdefs.h $(I)/macrorus.h $(I)/util.h +zeit.$o: zeit.c $(I)/machdefs.h $(I)/util.h diff --git a/contrib/blossom/concorde97/UTIL/allocrus.c b/contrib/blossom/concorde97/UTIL/allocrus.c new file mode 100644 index 0000000000000000000000000000000000000000..5f800b4804ffbf328dc12b6b71d5ae62c9322a15 --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/allocrus.c @@ -0,0 +1,400 @@ +/***************************************************************************/ +/* */ +/* MEMORY ALLOCATION MACROS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 2, 1995 (cofeb16) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* void *CCutil_allocrus (unsigned int size) */ +/* RETURNS a pointer to an allocated block of "size" memory. */ +/* */ +/* void CCutil_freerus (void *ptr) */ +/* FREES ptr. */ +/* */ +/* void *CCutil_reallocrus (void *ptr, unsigned int size) */ +/* REALLOCS ptr to size bytes. */ +/* */ +/* int CCutil_reallocrus_scale (void **pptr, int *pnnum, int count, */ +/* double scale, unsigned int size) */ +/* void **pptr (a reference to the pointer to the allocated space) */ +/* int *pnnum (a reference to the number of objects in the */ +/* allocated space) */ +/* int count (a minimum value for the new nnum) */ +/* double scale (a scale factor to apply to nnum) */ +/* int size (the size of objects to be realloced) */ +/* RETURNS 0 if *pptr was successfully changed to point to at */ +/* least max(*pnnum*scale, *pnnum+1000, count) objects. */ +/* *pnnum is changed to the new object count. */ +/* Otherwise, prints an error message, leaves *pptr and */ +/* *pnnum alone, and returns nonzero. */ +/* */ +/* int CCutil_reallocrus_count (void **pptr, int count, */ +/* unsigned int size) */ +/* void **pptr (a reference to the pointer to the allocated space) */ +/* int count (number of objects to be realloced) */ +/* int size (the size of the objects to be realloced) */ +/* RETURNS 0 is successful, and 1 if the realloc failed. */ +/* */ +/* */ +/* CCbigchunkptr *CCutil_bigchunkalloc (void) */ +/* RETURNS a CCbigchunkptr with the "this" field loaded with a */ +/* a pointer to a bigchunk of memory. */ +/* CCutil_bigchunkfree (CCbigchunkptr *bp) */ +/* ACTION: Gives the CCbigchunkptr back to the global supply. */ +/* int CCutil_bigchunk_free_world (void) */ +/* ACTION: Gives the global supply of CCbigchunkptrs and bigchunks */ +/* back to the system. It returns a nonzero value if there */ +/* was an error. */ +/* */ +/* NOTES: */ +/* Functions prototyped in allocrus.h. */ +/* The idea is to use bigchunks (the size of a bigchunk is defined */ +/* by BIGCHUNK in allocrus.h) to supply local routines with memory */ +/* for ptrs, so the memory can be shared with other local routines. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +static CCbigchunkptr *local_bigchunk_list = (CCbigchunkptr *) NULL; +static CCbigchunkptr *bigchunk_list = (CCbigchunkptr *) NULL; +static CCbigchunkptr *bigchunk_freelist = (CCbigchunkptr *) NULL; +static CCbigchunkptr *bigchunkptr_freelist = (CCbigchunkptr *) NULL; + +static int bigchunktotal = 0; +static int bigchunkreserve = 0; +static int bigchunkptrtotal = 0; + +#ifdef CC_PROTOTYPE_ANSI + +static void + bigchunkptrfree (CCbigchunkptr *bp); + +static CCbigchunkptr + *bigchunkptralloc (void); + +#else + +static void + bigchunkptrfree (); + +static CCbigchunkptr + *bigchunkptralloc (); + +#endif + + + +#ifdef CC_PROTOTYPE_ANSI +void *CCutil_allocrus (unsigned int size) +#else +void *CCutil_allocrus (size) +unsigned int size; +#endif +{ + void *mem = (void *) NULL; + + if (size == 0) { + fprintf (stderr, "Warning: 0 bytes allocated\n"); + } + + mem = (void *) malloc (size); + if (mem == (void *) NULL) { + fprintf (stderr, "Out of memory. Asked for %d bytes\n", size); + } + return mem; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_freerus (void *p) +#else +void CCutil_freerus (p) +void *p; +#endif +{ + if (!p) { + fprintf (stderr, "Warning: null pointer freed\n"); + return; + } + + free (p); +} + +#ifdef CC_PROTOTYPE_ANSI +void *CCutil_reallocrus (void *ptr, unsigned int size) +#else +void *CCutil_reallocrus (ptr, size) +void *ptr; +unsigned int size; +#endif +{ + void *newptr; + + if (!ptr) { + return CCutil_allocrus (size); + } else { + newptr = (void *) realloc (ptr, size); + if (!newptr) { + fprintf (stderr, "Out of memory. Tried to grow %d bytes\n", size); + } + return newptr; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_reallocrus_scale (void **pptr, int *pnnum, int count, double scale, + unsigned int size) +#else +int CCutil_reallocrus_scale (pptr, pnnum, count, scale, size) +void **pptr; +int *pnnum; +int count; +double scale; +unsigned int size; +#endif +{ + int newsize = (int) (((double) *pnnum) * scale); + void *p; + + if (newsize < *pnnum+1000) newsize = *pnnum+1000; + if (newsize < count) newsize = count; + p = CCutil_reallocrus (*pptr, newsize * size); + if (!p) { + return 1; + } else { + *pptr = p; + *pnnum = newsize; + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_reallocrus_count (void **pptr, int count, unsigned int size) +#else +int CCutil_reallocrus_count (pptr, count, size) +void **pptr; +int count; +unsigned int size; +#endif +{ + void *p = CCutil_reallocrus (*pptr, count * size); + + if (!p) { + return 1; + } else { + *pptr = p; + return 0; + } +} + + +#ifdef CC_PROTOTYPE_ANSI +CCbigchunkptr *CCutil_bigchunkalloc (void) +#else +CCbigchunkptr *CCutil_bigchunkalloc () +#endif +{ + void *p; + CCbigchunkptr *bp, *cp; + + if (!bigchunk_freelist) { + p = (void *) CCutil_allocrus (CC_BIGCHUNK); + if (!p) + return (CCbigchunkptr *) NULL; + bp = bigchunkptralloc (); + if (!bp) { + CC_FREE (p, void); + return (CCbigchunkptr *) NULL; + } + cp = bigchunkptralloc (); + if (!cp) { + CC_FREE (p, void); + bigchunkptrfree (bp); + return (CCbigchunkptr *) NULL; + } + bp->this = p; + cp->this = p; + cp->next = bigchunk_list; + bigchunk_list = cp; + bigchunktotal++; + return bp; + } else { + bp = bigchunk_freelist; + bigchunk_freelist = bp->next; + bigchunkreserve--; + return bp; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_bigchunkfree (CCbigchunkptr *bp) +#else +void CCutil_bigchunkfree (bp) +CCbigchunkptr *bp; +#endif +{ + bp->next = bigchunk_freelist; + bigchunk_freelist = bp; + bigchunkreserve++; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_bigchunkquery (int *total, int *reserve) +#else +void CCutil_bigchunkquery (total, reserve) +int *total, *reserve; +#endif +{ + *total = bigchunktotal; + *reserve = bigchunkreserve; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_bigchunk_free_world (void) +#else +int CCutil_bigchunk_free_world () +#endif +{ + int duplicates = 0, localcount, bpcount, i; + void **tosslist; + CCbigchunkptr *bp, *bpnext; + + /* First some checking, to see that the routines were used properly */ + + if (bigchunkreserve != bigchunktotal) { + fprintf (stderr, "WARNING: %d outstanding bigchunks\n", + bigchunktotal - bigchunkreserve); + } + for (bp = bigchunk_freelist; bp; bp = bp->next) + bp->this = (void *) NULL; + for (bp = bigchunk_freelist; bp; bp = bp->next) { + if (bp->this == (void *) 1) + duplicates++; + else + bp->this = (void *) 1; + } + if (duplicates) { + fprintf (stderr, "WARNING: %d duplicate bigchunks returned", + duplicates); + } + + /* Now free the global bigchunks */ + + for (bp = bigchunk_list; bp; bp = bpnext) { + bpnext = bp->next; + CC_FREE (bp->this, void); + bigchunkptrfree (bp); + } + for (bp = bigchunk_freelist; bp; bp = bpnext) { + bpnext = bp->next; + bigchunkptrfree (bp); + } + + /* Record the local bigchunks used by the bigchunkptrs */ + + localcount = 0; + for (bp = local_bigchunk_list; bp; bp = bp->next) + localcount++; + if (!localcount) + return 0; /* We haven't allocated anything */ + + tosslist = CC_SAFE_MALLOC(localcount, void *); + if (!tosslist) + return 1; + localcount = 0; + for (bp = local_bigchunk_list; bp; bp = bpnext) { + bpnext = bp->next; + tosslist[localcount++] = bp->this; + bigchunkptrfree (bp); + } + + /* Check that the bigchunkptrs were used correctly */ + + bpcount = 0; + for (bp = bigchunkptr_freelist; bp; bp = bp->next) { + bp->this = (void *) NULL; + bpcount++; + } + if (bpcount != bigchunkptrtotal) { + fprintf (stderr, "WARNING: %d outstanding bigchunkptrs\n", + bigchunkptrtotal - bpcount); + } + duplicates = 0; + for (bp = bigchunkptr_freelist; bp; bp = bp->next) { + if (bp->this == (void *) 1) + duplicates++; + else + bp->this = (void *) 1; + } + if (duplicates) { + fprintf (stderr, "WARNING: %d duplicate bigchunksptrs returned", + duplicates); + } + + /* And free the space used by the bigchunkptrs */ + + for (i = 0; i < localcount; i++) { + CC_FREE (tosslist[i], void); + } + CC_FREE (tosslist, void *); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static CCbigchunkptr *bigchunkptralloc (void) +#else +static CCbigchunkptr *bigchunkptralloc () +#endif +{ + CCbigchunkptr *bp; + + if (!bigchunkptr_freelist) { + int count = CC_BIGCHUNK / sizeof(CCbigchunkptr); + void *p; + + /* Grab a new bigchunk of memory */ + + p = (void *) CCutil_allocrus (CC_BIGCHUNK); + if (!p) + return (CCbigchunkptr *) NULL; + + /* Split it up into linked bigchunkptrs */ + + bigchunkptr_freelist = (CCbigchunkptr *) p; + for (bp = bigchunkptr_freelist + count -2; + bp >= bigchunkptr_freelist; bp--) { + bp->next = bp+1; + } + bigchunkptr_freelist[count - 1].next = (CCbigchunkptr *) NULL; + bigchunkptrtotal += count; + + /* And attach the bigchunk to the local bigchunklist */ + + bp = bigchunkptr_freelist; + bigchunkptr_freelist = bp->next; + bp->this = p; + bp->next = local_bigchunk_list; + local_bigchunk_list = bp; + } + bp = bigchunkptr_freelist; + bigchunkptr_freelist = bp->next; + return bp; +} + +#ifdef CC_PROTOTYPE_ANSI +static void bigchunkptrfree (CCbigchunkptr *bp) +#else +static void bigchunkptrfree (bp) +CCbigchunkptr *bp; +#endif +{ + bp->next = bigchunkptr_freelist; + bigchunkptr_freelist = bp; +} diff --git a/contrib/blossom/concorde97/UTIL/bgetopt.c b/contrib/blossom/concorde97/UTIL/bgetopt.c new file mode 100644 index 0000000000000000000000000000000000000000..7cc9db3425112d512c0ff6976981e4f768378fb5 --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/bgetopt.c @@ -0,0 +1,80 @@ +/***************************************************************************/ +/* */ +/* PORTABLE GETOPT */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: 1993 (?) (fmfeb02) */ +/* Modified: 15 February 1995 (bico) - added warning */ +/* */ +/* EXPORTED FUNCTIONS: Parses command-line strings */ +/* int CCutil_bix_getopt (int ac, char **av, char *def) */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +int CCutil_bix_optind = 1; +char *CCutil_bix_optarg = (char *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_bix_getopt (int ac, char **av, char *def) +#else +int CCutil_bix_getopt (ac, av, def) +int ac; +char **av; +char *def; +#endif +{ + int c; + char *sp = av[CCutil_bix_optind]; + char bwarn[2]; + + if (CCutil_bix_optind < 1 || CCutil_bix_optind >= ac) { + CCutil_bix_optind = ac; + return (EOF); + } + if ((int) *sp != (int) '-') + return (EOF); + if ((int) *(sp + 1) == (int) '-') { + CCutil_bix_optind++; + return (EOF); + } + (av[CCutil_bix_optind])++; + sp++; + while ((int) *sp != (int) *def && (int) *def != (int) '\0') + def++; + if ((int) *def == (int) '\0') { + CCutil_bix_optind = ac; + bwarn[0] = *sp; /* Bico: February 8, 1995 */ + bwarn[1] = '\0'; + printf ("Illegal option: -%s\n", bwarn); + return CC_BIX_GETOPT_UNKNOWN; + } + if ((int) *(def + 1) != (int) ':') { + c = *sp; + if ((int) *(sp + 1) != (int) '\0') + *sp = '-'; + else + CCutil_bix_optind++; + return (c); + } else { + if ((int) *(sp + 1) != (int) '\0') { + CCutil_bix_optarg = sp + 1; + c = *sp; + CCutil_bix_optind++; + return (c); + } else if (CCutil_bix_optind >= ac - 1) { + CCutil_bix_optind = ac; + return (EOF); + } else { + CCutil_bix_optarg = av[CCutil_bix_optind + 1]; + c = *sp; + CCutil_bix_optind += 2; + return (c); + } + } +} diff --git a/contrib/blossom/concorde97/UTIL/dheaps_i.c b/contrib/blossom/concorde97/UTIL/dheaps_i.c new file mode 100644 index 0000000000000000000000000000000000000000..26dde4c023b1f3bd0c871ca1beb31370f4d0ed4a --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/dheaps_i.c @@ -0,0 +1,299 @@ +/***************************************************************************/ +/* */ +/* DHEAP ROUTINES */ +/* */ +/* */ +/* TSP CODE */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 9, 1995 */ +/* Reference: R.E. Tarjan, Data Structures and Network Algorithms */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCutil_dheap_init (CCdheap *h, int k) */ +/* -h should point to a CCdheap struct. */ +/* -k the max number of elements in the dheap. */ +/* void CCutil_dheap_free (CCdheap *h) */ +/* -frees the spaces allocated by CCdheap_init */ +/* int CCutil_dheap_resize (CCdheap *h, int newsize) */ +/* -REALLOCs h so it can contain newsize elements. */ +/* -returns -1 if it can't resize the heap. */ +/* int CCutil_dheap_findmin (CCdheap *h) */ +/* -returns the index of the element with min value h->key[i] */ +/* -returns -1 if no elements in heap. */ +/* void CCutil_dheap_insert (CCdheap *h, int i) */ +/* -inserts the element with index i (so its key should be loaded */ +/* beforehand in h->key[i]). */ +/* void CCutil_dheap_delete (CCdheap *h, int i) */ +/* -deletes the element with index i. */ +/* int CCutil_dheap_deletemin (CCdheap *h) */ +/* -returns the min element in the heap, and deletes the min element */ +/* -returns -1 if no elements in heap. */ +/* void CCutil_dheap_changekey (CCdheap *h, int i, double newkey) */ +/* -changes the key of the element with index i to newkey. */ +/* */ +/* NOTES: */ +/* A k-element heap will malloc 16k bytes of memory. If memory is */ +/* tight, using integer keys (instead of doubles), brings it down to */ +/* 12k bytes, and if arbitrary deletions are not required, with a little */ +/* rewriting, the h->loc field can be eliminated, bring the space down */ +/* to 8k bytes. */ +/* These routines work with indices into the h->key array, so in */ +/* some cases, you will need to maintain a separate names array to know */ +/* what element belongs to index i. For an example, see the k_nearest */ +/* code in kdnear.c. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#define HEAP_D 3 +#define HEAP_UP(x) (((x)-1)/HEAP_D) +#define HEAP_DOWN(x) (((x)*HEAP_D)+1) + +#ifdef CC_PROTOTYPE_ANSI + +static void + dheap_siftup (CCdheap *h, int i, int x), + dheap_siftdown (CCdheap *h, int i, int x); + +static int + dheap_minchild (int x, CCdheap *h); + +#else + +static void + dheap_siftup (), + dheap_siftdown (); + +static int + dheap_minchild (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_dheap_init (CCdheap *h, int k) +#else +int CCutil_dheap_init (h, k) +CCdheap *h; +int k; +#endif +{ + h->loc = (int *) NULL; + h->key = (double *) NULL; + h->entry = CC_SAFE_MALLOC (k, int); + if (!h->entry) + return 1; + h->loc = CC_SAFE_MALLOC (k, int); + if (!h->loc) { + CC_FREE (h->entry, int); + return 1; + } + h->key = CC_SAFE_MALLOC (k, double); + if (!h->key) { + CC_FREE (h->entry, int); + CC_FREE (h->loc, int); + return 1; + } + h->total_space = k; + h->size = 0; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_dheap_free (CCdheap *h) +#else +void CCutil_dheap_free (h) +CCdheap *h; +#endif +{ + CC_IFFREE (h->entry, int); + CC_IFFREE (h->loc, int); + CC_IFFREE (h->key, double); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_dheap_resize (CCdheap *h, int newsize) +#else +int CCutil_dheap_resize (h, newsize) +CCdheap *h; +int newsize; +#endif +{ + if (newsize < h->size || newsize < h->total_space) return 0; + if (CCutil_reallocrus_count ((void **) &(h->key), newsize, + sizeof (double))) { + return -1; + } + if (CCutil_reallocrus_count ((void **) &(h->entry), newsize, + sizeof (int))) { + return -1; + } + if (CCutil_reallocrus_count ((void **) &(h->loc), newsize, + sizeof (int))) { + return -1; + } + h->total_space = newsize; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_dheap_findmin (CCdheap *h) +#else +int CCutil_dheap_findmin (h) +CCdheap *h; +#endif +{ + if (h->size == 0) + return -1; + else + return h->entry[0]; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_dheap_insert (CCdheap *h, int i) +#else +void CCutil_dheap_insert (h, i) +CCdheap *h; +int i; +#endif +{ + assert (h->size < h->total_space); + h->size++; + dheap_siftup (h, i, h->size - 1); +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_dheap_delete (CCdheap *h, int i) +#else +void CCutil_dheap_delete (h, i) +CCdheap *h; +int i; +#endif +{ + int j; + + h->size--; + j = h->entry[h->size]; + h->entry[h->size] = -1; + + if (j != i) { + if (h->key[j] <= h->key[i]) { + dheap_siftup (h, j, h->loc[i]); + } else { + dheap_siftdown (h, j, h->loc[i]); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_dheap_deletemin (CCdheap *h) +#else +int CCutil_dheap_deletemin (h) +CCdheap *h; +#endif +{ + int i; + + if (h->size == 0) + return -1; + else { + i = h->entry[0]; + CCutil_dheap_delete (h, i); + return i; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_dheap_changekey (CCdheap *h, int i, double newkey) +#else +void CCutil_dheap_changekey (h, i, newkey) +CCdheap *h; +int i; +double newkey; +#endif +{ + if (h->key[i] < newkey) { + h->key[i] = newkey; + dheap_siftup (h, i, h->loc[i]); + } else if (h->key[i] > newkey) { + h->key[i] = newkey; + dheap_siftdown (h, i, h->loc[i]); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void dheap_siftup (CCdheap *h, int i, int x) +#else +static void dheap_siftup (h, i, x) +CCdheap *h; +int i; +int x; +#endif +{ + int p; + + p = HEAP_UP (x); + while (x && h->key[h->entry[p]] > h->key[i]) { + h->entry[x] = h->entry[p]; + h->loc[h->entry[p]] = x; + x = p; + p = HEAP_UP (p); + } + h->entry[x] = i; + h->loc[i] = x; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dheap_siftdown (CCdheap *h, int i, int x) +#else +static void dheap_siftdown (h, i, x) +CCdheap *h; +int i; +int x; +#endif +{ + int c; + + c = dheap_minchild (x, h); + + while (c >= 0 && h->key[h->entry[c]] < h->key[i]) { + h->entry[x] = h->entry[c]; + h->loc[h->entry[c]] = x; + x = c; + c = dheap_minchild (c, h); + } + h->entry[x] = i; + h->loc[i] = x; +} + +#ifdef CC_PROTOTYPE_ANSI +static int dheap_minchild (int x, CCdheap *h) +#else +static int dheap_minchild (x, h) +int x; +CCdheap *h; +#endif +{ + int c = HEAP_DOWN (x); + int cend; + double minval; + int minloc; + + if (c >= h->size) + return -1; + minval = h->key[h->entry[c]]; + minloc = c; + cend = c + HEAP_D; + if (h->size < cend) + cend = h->size; + for (c++; c < cend; c++) { + if (h->key[h->entry[c]] < minval) { + minval = h->key[h->entry[c]]; + minloc = c; + } + } + return minloc; +} diff --git a/contrib/blossom/concorde97/UTIL/edg2cyc.c b/contrib/blossom/concorde97/UTIL/edg2cyc.c new file mode 100644 index 0000000000000000000000000000000000000000..5a122a16b65604f7de7c01fc62ba97e29256859e --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/edg2cyc.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* CONVERT AN EDGE LIST TO A CYCLE ARRAY */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 8, 1995 */ +/* */ +/* EXPORTED FUNCTION: */ +/* int CCutil_edge_to_cycle (int ncount, int *elist, int *cyc) */ +/* elist - edgelist in end1 end2 format */ +/* cyc - returns the cycle in node node node format */ +/* (the calling routine should allocate cyc) */ +/* Returns a nonzero value if there was and error. */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_edge_to_cycle (int ncount, int *elist, int *cyc) +#else +int CCutil_edge_to_cycle (ncount, elist, cyc) +int ncount; +int *elist, *cyc; +#endif +{ + int *Lside, *Rside; + int i, k, end1, end2, prev, this, next, start, okfirst, first = 0; + + Lside = CC_SAFE_MALLOC (ncount, int); + if (!Lside) + return 1; + Rside = CC_SAFE_MALLOC (ncount, int); + if (!Rside) { + CC_FREE (Lside, int); + return 1; + } + for (i = 0; i < ncount; i++) { + Lside[i] = Rside[i] = -1; + } + + for (i = 0, k = 0; i < ncount; i++) { + end1 = elist[k++]; + end2 = elist[k++]; + if (Lside[end1] == -1) + Lside[end1] = end2; + else + Rside[end1] = end2; + if (Lside[end2] == -1) + Lside[end2] = end1; + else + Rside[end2] = end1; + } + + for (i = 0, k = 0; i < ncount; i++) { + end1 = elist[k++]; + end2 = elist[k++]; + if (Lside[end1] == -1 || Rside[end1] == -1 || + Lside[end2] == -1 || Rside[end2] == -1) { + fprintf (stderr, "Error in circuit\n"); + CC_FREE (Lside, int); + CC_FREE (Rside, int); + return 1; + } + } + start = elist[0]; + prev = -2; + this = start; + k = 0; + okfirst = 0; + do { + if (this == first) + okfirst = 1; + if (Lside[this] != prev) + next = Lside[this]; + else + next = Rside[this]; + prev = this; + this = next; + k++; + } while (next != start && k < ncount); + + if (k != ncount || !okfirst) { + fprintf (stderr, "Error in circuit\n"); + CC_FREE (Lside, int); + CC_FREE (Rside, int); + return 1; + } + + start = first; + prev = -2; + this = start; + k = 0; + do { + cyc[k++] = this; + if (Lside[this] != prev) + next = Lside[this]; + else + next = Rside[this]; + prev = this; + this = next; + } while (next != start && k < ncount); + + CC_FREE (Lside, int); + CC_FREE (Rside, int); + return 0; +} diff --git a/contrib/blossom/concorde97/UTIL/edgelen.c b/contrib/blossom/concorde97/UTIL/edgelen.c new file mode 100644 index 0000000000000000000000000000000000000000..6692f7f8cf8917d82b8031cb437e310d16031b8d --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/edgelen.c @@ -0,0 +1,439 @@ +/***************************************************************************/ +/* */ +/* FUNCTIONS FOR COMPUTING EDGE LENGTHS FOR GEOMETRIC PROBLEMS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: Summer 1994 */ +/* Modified - March 2, 1995 */ +/* - October 5, 1995 (Bico) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int */ +/* CCutil_init_dat_edgelen (CCdatagroup *dat) */ +/* int */ +/* (*CCutil_dat_edgelen) (int i, int j, CCdatagroup *dat) */ +/* void */ +/* CCutil_dsjrand_init (int maxdist, int seed) */ +/* void */ +/* CCutil_freedata (int ncount, CCdatagroup *dat) */ +/* */ +/* NOTES: */ +/* Supported norms (with defs in edgelen.h) are: */ +/* MAXNORM - the L-infinity norm */ +/* EUCLIDEAN_CEIL - the norm for the plaXXXX problems */ +/* EUCLIDEAN - rounded L-2 norm */ +/* EUCLIDEAN_3d - rounded L-2 norm in 3 space */ +/* IBM - a norm for drilling problems in Bonn */ +/* GEOGRAPHIC - distances on a sphere (Groetshel and Holland) */ +/* ATT - pseudo-Euclidean norm for att532 */ +/* MATRIXNORM - complete graph (lower + diagonal matrix) */ +/* DSJRAND - random edgelengths */ +/* CRYSTAL - Bland-Shallcross xray norm */ +/* - The coordinates generated for CRYSTAL problems */ +/* (in getdata.c) have been diveded by the motor speeds */ +/* (this makes the edgelen function faster) and scaled by */ +/* CRYSTAL_SCALE (currently 10000) and rounded to the */ +/* nearest integer (this lets the edgelen function produce */ +/* integer lengths without further rounding). The result is */ +/* a closer approximation to the Bland - Shallcrosss */ +/* floating point length function than that given in */ +/* TSPLIB_1.2. */ +/* */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#ifdef CC_PROTOTYPE_ANSI + +static double + dtrunc (double); + +#else + +static double + dtrunc (); + +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846264 +#endif + +#ifdef CC_PROTOTYPE_ANSI +int (*CCutil_dat_edgelen) (int, int, CCdatagroup *); +#else +int (*CCutil_dat_edgelen) (); +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_init_dat_edgelen (CCdatagroup *dat) +#else +int CCutil_init_dat_edgelen (dat) +CCdatagroup *dat; +#endif +{ + switch (dat->norm) { + case CC_EUCLIDEAN_CEIL: + CCutil_dat_edgelen = CCutil_euclid_ceiling_edgelen; + break; + case CC_EUCLIDEAN: + CCutil_dat_edgelen = CCutil_euclid_edgelen; + break; + case CC_MAXNORM: + CCutil_dat_edgelen = CCutil_max_edgelen; + break; + case CC_EUCLIDEAN_3D: + CCutil_dat_edgelen = CCutil_euclid3d_edgelen; + break; + case CC_IBM: + CCutil_dat_edgelen = CCutil_ibm_edgelen; + break; + case CC_GEOGRAPHIC: + CCutil_dat_edgelen = CCutil_geographic_edgelen; + break; + case CC_ATT: + CCutil_dat_edgelen = CCutil_att_edgelen; + break; + case CC_MATRIXNORM: + CCutil_dat_edgelen = CCutil_matrix_edgelen; + break; + case CC_DSJRANDNORM: + CCutil_dat_edgelen = CCutil_dsjrand_edgelen; + break; + case CC_CRYSTAL: + CCutil_dat_edgelen = CCutil_crystal_edgelen; + break; + default: + fprintf (stderr, "ERROR: Unknown NORM %d.\n", dat->norm); + return 1; + } + return 0; +} + +/* Several variables that would normally be called y1 and y2 are called + yy1 and yyy2 to avoid conflict with the bessel functions */ + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_max_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_max_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + double t1 = dat->x[i] - dat->x[j], t2 = dat->y[i] - dat->y[j]; + + if (t1 < 0) + t1 *= -1; + if (t2 < 0) + t2 *= -1; + + return (int) (t1 < t2 ? t2 : t1); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_euclid_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_euclid_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + double t1 = dat->x[i] - dat->x[j], t2 = dat->y[i] - dat->y[j]; + int temp; + + temp = (int) (sqrt (t1 * t1 + t2 * t2) + 0.5); + return temp; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_euclid3d_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_euclid3d_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + double t1 = dat->x[i] - dat->x[j], t2 = dat->y[i] - dat->y[j]; + double t3 = dat->z[i] - dat->z[j]; + int temp; + + temp = (int) (sqrt (t1 * t1 + t2 * t2 + t3 * t3) + 0.5); + return temp; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_ibm_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_ibm_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + double dw = dat->x[i] - dat->x[j], dw1 = dat->y[i] - dat->y[j]; + static double ibm_xmult[7] = {1062.5, + 300.0, + 300.0, + 250.0, + 300.0, + 1000.0, + 154.6}; + static double ibm_xadd[7] = {155.0 - 0.01 * 1062.5, + 197.5 - 0.05 * 300.0, + 212.5 - 0.10 * 300.0, + 227.5 - 0.15 * 250.0, + 240.5 - 0.20 * 300.0, + 255.0 - 0.25 * 1000.0, + 305.0 - 0.30 * 154.6}; + static double ibm_ymult[7] = {1062.5, + 450.0, + 350.0, + 250.0, + 300.0, + 900.0, + 157.7}; + static double ibm_yadd[7] = {150.0 - 0.01 * 1062.5, + 192.5 - 0.05 * 450.0, + 215.0 - 0.10 * 350.0, + 232.5 - 0.15 * 250.0, + 245.5 - 0.20 * 300.0, + 250.0 - 0.25 * 900.0, + 295.0 - 0.30 * 157.7}; + + if (dw < 0.0) + dw = -dw; + dw /= 25400.0; + if (dw <= 0.01) { + dw *= 15500.0; + } else if (dw >= 0.30) { + dw = dw * 154.6 + (305.0 - 0.3 * 154.6); + } else { + dw = dw * ibm_xmult[(int) (dw / 0.05)] + + ibm_xadd[(int) (dw / 0.05)]; + } + if (dw1 < 0.0) + dw1 = -dw1; + dw1 /= 25400.0; + if (dw1 <= 0.01) { + dw1 *= 15000.0; + } else if (dw1 >= 0.30) { + dw1 = dw1 * 157.7 + (295.0 - 0.3 * 157.7); + } else { + dw1 = dw1 * ibm_ymult[(int) (dw1 / 0.05)] + + ibm_yadd[(int) (dw1 / 0.05)]; + } + if (dw < dw1) + dw = dw1; + return (int) dw; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_euclid_ceiling_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_euclid_ceiling_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + double t1 = dat->x[i] - dat->x[j], t2 = dat->y[i] - dat->y[j]; +/* + int rd; + double max; + + max = sqrt (t1 * t1 + t2 * t2); + rd = (int) max; + return (((max - rd) > .000000001) ? rd + 1 : rd); +*/ + return (int) (ceil (sqrt (t1 * t1 + t2 * t2))); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_geographic_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_geographic_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + double deg, min; + double lati, latj, longi, longj; + double q1, q2, q3; + int dd; + double x1 = dat->x[i], x2 = dat->x[j], yy1 = dat->y[i], yy2 = dat->y[j]; + + deg = dtrunc (x1); + min = x1 - deg; + lati = M_PI * (deg + 5.0 * min / 3.0) / 180.0; + deg = dtrunc (x2); + min = x2 - deg; + latj = M_PI * (deg + 5.0 * min / 3.0) / 180.0; + + deg = dtrunc (yy1); + min = yy1 - deg; + longi = M_PI * (deg + 5.0 * min / 3.0) / 180.0; + deg = dtrunc (yy2); + min = yy2 - deg; + longj = M_PI * (deg + 5.0 * min / 3.0) / 180.0; + + q1 = cos (longi - longj); + q2 = cos (lati - latj); + q3 = cos (lati + latj); + dd = (int) (6378.388 * acos (0.5 * ((1.0 + q1) * q2 - (1.0 - q1) * q3)) + + 1.0); + return dd; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_att_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_att_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + double xd = dat->x[i] - dat->x[j]; + double yd = dat->y[i] - dat->y[j]; + double rij = sqrt ((xd * xd + yd * yd) / 10.0); + double tij = dtrunc (rij); + int dij; + + if (tij < rij) + dij = (int) tij + 1; + else + dij = (int) tij; + return dij; +} + +#ifdef CC_PROTOTYPE_ANSI +static double dtrunc (double x) +#else +static double dtrunc (x) +double x; +#endif +{ + int k; + + k = (int) x; + x = (double) k; + return x; +} + +static int dsjrand_param = 1; +static double dsjrand_factor = 1.0; + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_dsjrand_init (int maxdist, int seed) +#else +void CCutil_dsjrand_init (maxdist, seed) +int maxdist, seed; +#endif +{ + dsjrand_factor = maxdist/2147483648.0; + dsjrand_param = 104*seed+1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_dsjrand_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_dsjrand_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + int di = (int) dat->x[i]; + int dj = (int) dat->x[j]; + int x, y, z; + + x = di&dj; + y = di|dj; + z = dsjrand_param; + + x *= z; + y *= x; + z *= y; + + z ^= dsjrand_param; + + x *= z; + y *= x; + z *= y; + + x = ((di+dj)^z)&0x7fffffff; + return (int)(x*dsjrand_factor); +} + +#define CRYSTAL_SCALE 10000 + +#define CRYSTAL_FLIP_TOL ((180 * CRYSTAL_SCALE * 4) / 5) +#define CRYSTAL_NEEDS_FLIP(x) ((x) > (CRYSTAL_FLIP_TOL)) +#define CRYSTAL_FLIP(x) ((2 * (CRYSTAL_FLIP_TOL)) - (x)) + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_crystal_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_crystal_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + double w, w1; + + w = dat->x[i] - dat->x[j]; + if (w < 0) + w = -w; + w1 = dat->y[i] - dat->y[j]; + if (w1 < 0) + w1 = -w1; + if (CRYSTAL_NEEDS_FLIP (w1)) + w1 = CRYSTAL_FLIP (w1); + if (w < w1) + w = w1; + w1 = dat->z[i] - dat->z[j]; + if (w1 < 0) + w1 = -w1; + if (w < w1) + w = w1; + + return (int) w; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_matrix_edgelen (int i, int j, CCdatagroup *dat) +#else +int CCutil_matrix_edgelen (i, j, dat) +int i, j; +CCdatagroup *dat; +#endif +{ + if (i > j) + return (dat->adj[i])[j]; + else + return (dat->adj[j])[i]; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_freedatagroup (int ncount, CCdatagroup *dat) +#else +void CCutil_freedatagroup (ncount, dat) +int ncount; +CCdatagroup *dat; +#endif +{ + int i; + + CC_IFFREE (dat->x, double); + CC_IFFREE (dat->y, double); + CC_IFFREE (dat->z, double); + if (dat->adj) { + for (i = 0; i < ncount; i++) { + CC_IFFREE (dat->adj[i], int); + } + CC_FREE (dat->adj, int *); + } +} diff --git a/contrib/blossom/concorde97/UTIL/fastread.c b/contrib/blossom/concorde97/UTIL/fastread.c new file mode 100644 index 0000000000000000000000000000000000000000..e3624b155489c6edc595ba51370aef13a7a1cee0 --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/fastread.c @@ -0,0 +1,49 @@ +/***************************************************************************/ +/* */ +/* CODE TO READ ASCI INTS FAST */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Dave */ +/* Date: Septmember 1994 (Bonn) (cofeb16) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCutil_readint (FILE *f) */ +/* - Returns the next int in the file f. */ +/* */ +/* NOTES: */ +/* This is much faster that scanf. Its useful for big files and */ +/* and for profiling. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_readint (FILE *f) +#else +int CCutil_readint (f) +FILE *f; +#endif +{ + int v = 0; + int c; + + while (( c = getc(f)) != EOF && !((c >= '0' && c <= '9') || c == '-')); + if (c == '-') { + v = 0; + while ((c = getc(f)) != EOF && c >= '0' && c <= '9') { + v = v * 10 + c - '0'; + } + return -v; + } else { + v = c - '0'; + while ((c = getc(f)) != EOF && c >= '0' && c <= '9') { + v = v * 10 + c - '0'; + } + return v; + } +} diff --git a/contrib/blossom/concorde97/UTIL/genhash.c b/contrib/blossom/concorde97/UTIL/genhash.c new file mode 100644 index 0000000000000000000000000000000000000000..bb0953c7b812f7a5ded1a79cf858b56570307187 --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/genhash.c @@ -0,0 +1,433 @@ +/***************************************************************************/ +/* */ +/* GENERIC HASH TABLE ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: November 12, 1996 */ +/* */ +/* These routines use a hash table to implement a generic associative */ +/* array. */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCutil_genhash_init (CCgenhash *h, int size, */ +/* int (*hcmp) (void *key1, void *key2, void *u_data), */ +/* unsigned int (*hfunc) (void *key, void *u_data), */ +/* void *u_data, double maxdensity, double lowdensity) */ +/* -CCgenhash *h (a pointer to a CCgenhash structure to be */ +/* initialized) */ +/* -int size (the initial size of the hash table) */ +/* -int (*hcmp) (void *key1, void *key2, void *u_data) (a pointer to */ +/* a function which returns 0 if key1 == key2, nonzero otherwise. */ +/* u_data will be the u_data passed to CCgenhash_init) */ +/* -unsigned int (*hfunc) (void *key, void *u_data) (a pointer to a */ +/* function which computes a hash function of key. */ +/* u_data will be the u_data passed to CCgenhash_init) */ +/* -void *u_data (a pointer which will be passed into hcmp and hfunc) */ +/* -double maxdensity (the maximum density (# elems / size) for the */ +/* hash table. When this density is reached the hash table is */ +/* expanded. 0.0 means never expand the hash table) */ +/* -double lowdensity (the density of a hash table immediately after */ +/* expansion) */ +/* RETURNS 0 for success, -1 if out of memory. */ +/* */ +/* void CCutil_genhash_free (CCgenhash *h, void (*freefunc)(void *k, */ +/* void *d, void *u_data) */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -void (*freefunc)(void *key, void *data, void *u_data) (a pointer */ +/* to a function to be called for each (key, data) pair in the */ +/* hashtable, or NULL) */ +/* ACTION: deletes all entries in h, and frees the space for h. */ +/* */ +/* void CCutil_genhash_u_data (CCgenhash *h, void *u_data), */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -void *u_data (a new value for u_data) */ +/* ACTION: changes the u_data stored with the hash table, and */ +/* passed to hcomp and hfunc) */ +/* */ +/* int CCutil_genhash_insert (CCgenhash *h, void *key, void *data) */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -void *key (a pointer to the key data for this entry) */ +/* -void *data (the data to be stored) */ +/* ACTION: h[key] = data */ +/* COMMENT: if h[key] already has a value, this acts like a stack */ +/* CCutil_genhash_delete (key) will reveal the old value. */ +/* RETURNS 0 for success, -1 if out of memory. */ +/* */ +/* int CCutil_genhash_replace (CCgenhash *h, void *key, void *data) */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -void *key (a pointer to the key data for this entry) */ +/* -void *data (the data to be stored) */ +/* ACTION: h[key] = data */ +/* COMMENT: if h[key] already has a value, this replaces that */ +/* value. */ +/* RETURNS 0 for success, -1 if out of memory. */ +/* */ +/* int CCutil_genhash_delete (CCgenhash *h, void *key) */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -void *key (a pointer to the key data for this entry) */ +/* ACTION: h[key] = NULL */ +/* RETURNS 0 for success, -1 if h[key] was already NULL */ +/* */ +/* void *CCutil_genhash_lookup (CCgenhash *h, void *key) */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -void *key (a pointer to the key data for this entry) */ +/* RETURNS h[key], or NULL if h[key] not defined */ +/* */ +/* unsigned int CCutil_genhash_hash (CCgenhash *h, void *key) */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -void *key (a pointer to key data) */ +/* RETURNS the hash function of key (ie, h->hfunc(key)) */ +/* */ +/* int CCutil_genhash_insert_h (CCgenhash *h, unsigned int hashval, */ +/* void *key, void *data) */ +/* int CCutil_genhash_replace_h (CCgenhash *h, unsigned int hashval, */ +/* void *key, void *data) */ +/* int CCutil_genhash_delete_h (CCgenhash *h, unsigned int hashval, */ +/* void *key) */ +/* int CCutil_genhash_lookup_h (CCgenhash *h, unsigned int hashval, */ +/* void *key) */ +/* NOTE: These are alternate versions of the same functions without */ +/* the _h suffix, and take an additional argument, hashval, which */ +/* should be equal to CCutil_genhash_hash (key). They provide a */ +/* method to avoid recomputing CCgenhash_hash over multiple calls */ +/* with the same key. */ +/* */ +/* void CCutil_genhash_start (CCgenhash *h, CCgenhash_iter *iter) */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -CCgenhash_iter *iter (a pointer to the iterator to be */ +/* initialized) */ +/* ACTION: initializes iter for iterating over elements of h using */ +/* CCutil_genhash_next (). */ +/* */ +/* void *CCutil_genhash_next (CCgenhash *h, CCgenhash_iter *iter, */ +/* void **key, int *keysize) */ +/* -CCgenhash *h (a pointer to the hash table) */ +/* -CCgenhash_iter *iter (a pointer to an iterator) */ +/* -void **key (a pointer to a location for the key value) */ +/* -int *keysize (a pointer to a location for the key size) */ +/* RETURNS: a next data value from the hash table (corresponding */ +/* to the returned key and keysize), or NULL if there */ +/* are no more elements. */ +/* NOTE: CCgenhash_next can tolerate the deletion of the current */ +/* (last returned) element and arbitrary lookups and replaces */ +/* between calls to CCgenhash_next. However, deletion of */ +/* elements other than the current one are not permitted, and */ +/* insertion a table which could be expanded can result in */ +/* elements being skipped. */ +/* */ +/* NOTES: */ +/* Functions prototyped in genhash.h. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +typedef struct CCgenhash_elem { + void *key; + void *data; + struct CCgenhash_elem *next; +} CCgenhash_elem; + +CC_PTR_ALLOC_ROUTINE (CCgenhash_elem, CCgenhash_elemalloc, + CCgenhash_elemchunklist, CCgenhash_elemfreelist) +CC_PTR_FREE_ROUTINE (CCgenhash_elem, CCgenhash_elemfree, + CCgenhash_elemfreelist) +CC_PTR_FREE_WORLD_ROUTINE (CCgenhash_elem, CCgenhash_elemfree_world, + CCgenhash_elemchunklist, CCgenhash_elemfreelist) +CC_PTR_LEAKS_ROUTINE (CCgenhash_elem, CCgenhash_elem_check_leaks, + CCgenhash_elemchunklist, CCgenhash_elemfreelist, + data, void *) +CC_PTR_STATUS_ROUTINE (CCgenhash_elem, CCgenhash_elem_status, + CCgenhash_elemchunklist, CCgenhash_elemfreelist) + +#ifdef CC_PROTOTYPE_ANSI + +static int + genhash_resize (CCgenhash *h); + +#else + +static int + genhash_resize (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_genhash_init (CCgenhash *h, int size, + int (*hcmp) (void *key1, void *key2, void *u_data), + unsigned int (*hfunc) (void *key, void *u_data), + void *u_data, double maxdensity, double lowdensity) +#else +int CCutil_genhash_init (h, size, hcmp, hfunc, u_data, maxdensity, lowdensity) +CCgenhash *h; +int size; +int (*hcmp)(); +unsigned int (*hfunc)(); +void *u_data; +double maxdensity; +double lowdensity; +#endif +{ + int i; + + h->nelem = 0; + h->size = CCutil_nextprime ((unsigned int) size); + h->hcmp = hcmp; + h->hfunc = hfunc; + h->u_data = u_data; + h->maxdensity = maxdensity; + h->lowdensity = lowdensity; + + if (maxdensity <= 0.0) { + h->maxelem = 0; + } else { + h->maxelem = (int) (h->maxdensity * h->size); + } + + h->table = CC_SAFE_MALLOC (h->size, CCgenhash_elem *); + if (!h->table) { + return -1; + } + for (i=0; i<h->size; i++) { + h->table[i] = (CCgenhash_elem *) NULL; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_genhash_insert (CCgenhash *h, void *key, void *data) +#else +int CCutil_genhash_insert (h, key, data) +CCgenhash *h; +void *key; +void *data; +#endif +{ + return CCutil_genhash_insert_h (h, h->hfunc(key, h->u_data), key, data); +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_genhash_u_data (CCgenhash *h, void *u_data) +#else +void CCutil_genhash_u_data (h, u_data) +CCgenhash *h; +void *u_data; +#endif +{ + h->u_data = u_data; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_genhash_insert_h (CCgenhash *h, unsigned int hashval, void *key, + void *data) +#else +int CCutil_genhash_insert_h (h, hashval, key, data) +CCgenhash *h; +unsigned int hashval; +void *key; +void *data; +#endif +{ + int loc; + CCgenhash_elem *e; + + if (h->maxelem && h->nelem >= h->maxelem) { + if (genhash_resize (h)) { + return -1; + } + } + + loc = hashval % h->size; + e = CCgenhash_elemalloc(); + if (!e) return -1; + + e->key = key; + e->data = data; + e->next = h->table[loc]; + h->table[loc] = e; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_genhash_replace (CCgenhash *h, void *key, void *data) +#else +int CCutil_genhash_replace (h, key, data) +CCgenhash *h; +void *key; +void *data; +#endif +{ + return CCutil_genhash_replace_h (h, h->hfunc (key, h->u_data), key, data); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_genhash_replace_h (CCgenhash *h, unsigned int hashval, void *key, + void *data) +#else +int CCutil_genhash_replace_h (h, hashval, key, data) +CCgenhash *h; +unsigned int hashval; +void *key; +void *data; +#endif +{ + CCgenhash_elem *e; + + for (e = h->table[hashval % h->size]; e; e = e->next) { + if (h->hcmp(e->key, key, h->u_data) == 0) { + e->data = data; + return 0; + } + } + return CCutil_genhash_insert_h (h, hashval, key, data); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_genhash_delete (CCgenhash *h, void *key) +#else +int CCutil_genhash_delete (h, key) +CCgenhash *h; +void *key; +#endif +{ + return CCutil_genhash_delete_h (h, h->hfunc(key, h->u_data), key); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_genhash_delete_h (CCgenhash *h, unsigned int hashval, void *key) +#else +int CCutil_genhash_delete_h (h, hashval, key) +CCgenhash *h; +unsigned int hashval; +void *key; +#endif +{ + int loc = hashval % h->size; + CCgenhash_elem *e, **eprev; + + for (e = h->table[loc], eprev = &h->table[loc]; e; + eprev = &e->next, e = e->next) { + if (h->hcmp(e->key, key, h->u_data) == 0) { + *eprev = e->next; + CCgenhash_elemfree (e); + return 0; + } + } + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +unsigned int CCutil_genhash_hash (CCgenhash *h, void *key) +#else +unsigned int CCutil_genhash_hash (h, key) +CCgenhash *h; +void *key; +#endif +{ + return h->hfunc (key, h->u_data); +} + +#ifdef CC_PROTOTYPE_ANSI +void *CCutil_genhash_lookup (CCgenhash *h, void *key) +#else +void *CCutil_genhash_lookup (h, key) +CCgenhash *h; +void *key; +#endif +{ + return CCutil_genhash_lookup_h (h, h->hfunc(key, h->u_data), key); +} + +#ifdef CC_PROTOTYPE_ANSI +void *CCutil_genhash_lookup_h (CCgenhash *h, unsigned int hashval, void *key) +#else +void *CCutil_genhash_lookup_h (h, hashval, key) +CCgenhash *h; +unsigned int hashval; +void *key; +#endif +{ + CCgenhash_elem *e; + + for (e = h->table[hashval % h->size]; e; e = e->next) { + if (h->hcmp(e->key, key, h->u_data) == 0) { + return e->data; + } + } + return (void *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_genhash_free (CCgenhash *h, void (*freefunc)(void *key, void *data, + void *u_data)) +#else +void CCutil_genhash_free (h, freefunc) +CCgenhash *h; +void (*freefunc)(); +#endif +{ + int i; + CCgenhash_elem *e, *enext; + int total, onlist; + + for (i=0; i<h->size; i++) { + for (e = h->table[i]; e; e = enext) { + enext = e->next; + if (freefunc) { + (*freefunc)(e->key, e->data, h->u_data); + } + CCgenhash_elemfree (e); + } + } + if (!CCgenhash_elem_status (&total, &onlist)) { + CCgenhash_elemfree_world(); + } + CC_FREE (h->table, CCgenhash_elem *); +} + +#ifdef CC_PROTOTYPE_ANSI +static int genhash_resize (CCgenhash *h) +#else +static int genhash_resize (h) +CCgenhash *h; +#endif +{ + int newsize = CCutil_nextprime ((unsigned int) (h->nelem / h->lowdensity)); + CCgenhash_elem **newtable; + CCgenhash_elem *e, *enext; + int loc; + int i; + + if (newsize <= h->nelem) + newsize = CCutil_nextprime ((unsigned int) h->nelem + 1); + + newtable = CC_SAFE_MALLOC (newsize, CCgenhash_elem *); + if (!newtable) { + return -1; + } + + for (i=0; i<newsize; i++) { + newtable[i] = (CCgenhash_elem *) NULL; + } + + for (i=0; i<h->size; i++) { + for (e = h->table[i]; e; e = enext) { + enext = e; + loc = h->hfunc(e->key, h->u_data) % newsize; + e->next = newtable[loc]; + newtable[loc] = e; + } + } + + CC_FREE (h->table, CCgenhash_elem *); + + h->table = newtable; + h->size = newsize; + h->maxelem = (int) (h->maxdensity * h->size); + + return 0; +} diff --git a/contrib/blossom/concorde97/UTIL/getdata.c b/contrib/blossom/concorde97/UTIL/getdata.c new file mode 100644 index 0000000000000000000000000000000000000000..cb98d098d926c2b0e5e2ae04b17ae2a464d360be --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/getdata.c @@ -0,0 +1,1983 @@ +/***************************************************************************/ +/* */ +/* SOME DATA READING ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 2, 1995 */ +/* Changes: 17.7.96 (Bico) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCutil_getdata (char *datname, char *weightname, int binary_in, */ +/* int innorm, inusenodeweights, int *ncount, CCdatagroup *dat, */ +/* double **wcoord) */ +/* RETURNS the data to generate edge lengths in the dat structure. */ +/* The calling routine should be sure that dat points to */ +/* a structure. If datname is NULL then random entries will be */ +/* generated. */ +/* -datname is the name of the datfile or the matrix file, if NULL */ +/* then random data will be generated, according to the norm type. */ +/* For D2 and D3 norms, the coordinates will be uniform between 0 and */ +/* ncount -1 (GEOGRAPHIC norms have x between -90 and 90 and y */ +/* between -180 and 180). (For D2, the points will be distinct.) */ +/* For MATRIX norms, the entries will be */ +/* uniform between 0 and MATRAND_SCALE * ncount - 1 (currently */ +/* 10*ncount - 1. For CRYSTAL norms, a random matrix and bounds in */ +/* range of the TSPLIB problems is generated - the wavelength is */ +/* chosen to be 1.0, 1.35, or 1.70 depending on the ncount (but the */ +/* problem will not be very close to hitting ncount.). */ +/* -binary_in should be 1 if the datname file is in binary integers. */ +/* -innorm is the norm. */ +/* -ncount will return the number of nodes. If datname is NULL, then */ +/* ncount should be passed in with the number of nodes to be used in */ +/* the random problem generation. */ +/* -dat will contain the info to call the edgelen function. */ +/* */ +/* */ +/* int CCutil_writemaster (char *mastername, int ncount, */ +/* CCdatagroup *dat, int *perm) */ +/* WRITES the dat information and the permutation into a binary file. */ +/* This is used in the TSP, where the dat file has usually */ +/* been permuted to but the nodes into tour order. */ +/* -mastername is the name of the file (cannot be NULL) */ +/* -ncount is the number of nodes */ +/* -dat contains the edgelen info (e.g. x,y coordinates), it can be */ +/* NULL */ +/* -perm contains a permutation of 0 to ncount - 1 (so a tour in */ +/* node node node format) */ +/* */ +/* int CCutil_getmaster (char *mastername, int *ncount, CCdatagroup *dat,*/ +/* int *perm) */ +/* RETURNS the dat information and the permutation from a binary file */ +/* (written by a call to writemaster). Used by the TSP code. */ +/* -mastername is the name of the file (cannot be NULL) */ +/* -ncount returns the number of nodes */ +/* -dat returns the edgelen info (e.g. x,y coordinates), or NULL */ +/* -perm returns a permutation of 0 to ncount - 1 (so a tour in */ +/* node node node format) */ +/* */ +/* int CCutil_getnodeweights (char *weightname, int ncount, */ +/* int weight_limit, double **wcoord) */ +/* RETURNS a list of nonnegative nodesweights (they will be translated */ +/* if the weightname file has negative entries). If weightname */ +/* is NULL then random entries (from 0 to ncount - 1 will be */ +/* generated. */ +/* -weightname is the name of a file containing nodeweights. It will */ +/* only be read if inusenodeweights is 1. If NULL, random entries */ +/* will be generated (between 0 and weight_limit - 1) */ +/* -wcoord will contain the nonnegative node weights (it will be */ +/* here in getnodeweights) */ +/* */ +/* int CCutil_gettsplib (char *datname, int *ncount, CCdatagroup *dat) */ +/* READS an xxx.tsp TSPLIB file, and returns the dat structure to */ +/* generate edge lengths. */ +/* -datname should be the name of a TSPLIB xxx.tsp file. */ +/* -ncount returns the number of nodes. */ +/* -dat returns the data. */ +/* */ +/* int CCutil_getedgelist (int ncount, char *fname, int *ecount, */ +/* int **elist, int **elen) */ +/* READS an edgelist in end1 end2 length format. */ +/* -fname name of the file */ +/* -ecount returns the number of edges */ +/* -elist returns the edges in end1 end2 format (it will be allocated */ +/* by getedgelist) */ +/* -elen returns the length of the edges in len len len format */ +/* */ +/* int CCutil_getedgelist_n (int *ncount, char *fname, int *ecount, */ +/* int **elist, int **elen) */ +/* READS an edgelist in end1 end2 length format. */ +/* Like CCutil_getedgelist (), but it also returns ncount. */ +/* */ +/* int CCutil_getcycle_edgelist (int ncount, char *cyclename, */ +/* int *outcycle) */ +/* READS a cycle in end1 end2 length format, and returns the cycle in */ +/* node node format in the array outcycle. */ +/* -outcycle should be allocated by the calling routine (and should be */ +/* be at least ncount long) */ +/* */ +/* int CCutil_getcycle (int ncount, char *cyclename, int *outcycle) */ +/* READS a cycle in node node format, and returns the cycle in node */ +/* node format in the array outcycle. */ +/* -outcycle should be allocated by the calling routine */ +/* */ +/* int CCutil_getedges_double (int *ncount, char *fname, int *ecount, */ +/* int **elist, double **elen, int binary_in) */ +/* READS the edgelist in end1 end2 length format, where the length */ +/* is a double (used for x-vectors) */ +/* -returns the number of nodes */ +/* -fname is the name of the file to read. */ +/* -ecount returns the number of edges. */ +/* -elist returns the list of edges in end1 end2 format (it will be */ +/* allocated by getedges_double). */ +/* -elen returns the lengths of the edges. */ +/* -binary_in indicates whether the file should be written in binary */ +/* or in ascii (1 is binary, 0 is ascii) */ +/* */ +/* int CCutil_writeedges (int ncount, char *outedgename, int ecount, */ +/* int *elist, CCdatagroup *dat) */ +/* WRITES the edgelist in end1 end2 length format. */ +/* -ncount the number of nodes */ +/* -outedgename is the name of the file to write to. */ +/* -ecount is the number of edges. */ +/* -elist is the list of edges in end1 end2 format. */ +/* -dat contains the data to compute edgelengths. */ +/* */ +/* int CCutil_writecycle_edgelist (int ncount, char *outedgename, */ +/* int *cycle, CCdatagroup *dat) */ +/* WRITES the cycle int end1 end1 length format. */ +/* */ +/* int CCutil_writecycle (int ncount, char *outcyclename, int *cycle) */ +/* WRITES the cycle in node node node format. */ +/* */ +/* int CCutil_writeedges_double (int ncount, char *outedgename, */ +/* int ecount, int *elist, double *elen, int binary_out) */ +/* WRITES the edgelist in end1 end2 length format, where the length */ +/* is a double (used for x-vectors) */ +/* -ncount the number of nodes */ +/* -outedgename is the name of the file to write to. */ +/* -ecount is the number of edges. */ +/* -elist is the list of edges in end1 end2 format. */ +/* -elen are the lengths of the edges. */ +/* -binary_out indicates whether the file should be written in binary */ +/* or in ascii (1 is binary, 0 is ascii) */ +/* */ +/* int CCutil_datagroup_perm (int ncount, CCdatagroup *dat, int *perm) */ +/* REORDERS the nodes to match the order given in perm. */ +/* */ +/* NOTES: */ +/* Functions prototyped in util.h. Functions return 0 when they */ +/* succeed and nonzero when they fail (usually do to bad filenames or */ +/* not enough memory). */ +/* The TSPLIB reader works for all problems in TSPLIB_1.2, but does */ +/* not include all of the options listed in Reinelt's orginal TSPLIB */ +/* paper. It returns a failure on linhp318.tsp, since there is no */ +/* place for fixed edges in our edge length dat structure. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#define MATRAND_SCALE 10 /* Range of edge lengths: [0, MATRAND_SCALE * n) */ + +#ifdef CC_PROTOTYPE_ANSI + +static void + make_weights_nonnegative (int ncount, double *wcoord); +static int + read_crystal (char *datname, int *ncount, CCdatagroup *dat); + +#else + +static void + make_weights_nonnegative (); +static int + read_crystal (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_getdata (char *datname, int binary_in, int innorm, + int *ncount, CCdatagroup *dat) +#else +int CCutil_getdata (datname, binary_in, innorm, ncount, dat) +char *datname; +int binary_in, innorm; +int *ncount; +CCdatagroup *dat; +#endif +{ + int i, j; + int xi, yi, zi; + + dat->x = (double *) NULL; + dat->y = (double *) NULL; + dat->z = (double *) NULL; + dat->adj = (int **) NULL; + dat->norm = innorm; + + if (datname == (char *) NULL && *ncount == 0) { + fprintf (stderr, "getdata needs a datfile or a nodecount\n"); + return 1; + } + + if (innorm == CC_CRYSTAL) { + return read_crystal (datname, ncount, dat); + } else if ((innorm & CC_NORM_SIZE_BITS) == CC_D2_NORM_SIZE || + (innorm & CC_NORM_SIZE_BITS) == CC_D3_NORM_SIZE) { + if (datname != (char *) NULL) { + if (binary_in) { + CC_SFILE *f = CCutil_sopen (datname, "r"); + if (f == (CC_SFILE *) NULL) + return 1; + if (CCutil_sread_int (f, (unsigned int *) ncount)) { + CCutil_sclose (f); + return 1; + } + printf ("nnodes = %d\n", *ncount); + fflush (stdout); + dat->x = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x) { + if (CCutil_sclose (f)) + fprintf (stderr, "Could not close file\n"); + return 1; + } + dat->y = CC_SAFE_MALLOC (*ncount, double); + if (!dat->y) { + if (CCutil_sclose (f)) + fprintf (stderr, "Could not close file\n"); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + if ((innorm & CC_NORM_SIZE_BITS) == CC_D3_NORM_SIZE) { + dat->z = CC_SAFE_MALLOC (*ncount, double); + if (!dat->z) { + if (CCutil_sclose (f)) + fprintf (stderr, "Could not close file\n"); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + } + for (i = 0; i < *ncount; i++) { + if (CCutil_sread_int (f, (unsigned int *) &xi)) { + CCutil_sclose (f); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + if (CCutil_sread_int (f, (unsigned int *) &yi)) { + CCutil_sclose (f); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + dat->x[i] = (double) xi; + dat->y[i] = (double) yi; + if ((innorm & CC_NORM_SIZE_BITS) == CC_D3_NORM_SIZE) { + if (CCutil_sread_int (f, (unsigned int *) &zi)) { + CCutil_sclose (f); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + dat->z[i] = (double) zi; + } + } + if (CCutil_sclose (f)) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + } else { + FILE *datin = fopen (datname, "r"); + if (datin == (FILE *) NULL) { + perror (datname); + fprintf (stderr, "Unable to open %s for input\n", datname); + return 1; + } + fscanf (datin, "%d", ncount); + printf ("nnodes = %d\n", *ncount); + dat->x = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x) { + fclose (datin); + return 1; + } + dat->y = CC_SAFE_MALLOC (*ncount, double); + if (!dat->y) { + fclose (datin); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + if ((innorm & CC_NORM_SIZE_BITS) == CC_D3_NORM_SIZE) { + dat->z = CC_SAFE_MALLOC (*ncount, double); + if (!dat->z) { + fclose (datin); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + for (i = 0; i < *ncount; i++) { + fscanf (datin, "%lf %lf %lf", + &(dat->x[i]), &(dat->y[i]), &(dat->z[i])); + } + } else { + for (i = 0; i < *ncount; i++) { + fscanf (datin, "%lf %lf", &(dat->x[i]), &(dat->y[i])); + } + } + fclose (datin); + } + } else { + printf ("Random %d point set\n", *ncount); + fflush (stdout); + dat->x = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x) + return 1; + dat->y = CC_SAFE_MALLOC (*ncount, double); + if (!dat->y) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + if ((innorm & CC_NORM_SIZE_BITS) == CC_D3_NORM_SIZE) { + dat->z = CC_SAFE_MALLOC (*ncount, double); + if (!dat->z) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + for (i = 0; i < *ncount; i++) { + dat->x[i] = (double) (CCutil_lprand () % (*ncount)); + dat->y[i] = (double) (CCutil_lprand () % (*ncount)); + dat->z[i] = (double) (CCutil_lprand () % (*ncount)); + } + } else if (innorm == CC_GEOGRAPHIC) { + for (i = 0; i < *ncount; i++) { + dat->x[i] = (double) (CCutil_lprand () % 180) - 90.0; + dat->y[i] = (double) (CCutil_lprand () % 360) - 180.0; + } + } else { + int **hit = (int **) NULL; + int *hitcount = (int *) NULL; + int winner, x, y; + + hit = CC_SAFE_MALLOC (*ncount, int *); + hitcount = CC_SAFE_MALLOC (*ncount, int); + if (!hit || !hitcount) { + fprintf (stderr, "out of memory in getdata\n"); + CC_IFFREE (hit, int *); + CC_IFFREE (hitcount, int); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + + for (i = 0; i < *ncount; i++) { + hit[i] = (int *) NULL; + hitcount[i] = 0; + } + + for (i = 0; i < *ncount; i++) { + winner = 0; + do { + x = CCutil_lprand () % (*ncount); + y = CCutil_lprand () % (*ncount); + for (j = 0; j < hitcount[x]; j++) { + if (hit[x][j] == y) break; + } + if (j == hitcount[x]) { + if (CCutil_reallocrus_count ((void **) &(hit[x]), + hitcount[x] + 1, sizeof (int))) { + fprintf (stderr, "reallocrus_count failed\n"); + for (i = 0; i < *ncount; i++) { + CC_IFFREE (hit[i], int); + } + CC_IFFREE (hit, int *); + CC_IFFREE (hitcount, int); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + hit[x][hitcount[x]] = y; + hitcount[x]++; + winner = 1; + } + if (!winner) { + printf ("X"); fflush (stdout); + } + } while (!winner); + dat->x[i] = (double) x; + dat->y[i] = (double) y; + } + for (i = 0; i < *ncount; i++) { + CC_IFFREE (hit[i], int); + } + CC_IFFREE (hit, int *); + CC_IFFREE (hitcount, int); + } + } + } else if ((innorm & CC_NORM_SIZE_BITS) == CC_MATRIX_NORM_SIZE){ + if (datname != (char *) NULL) { + /* Matrix is the lower triangle plus the diagonal */ + if (binary_in) { + CC_SFILE *f = CCutil_sopen (datname, "r"); + if (f == (CC_SFILE *) NULL) + return 1; + if (CCutil_sread_int (f, (unsigned int *) ncount)) { + CCutil_sclose (f); + return 1; + } + printf ("nnodes = %d\n", *ncount); + fflush (stdout); + dat->adj = CC_SAFE_MALLOC (*ncount, int *); + if (!dat->adj) { + if (CCutil_sclose (f)) + fprintf (stderr, "Could not close file\n"); + return 1; + } + for (i = 0; i < *ncount; i++) + dat->adj[i] = (int *) NULL; + for (i = 0; i < *ncount; i++) { + dat->adj[i] = CC_SAFE_MALLOC (i + 1, int); + if (!dat->adj[i]) { + CCutil_freedatagroup (*ncount, dat); + if (CCutil_sclose (f)) + fprintf (stderr, "Could not close file\n"); + return 1; + } + } + for (i = 0; i < *ncount; i++) { + for (j = 0; j <= i; j++) { + if (CCutil_sread_int (f, + (unsigned int *) &(dat->adj[i][j]))) { + CCutil_sclose (f); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + } + } + if (CCutil_sclose (f)) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + } else { + FILE *datin = fopen (datname, "r"); + if (datin == (FILE *) NULL) { + perror (datname); + fprintf (stderr, "Unable to open %s for input\n", datname); + return 1; + } + *ncount = CCutil_readint (datin); + printf ("nnodes = %d\n", *ncount); + dat->adj = CC_SAFE_MALLOC (*ncount, int *); + if (!dat->adj) { + fclose (datin); + return 1; + } + for (i = 0; i < *ncount; i++) + dat->adj[i] = (int *) NULL; + for (i = 0; i < *ncount; i++) { + dat->adj[i] = CC_SAFE_MALLOC (i + 1, int); + if (!dat->adj[i]) { + CCutil_freedatagroup (*ncount, dat); + fclose (datin); + return 1; + } + } + for (i = 0; i < *ncount; i++) { + for (j = 0; j <= i; j++) { + dat->adj[i][j] = CCutil_readint (datin); + } + } + + fclose (datin); + } + } else { + printf ("Complete graph with %d nodes and random edge lengths\n", + *ncount); + fflush (stdout); + dat->adj = CC_SAFE_MALLOC (*ncount, int *); + if (!dat->adj) + return 1; + for (i = 0; i < *ncount; i++) + dat->adj[i] = (int *) NULL; + for (i = 0; i < *ncount; i++) { + dat->adj[i] = CC_SAFE_MALLOC (i + 1, int); + if (!dat->adj[i]) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + } + for (i = 0; i < *ncount; i++) { + for (j = 0; j < i; j++) + dat->adj[i][j] = + CCutil_lprand () % (MATRAND_SCALE * (*ncount)); + dat->adj[i][i] = 0; + } + } + } else if (innorm == CC_DSJRANDNORM) { + int maxdist, seed; + dat->x = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x) + return 1; + for (i = 0; i < *ncount; i++) + dat->x[i] = 0x12345672*(i+1) + 1; + if (datname != (char *) NULL) { + FILE *datin = fopen (datname, "r"); + if (datin == (FILE *) NULL) { + perror (datname); + fprintf (stderr, "Unable to open %s for input\n", datname); + return 1; + } + fscanf (datin, "%d", &seed); + fscanf (datin, "%d", &maxdist); + fclose (datin); + } else { + seed = 1; + maxdist = 1000000; + } + CCutil_dsjrand_init (maxdist, seed); + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_writemaster (char *mastername, int ncount, CCdatagroup *dat, + int *perm) +#else +int CCutil_writemaster (mastername, ncount, dat, perm) +char *mastername; +int ncount; +CCdatagroup *dat; +int *perm; +#endif +{ + CC_SFILE *out = (CC_SFILE *) NULL; + int i, j; + + if (mastername == (char *) NULL) { + fprintf (stderr, "writemaster needs a filename\n"); + return 1; + } + + out = CCutil_sopen (mastername, "w"); + if (out == (CC_SFILE *) NULL) { + fprintf (stderr, "Unable to open %s for output\n", mastername); + return 1; + } + + if (CCutil_swrite_int (out, (unsigned int) ncount)) { + CCutil_sclose (out); + return 1; + } + + if (dat) { + if (CCutil_swrite_int (out, (unsigned int) CC_MASTER_DAT)) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_int (out, (unsigned int) dat->norm)) { + CCutil_sclose (out); + return 1; + } + + if (dat->norm == CC_CRYSTAL) { + for (i = 0; i < ncount; i++) { + if (CCutil_swrite_double (out, dat->x[i])) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_double (out, dat->y[i])) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_double (out, dat->z[i])) { + CCutil_sclose (out); + return 1; + } + } + } else if (((dat->norm) & CC_NORM_SIZE_BITS) == CC_D2_NORM_SIZE) { + for (i = 0; i < ncount; i++) { + if (CCutil_swrite_double (out, dat->x[i])) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_double (out, dat->y[i])) { + CCutil_sclose (out); + return 1; + } + } + } else if (((dat->norm) & CC_NORM_SIZE_BITS) == CC_D3_NORM_SIZE) { + for (i = 0; i < ncount; i++) { + if (CCutil_swrite_double (out, dat->x[i])) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_double (out, dat->y[i])) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_double (out, dat->z[i])) { + CCutil_sclose (out); + return 1; + } + } + } else if (((dat->norm) & CC_NORM_SIZE_BITS) == CC_MATRIX_NORM_SIZE){ + /* Matrix is the lower triangle plus the diagonal */ + for (i = 0; i < ncount; i++) { + for (j = 0; j <= i; j++) { + if (CCutil_swrite_int (out, + (unsigned int) dat->adj[i][j])) { + CCutil_sclose (out); + return 1; + } + } + } + } else if (dat->norm == CC_DSJRANDNORM) { + for (i = 0; i < ncount; i++) { + if (CCutil_swrite_double (out, dat->x[i])) { + CCutil_sclose (out); + return 1; + } + } + } else { + fprintf (stderr, "unknown norm: %d\n", dat->norm); + return 1; + } + } else { + if (CCutil_swrite_int (out, (unsigned int) CC_MASTER_NO_DAT)) { + CCutil_sclose (out); + return 1; + } + } + + for (i = 0; i < ncount; i++) { + if (perm[i] < 0 || perm[i] >= ncount) { + fprintf (stderr, "permutation in wrong format\n"); + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_int (out, (unsigned int) perm[i])) { + CCutil_sclose (out); + return 1; + } + } + + CCutil_sclose (out); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_getmaster (char *mastername, int *ncount, CCdatagroup *dat, + int **perm) +#else +int CCutil_getmaster (mastername, ncount, dat, perm) +char *mastername; +int *ncount; +CCdatagroup *dat; +int **perm; +#endif +{ + CC_SFILE *in = (CC_SFILE *) NULL; + int i, j; + int havedat = 0; + + *ncount = 0; + dat->x = (double *) NULL; + dat->y = (double *) NULL; + dat->z = (double *) NULL; + dat->adj = (int **) NULL; + dat->norm = 0; + *perm = (int *) NULL; + + if (mastername == (char *) NULL) { + fprintf (stderr, "getmaster needs a filename\n"); + return 1; + } + + in = CCutil_sopen (mastername, "r"); + if (in == (CC_SFILE *) NULL) { + fprintf (stderr, "Unable to open %s for input\n", mastername); + return 1; + } + + if (CCutil_sread_int (in, (unsigned int *) ncount)) { + CCutil_sclose (in); + return 1; + } + + if (CCutil_sread_int (in, (unsigned int *) &havedat)) { + CCutil_sclose (in); + return 1; + } + + if (havedat == CC_MASTER_DAT) { + if (CCutil_sread_int (in, (unsigned int *) &(dat->norm))) { + CCutil_sclose (in); + return 1; + } + + if (dat->norm == CC_CRYSTAL) { + dat->x = CC_SAFE_MALLOC (*ncount, double); + dat->y = CC_SAFE_MALLOC (*ncount, double); + dat->z = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x || !dat->y || !dat->z) { + fprintf (stderr, "out of memory in getmaster\n"); + goto CLEANUP; + } + for (i = 0; i < *ncount; i++) { + if (CCutil_sread_double (in, &(dat->x[i]))) goto CLEANUP; + if (CCutil_sread_double (in, &(dat->y[i]))) goto CLEANUP; + if (CCutil_sread_double (in, &(dat->z[i]))) goto CLEANUP; + } + } else if (((dat->norm) & CC_NORM_SIZE_BITS) == CC_D2_NORM_SIZE) { + dat->x = CC_SAFE_MALLOC (*ncount, double); + dat->y = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x || !dat->y) { + fprintf (stderr, "out of memory in getmaster\n"); + goto CLEANUP; + } + for (i = 0; i < *ncount; i++) { + if (CCutil_sread_double (in, &(dat->x[i]))) goto CLEANUP; + if (CCutil_sread_double (in, &(dat->y[i]))) goto CLEANUP; + } + } else if (((dat->norm) & CC_NORM_SIZE_BITS) == CC_D3_NORM_SIZE) { + dat->x = CC_SAFE_MALLOC (*ncount, double); + dat->y = CC_SAFE_MALLOC (*ncount, double); + dat->z = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x || !dat->y || !dat->z) { + fprintf (stderr, "out of memory in getmaster\n"); + goto CLEANUP; + } + for (i = 0; i < *ncount; i++) { + if (CCutil_sread_double (in, &(dat->x[i]))) goto CLEANUP; + if (CCutil_sread_double (in, &(dat->y[i]))) goto CLEANUP; + if (CCutil_sread_double (in, &(dat->z[i]))) goto CLEANUP; + } + } else if (((dat->norm) & CC_NORM_SIZE_BITS) == CC_MATRIX_NORM_SIZE){ + /* Matrix is the lower triangle plus the diagonal */ + + dat->adj = CC_SAFE_MALLOC (*ncount, int *); + if (!dat->adj) goto CLEANUP; + for (i = 0; i < *ncount; i++) + dat->adj[i] = (int *) NULL; + + for (i = 0; i < *ncount; i++) { + dat->adj[i] = CC_SAFE_MALLOC (i + 1, int); + if (!dat->adj[i]) goto CLEANUP; + for (j = 0; j <= i; j++) { + if (CCutil_sread_int (in, + (unsigned int *) &(dat->adj[i][j]))) { + goto CLEANUP; + } + } + } + } else if (dat->norm == CC_DSJRANDNORM) { + dat->x = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x) { + fprintf (stderr, "out of memory in getmaster\n"); + goto CLEANUP; + } + for (i = 0; i < *ncount; i++) { + if (CCutil_sread_double (in, &(dat->x[i]))) goto CLEANUP; + } + } else { + fprintf (stderr, "unknown norm: %d\n", dat->norm); + goto CLEANUP; + } + } + + *perm = CC_SAFE_MALLOC (*ncount, int); + if (!(*perm)) { + fprintf (stderr, "out of memory in getmaster\n"); + goto CLEANUP; + } + + for (i = 0; i < *ncount; i++) { + if (CCutil_sread_int (in, (unsigned int *) &((*perm)[i]))) goto CLEANUP; + } + + CCutil_sclose (in); + return 0; + +CLEANUP: + + CC_IFFREE (*perm, int); + CC_IFFREE (dat->x, double); + CC_IFFREE (dat->y, double); + CC_IFFREE (dat->z, double); + if (dat->adj) { + for (i = 0; i < *ncount; i++) { + CC_IFFREE (dat->adj[i], int); + } + CC_FREE (dat->adj, int *); + } + + CCutil_sclose (in); + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_getnodeweights (char *weightname, int ncount, int weight_limit, + double **wcoord) +#else +int CCutil_getnodeweights (weightname, ncount, weight_limit, wcoord) +char *weightname; +int ncount, weight_limit; +double **wcoord; +#endif +{ + int i, k; + + *wcoord = CC_SAFE_MALLOC (ncount, double); + if (!(*wcoord)) + return 1; + if (weightname != (char *) NULL) { + FILE *weightin = fopen (weightname, "r"); + if (weightin == (FILE *) NULL) { + perror (weightname); + fprintf (stderr, "Unable to open %s for input\n", weightname); + CC_FREE (*wcoord, double); + return 1; + } + fscanf (weightin, "%d", &k); + if (k != ncount) { + fprintf (stderr, "Weight file does not match node file\n"); + fclose (weightin); + CC_FREE (*wcoord, double); + return 1; + } + for (i = 0; i < k; i++) { + fscanf (weightin, "%lf", &((*wcoord)[i])); + } + make_weights_nonnegative (ncount, *wcoord); + fclose (weightin); + } else { + for (i = 0; i < ncount; i++) + (*wcoord)[i] = (double) (CCutil_lprand () % (weight_limit)); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void make_weights_nonnegative (int ncount, double *wcoord) +#else +static void make_weights_nonnegative (ncount, wcoord) +int ncount; +double *wcoord; +#endif +{ + int i; + double minx; + + minx = wcoord[0]; + + for (i = 1; i < ncount; i++) { + if (wcoord[i] < minx) + minx = wcoord[i]; + } + if (minx < 0.0) { + printf ("****WARNING**** Adjusting node weights by %f\n", minx); + for (i = 0; i < ncount; i++) + wcoord[i] -= minx; + } +} + +#define MATRIX_LOWER_DIAG_ROW 0 +#define MATRIX_UPPER_ROW 1 +#define MATRIX_UPPER_DIAG_ROW 2 +#define MATRIX_FULL_MATRIX 3 + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_gettsplib (char *datname, int *ncount, CCdatagroup *dat) +#else +int CCutil_gettsplib (datname, ncount, dat) +char *datname; +int *ncount; +CCdatagroup *dat; +#endif +{ + char buf[256], key[256], field[256]; + char *p; + FILE *in; + int matrixform = MATRIX_LOWER_DIAG_ROW; + + dat->x = (double *) NULL; + dat->y = (double *) NULL; + dat->z = (double *) NULL; + dat->adj = (int **) NULL; + dat->norm = -1; + *ncount = -1; + + if ((in = fopen (datname, "r")) == (FILE *) NULL) { + perror (datname); + fprintf (stderr, "Unable to open %s for input\n", datname); + return 1; + } + + while (fgets (buf, 254, in) != (char *) NULL) { + p = buf; + while (*p != '\0') { + if (*p == ':') + *p = ' '; + p++; + } + p = buf; + if (sscanf (p, "%s", key) != EOF) { + p += strlen (key); + while (*p == ' ') + p++; + if (!strcmp (key, "NAME")) { + printf ("Problem Name: %s", p); + } else if (!strcmp (key, "TYPE")) { + printf ("Problem Type: %s", p); + if (sscanf (p, "%s", field) == EOF || strcmp (field, "TSP")) { + fprintf (stderr, "Not a TSP problem\n"); + return 1; + } + } else if (!strcmp (key, "COMMENT")) { + printf ("%s", p); + } else if (!strcmp (key, "DIMENSION")) { + if (sscanf (p, "%s", field) == EOF) { + fprintf (stderr, "ERROR in DIMENSION line\n"); + return 1; + } + *ncount = atoi (field); + printf ("Number of Nodes: %d\n", *ncount); + } else if (!strcmp (key, "EDGE_WEIGHT_TYPE")) { + if (sscanf (p, "%s", field) == EOF) { + fprintf (stderr, "ERROR in EDGE_WEIGHT_TYPE line\n"); + return 1; + } + if (!strcmp (field, "EXPLICIT")) { + dat->norm = CC_MATRIXNORM; + printf ("Explicit Lengths (CC_MATRIXNORM)\n"); + } else if (!strcmp (field, "EUC_2D")) { + dat->norm = CC_EUCLIDEAN; + printf ("Rounded Euclidean Norm (CC_EUCLIDEAN)\n"); + } else if (!strcmp (field, "EUC_3D")) { + dat->norm = CC_EUCLIDEAN_3D; + printf ("Rounded Euclidean 3D Norm (CC_EUCLIDEAN_3D)\n"); + } else if (!strcmp (field, "MAX_2D")) { + dat->norm = CC_MAXNORM; + printf ("Max Norm (CC_MAXNORM)\n"); + } else if (!strcmp (field, "GEO")) { + dat->norm = CC_GEOGRAPHIC; + printf ("Geographical Norm (CC_GEOGRAPHIC)\n"); + } else if (!strcmp (field, "ATT")) { + dat->norm = CC_ATT; + printf ("ATT Norm (ATT)\n"); + } else if (!strcmp (field, "CEIL_2D")) { + dat->norm = CC_EUCLIDEAN_CEIL; + printf ("Rounded Up Euclidean Norm (CC_EUCLIDEAN_CEIL)\n"); + } else { + fprintf (stderr, "ERROR: Not set up for norm %s\n", field); + return 1; + } + } else if (!strcmp (key, "EDGE_WEIGHT_FORMAT")) { + if (sscanf (p, "%s", field) == EOF) { + fprintf (stderr, "ERROR in EDGE_WEIGHT_FORMAT line\n"); + return 1; + } + if (!strcmp (field, "LOWER_DIAG_ROW")) { + matrixform = MATRIX_LOWER_DIAG_ROW; + } else if (!strcmp (field, "UPPER_ROW")) { + matrixform = MATRIX_UPPER_ROW; + } else if (!strcmp (field, "UPPER_DIAG_ROW")) { + matrixform = MATRIX_UPPER_DIAG_ROW; + } else if (!strcmp (field, "FULL_MATRIX")) { + matrixform = MATRIX_FULL_MATRIX; + } else if (strcmp (field, "FUNCTION")) { + fprintf (stderr, "Cannot handle format: %s\n", field); + return 1; + } + } else if (!strcmp (key, "NODE_COORD_SECTION")) { + int i; + if (*ncount <= 0) { + fprintf (stderr, "ERROR: Dimension not specified\n"); + return 1; + } + if (dat->x != (double *) NULL) { + fprintf (stderr, "ERROR: A second NODE_COORD_SECTION?\n"); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + if (((dat->norm) & CC_NORM_SIZE_BITS) == CC_D2_NORM_SIZE) { + dat->x = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + dat->y = CC_SAFE_MALLOC (*ncount, double); + if (!dat->y) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + for (i = 0; i < *ncount; i++) { + fscanf (in, "%*d %lf %lf", &(dat->x[i]), &(dat->y[i])); + } + } else if (((dat->norm) & CC_NORM_SIZE_BITS) == + CC_D3_NORM_SIZE) { + dat->x = CC_SAFE_MALLOC (*ncount, double); + if (!dat->x) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + dat->y = CC_SAFE_MALLOC (*ncount, double); + if (!dat->y) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + dat->z = CC_SAFE_MALLOC (*ncount, double); + if (!dat->z) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + for (i = 0; i < *ncount; i++) { + fscanf (in, "%*d %lf %lf %lf", + &(dat->x[i]), &(dat->y[i]), &(dat->z[i])); + } + } else { + fprintf (stderr, "ERROR: Node coordinates with norm %d?\n", + dat->norm); + return 1; + } + } else if (!strcmp (key, "EDGE_WEIGHT_SECTION")) { + int i, j; + if (*ncount <= 0) { + fprintf (stderr, "ERROR: Dimension not specified\n"); + return 1; + } + if (dat->adj != (int **) NULL) { + fprintf (stderr, "ERROR: A second NODE_COORD_SECTION?\n"); + CCutil_freedatagroup (*ncount, dat); + return 1; + } + if (((dat->norm) & CC_NORM_SIZE_BITS) == CC_MATRIX_NORM_SIZE) { + dat->adj = CC_SAFE_MALLOC (*ncount, int *); + if (!dat->adj) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + if (matrixform == MATRIX_LOWER_DIAG_ROW) { + for (i = 0; i < *ncount; i++) { + dat->adj[i] = CC_SAFE_MALLOC (i + 1, int); + if (!dat->adj[i]) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + for (j = 0; j <= i; j++) + fscanf (in, "%d", &(dat->adj[i][j])); + } + } else if (matrixform == MATRIX_UPPER_ROW || + matrixform == MATRIX_UPPER_DIAG_ROW || + matrixform == MATRIX_FULL_MATRIX) { + int **tempadj; + tempadj = CC_SAFE_MALLOC (*ncount, int *); + if (!tempadj) { + CCutil_freedatagroup (*ncount, dat); + return 1; + } + for (i = 0; i < *ncount; i++) { + tempadj[i] = CC_SAFE_MALLOC (*ncount, int); + if (!tempadj[i]) { + CCutil_freedatagroup (*ncount, dat); + for (j = 0; j < i; j++) + CC_FREE (tempadj[j], int); + CC_FREE (tempadj, int *); + return 1; + } + if (matrixform == MATRIX_UPPER_ROW) { + tempadj[i][i] = 0; + for (j = i + 1; j < *ncount; j++) + fscanf (in, "%d", &(tempadj[i][j])); + } else if (matrixform == MATRIX_UPPER_DIAG_ROW) { + for (j = i; j < *ncount; j++) + fscanf (in, "%d", &(tempadj[i][j])); + } else { + for (j = 0; j < *ncount; j++) + fscanf (in, "%d", &(tempadj[i][j])); + } + } + for (i = 0; i < *ncount; i++) { + dat->adj[i] = CC_SAFE_MALLOC (i + 1, int); + if (!dat->adj[i]) { + CCutil_freedatagroup (*ncount, dat); + for (j = 0; j < *ncount; j++) + CC_FREE (tempadj[j], int); + CC_FREE (tempadj, int *); + return 1; + } + for (j = 0; j <= i; j++) + dat->adj[i][j] = tempadj[j][i]; + } + for (i = 0; i < *ncount; i++) + CC_FREE (tempadj[i], int); + CC_FREE (tempadj, int *); + } + } else { + fprintf (stderr, "ERROR: Matrix with norm %d?\n", + dat->norm); + return 1; + } + } else if (!strcmp (key, "FIXED_EDGES_SECTION")) { + fprintf (stderr, "ERROR: Not set up for fixed edges\n"); + return 1; + } + } + } + fclose (in); + + if (dat->x == (double *) NULL && dat->adj == (int **) NULL) { + fprintf (stderr, "ERROR: Didn't find the data\n"); + return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_datagroup_perm (int ncount, CCdatagroup *dat, int *perm) +#else +int CCutil_datagroup_perm (ncount, dat, perm) +int ncount; +CCdatagroup *dat; +int *perm; +#endif +{ + int i, j; + + if (dat->x != (double *) NULL) { + double *tempx; + + tempx = CC_SAFE_MALLOC (ncount, double); + if (!tempx) + return 1; + for (i = 0; i < ncount; i++) { + tempx[i] = dat->x[perm[i]]; + } + CC_FREE (dat->x, double); + dat->x = tempx; + } + if (dat->y != (double *) NULL) { + double *tempy; + + tempy = CC_SAFE_MALLOC (ncount, double); + if (!tempy) + return 1; + for (i = 0; i < ncount; i++) { + tempy[i] = dat->y[perm[i]]; + } + CC_FREE (dat->y, double); + dat->y = tempy; + } + if (dat->z != (double *) NULL) { + double *tempz; + + tempz = CC_SAFE_MALLOC (ncount, double); + if (!tempz) + return 1; + for (i = 0; i < ncount; i++) { + tempz[i] = dat->z[perm[i]]; + } + CC_FREE (dat->z, double); + dat->z = tempz; + } + if (dat->adj != (int **) NULL) { + int **tempadj; + + tempadj = CC_SAFE_MALLOC (ncount, int *); + if (!tempadj) + return 1; + + for (i = 0; i < ncount; i++) { + tempadj[i] = CC_SAFE_MALLOC (i + 1, int); + if (!tempadj[i]) { + for (j = 0; j < i; j++) { + CC_FREE (tempadj[j], int); + } + CC_FREE (tempadj, int *); + return 1; + } + for (j = 0; j <= i; j++) { + if (perm[i] < perm[j]) + tempadj[i][j] = dat->adj[perm[j]][perm[i]]; + else + tempadj[i][j] = dat->adj[perm[i]][perm[j]]; + } + } + for (i = 0; i < ncount; i++) + CC_FREE (dat->adj[i], int); + CC_FREE (dat->adj, int *); + dat->adj = tempadj; + } + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_getedgelist (int ncount, char *fname, int *ecount, int **elist, + int **elen) +#else +int CCutil_getedgelist (ncount, fname, ecount, elist, elen) +int ncount; +char *fname; +int *ecount, **elist, **elen; +#endif +{ + int k; + + if (CCutil_getedgelist_n (&k, fname, ecount, elist, elen)) { + fprintf (stderr, "CCutil_getedgelist_n failed\n"); + return 1; + } + + if (k != ncount) { + fprintf (stderr, "Edge file does not match problem\n"); + return 1; + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_getedgelist_n (int *ncount, char *fname, int *ecount, int **elist, + int **elen) +#else +int CCutil_getedgelist_n (ncount, fname, ecount, elist, elen) +int *ncount; +char *fname; +int *ecount, **elist, **elen; +#endif +{ + FILE *in; + int i, k; + + *elist = (int *) NULL; + *elen = (int *) NULL; + + if ((in = fopen (fname, "r")) == (FILE *) NULL) { + perror (fname); + fprintf (stderr, "Unable to open %s for input\n", fname); + return 1; + } + + k = CCutil_readint (in); + *ncount = k; + *ecount = CCutil_readint (in); + + *elist = CC_SAFE_MALLOC(2 * (*ecount), int); + if (!(*elist)) { + fprintf (stderr, "out of memory in getedgelist\n"); + fclose (in); + return 1; + } + *elen = CC_SAFE_MALLOC(*ecount, int); + if (!(*elen)) { + fprintf (stderr, "out of memory in getedgelist\n"); + CC_FREE (*elist, int); + fclose (in); + return 1; + } + + for (i = 0, k = 0; i < *ecount; i++) { + (*elist)[k++] = CCutil_readint (in); + (*elist)[k++] = CCutil_readint (in); + (*elen)[i] = CCutil_readint (in); + } + + fclose (in); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_getcycle_edgelist (int ncount, char *cyclename, int *outcycle) +#else +int CCutil_getcycle_edgelist (ncount, cyclename, outcycle) +int ncount; +char *cyclename; +int *outcycle; +#endif +{ + FILE *cycin = fopen (cyclename, "r"); + int *elist = (int *) NULL; + int i, k; + + if (cycin == (FILE *) NULL) { + perror (cyclename); + fprintf (stderr, "Unable to open %s for input\n", cyclename); + return 1; + } + elist = CC_SAFE_MALLOC (2 * ncount, int); + if (!elist) { + fclose (cycin); + return 1; + } + + fscanf (cycin, "%d %d", &i, &k); + if (i != ncount || k != ncount) { + fprintf (stderr, "file is not a cycle-edge file for this problem\n"); + CC_FREE (elist, int); + fclose (cycin); + return 1; + } + + for (i = 0; i < ncount; i++) + fscanf (cycin, "%d %d %*d", &(elist[2 * i]), &(elist[(2 * i) + 1])); + + if (CCutil_edge_to_cycle (ncount, elist, outcycle)) { + fprintf (stderr, "CCutil_edge_to_cycle failed\n"); + CC_FREE (elist, int); + fclose (cycin); + return 1; + } + + CC_FREE (elist, int); + fclose (cycin); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_getcycle (int ncount, char *cyclename, int *outcycle) +#else +int CCutil_getcycle (ncount, cyclename, outcycle) +int ncount; +char *cyclename; +int *outcycle; +#endif +{ + FILE *cycin = fopen (cyclename, "r"); + int i; + + if (cycin == (FILE *) NULL) { + perror (cyclename); + fprintf (stderr, "Unable to open %s for input\n", cyclename); + return 1; + } + + i = CCutil_readint (cycin); + if (i != ncount) { + fprintf (stderr, "Cycle files has wrong number of nodes\n"); + return 1; + } + for (i = 0; i < ncount; i++) + outcycle[i] = CCutil_readint (cycin); + + fclose (cycin); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_getedges_double (int *ncount, char *fname, int *ecount, int **elist, + double **elen, int binary_in) +#else +int CCutil_getedges_double (ncount, fname, ecount, elist, elen, binary_in) +int *ncount; +char *fname; +int *ecount, **elist; +double **elen; +int binary_in; +#endif +{ + int i, k; + + if (binary_in) { + CC_SFILE *in; + + *elist = (int *) NULL; + *elen = (double *) NULL; + + if ((in = CCutil_sopen (fname, "r")) == (CC_SFILE *) NULL) { + fprintf (stderr, "Unable to open %s for input\n", fname); + return 1; + } + + if (CCutil_sread_int (in, (unsigned int *) ncount)) { + CCutil_sclose (in); + return 1; + } + + if (CCutil_sread_int (in, (unsigned int *) ecount)) { + CCutil_sclose (in); + return 1; + } + + *elist = CC_SAFE_MALLOC(2 * (*ecount), int); + if (!(*elist)) { + CCutil_sclose (in); + return 1; + } + *elen = CC_SAFE_MALLOC(*ecount, double); + if (!(*elen)) { + CC_FREE (*elist, int); + CCutil_sclose (in); + return 1; + } + + for (i = 0, k = 0; i < *ecount; i++) { + if (CCutil_sread_int (in, (unsigned int *) &((*elist)[k++]))) { + CCutil_sclose (in); + return 1; + } + if (CCutil_sread_int (in, (unsigned int *) &((*elist)[k++]))) { + CCutil_sclose (in); + return 1; + } + if (CCutil_sread_double (in, &((*elen)[i]))) { + CCutil_sclose (in); + return 1; + } + } + + CCutil_sclose (in); + } else { + FILE *in; + + *elist = (int *) NULL; + *elen = (double *) NULL; + + if ((in = fopen (fname, "r")) == (FILE *) NULL) { + perror (fname); + fprintf (stderr, "Unable to open %s for input\n", fname); + return 1; + } + + *ncount = CCutil_readint (in); + *ecount = CCutil_readint (in); + + *elist = CC_SAFE_MALLOC(2 * (*ecount), int); + if (!(*elist)) { + fclose (in); + return 1; + } + *elen = CC_SAFE_MALLOC(*ecount, double); + if (!(*elen)) { + CC_FREE (*elist, int); + fclose (in); + return 1; + } + + for (i = 0, k = 0; i < *ecount; i++) { + (*elist)[k++] = CCutil_readint (in); + (*elist)[k++] = CCutil_readint (in); + if (fscanf (in, "%lf", &((*elen)[i])) != 1) { + fprintf (stderr, "input file is in the wrong format\n"); + fclose (in); + return 1; + } + } + + fclose (in); + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_writeedges (int ncount, char *outedgename, int ecount, int *elist, + CCdatagroup *dat) +#else +int CCutil_writeedges (ncount, outedgename, ecount, elist, dat) +int ncount; +char *outedgename; +int ecount, *elist; +CCdatagroup *dat; +#endif +{ + FILE *out = fopen (outedgename, "w"); + int i; + + if (out == (FILE *) NULL) { + perror (outedgename); + fprintf (stderr, "Unable to open %s for output\n", outedgename); + return 1; + } + + fprintf (out, "%d %d\n", ncount, ecount); + for (i = 0; i < ecount; i++) { + fprintf (out, "%d %d %d\n", elist[2 * i], elist[(2 * i) + 1], + CCutil_dat_edgelen (elist[2 * i], elist[(2 * i) + 1], dat)); + } + fclose (out); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_writecycle_edgelist (int ncount, char *outedgename, int *cycle, + CCdatagroup *dat) +#else +int CCutil_writecycle_edgelist (ncount, outedgename, cycle, dat) +int ncount; +char *outedgename; +int *cycle; +CCdatagroup *dat; +#endif +{ + FILE *out = fopen (outedgename, "w"); + int i; + + if (out == (FILE *) NULL) { + perror (outedgename); + fprintf (stderr, "Unable to open %s for output\n", outedgename); + return 1; + } + + fprintf (out, "%d %d\n", ncount, ncount); + for (i = 1; i < ncount; i++) { + fprintf (out, "%d %d %d\n", cycle[i - 1], cycle[i], + CCutil_dat_edgelen (cycle[i - 1], cycle[i], dat)); + } + fprintf (out, "%d %d %d\n", cycle[ncount - 1], cycle[0], + CCutil_dat_edgelen (cycle[ncount - 1], cycle[0], dat)); + fclose (out); + + return 0; +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_writecycle (int ncount, char *outcyclename, int *cycle) +#else +int CCutil_writecycle (ncount, outcyclename, cycle) +int ncount; +char *outcyclename; +int *cycle; +#endif +{ + FILE *cycout = fopen (outcyclename, "w"); + int i; + + if (cycout == (FILE *) NULL) { + perror (outcyclename); + fprintf (stderr, "Unable to open %s for output\n", outcyclename); + return 1; + } + + fprintf (cycout, "%d\n", ncount); + for (i = 0; i < ncount; i++) { + fprintf (cycout, "%d ", cycle[i]); + if (i % 10 == 9) + fprintf (cycout, "\n"); + } + if (i % 10) + fprintf (cycout, "\n"); + fclose (cycout); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_writeedges_double (int ncount, char *outedgename, int ecount, + int *elist, double *elen, int binary_out) +#else +int CCutil_writeedges_double (ncount, outedgename, ecount, elist, elen, binary_out) +int ncount; +char *outedgename; +int ecount, *elist; +double *elen; +int binary_out; +#endif +{ + int i; + + if (binary_out) { + CC_SFILE *out = CCutil_sopen (outedgename, "w"); + + if (out == (CC_SFILE *) NULL) { + fprintf (stderr, "Unable to open %s for output\n", outedgename); + return 1; + } + + if (CCutil_swrite_int (out, (unsigned int) ncount)) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_int (out, (unsigned int) ecount)) { + CCutil_sclose (out); + return 1; + } + + for (i = 0; i < ecount; i++) { + if (CCutil_swrite_int (out, (unsigned int) elist[2 * i])) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_int (out, (unsigned int) elist[(2 * i) + 1])) { + CCutil_sclose (out); + return 1; + } + if (CCutil_swrite_double (out, elen[i])) { + CCutil_sclose (out); + return 1; + } + } + CCutil_sclose (out); + } else { + FILE *out = fopen (outedgename, "w"); + + if (out == (FILE *) NULL) { + perror (outedgename); + fprintf (stderr, "Unable to open %s for output\n", outedgename); + return 1; + } + + fprintf (out, "%d %d\n", ncount, ecount); + for (i = 0; i < ecount; i++) { + fprintf (out, "%d %d %f\n", elist[2 * i], elist[(2 * i) + 1], + elen[i]); + } + fclose (out); + } + + return 0; +} + + + +/* The crystal functions are based on David Shallcross's fortran code */ + +#define CRYSTAL_SCALE 10000 + +typedef struct three_d { + double phi; + double chi; + double twoth; +} three_d; + + +#ifdef CC_PROTOTYPE_ANSI + +static void + cry_quicksort (three_d *x, int l, int u), + cryswap (three_d *x, three_d *y); +static int + point_compare (three_d *x, three_d *y), + crygenpts (double orient[3][3], double lambda, int bounds[3][2]), + cryangles (int h, int k, int l, double orient[3][3], double lambda, + double omega, double *phi, double *chi, double *twoth); +static double + userint (double f); + +#else + +static void + cry_quicksort (), + cryswap (); +static int + point_compare (), + crygenpts (), + cryangles (); +static double + userint (); + +#endif + + +static three_d *crypoints = (three_d *) NULL; +static int ncrypoints = 0; + +#define CRY_MIN_ORIENT -0.2 /* For random problems */ +#define CRY_MAX_ORIENT 0.2 + +#define CRY_MIN_BOUND 10 +#define CRY_MAX_BOUND 20 + +#define CRY_1_00_CUTOFF 15000 +#define CRY_1_35_CUTOFF 10000 + +#ifdef CC_PROTOTYPE_ANSI +static int read_crystal (char *datname, int *ncount, CCdatagroup *dat) +#else +static int read_crystal (datname, ncount, dat) +char *datname; +int *ncount; +CCdatagroup *dat; +#endif +{ + FILE *datin; + double lambda; + double orient[3][3]; + int bounds[3][2]; + int i, j; + + if (!datname) { + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + orient[i][j] = CRY_MIN_ORIENT + + ((CRY_MAX_ORIENT - CRY_MIN_ORIENT) * + ((double) (CCutil_lprand () % 1000) / 1000.0)); + } + } + for (i = 0; i < 3; i++) { + bounds[i][1] = CRY_MIN_BOUND + + (CCutil_lprand () % (CRY_MAX_BOUND - CRY_MIN_BOUND + 1)); + bounds[i][0] = -bounds[i][1]; + } + + if (*ncount > CRY_1_00_CUTOFF) + lambda = 1.0; + else if (*ncount > CRY_1_35_CUTOFF) + lambda = 1.35; + else + lambda = 1.70; + + printf ("Random crystal problem\n"); + printf ("Note that the number of nodes will not match the request\n"); + printf ("Orient:\n"); + for (i = 0; i < 3; i++) + printf (" %.4f %.4f %.4f\n", orient[i][0], orient[i][1], + orient[i][2]); + printf ("Bounds:\n"); + for (i = 0; i < 3; i++) + printf (" %d %d ", bounds[i][0], bounds[i][1]); + printf ("\nWavelength:\n"); + printf (" %.2f\n", lambda); + fflush (stdout); + } else { + datin = fopen (datname, "r"); + if (datin == (FILE *) NULL) { + perror (datname); + fprintf (stderr, "Unable to open %s for input\n", datname); + return 1; + } + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + fscanf (datin, "%lf", &orient[i][j]); + } + } + fscanf (datin, "%lf", &lambda); + for (i = 0; i < 3; i++) { + for (j = 0; j < 2; j++) { + fscanf (datin, "%d", &(bounds[i][j])); + } + } + fclose (datin); + } + + if (crygenpts (orient, lambda, bounds)) { + fprintf (stderr, "crygenpts failed\n"); + if (crypoints) + CC_FREE (crypoints, three_d); + return 1; + } + cry_quicksort (crypoints, 0, ncrypoints -1); + printf ("Number of crystal points: %d\n", ncrypoints); + + dat->x = CC_SAFE_MALLOC (ncrypoints, double); + if (!dat->x) { + CC_FREE (crypoints, three_d); + return 1; + } + dat->y = CC_SAFE_MALLOC (ncrypoints, double); + if (!dat->y) { + CC_FREE (crypoints, three_d); + CCutil_freedatagroup (ncrypoints, dat); + return 1; + } + dat->z = CC_SAFE_MALLOC (ncrypoints, double); + if (!dat->z) { + CC_FREE (crypoints, three_d); + CCutil_freedatagroup (ncrypoints, dat); + return 1; + } + + for (i = 0; i < ncrypoints; i++) { + dat->x[i] = userint (crypoints[i].chi * CRYSTAL_SCALE), + dat->y[i] = userint (crypoints[i].phi * CRYSTAL_SCALE), + dat->z[i] = userint (crypoints[i].twoth * CRYSTAL_SCALE); + } + *ncount = ncrypoints; + + if (crypoints) + CC_FREE (crypoints, three_d); + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int point_compare (three_d *x, three_d *y) +#else +static int point_compare (x, y) +three_d *x; +three_d *y; +#endif +{ + int del; + + del = (int) userint (x->chi * CRYSTAL_SCALE) - + (int) userint (y->chi * CRYSTAL_SCALE); + if (del) + return del; + del = (int) userint (x->phi * CRYSTAL_SCALE) - + (int) userint (y->phi * CRYSTAL_SCALE); + if (del) + return del; + del = (int) userint (x->twoth * CRYSTAL_SCALE) - + (int) userint (y->twoth * CRYSTAL_SCALE); + return del; +} + +#ifdef CC_PROTOTYPE_ANSI +static double userint (double f) +#else +static double userint (f) +double f; +#endif +{ + double t; + int u; + + if (f > 0.0) { + u = (int) f; + t = (double) u; + return (f - t < 0.5 ? t : t + 1.0); + } else { + u = (int) f; + t = (double) u; + return (t - f < 0.5 ? t : t - 1.0); + } +} + + +/* genpts builds points, the array of accessible points of the lattice */ + +#ifdef CC_PROTOTYPE_ANSI +static int crygenpts (double orient[3][3], double lambda, int bounds[3][2]) +#else +static int crygenpts (orient, lambda, bounds) +double orient[3][3]; +double lambda; +int bounds[3][2]; +#endif +{ + int h, k, l; + double p = 0.0, c = 0.0, t = 0.0; + double minp = 360.0, minc = 180.0, mint = 155.0; + double maxp = 0.0, maxc = -180.0, maxt = -55.0; + + ncrypoints = 0; + + crypoints = CC_SAFE_MALLOC (100000, three_d); + if (!crypoints) + return 1; + + for (h = bounds[0][0]; h <= bounds[0][1]; h++) { + for (k = bounds[1][0]; k <= bounds[1][1]; k++) { + for (l = bounds[2][0]; l <= bounds[2][1]; l++) { + if (cryangles (h, k, l, orient, lambda, 0.0, &p, &c, &t)) { + crypoints[ncrypoints].phi = p; + crypoints[ncrypoints].chi = c; + crypoints[ncrypoints].twoth = t; + ncrypoints++; + if (p < minp) + minp = p; + if (p > maxp) + maxp = p; + if (c < minc) + minc = c; + if (c > maxc) + maxc = c; + if (t < mint) + mint = t; + if (t > maxt) + maxt = t; + } + } + } + } + return 0; +} + +/* + angles computes positioning information for the detector given the + miller indices. (From Matt Small, April 5, 1984) +*/ + +#ifdef CC_PROTOTYPE_ANSI +static int cryangles (int h, int k, int l, double orient[3][3], double lambda, + double omega, double *phi, double *chi, double *twoth) +#else +static int cryangles (h, k, l, orient, lambda, omega, phi, chi, twoth) +int h, k, l; +double lambda, omega; +double orient[3][3]; +double *phi, *chi, *twoth; +#endif +{ + /* The original had pi = 3.14159265368979; */ + static double pi = 3.14159265358979; + double x, y, z, d, dum, cosomg, sinchi, sinphi, cosphi, q, r; + double rh = h, rk = k, rl = l; + double t1, t2, t3; + + omega = omega / 180.0 * pi; + cosomg = cos (omega); + + x = orient[0][0] * rh + orient[0][1] * rk + orient[0][2] * rl; + y = orient[1][0] * rh + orient[1][1] * rk + orient[1][2] * rl; + z = orient[2][0] * rh + orient[2][1] * rk + orient[2][2] * rl; + d = sqrt (x * x + y * y + z * z); + dum = lambda * d / 2.0; + if (dum < .000001 || dum >= 1.0) { + return 0; + } + *twoth = asin (dum) * 2.0; + t1 = x / d; + t2 = y / d; + t3 = z / d; + if ((t3 < 0.0 ? -t3 : t3) >= (cosomg < 0.0 ? -cosomg : cosomg)) { + return 0; + } + sinchi = -t3 / cosomg; + *chi = asin (sinchi); + q = sin (omega); + r = cosomg * cos (*chi); + cosphi = (q * t1 + r * t2) / (t1 * t1 + t2 * t2); + sinphi = (r * t1 - q * t2) / (t1 * t1 + t2 * t2); + if (sinphi <= -.7) + *phi = -acos (cosphi); + else if (sinphi >= .7) + *phi = acos (cosphi); + else if (cosphi <= 0.0) + *phi = pi - asin (sinphi); + else + *phi = asin (sinphi); + *phi *= 180.0 / pi; + *chi *= 180.0 / pi; + *twoth *= 180.0 / pi; + *phi /= 1.25; /* FOR VARYING MORTOR SPEEDS */ + *chi /= 1.5; + *twoth /= 1.15; + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static void cry_quicksort (three_d *x, int l, int u) +#else +static void cry_quicksort (x, l, u) +three_d *x; +int l, u; +#endif +{ + int i, j; + three_d *t; + + if (l >= u) + return; + + cryswap (x + l, x + ((l+u)/2)); + + i = l; + j = u + 1; + t = x + l; + + while (1) { + do i++; while (i <= u && (point_compare (x + i, t) < 0)); + do j--; while (point_compare (x + j, t) > 0); + if (j < i) break; + cryswap (x + i, x + j); + } + cryswap (x + l, x + j); + cry_quicksort (x, l, j - 1); + cry_quicksort (x, i, u); +} + +#ifdef CC_PROTOTYPE_ANSI +static void cryswap (three_d *x, three_d *y) +#else +static void cryswap (x, y) +three_d *x, *y; +#endif +{ + three_d t; + + t.phi = x->phi; + t.chi = x->chi; + t.twoth = x->twoth; + + x->phi = y->phi; + x->chi = y->chi; + x->twoth = y->twoth; + + y->phi = t.phi; + y->chi = t.chi; + y->twoth = t.twoth; +} diff --git a/contrib/blossom/concorde97/UTIL/priority.c b/contrib/blossom/concorde97/UTIL/priority.c new file mode 100644 index 0000000000000000000000000000000000000000..1c3e421a078a32d166933d78fb7a8798e06b16c7 --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/priority.c @@ -0,0 +1,189 @@ +/***************************************************************************/ +/* */ +/* PRIORITY QUEUE ROUTINES */ +/* */ +/* */ +/* TSP CODE */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: March 3, 1997 */ +/* Reference: R.E. Tarjan, Data Structures and Network Algorithms */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* int CCutil_priority_init (CCpriority *pri, int k) */ +/* -h should point to a CCpriority struct. */ +/* -k an initial allocation for the priority queue. */ +/* void CCutil_priority_free (CCpriority *pri) */ +/* -frees the spaces allocated for the priority queue. */ +/* void *CCutil_priority_findmin (CCpriority *pri, double *keyval) */ +/* -returns the entry with least key value. */ +/* -returns NULL if no entries in heap. */ +/* -if (keyval != NULL), *keyval will be the minimum key value. */ +/* int CCutil_priority_insert (CCpriority *pri, void *data, */ +/* double keyval) */ +/* -adds (data, keyval) to h. */ +/* -returns a handle (>= 0) to use when deleting or changing the entry*/ +/* -returns -1 if out of memory. */ +/* void CCutil_priority_delete (CCpriority *pri, int handle) */ +/* -deletes an entry from the queue. handle is the value returned by */ +/* CCpriority_insert. */ +/* void *CCutil_priority_deletemin (CCpriority *pri, double *keyval) */ +/* -like CCpriority_findmin, but also deletes the entry. */ +/* void CCutil_priority_changekey (CCpriority *pri, int handle, */ +/* double newkey) */ +/* -changes the key of an entry in the queue. handle is the value */ +/* returned by CCpriority_insert. */ +/* */ +/* NOTES: */ +/* These priority queue routines use the dheap routines to maintain */ +/* the priority queue. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_priority_init (CCpriority *pri, int k) +#else +int CCutil_priority_init (pri, k) +CCpriority *pri; +int k; +#endif +{ + int i; + int list; + + pri->space = k; + pri->pri_info = CC_SAFE_MALLOC (k, union pri_data); + if (!pri->pri_info) { + return -1; + } + if (CCutil_dheap_init (&pri->heap, k)) { + CC_FREE (pri->pri_info, union pri_data); + return -1; + } + + list = -1; + for (i=k-1; i>=0; i--) { + pri->pri_info[i].next = list; + list = i; + } + pri->freelist = list; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_priority_free (CCpriority *pri) +#else +void CCutil_priority_free (pri) +CCpriority *pri; +#endif +{ + CCutil_dheap_free (&pri->heap); + CC_FREE (pri->pri_info, union pri_data); + pri->space = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void *CCutil_priority_findmin (CCpriority *pri, double *keyval) +#else +void *CCutil_priority_findmin (pri, keyval) +CCpriority *pri; +double *keyval; +#endif +{ + int handle = CCutil_dheap_findmin (&pri->heap); + + if (handle < 0) { + return (void *) NULL; + } else { + if (keyval) *keyval = pri->heap.key[handle]; + return pri->pri_info[handle].data; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_priority_insert (CCpriority *pri, void *data, double keyval) +#else +int CCutil_priority_insert (pri, data, keyval) +CCpriority *pri; +void *data; +double keyval; +#endif +{ + int newsize; + int i; + int list; + + if (pri->freelist == -1) { + newsize = (int) (1.3 * pri->space); + if (newsize < pri->space + 1000) newsize = pri->space + 1000; + if (CCutil_dheap_resize (&pri->heap, newsize)) { + return -1; + } + if (CCutil_reallocrus_count ((void **) &pri->pri_info, newsize, + sizeof (union pri_data))) { + return -1; + } + list = -1; + for (i=newsize-1; i>=pri->space; i--) { + pri->pri_info[i].next = list; + list = i; + } + pri->freelist = list; + } + + i = pri->freelist; + pri->freelist = pri->pri_info[i].next; + pri->pri_info[i].data = data; + pri->heap.key[i] = keyval; + CCutil_dheap_insert (&pri->heap, i); + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_priority_delete (CCpriority *pri, int handle) +#else +void CCutil_priority_delete (pri, handle) +CCpriority *pri; +int handle; +#endif +{ + CCutil_dheap_delete (&pri->heap, handle); + pri->pri_info[handle].next = pri->freelist; + pri->freelist = handle; +} + +#ifdef CC_PROTOTYPE_ANSI +void *CCutil_priority_deletemin (CCpriority *pri, double *keyval) +#else +void *CCutil_priority_deletemin (pri, keyval) +CCpriority *pri; +double *keyval; +#endif +{ + int handle = CCutil_dheap_deletemin (&pri->heap); + void *data; + + if (handle < 0) { + return (void *) NULL; + } else { + if (keyval) *keyval = pri->heap.key[handle]; + data = pri->pri_info[handle].data; + pri->pri_info[handle].next = pri->freelist; + pri->freelist = handle; + return data; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_priority_changekey (CCpriority *pri, int handle, double newkey) +#else +void CCutil_priority_changekey (pri, handle, newkey) +CCpriority *pri; +int handle; +double newkey; +#endif +{ + CCutil_dheap_changekey (&pri->heap, handle, newkey); +} diff --git a/contrib/blossom/concorde97/UTIL/safe_io.c b/contrib/blossom/concorde97/UTIL/safe_io.c new file mode 100644 index 0000000000000000000000000000000000000000..45608ed0ef9d9dc6eff8b0f19b00c359405406c3 --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/safe_io.c @@ -0,0 +1,1086 @@ +/***************************************************************************/ +/* */ +/* INPUT/OUTPUT ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 13, 1995 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* CC_SFILE */ +/* *CCutil_sopen (char *f, char *s), */ +/* *CCutil_sdopen (int d, char *s); */ +/* int */ +/* CCutil_swrite (CC_SFILE *f, unsigned char *buf, int size), */ +/* CCutil_swrite_bits (CC_SFILE *f, unsigned int x, int xbits), */ +/* CCutil_swrite_char (CC_SFILE *f, unsigned char x), */ +/* CCutil_swrite_string (CC_SFILE *f, unsigned char *s) */ +/* CCutil_swrite_short (CC_SFILE *f, unsigned short x), */ +/* CCutil_swrite_int (CC_SFILE *f, unsigned int x), */ +/* CCutil_swrite_double (CC_SFILE *f, double x), */ +/* CCutil_sread (CC_SFILE *f, unsigned char *buf, int size), */ +/* CCutil_sread_bits (CC_SFILE *f, unsigned int x, int xbits), */ +/* CCutil_sread_char (CC_SFILE *f, unsigned char *x), */ +/* CCutil_sread_string (CC_SFILE *f, unsigned char *x, int maxlen) */ +/* CCutil_sread_short (CC_SFILE *f, unsigned short *x), */ +/* CCutil_sread_short_r (CC_SFILE *f, unsigned short *x), */ +/* CCutil_sread_int (CC_SFILE *f, unsigned int *x), */ +/* CCutil_sread_int_r (CC_SFILE *f, unsigned int *x), */ +/* CCutil_sread_double (CC_SFILE *f, double *x), */ +/* CCutil_sread_double_r (CC_SFILE *f, double *x), */ +/* CCutil_sflush (CC_SFILE *f), */ +/* CCutil_stell (CC_SFILE *f), */ +/* CCutil_sseek (CC_SFILE *f, int offset), */ +/* CCutil_srewind (CC_SFILE *f), */ +/* CCutil_sclose (CC_SFILE *f), */ +/* CCutil_sbits (unsigned int x), */ +/* CCutil_sdelete_file (char *f), */ +/* CCutil_sdelete_file_backup (char *f) */ +/* */ +/* This routines provide buffered binary I/O. The routines sopen, */ +/* sdopen, swrite, sread, sflush, stell, sseek, srewind, and sclose */ +/* resemble the stdio routines fopen, fdopen, fwrite, fread, fflush, */ +/* ftell, fseek, rewind, and fclose. swrite_{char,short,int,double} */ +/* and sread_{char,short,int,double} provide a somewhat machine */ +/* independent binary I/O mechanism. sread_{short,int,double}_r read */ +/* the values in reverse order, and are provided for compatibility */ +/* reasons. sread_bits and swrite_bits write variable-length bit */ +/* strings. sbits can be used to compute the number of bits necessary */ +/* to represent a number. The variable-length bit strings are padded */ +/* to a byte boundary when one of the other read/write routines, flush, */ +/* tell, seek, rewind, or close are called. */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#ifndef SEEK_SET +#ifdef L_SET +#define SEEK_SET L_SET +#else +#define SEEK_SET 0 +#endif +#endif + +#ifdef CC_PROTOTYPE_ANSI + +static CC_SFILE + *sopen_write (char *f), + *sdopen_write (int t), + *sopen_read (char *f), + *sdopen_read (int t); + +static int + swrite_buffer (CC_SFILE *f), + sread_buffer (CC_SFILE *f); + +static void + sinit (CC_SFILE *s); + +#else + +static CC_SFILE + *sopen_write (), + *sdopen_write (), + *sopen_read (), + *sdopen_read (); + +static int + swrite_buffer (), + sread_buffer (); + +static void + sinit (); + +#endif + + +/* VERSION A3 */ + +/* sopen interprets filenames "stdin" as descriptor 0, "stdout" as + * descriptor 1, and "stderr" as descriptor 2. "-" is interpreted as + * 0 or 1, depending on whether the file is opened for reading or writing. + * + * sclose doesn't close descriptors 0, 1, and 2. + */ + +/* When writing, written data extends from buffer[0] bit 7 through + * buffer[chars_in_buffer-1] bit bits_in_last_char. Empty space extends + * from buffer[chars_in_buffer-1] bit bits_in_last_char-1 through + * buffer[CC_SBUFFER_SIZE-1] bit 0. + * + * When reading, read data extends from buffer[0] bit 7 through + * buffer[current_buffer_char] bit bits_in_last_char. unread data + * extends from buffer[current_buffer_char] bit bits_in_last_char-1 + * through buffer[chars_in_buffer-1] bit 0. Empty space extends from + * buffer[chars_in_buffer] bit 7 through buffer[CC_SBUFFER_SIZE-1] bit 0. + */ + +/* If the routines detect an error, they return -1. + */ + +#define SREAD 1 +#define SWRITE 2 + +#define NBITMASK(n) ((1<<(n))-1) +#define BITRANGE(x,start,length) (((x) >> (start)) & NBITMASK(length)) +#define BITS_PER_CHAR (8) + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_EXCL +#define O_EXCL 0 +#endif + +#ifdef CC_PROTOTYPE_ANSI +CC_SFILE *CCutil_sopen (char *f, char *s) +#else +CC_SFILE *CCutil_sopen (f, s) +char *f; +char *s; +#endif +{ + if (s[0] == 'r' || s[0] == 'R') { + return sopen_read (f); + } else if (s[0] == 'w' || s[0] == 'W') { + return sopen_write (f); + } else { + fprintf (stderr, "Need to specify read/write in sopen\n"); + return (CC_SFILE *) NULL; + } +} + +#ifdef CC_PROTOTYPE_ANSI +CC_SFILE *CCutil_sdopen (int d, char *s) +#else +CC_SFILE *CCutil_sdopen (d, s) +int d; +char *s; +#endif +{ + if (s[0] == 'r' || s[0] == 'R') { + return sdopen_read (d); + } else if (s[0] == 'w' || s[0] == 'W') { + return sdopen_write (d); + } else { + fprintf (stderr, "Need to specify read/write in sopen\n"); + return (CC_SFILE *) NULL; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static CC_SFILE *sopen_write (char *f) +#else +static CC_SFILE *sopen_write (f) +char *f; +#endif +{ + CC_SFILE *s = (CC_SFILE *) NULL; + int t; + char fbuf[CC_SFNAME_SIZE]; + char fbuf_N[CC_SFNAME_SIZE + 32]; + char fbuf_Nx[CC_SFNAME_SIZE + 64]; + + strncpy (fbuf, f, sizeof (fbuf) - 12); + fbuf[sizeof (fbuf) - 12] = '\0'; + sprintf (fbuf_N, "N%s", fbuf); + sprintf (fbuf_Nx, "N%s~", fbuf); + + + if (!strcmp (f, "stdout") || !strcmp (f, "-")) { + s = sdopen_write (1); + } else if (!strcmp (f, "stderr")) { + s = sdopen_write (2); + } else { + t = open (fbuf_N, O_WRONLY | O_CREAT | O_BINARY | O_EXCL, 0644); + if (t == -1 && errno == EEXIST) { + fprintf (stderr, "%s already exists, renaming to %s\n", + fbuf_N, fbuf_Nx); + if (rename (fbuf_N, fbuf_Nx)) { + perror (fbuf_Nx); + fprintf (stderr, "Couldn't rename %s to %s\n", fbuf_N, + fbuf_Nx); + return (CC_SFILE *) NULL; + } + t = open (fbuf_N, O_WRONLY | O_CREAT | O_BINARY | O_EXCL, 0644); + } + if (t == -1) { + perror (fbuf_N); + fprintf (stderr, "Couldn't open %s for output\n", fbuf_N); + return (CC_SFILE *) NULL; + } + s = sdopen_write (t); + if (!s) { + close (t); + } + } + if (s) { + strncpy (s->fname, fbuf, sizeof (s->fname)); + s->fname[sizeof (s->fname)-1] = '\0'; + } + return s; +} + +#ifdef CC_PROTOTYPE_ANSI +static CC_SFILE *sdopen_write (int t) +#else +static CC_SFILE *sdopen_write (t) +int t; +#endif +{ + CC_SFILE *s = (CC_SFILE *) NULL; + + if (t < 0) { + fprintf (stderr, "Invalid descriptor %d\n", t); + return (CC_SFILE *) NULL; + } + + s = CC_SAFE_MALLOC (1, CC_SFILE); + if (s == (CC_SFILE *) NULL) { + return s; + } + sinit (s); + + s->status = SWRITE; + s->desc = t; + sprintf (s->fname, "descriptor %d", t); + return s; +} + +#ifdef CC_PROTOTYPE_ANSI +static CC_SFILE *sopen_read (char *f) +#else +static CC_SFILE *sopen_read (f) +char *f; +#endif +{ + CC_SFILE *s = (CC_SFILE *) NULL; + int t; + + if (!strcmp (f, "stdin") || !strcmp (f, "-")) { + s = sdopen_read (0); + } else { + t = open (f, O_RDONLY | O_BINARY, 0644); + if (t == -1) { + perror (f); + fprintf (stderr, "Couldn't open for input\n"); + s = (CC_SFILE *) NULL; + } + s = sdopen_read (t); + if (!s) { + close (t); + } + } + if (s) { + strncpy (s->fname, f, sizeof (s->fname)); + s->fname[sizeof (s->fname)-1] = '\0'; + } + return s; +} + +#ifdef CC_PROTOTYPE_ANSI +static CC_SFILE *sdopen_read (int t) +#else +static CC_SFILE *sdopen_read (t) +int t; +#endif +{ + CC_SFILE *s = (CC_SFILE *) NULL; + + if (t < 0) { + fprintf (stderr, "Invalid descriptor %d\n", t); + return (CC_SFILE *) NULL; + } + + s = CC_SAFE_MALLOC (1, CC_SFILE); + if (s == (CC_SFILE *) NULL) { + return s; + } + sinit (s); + + s->status = SREAD; + s->desc = t; + sprintf (s->fname, "descriptor %d", t); + return s; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_swrite (CC_SFILE *f, unsigned char *buf, int size) +#else +int CCutil_swrite (f, buf, size) +CC_SFILE *f; +unsigned char *buf; +int size; +#endif +{ + int i; + + for (i=0; i<size; i++) { + if (CCutil_swrite_char (f, buf[i])) return -1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_swrite_bits (CC_SFILE *f, unsigned int x, int xbits) +#else +int CCutil_swrite_bits (f, x, xbits) +CC_SFILE *f; +unsigned int x; +int xbits; +#endif +{ + int getbits; + unsigned int v; + + if (!f) return -1; + if (f->status != SWRITE) { + fprintf (stderr, "%s not open for output\n", f->fname); + return -1; + } + while (xbits) { + if (f->bits_in_last_char == 0) { + if (f->chars_in_buffer == CC_SBUFFER_SIZE) { + if (swrite_buffer (f)) return -1; + } + f->buffer[f->chars_in_buffer++] = 0; + f->bits_in_last_char = BITS_PER_CHAR; + } + getbits = f->bits_in_last_char; + if (getbits > xbits) + getbits = xbits; + xbits -= getbits; + f->bits_in_last_char -= getbits; + v = BITRANGE (x, xbits, getbits); + f->buffer[f->chars_in_buffer - 1] |= + v << f->bits_in_last_char; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_swrite_char (CC_SFILE *f, unsigned char x) +#else +int CCutil_swrite_char (f, x) +CC_SFILE *f; +unsigned char x; +#endif +{ + if (!f) return -1; + if (f->status != SWRITE) { + fprintf (stderr, "%s not open for output\n", f->fname); + return -1; + } + + f->bits_in_last_char = 0; + if (f->chars_in_buffer + 1 > CC_SBUFFER_SIZE) { + if (swrite_buffer (f)) return -1; + } + f->buffer[f->chars_in_buffer++] = ((unsigned int) x) & 0xff; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_swrite_string (CC_SFILE *f, unsigned char *s) +#else +int CCutil_swrite_string (f, s) +CC_SFILE *f; +unsigned char *s; +#endif +{ + int rval; + + while (*s) { + rval = CCutil_swrite_char (f, *s); + if (rval) + return rval; + s++; + } + CCutil_swrite_char (f, (unsigned char) 0); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_swrite_short (CC_SFILE *f, unsigned short x) +#else +int CCutil_swrite_short (f, x) +CC_SFILE *f; +unsigned short x; +#endif +{ + if (!f) return -1; + if (f->status != SWRITE) { + fprintf (stderr, "%s not open for output\n", f->fname); + return -1; + } + + f->bits_in_last_char = 0; + if (f->chars_in_buffer + 2 > CC_SBUFFER_SIZE) { + if (swrite_buffer (f)) return -1; + } + + f->buffer[f->chars_in_buffer++] = (((unsigned int) x) >> 8) & 0xff; + f->buffer[f->chars_in_buffer++] = ((unsigned int) x) & 0xff; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_swrite_int (CC_SFILE *f, unsigned int x) +#else +int CCutil_swrite_int (f, x) +CC_SFILE *f; +unsigned int x; +#endif +{ + if (!f) return -1; + if (f->status != SWRITE) { + fprintf (stderr, "%s not open for output\n", f->fname); + return -1; + } + + f->bits_in_last_char = 0; + if (f->chars_in_buffer + 4 > CC_SBUFFER_SIZE) { + if (swrite_buffer (f)) return -1; + } + + f->buffer[f->chars_in_buffer++] = (((unsigned int) x) >> 24) & 0xff; + f->buffer[f->chars_in_buffer++] = (((unsigned int) x) >> 16) & 0xff; + f->buffer[f->chars_in_buffer++] = (((unsigned int) x) >> 8) & 0xff; + f->buffer[f->chars_in_buffer++] = ((unsigned int) x) & 0xff; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_swrite_double (CC_SFILE *f, double x) +#else +int CCutil_swrite_double (f, x) +CC_SFILE *f; +double x; +#endif +{ + unsigned short e; + unsigned int m1; + unsigned int m2; + + e = 128; + + if (x < 0) { + e += 256; + x = -x; + } + + if (x >= 1.0) { +#define MUNCH_HI_EXP(x,e,v,lv) if (x >= v) {e += lv; x *= 1/v;} + MUNCH_HI_EXP(x,e,18446744073709551616.0,64); + MUNCH_HI_EXP(x,e,4294967296.0,32); + MUNCH_HI_EXP(x,e,65536.0, 16); + MUNCH_HI_EXP(x,e,256.0, 8); + MUNCH_HI_EXP(x,e,16.0, 4); + MUNCH_HI_EXP(x,e,4.0, 2); + MUNCH_HI_EXP(x,e,2.0, 1); + x /= 2; e++; + } else if (x < 0.5) { +#define MUNCH_LO_EXP(x,e,v,lv) if (x < 1/v) {e -= lv; x *= v;} + MUNCH_LO_EXP(x,e,18446744073709551616.0,64); + MUNCH_LO_EXP(x,e,4294967296.0,32); + MUNCH_LO_EXP(x,e,65536.0, 16); + MUNCH_LO_EXP(x,e,256.0, 8); + MUNCH_LO_EXP(x,e,16.0, 4); + MUNCH_LO_EXP(x,e,4.0, 2); + MUNCH_LO_EXP(x,e,2.0, 1); + } + x *= 4294967296.0; + m1 = (unsigned int) x; + m2 = (unsigned int) ((x - m1) * 4294967296.0); + if (CCutil_swrite_short (f, e)) return -1; + if (CCutil_swrite_int (f, m1)) return -1; + if (CCutil_swrite_int (f, m2)) return -1; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread (CC_SFILE *f, unsigned char *buf, int size) +#else +int CCutil_sread (f, buf, size) +CC_SFILE *f; +unsigned char *buf; +int size; +#endif +{ + int i; + + for (i=0; i<size; i++) { + if (CCutil_sread_char (f, &buf[i])) return -1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_bits (CC_SFILE *f, unsigned int *x, int xbits) +#else +int CCutil_sread_bits (f, x, xbits) +CC_SFILE *f; +unsigned int *x; +int xbits; +#endif +{ + int getbits; + unsigned int v; + + if (!f) return -1; + if (f->status != SREAD) { + fprintf (stderr, "%s not open for input\n", f->fname); + return -1; + } + *x = 0; + while (xbits) { + if (f->bits_in_last_char == 0) { + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + f->current_buffer_char++; + f->bits_in_last_char = BITS_PER_CHAR; + } + getbits = f->bits_in_last_char; + if (getbits > xbits) + getbits = xbits; + f->bits_in_last_char -= getbits; + xbits -= getbits; + v = BITRANGE ((unsigned int) f->buffer[f->current_buffer_char], + f->bits_in_last_char, getbits); + *x |= v << xbits; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_char (CC_SFILE *f, unsigned char *x) +#else +int CCutil_sread_char (f, x) +CC_SFILE *f; +unsigned char *x; +#endif +{ + if (!f) return -1; + if (f->status != SREAD) { + fprintf (stderr, "%s not open for input\n", f->fname); + return -1; + } + f->bits_in_last_char = 0; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x = ((unsigned char) f->buffer[++f->current_buffer_char]); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_string (CC_SFILE *f, unsigned char *x, int maxlen) +#else +int CCutil_sread_string (f, x, maxlen) +CC_SFILE *f; +unsigned char *x; +int maxlen; +#endif +{ + int i, rval; + + maxlen--; + for (i = 0; i < maxlen; i++, x++) { + rval = CCutil_sread_char (f, x); + if (rval) + return rval; + if (*x == 0) + return 0; + } + *x = 0; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_short (CC_SFILE *f, unsigned short *x) +#else +int CCutil_sread_short (f, x) +CC_SFILE *f; +unsigned short *x; +#endif +{ + if (!f) return -1; + if (f->status != SREAD) { + fprintf (stderr, "%s not open for input\n", f->fname); + return -1; + } + f->bits_in_last_char = 0; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x = ((unsigned short) f->buffer[++f->current_buffer_char]) << 8; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x |= ((unsigned short) f->buffer[++f->current_buffer_char]); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_short_r (CC_SFILE *f, unsigned short *x) +#else +int CCutil_sread_short_r (f, x) +CC_SFILE *f; +unsigned short *x; +#endif +{ + if (!f) return -1; + if (f->status != SREAD) { + fprintf (stderr, "%s not open for input\n", f->fname); + return -1; + } + f->bits_in_last_char = 0; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x = ((unsigned short) f->buffer[++f->current_buffer_char]); + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x |= ((unsigned short) f->buffer[++f->current_buffer_char]) << 8; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_int (CC_SFILE *f, unsigned int *x) +#else +int CCutil_sread_int (f, x) +CC_SFILE *f; +unsigned int *x; +#endif +{ + if (!f) return -1; + if (f->status != SREAD) { + fprintf (stderr, "%s not open for input\n", f->fname); + return -1; + } + f->bits_in_last_char = 0; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x = ((unsigned short) f->buffer[++f->current_buffer_char]) << 24; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x |= ((unsigned short) f->buffer[++f->current_buffer_char]) << 16; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x |= ((unsigned short) f->buffer[++f->current_buffer_char]) << 8; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x |= ((unsigned short) f->buffer[++f->current_buffer_char]); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_int_r (CC_SFILE *f, unsigned int *x) +#else +int CCutil_sread_int_r (f, x) +CC_SFILE *f; +unsigned int *x; +#endif +{ + if (!f) return -1; + if (f->status != SREAD) { + fprintf (stderr, "%s not open for input\n", f->fname); + return -1; + } + f->bits_in_last_char = 0; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x = ((unsigned short) f->buffer[++f->current_buffer_char]); + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x |= ((unsigned short) f->buffer[++f->current_buffer_char]) << 8; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x |= ((unsigned short) f->buffer[++f->current_buffer_char]) << 16; + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + if (sread_buffer (f)) return -1; + } + *x |= ((unsigned short) f->buffer[++f->current_buffer_char]) << 24; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_double (CC_SFILE *f, double *x) +#else +int CCutil_sread_double (f, x) +CC_SFILE *f; +double *x; +#endif +{ + unsigned short e; + unsigned int m1; + unsigned int m2; + + if (CCutil_sread_short (f, &e)) return -1; + if (CCutil_sread_int (f, &m1)) return -1; + if (CCutil_sread_int (f, &m2)) return -1; + + *x = ((m2 / 4294967296.0) + m1) / 4294967296.0; + + if (e >= 256) { + *x = -*x; + e -= 256; + } + + if (e > 128) { +#define UNMUNCH_HI_EXP(x,e,v,lv) if (e >= (unsigned short) (128 + lv)) \ + {e -= lv; x *= v;} + UNMUNCH_HI_EXP(*x,e,18446744073709551616.0,64); + UNMUNCH_HI_EXP(*x,e,4294967296.0,32); + UNMUNCH_HI_EXP(*x,e,65536.0, 16); + UNMUNCH_HI_EXP(*x,e,256.0, 8); + UNMUNCH_HI_EXP(*x,e,16.0, 4); + UNMUNCH_HI_EXP(*x,e,4.0, 2); + UNMUNCH_HI_EXP(*x,e,2.0, 1); + } else if (e < 128) { +#define UNMUNCH_LO_EXP(x,e,v,lv) if (e <= (unsigned short) (128 - lv)) \ + {e += lv; x *= 1/v;} + UNMUNCH_LO_EXP(*x,e,18446744073709551616.0,64); + UNMUNCH_LO_EXP(*x,e,4294967296.0,32); + UNMUNCH_LO_EXP(*x,e,65536.0, 16); + UNMUNCH_LO_EXP(*x,e,256.0, 8); + UNMUNCH_LO_EXP(*x,e,16.0, 4); + UNMUNCH_LO_EXP(*x,e,4.0, 2); + UNMUNCH_LO_EXP(*x,e,2.0, 1); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sread_double_r (CC_SFILE *f, double *x) +#else +int CCutil_sread_double_r (f, x) +CC_SFILE *f; +double *x; +#endif +{ + unsigned short e; + unsigned int m1; + unsigned int m2; + + if (CCutil_sread_short_r (f, &e)) return -1; + if (CCutil_sread_int_r (f, &m1)) return -1; + if (CCutil_sread_int_r (f, &m2)) return -1; + + *x = ((m2 / 4294967296.0) + m1) / 4294967296.0; + + if (e >= 256) { + *x = -*x; + e -= 256; + } + + if (e > 128) { +#define UNMUNCH_HI_EXP(x,e,v,lv) if (e >= (unsigned short) (128 + lv)) \ + {e -= lv; x *= v;} + UNMUNCH_HI_EXP(*x,e,18446744073709551616.0,64); + UNMUNCH_HI_EXP(*x,e,4294967296.0,32); + UNMUNCH_HI_EXP(*x,e,65536.0, 16); + UNMUNCH_HI_EXP(*x,e,256.0, 8); + UNMUNCH_HI_EXP(*x,e,16.0, 4); + UNMUNCH_HI_EXP(*x,e,4.0, 2); + UNMUNCH_HI_EXP(*x,e,2.0, 1); + } else if (e < 128) { +#define UNMUNCH_LO_EXP(x,e,v,lv) if (e <= (unsigned short) (128 - lv)) \ + {e += lv; x *= 1/v;} + UNMUNCH_LO_EXP(*x,e,18446744073709551616.0,64); + UNMUNCH_LO_EXP(*x,e,4294967296.0,32); + UNMUNCH_LO_EXP(*x,e,65536.0, 16); + UNMUNCH_LO_EXP(*x,e,256.0, 8); + UNMUNCH_LO_EXP(*x,e,16.0, 4); + UNMUNCH_LO_EXP(*x,e,4.0, 2); + UNMUNCH_LO_EXP(*x,e,2.0, 1); + } + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sflush (CC_SFILE *f) +#else +int CCutil_sflush (f) +CC_SFILE *f; +#endif +{ + if (!f) return -1; + if (f->status == SREAD) { + f->bits_in_last_char = 0; + return 0; + } else if (f->status == SWRITE) { + return swrite_buffer (f); + } else { + fprintf (stderr, "Buffer %s has invalid status %d\n", f->fname, + f->status); + return -1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_stell (CC_SFILE *f) +#else +int CCutil_stell (f) +CC_SFILE *f; +#endif +{ + if (!f) return -1; + f->bits_in_last_char = 0; + if (f->status == SREAD) { + return f->pos - f->chars_in_buffer + f->current_buffer_char + 1; + } else if (f->status == SWRITE) { + return f->pos + f->chars_in_buffer; + } else { + fprintf (stderr, "Buffer %s has invalid status %d\n", f->fname, + f->status); + return -1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sseek (CC_SFILE *f, int offset) +#else +int CCutil_sseek (f, offset) +CC_SFILE *f; +int offset; +#endif +{ + int curloc; + + if (!f) return -1; + if (CCutil_sflush (f)) return -1; + curloc = CCutil_stell (f); + if (curloc < 0) return curloc; + if (curloc == offset) return 0; + if (lseek (f->desc, offset, SEEK_SET) < 0) { + perror (f->fname); + fprintf (stderr, "Unable to lseek on %s\n", f->fname); + return -1; + } + f->chars_in_buffer = 0; + f->current_buffer_char = -1; + f->pos = offset; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_srewind (CC_SFILE *f) +#else +int CCutil_srewind (f) +CC_SFILE *f; +#endif +{ + return CCutil_sseek (f, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sclose (CC_SFILE *f) +#else +int CCutil_sclose (f) +CC_SFILE *f; +#endif +{ + int retval = 0; + char fbuf_O[CC_SFNAME_SIZE + 32]; + char fbuf_N[CC_SFNAME_SIZE + 32]; + + if (!f) return -1; + + if (f->status == SWRITE && f->chars_in_buffer) { + if (swrite_buffer (f)) retval = -1; + } + + if (f->desc >= 3) { + if (close (f->desc)) { + perror ("close"); + fprintf (stderr, "Unable to close swrite file %s\n", f->fname); + retval = -1; + } + if (f->status == SWRITE) { + sprintf (fbuf_N, "N%s", f->fname); + sprintf (fbuf_O, "O%s", f->fname); + rename (f->fname, fbuf_O); + if (rename (fbuf_N, f->fname)) { + perror (f->fname); + fprintf (stderr, "Couldn't rename %s to %s\n", + fbuf_N, f->fname); + retval = -1; + } + } + } + + CC_FREE (f, CC_SFILE); + + return retval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int swrite_buffer (CC_SFILE *f) +#else +static int swrite_buffer (f) +CC_SFILE *f; +#endif +{ + char *p; + int nleft; + int n; + + if (!f) return -1; + if (f->status != SWRITE) { + fprintf (stderr, "%s not open for output\n", f->fname); + return -1; + } + p = (char *) f->buffer; + nleft = f->chars_in_buffer; + while (nleft) { + n = write (f->desc, p, nleft); + if (n == -1) { + if (errno == EINTR) { + fprintf (stderr, "swrite interrupted, retrying\n"); + continue; + } + perror ("write"); + fprintf (stderr, "swrite of %d chars to %s failed\n", nleft, + f->fname); + return -1; + } + nleft -= n; + p += n; + f->pos += n; + } + f->bits_in_last_char = 0; + f->chars_in_buffer = 0; + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int sread_buffer (CC_SFILE *f) +#else +static int sread_buffer (f) +CC_SFILE *f; +#endif +{ + int n; + + if (!f) return -1; + if (f->status != SREAD) { + fprintf (stderr, "%s not open for input\n", f->fname); + return -1; + } + if (f->current_buffer_char + 1 == f->chars_in_buffer) { + f->chars_in_buffer = 0; + f->current_buffer_char = -1; + } + if (f->chars_in_buffer == CC_SBUFFER_SIZE) { + fprintf (stderr, "sread_buffer for %s when buffer full\n", f->fname); + return 0; + } + +retry: + n = read (f->desc, (char *) f->buffer + f->chars_in_buffer, + CC_SBUFFER_SIZE - f->chars_in_buffer); + + if (n == -1) { + if (errno == EINTR) { + fprintf (stderr, "sread interrupted, retrying\n"); + goto retry; + } + perror ("read"); + fprintf (stderr, "sread failed\n"); + return -1; + } + if (n == 0) { + fprintf (stderr, "sread encountered EOF\n"); + return -1; + } + f->pos += n; + f->chars_in_buffer += n; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void sinit (CC_SFILE *s) +#else +static void sinit (s) +CC_SFILE *s; +#endif +{ + s->status = 0; + s->desc = -1; + s->chars_in_buffer = 0; + s->current_buffer_char = -1; + s->bits_in_last_char = 0; + s->pos = 0; + s->fname[0] = '\0'; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sbits (unsigned int x) +#else +int CCutil_sbits (x) +unsigned int x; +#endif +{ + int i; + int ux = x; + unsigned int b; + + i = 32; + b = ((unsigned int) 1) << 31; + while ((ux & b) == 0 && i > 1) { + b >>= 1; + i--; + } + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sdelete_file (char *fname) +#else +int CCutil_sdelete_file (fname) +char *fname; +#endif +{ + int rval; + + rval = unlink (fname); + if (rval) { + perror (fname); + fprintf (stderr, "unlink: could not delete %s\n", fname); + } + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_sdelete_file_backup (char *fname) +#else +int CCutil_sdelete_file_backup (fname) +char *fname; +#endif +{ + int rval; + char fbuf_O[CC_SFNAME_SIZE + 32]; + + sprintf (fbuf_O, "O%s", fname); + rval = unlink (fbuf_O); + + return rval; +} diff --git a/contrib/blossom/concorde97/UTIL/sortrus.c b/contrib/blossom/concorde97/UTIL/sortrus.c new file mode 100644 index 0000000000000000000000000000000000000000..a5fb7b3e01f6bc11729cf5a616ef218b6449359d --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/sortrus.c @@ -0,0 +1,331 @@ +/****************************************************************************/ +/* */ +/* SORTING ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* DATE: February 24, 1994 */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* char *CCutil_linked_radixsort (char *data, char *datanext, */ +/* char *dataval, int valsize) */ +/* USAGE: */ +/* head = (bar *) CCutil_linked_radixsort ((char *) head, */ +/* (char *) &(head->next), (char *) &(head->val), sizeof (int));*/ +/* Then head is the start of the linked list in increasing order of */ +/* val, with next as the field that links the bars. */ +/* WARNING: DOES NOT HANDLE NEGATIVE NUMBERS PROPERLY. */ +/* */ +/* void CCutil_int_array_quicksort (int *len, int n) */ +/* len - the array to be sorted */ +/* n - the number of elements in len */ +/* Uses quicksort to put len in increasing order. */ +/* */ +/* void CCutil_int_perm_quicksort (int *perm, int *len, int n) */ +/* void CCutil_double_perm_quicksort (int *perm, double *len, int n) */ +/* perm - must be allocated and initialized by the calling routine, */ +/* it will be arranged in increasing order of len. */ +/* n - the number of elements in perm and len. */ +/* */ +/* void CCutil_rselect (int *arr, int l, int r, int m, double *coord) */ +/* arr - permutation that will be rearranged */ +/* l,r - specify the range of arr that we are interested in */ +/* m - is the index into l,r that is the break point for the perm */ +/* coord - gives the keys that determine the ordering */ +/* */ +/****************************************************************************/ + +#include "machdefs.h" +#include "util.h" + +#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) +#define BITS_PER_PASS (8) + +#define NBINS (1<<BITS_PER_PASS) + +#ifdef CC_PROTOTYPE_ANSI + +static void + select_split (int *arr, int n, double v, int *start, int *end, + double *coord), + select_sort (int *arr, int n, double *coord), + select_sort_dsample (double *samp, int n); + +#else + +static void + select_split (), + select_sort (), + select_sort_dsample (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +char *CCutil_linked_radixsort (char *data, char *datanext, char *dataval, + int valsize) +#else +char *CCutil_linked_radixsort (data, datanext, dataval, valsize) +char *data; +char *datanext; +char *dataval; +int valsize; +#endif +{ + int nextoff = datanext - data; + int valoff = dataval - data; + int i; + char *head[NBINS]; + char **tail[NBINS]; + char *p; + char **last; + int j; + int v; + + for (j = valsize - 1; j >= 0; j--) { + for (i = 0; i < NBINS; i++) { + head[i] = (char *) NULL; + tail[i] = &head[i]; + } + for (p = data; p; p = *(char **) (p + nextoff)) { + v = (unsigned char) p[valoff + j]; + *tail[v] = p; + tail[v] = (char **) (p + nextoff); + } + last = &data; + for (i = 0; i < NBINS; i++) { + if (head[i]) { + *last = head[i]; + last = tail[i]; + } + } + *last = (char *) NULL; + } + return data; +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_int_array_quicksort (int *len, int n) +#else +void CCutil_int_array_quicksort (len, n) +int *len; +int n; +#endif +{ + int i, j, temp, t; + + if (n <= 1) + return; + + SWAP (len[0], len[(n - 1)/2], temp); + + i = 0; + j = n; + t = len[0]; + + while (1) { + do i++; while (i < n && len[i] < t); + do j--; while (len[j] > t); + if (j < i) break; + SWAP (len[i], len[j], temp); + } + SWAP (len[0], len[j], temp); + + CCutil_int_array_quicksort (len, j); + CCutil_int_array_quicksort (len + i, n - i); +} + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_int_perm_quicksort (int *perm, int *len, int n) +#else +void CCutil_int_perm_quicksort (perm, len, n) +int *perm; +int *len; +int n; +#endif +{ + int i, j, temp, t; + + if (n <= 1) + return; + + SWAP (perm[0], perm[(n - 1)/2], temp); + + i = 0; + j = n; + t = len[perm[0]]; + + while (1) { + do i++; while (i < n && len[perm[i]] < t); + do j--; while (len[perm[j]] > t); + if (j < i) break; + SWAP (perm[i], perm[j], temp); + } + SWAP (perm[0], perm[j], temp); + + CCutil_int_perm_quicksort (perm, len, j); + CCutil_int_perm_quicksort (perm + i, len, n - i); +} + + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_double_perm_quicksort (int *perm, double *len, int n) +#else +void CCutil_double_perm_quicksort (perm, len, n) +int *perm; +double *len; +int n; +#endif +{ + int i, j, temp; + double t; + + if (n <= 1) + return; + + SWAP (perm[0], perm[(n - 1)/2], temp); + + i = 0; + j = n; + t = len[perm[0]]; + + while (1) { + do i++; while (i < n && len[perm[i]] < t); + do j--; while (len[perm[j]] > t); + if (j < i) break; + SWAP (perm[i], perm[j], temp); + } + SWAP (perm[0], perm[j], temp); + + CCutil_double_perm_quicksort (perm, len, j); + CCutil_double_perm_quicksort (perm + i, len, n - i); +} + + +/********** Median - Select Routines **********/ + +/* NSAMPLES should be odd */ +#define NSAMPLES 3 +#define SORTSIZE 20 + + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_rselect (int *arr, int l, int r, int m, double *coord) +#else +void CCutil_rselect (arr, l, r, m, coord) +int *arr; +int l; +int r; +int m; +double *coord; +#endif +{ + double samplevals[NSAMPLES]; + int i; + int st, en; + int n; + + arr += l; + n = r - l + 1; + m -= l; + + while (n > SORTSIZE) { + for (i = 0; i < NSAMPLES; i++) { + samplevals[i] = coord[arr[CCutil_lprand () % n]]; + } + select_sort_dsample (samplevals, NSAMPLES); + select_split (arr, n, samplevals[(NSAMPLES - 1) / 2], &st, &en, coord); + if (st > m) { + n = st; + } else if (en <= m) { + arr += en; + n -= en; + m -= en; + } else { + return; + } + } + + select_sort (arr, n, coord); + return; +} + +#ifdef CC_PROTOTYPE_ANSI +static void select_split (int *arr, int n, double v, int *start, int *end, + double *coord) +#else +static void select_split (arr, n, v, start, end, coord) +int *arr; +int n; +double v; +int *start, *end; +double *coord; +#endif +{ + int i, j, k; + int t; + + i = 0; + j = k = n; + + while (i < j) { + if (coord[arr[i]] < v) { + i++; + } else if (coord[arr[i]] == v) { + j--; + SWAP (arr[i], arr[j], t); + } else { + j--; + k--; + t = arr[i]; + arr[i] = arr[j]; + arr[j] = arr[k]; + arr[k] = t; + } + } + *start = j; + *end = k; + return; +} + +#ifdef CC_PROTOTYPE_ANSI +static void select_sort (int *arr, int n, double *coord) +#else +static void select_sort (arr, n, coord) +int *arr; +int n; +double *coord; +#endif +{ + int i, j; + int t; + + for (i = 1; i < n; i++) { + t = arr[i]; + for (j = i; j > 0 && coord[arr[j - 1]] > coord[t]; j--) { + arr[j] = arr[j - 1]; + } + arr[j] = t; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void select_sort_dsample (double *samp, int n) +#else +static void select_sort_dsample (samp, n) +double *samp; +int n; +#endif +{ + int i, j; + double t; + + for (i = 1; i < n; i++) { + t = samp[i]; + for (j = i; j > 0 && samp[j - 1] > t; j--) { + samp[j] = samp[j - 1]; + } + samp[j] = t; + } +} diff --git a/contrib/blossom/concorde97/UTIL/urandom.c b/contrib/blossom/concorde97/UTIL/urandom.c new file mode 100644 index 0000000000000000000000000000000000000000..2b6b09049651b4ad2c87f4af0d1a7eb5ac12210d --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/urandom.c @@ -0,0 +1,140 @@ +/***************************************************************************/ +/* */ +/* MACHINE INDEPENDENT RANDOM NUMBER GENERATOR */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: DIMACS (modified for TSP) */ +/* Date: February 7, 1995 (cofeb16) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* void CCutil_sprand (int seed) */ +/* - Call once to initialize the generator. */ +/* int CCutil_lprand (void) */ +/* - Returns an integer in the range 0 to PRANDMAX - 1. */ +/* */ +/* NOTES (from DIMACS): */ +/* This file contains a set of c-language functions for generating */ +/* uniform integers. This is a COMPLETELY PORTABLE generator. It will */ +/* give IDENTICAL sequences of random numbers for any architecture with */ +/* at least 30-bit integers, regardless of the integer representation, */ +/* MAXINT value, or roundoff/truncation method, etc. */ +/* This Truly Remarkable RNG is described more fully in */ +/* J. Bentley's column, ``The Software Exploratorium ''. It is based on */ +/* one in Knuth, Vol 2, Section 3.2.2 (Algorithm A). */ +/* */ +/***************************************************************************/ + + +#include "machdefs.h" +#include "util.h" + +#define PRANDMAX 1000000000 +static int a; +static int b; +static int arr[55]; + + +#ifdef CC_PROTOTYPE_ANSI +void CCutil_sprand (int seed) +#else +void CCutil_sprand (seed) +int seed; +#endif +{ + int i, ii; + int last, next; + + seed %= PRANDMAX; + if (seed < 0) seed += PRANDMAX; + + arr[0] = last = seed; + next = 1; + for (i = 1; i < 55; i++) { + ii = (21 * i) % 55; + arr[ii] = next; + next = last - next; + if (next < 0) + next += PRANDMAX; + last = arr[ii]; + } + a = 0; + b = 24; + for (i = 0; i < 165; i++) + last = CCutil_lprand (); +} + + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_lprand (void) +#else +int CCutil_lprand () +#endif +{ + int t; + + if (a-- == 0) + a = 54; + if (b-- == 0) + b = 54; + + t = arr[a] - arr[b]; + + if (t < 0) + t += PRANDMAX; + + arr[a] = t; + + return t; +} + + +#ifdef TRY_CODE + +/*-----------------------------------------------*/ +/* This is a little driver program so you can */ +/* test the code. */ +/* Typing: a.out 0 3 1 */ +/* should produce */ +/* 921674862 */ +/* 250065336 */ +/* 377506581 */ +/* Typing: a.out 1000000 1 2 */ +/* should produce */ +/* 57265995 */ +/*-----------------------------------------------*/ + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + int i; + int j; + int n; + int m; + int seed; + + if (ac < 4) { + fprintf (stderr, "Usage: #discard #print #seed\n"); + return 0; + } + m = atoi (av[1]); /* Number to discard initially */ + n = atoi (av[2]); /* Number to print */ + seed = atoi (av[3]); /* Seed */ + + CCutil_sprand (seed); + + for (i = 0; i < m; i++) + j = CCutil_lprand (); + for (i = 0; i < n; i++) + printf ("%ld\n", CCutil_lprand ()); + return 0; +} + +#endif /* TRY_CODE */ diff --git a/contrib/blossom/concorde97/UTIL/util.c b/contrib/blossom/concorde97/UTIL/util.c new file mode 100644 index 0000000000000000000000000000000000000000..50e6fa6fbea792e075bea31b822020cc4586a4e8 --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/util.c @@ -0,0 +1,96 @@ +/***************************************************************************/ +/* */ +/* MISCELLANEOUS UTILITY ROUTINES */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: October 12, 1995 */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "macrorus.h" +#include "util.h" + +#ifdef CC_PROTOTYPE_ANSI + +static int + isprime (unsigned int x); + +#else + +static int + isprime (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +unsigned int CCutil_nextprime (unsigned int x) +#else +unsigned int CCutil_nextprime (x) +unsigned int x; +#endif +{ + if (x < 3) return 3; + x |= 1; + while (!isprime (x)) x += 2; + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static int isprime (unsigned int p) +#else +static int isprime (p) +unsigned int p; +#endif +{ + unsigned int i; + + if ((p&1) == 0) return 0; + for (i=3; i*i<=p; i+=2) { + if (p%i == 0) return 0; + } + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +int CCutil_our_gcd (int a, int b) +#else +int CCutil_our_gcd (a, b) +int a; +int b; +#endif +{ + int c; + + if (a < 0) a = -a; + if (b < 0) b = -b; + if (a > b) CC_SWAP (a, b, c); + + while (a) { + c = b % a; + b = a; + a = c; + } + return b; +} + +#ifdef CC_PROTOTYPE_ANSI +char *CCutil_strrchr (char *s, int c) +#else +char *CCutil_strrchr (s, c) +char *s; +int c; +#endif +{ + char *l = (char *) NULL; + + while (*s) { + if (*s == c) l = s; + s++; + } + return l; +} + diff --git a/contrib/blossom/concorde97/UTIL/zeit.c b/contrib/blossom/concorde97/UTIL/zeit.c new file mode 100644 index 0000000000000000000000000000000000000000..3b9a677c1a3cb411028d2118441dfc239e7a186f --- /dev/null +++ b/contrib/blossom/concorde97/UTIL/zeit.c @@ -0,0 +1,92 @@ +/***************************************************************************/ +/* */ +/* TIMING FUNCTIONS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: Summer 1994 (cofeb16) */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* double CCutil_zeit (void) */ +/* - To measure cpu time. */ +/* */ +/* double CCutil_real_zeit (void) */ +/* - To measure wall clock time. */ +/* */ +/* NOTES: */ +/* To use these, set double t = CCutil_zeit (), run the function you */ +/* want to time, then commpute CCutil_zeit () - t. */ +/* */ +/***************************************************************************/ + + +#include "machdefs.h" +#include "util.h" + +#ifdef CC_ZEIT_RUSAGE + +#include <sys/time.h> +#include <sys/resource.h> + +#ifdef CC_PROTOTYPE_ANSI +double CCutil_zeit (void) +#else +double CCutil_zeit () +#endif +{ + struct rusage ru; + + getrusage (RUSAGE_SELF, &ru); + + return ((double) ru.ru_utime.tv_sec) + + ((double) ru.ru_utime.tv_usec) / 1000000.0; +} +#endif /* CC_ZEIT_RUSAGE */ + +#ifdef CC_ZEIT_TIMES + +#include <sys/param.h> +#include <sys/times.h> + +#ifdef CLK_TCK +#define MACHINE_FREQ CLK_TCK +#else +#define MACHINE_FREQ HZ +#endif + +#ifdef CC_PROTOTYPE_ANSI +double CCutil_zeit (void) +#else +double CCutil_zeit () +#endif +{ + struct tms now; + + times (&now); + return ((double) now.tms_utime) / ((double) MACHINE_FREQ); +} +#endif /* CC_ZEIT_TIMES */ + +#ifdef CC_ZEIT_DUMMY + +#ifdef CC_PROTOTYPE_ANSI +double CCutil_zeit (void) +#else +double CCutil_zeit () +#endif +{ + return 0.0; +} +#endif /* CC_ZEIT_DUMMY */ + +#ifdef CC_PROTOTYPE_ANSI +double CCutil_real_zeit (void) +#else +double CCutil_real_zeit () +#endif +{ + return (double) time (0); +} diff --git a/contrib/blossom/concorde97/XSTUFF/Makefile b/contrib/blossom/concorde97/XSTUFF/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..25383be61bb23849300913ea99374e747aac80ac --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Makefile @@ -0,0 +1,73 @@ +SHELL=/bin/sh +ROOT=.. +INCLUDE=$(ROOT)/INCLUDE + +include $(ROOT)/Makefile.conf + +# place overrides for COMFLAGS, OPTFLAGS, and LOADFLAGS here +#OPTFLAGS=-g + +LIB=Xstuff.a +LIBSRCS=Xourallo.c Xgraph.c Xshrink.c Xflow.c Xcututil.c Xcuthash.c \ + Xcclean.c Xcutload.c Xblock.c Xclique.c Xgomhu.c Xblossom.c \ + Xcuts.c Xblobs.c Xstuff.c Xpqnew.c Xnewkids.c Xallcuts.c \ + Xnecklac.c +ALLSRCS=Xtest.c $(LIBSRCS) + +LIBS=$(ROOT)/TSP/tsp.a $(ROOT)/BIGGUY/bigguy.a \ + $(ROOT)/LP/lp.a $(ROOT)/CUT/cut.a \ + $(ROOT)/FMATCH/fmatch.a $(ROOT)/EDGEGEN/edgegen.a \ + $(ROOT)/KDTREE/kdtree.a $(ROOT)/LINKERN/linkern.a \ + $(ROOT)/UTIL/util.a + +all: Xtest $(LIB) + +Xtest: Xtest.$o $(LIB) $(LIBS) + $(CC) $(LDFLAGS) -o $@ $+ $(CPLEX_LIB) -lm + +clean: + -rm -f *.$o $(LIB) Xtest + +include $(INCLUDE)/Makefile.common + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +I=$(INCLUDE) + +Xallcuts.$o: Xallcuts.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xblobs.$o: Xblobs.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xblock.$o: Xblock.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xblossom.$o: Xblossom.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xcclean.$o: Xcclean.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xclique.$o: Xclique.c $(I)/machdefs.h Xsubtour.h Xcutpool.h +Xcuthash.$o: Xcuthash.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xcutload.$o: Xcutload.c $(I)/machdefs.h Xsubtour.h Xcutpool.h +Xcuts.$o: Xcuts.c $(I)/machdefs.h Xsubtour.h Xcutpool.h +Xcututil.$o: Xcututil.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xflow.$o: Xflow.c $(I)/machdefs.h Xsubtour.h Xcutpool.h +Xgomhu.$o: Xgomhu.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xgraph.$o: Xgraph.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h +Xnecklac.$o: Xnecklac.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h Xpq.h Xpqsets.h Xnecklac.h +Xnewkids.$o: Xnewkids.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h Xpq.h Xpqsets.h +Xourallo.$o: Xourallo.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h Xnecklac.h +Xpqnew.$o: Xpqnew.c $(I)/machdefs.h $(I)/util.h Xsubtour.h \ + Xcutpool.h Xpq.h Xpqsets.h +Xshrink.$o: Xshrink.c $(I)/machdefs.h Xsubtour.h Xcutpool.h +Xstuff.$o: Xstuff.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h Xsubtour.h Xcutpool.h $(I)/Xstuff.h +Xtest.$o: Xtest.c $(I)/machdefs.h $(I)/util.h $(I)/tsp.h \ + $(I)/edgegen.h $(I)/bigguy.h $(I)/lp.h $(I)/cut.h \ + $(I)/kdtree.h $(I)/Xstuff.h diff --git a/contrib/blossom/concorde97/XSTUFF/Xallcuts.c b/contrib/blossom/concorde97/XSTUFF/Xallcuts.c new file mode 100644 index 0000000000000000000000000000000000000000..7c72b46992d38efd107cd8fc585afebbc29b6540 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xallcuts.c @@ -0,0 +1,489 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTION: */ +/* void all_tightcuts () */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + magiclabel_nodes (Xnodeptr *S, int v), + test_cut (Xnode *, Xedge *), + found_tight_cut (Xnodeptr *), + unbump_S (Xnodeptr *, Xedge *), + buildpseudonodelist_pathshrink (int), + collect_nodes (Xnode *); + +static int + next_min_cut (Xnodeptr *, Xnode *, Xnode *, Xedge *, Xnodeptr **); + +static double + cut_value (Xnodeptr *S); + +static Xnode + *next_node (Xnode *, Xnode *); + +#else + +static void + magiclabel_nodes (), + test_cut (), + found_tight_cut (), + unbump_S (), + buildpseudonodelist_pathshrink (), + collect_nodes (); + +static int + next_min_cut (); + +static double + cut_value (); + +static Xnode + *next_node (); + +#endif + + +#define EPSILON (0.0005) + +#define TWO 2.0 +#define TWOPLUS (2.0 + EPSILON) +#define TWOMINUS (2.0 - EPSILON) +#define ONEMINUS (1.0 - EPSILON/2) + +static Xclique **cliquelist; +static int *ncliques; +static int quiet = 0; +static Xgraph *G; + +#ifdef CC_PROTOTYPE_ANSI +void Xall_tightcuts (Xgraph *Gin, Xclique **cliquelistin, int *ncliquesin) +#else +void Xall_tightcuts (Gin, cliquelistin, ncliquesin) +Xgraph *Gin; +Xclique **cliquelistin; +int *ncliquesin; +#endif +{ + Xnode *s; + Xedgeptr *ep; + Xedge *e; + int i; + Xclique *c; + Xintptr *p; + + G = Gin; + cliquelist = cliquelistin; + ncliques = ncliquesin; + + buildpseudonodelist_pathshrink (1); + + for (i = 0; i < G->nedges; i++) { + if (G->edgelist[i].x > ONEMINUS) { + c = Xcliquealloc (); + p = Xintptralloc (); + p->this = G->edgelist[i].ends[0] - G->nodelist; + p->next = (Xintptr *) NULL; + c->nodes = p; + p = Xintptralloc (); + p->this = G->edgelist[i].ends[1] - G->nodelist; + p->next = c->nodes; + c->nodes = p; + c->slack = 1.0 - G->edgelist[i].x; + c->next = *cliquelist; + *cliquelist = c; + (*ncliques)++; + } + } + + for (s = G->pseudonodelist->next; s; s = s->next) { + for (ep = s->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (s == e->cends[0]) { + test_cut (s, e); + e->x += 2.5; /* So we won't hit these again */ + } + } + } + + for (s = G->pseudonodelist->next; s; s = s->next) { + Xedgeptr_list_free (s->cadj.head); + s->cadj.head = (Xedgeptr *) NULL; + s->cadj.tail = (Xedgeptr *) NULL; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void test_cut (Xnode *s, Xedge *st) +#else +static void test_cut (s, st) +Xnode *s; +Xedge *st; +#endif +{ + Xnodeptr *S, *smallest; + Xnode *t; + + /* Find all cuts containing edge st (and chose the side missing s) */ + + t = OTHERCURRENTEND (st, s); + smallest = (Xnodeptr *) NULL; + Xadd_nodeptr (&smallest, t); + + /* printf ("Cuts containing (%d, %d)\n", s - G->nodelist, t - G->nodelist); */ + do { + S = smallest; + if (next_min_cut (S, s, t, st, &smallest)) { + found_tight_cut (smallest); + if (!quiet && (cut_value (smallest) < TWOMINUS || + cut_value (smallest) > TWOPLUS)) { + fprintf (stderr, "PROBLEM WITH CUT VALUE %f\n", + cut_value (smallest)); + fflush (stderr); + } + } + Xnodeptr_list_free (S); + } while (smallest); +} + +#ifdef CC_PROTOTYPE_ANSI +static void found_tight_cut (Xnodeptr *smallest) +#else +static void found_tight_cut (smallest) +Xnodeptr *smallest; +#endif +{ + int count; + Xnodeptr *np, *np2; + int match; + int i; + Xclique *c; + Xintptr *p; + + for (i = 0; i < G->nnodes; i++) { + G->nodelist[i].mark = 0; + } + + for (count = 0, np = smallest; np; np = np->next) { + for (np2 = np->this->base.head; np2; np2 = np2->next) { + count++; + np2->this->mark = 1; + } + } + + if (count != (G->nnodes - 1) && count != 1) { + if (count > G->nnodes / 2) + match = 0; + else + match = 1; + c = Xcliquealloc (); + c->nodes = (Xintptr *) NULL; + for (i = 0; i < G->nnodes; i++) { + if (G->nodelist[i].mark == match) { + p = Xintptralloc (); + p->this = i; + p->next = c->nodes; + c->nodes = p; + } + } + c->slack = 0.0; + c->next = *cliquelist; + *cliquelist = c; + (*ncliques)++; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int next_min_cut (Xnodeptr *S, Xnode *s, Xnode *t, Xedge *st, Xnodeptr **smallest) +#else +static int next_min_cut (S, s, t, st, smallest) +Xnodeptr *S; +Xnode *s, *t; +Xedge *st; +Xnodeptr **smallest; +#endif +{ + Xnodeptr *np, *nlist; + Xnode *n; + Xedgeptr *ep, *delta; + Xedge *e; + int least_count, count, label; + double val; + + *smallest = (Xnodeptr *) NULL; + + G->magicnum++; + for (np = S; np; np = np->next) { + if (np->this == s) { + printf ("%d in S\n", (int) (s - G->nodelist)); + return 0; + } + np->this->magiclabel = G->magicnum; + } + delta = (Xedgeptr *) NULL; + for (np = S; np; np = np->next) { + n = np->this; + for (ep = n->cadj.head; ep; ep = ep->next) { + if ((e = ep->this) == st) + continue; + if ((OTHERCURRENTEND (e, n))->magiclabel == G->magicnum) { + if (e->x < 4.0) + e->x += 4.0; + } else + Xadd_edgeptr (&delta, e); + } + } + + if (Xflow (G, s, t, TWOPLUS) >= TWOPLUS) { + unbump_S (S, st); + Xedgeptr_list_free (delta); + return 0; + } + least_count = G->nnodes + 1; + for (ep = delta; ep; ep = ep->next) { + e = ep->this; + e->x += 4.0; + if (Xmincut (G, s, t, TWOPLUS, &val, &label)) { + count = 0; + nlist = (Xnodeptr *) NULL; + for (n = G->pseudonodelist->next; n; n = n->next) + if (n->magiclabel == label) { + count++; + Xadd_nodeptr (&nlist, n); + } + if (count < least_count) { + least_count = count; + if (*smallest) + Xnodeptr_list_free (*smallest); + *smallest = nlist; + } else + Xnodeptr_list_free (nlist); + } + e->x -= 4.0; + } + + unbump_S (S, st); + Xedgeptr_list_free (delta); + + return (*smallest != (Xnodeptr *) NULL); +} + +#ifdef CC_PROTOTYPE_ANSI +static void unbump_S (Xnodeptr *S, Xedge *st) +#else +static void unbump_S (S, st) +Xnodeptr *S; +Xedge *st; +#endif +{ + Xnodeptr *np; + Xnode *n; + Xedgeptr *ep; + Xedge *e; + + magiclabel_nodes (S, ++G->magicnum); + for (np = S; np; np = np->next) { + n = np->this; + for (ep = n->cadj.head; ep; ep = ep->next) { + if ((e = ep->this) == st) + continue; + if ((OTHERCURRENTEND (e, n))->magiclabel == G->magicnum) { + if (e->x >= 4.0) + e->x -= 4.0; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void buildpseudonodelist_pathshrink (int all) +#else +static void buildpseudonodelist_pathshrink (all) +int all; +#endif +{ + /* modified 2/10 to compress paths of ones */ + int i; + Xnode *n; + Xedge *e; + Xedgeptr *e1; + static Xnode pseudodummy; + Xnode *nprev; + Xnode *n2; + + for (i = 0; i < G->nnodes; i++) { + G->nodelist[i].Tmark = 0; + G->nodelist[i].tnext = (Xnode *) NULL; + } + + for (i = 0; i < G->nedges; i++) { + if (G->edgelist[i].x > ONEMINUS) { + G->edgelist[i].ends[0]->Tmark++; + G->edgelist[i].ends[1]->Tmark++; + } + } + + G->pseudonodelist = &pseudodummy; + pseudodummy.prev = (Xnode *) NULL; + pseudodummy.next = (Xnode *) NULL; + nprev = G->pseudonodelist; + for (i = 0, n = G->nodelist; i < G->nnodes; i++, n++) { + n->base.head = Xnodeptralloc (); + n->base.tail = n->base.head; + n->base.head->next = (Xnodeptr *) NULL; + n->base.head->this = n; + if (n->Tmark == 1) { + collect_nodes (n); + } + n->cadj.head = n->cadj.tail = (Xedgeptr *) NULL; + if (n->Tmark != 2) { + n->prev = nprev; + nprev->next = n; + nprev = n; + n->tnext = n; + } + } + for (i=0; i<G->nnodes; i++) { + if (G->nodelist[i].tnext == (Xnode *) NULL) { + printf ("ALLCUTS GRAPH CONTAINS CYCLE\n"); + n = next_node (&G->nodelist[i], (Xnode *) NULL); + n2 = next_node (&G->nodelist[i], n); /* this trusts that next_node is consistent between calls */ + G->nodelist[i].Tmark = 1; + n2->Tmark = 1; + collect_nodes (&G->nodelist[i]); + G->nodelist[i].prev = nprev; + nprev->next = &G->nodelist[i]; + nprev = &G->nodelist[i]; + G->nodelist[i].tnext = &G->nodelist[i]; + } + } + nprev->next = (Xnode *) NULL; + + for (i = G->nedges, e = G->edgelist; i; i--, e++) { + if ((all || e->x > 0.0) && e->ends[0]->tnext != e->ends[1]->tnext) { + e->stay = 1; + e->cends[0] = e->ends[0]->tnext; + e->cends[1] = e->ends[1]->tnext; + e1 = Xedgeptralloc (); + e1->next = (e->cends[0])->cadj.head; + e1->this = e; + (e->cends[0])->cadj.head = e1; + if ((e->cends[0])->cadj.tail == (Xedgeptr *) NULL) { + (e->cends[0])->cadj.tail = e1; + } + e1 = Xedgeptralloc (); + e1->next = (e->cends[1])->cadj.head; + e1->this = e; + (e->cends[1])->cadj.head = e1; + if ((e->cends[1])->cadj.tail == (Xedgeptr *) NULL) { + (e->cends[1])->cadj.tail = e1; + } + } else { + e->stay = 0; + } + } + G->npseudonodes = G->nnodes; +} + +#ifdef CC_PROTOTYPE_ANSI +static Xnode *next_node (Xnode *n, Xnode *nold) +#else +static Xnode *next_node (n, nold) +Xnode *n; +Xnode *nold; +#endif +{ + Xedgeptr *ep; + + for (ep = n->adj.head; ep; ep = ep->next) { + if (ep->this->x > ONEMINUS) { + if (ep->this->ends[0] != n && ep->this->ends[0] != nold) { + return ep->this->ends[0]; + } else if (ep->this->ends[1] != n && ep->this->ends[1] != nold) { + return ep->this->ends[1]; + } + } + } + return (Xnode *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static void collect_nodes (Xnode *n) +#else +static void collect_nodes (n) +Xnode *n; +#endif +{ + Xnode *nold; + Xnode *nnew; + Xnode *ncur; + Xnodeptr *np; + + ncur = n; + nold = (Xnode *) NULL; + + while ((nnew = next_node (ncur, nold)) && nnew->Tmark == 2) { + nold = ncur; + ncur = nnew; + ncur->tnext = n; + np = Xnodeptralloc (); + np->this = ncur; + np->next = (Xnodeptr *) NULL; + if (!n->base.tail) { + n->base.tail = n->base.head = np; + } else { + n->base.tail->next = np; + n->base.tail = np; + } + } + if (!nnew) { + fprintf (stderr, "Path vanished\n"); + exit (1); + } + nnew->Tmark = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static double cut_value (Xnodeptr *S) +#else +static double cut_value (S) +Xnodeptr *S; +#endif +{ + double val = 0.0; + Xnodeptr *np; + Xnode *n; + Xedgeptr *ep; + Xedge *e; + + magiclabel_nodes (S, ++(G->magicnum)); + for (np = S; np; np = np->next) { + n = np->this; + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (OTHERCURRENTEND (e, n)->magiclabel != G->magicnum) + val += e->x; + } + } + return val; +} + +#ifdef CC_PROTOTYPE_ANSI +static void magiclabel_nodes (Xnodeptr *S, int v) +#else +static void magiclabel_nodes (S, v) +Xnodeptr *S; +int v; +#endif +{ + Xnodeptr *np; + + for (np = S; np; np = np->next) + np->this->magiclabel = v; +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xblobs.c b/contrib/blossom/concorde97/XSTUFF/Xblobs.c new file mode 100644 index 0000000000000000000000000000000000000000..a13429a7dfb7bb55a00f29e5fe91e7b66e5abb1e --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xblobs.c @@ -0,0 +1,1293 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void */ +/* Xpancakex (Xgraph *G, double *x), */ +/* Xfreepancake (void), */ +/* Xshrinksmallblobs (Xgraph *G, int rnum, int biggest), */ +/* Xtightblobs (Xgraph *G); */ +/* */ +/* int */ +/* Xblobsviolated (Xgraph *G, Xcplane **list ); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + +typedef struct pannode { + struct panedge **edgelist; + struct panedge **goodedge; + int degree; + struct vaseknode *vptr; +} pannode; + +typedef struct panedge { + double panweight; + pannode *ends[2]; + int elim; + int tag; + struct vaseknode *a[2]; + struct vaseknode *roof; + struct vaseknode *top; + struct panedge *next; + double rc; + double realrc; +} panedge; + +typedef struct vaseknode { + struct vaseknode *parent; + struct vaseknode *child; + struct vaseknode *sibling; + struct vaseknode *anc; + struct vaseknode *ptr; + struct vaseknode *qtr; + struct vaseknode *listpointer; + int b; + int d; + int n; + int tag; + int fringe; + double y; + double w; + double mult; + struct panedge *tree; + struct panedge *junk; + struct triomino *adj; + struct triomino *scan; +} vaseknode; + +typedef struct triomino { + panedge *edge; + vaseknode *end; + struct triomino *next; +} triomino; + + +static panedge **panedgespace, *panedgelist; +static pannode *pannodelist; + + +#define XPOSITIVE 1 + +#define VNODEALLOC(vrequest) { \ + if (vnodestack == (vaseknode *) NULL) { \ + printf ("Ran out of vnode supply\n"); \ + exit (1); \ + } \ + vrequest = vnodestack; \ + vnodestack = vnodestack->ptr; \ + } + +#define VNODEFREE(vreturn) { \ + vreturn->ptr = vnodestack; \ + vnodestack = vreturn; \ + } + +#define TRIALLOC(trequest) { \ + trequest = tristack; \ + tristack = tristack->next; \ + } + +#define TRIFREE(treturn) { \ + treturn->next = tristack; \ + tristack = treturn; \ + } + +#define XSHORT 1000 +#define XFEW 1 + +#ifdef CC_PROTOTYPE_ANSI + +static void + panalloc (Xgraph *G), + buildpanadjlist (Xgraph *G), + pancakemain (Xgraph *G), + initpancake (Xgraph *G), + buildfirsttree (Xgraph *G), + decompositiontree (Xgraph *G), + initdecompositiontree (Xgraph *G), + drop (panedge *e, vaseknode *x), + throw (vaseknode *x, vaseknode *y, panedge *e), + trickledown (int i), + hookup (vaseknode *parent, vaseknode *child), + distribute (void), + initdistribute (void), + split (vaseknode *a), + bruteforce (panedge *e), + update (panedge *e), + dealwith (panedge *e, vaseknode **pa), + attach (panedge *e), + magicrc (void), + labeler (Xgraph *G, vaseknode *p), + shrinkblob (Xgraph *G, vaseknode *v); + +static int + ssblob (Xgraph *G, vaseknode *v, int rnum, int biggest, int *shrunk); + +static double + min2 (panedge **elist), + findbound (void), + blnode (Xgraph *G, Xcplane **list, vaseknode *v, int *hit), + tblob (Xgraph *G, vaseknode *v, int *count); + +static vaseknode + *anc (vaseknode *v), + *vsmall (Xgraph *G, vaseknode *p), + *newcomp (vaseknode *v, double w); + +#else + +static void + panalloc (), + buildpanadjlist (), + pancakemain (), + initpancake (), + buildfirsttree (), + decompositiontree (), + initdecompositiontree (), + drop (), + throw (), + trickledown (), + hookup (), + distribute (), + initdistribute (), + split (), + bruteforce (), + update (), + dealwith (), + attach (), + magicrc (), + labeler (), + shrinkblob (); + +static int + ssblob (); + +static double + min2 (), + findbound (), + blnode (), + tblob (); + +static vaseknode + *anc (), + *vsmall (), + *newcomp (); + +#endif + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void + dumpwork (void), + dumpdecompositiontree (Xgraph *G), + dumpvaseknodes (Xgraph *G, vaseknode *pv), + printvaseknode (vaseknode *v); +#else +static void + dumpdecompositiontree (), + dumpwork (), + dumpvaseknodes (), + printvaseknode (); +#endif +#endif /* DEBUG */ + +#define XMAGICNODE 0 + +static int step = 0; +static vaseknode *root; +static vaseknode *vpannodes = (vaseknode *) NULL, *vnodehit; +static vaseknode *head, *tail; +static vaseknode *vnodestack = (vaseknode *) NULL; +static triomino *trisupply, *tristack; +static panedge *work; +static panedge **vheap; +static int vheapend = 0; +static int componentcount = 0; + + +#ifdef CC_PROTOTYPE_ANSI +void Xpancakex (Xgraph *G, double *x) +#else +void Xpancakex (G, x) +Xgraph *G; +double *x; +#endif +{ + double *dp; + int i; + panedge *pm; + + panalloc (G); + Xloadx (G, x); + + for (i = G->nedges, pm = panedgelist, dp = x; i; i--, pm++) + pm->panweight = -(*dp++); + + pancakemain (G); +} + +#ifdef CC_PROTOTYPE_ANSI +static void panalloc (Xgraph *G) +#else +static void panalloc (G) +Xgraph *G; +#endif +{ + int i; + Xedge *pe; + panedge *pa; + + pannodelist = CC_SAFE_MALLOC (G->nnodes + 1000, pannode); + panedgelist = CC_SAFE_MALLOC (G->nedges + 1000, panedge); + if (!pannodelist || !panedgelist) { + fprintf (stderr, "out of memory in panalloc\n"); + exit (1); + } + + for (i = G->nedges, pa = panedgelist, pe = G->edgelist; i; + i--, pa++, pe++) { + pa->ends[0] = pannodelist + (pe->ends[0] - G->nodelist); + pa->ends[1] = pannodelist + (pe->ends[1] - G->nodelist); + } + + buildpanadjlist (G); +} + + +#ifdef CC_PROTOTYPE_ANSI +static void buildpanadjlist (Xgraph *G) +#else +static void buildpanadjlist (G) +Xgraph *G; +#endif +{ + int i, *degrees, *pint; + pannode *pv; + panedge *pa, **edgespace; + Xedge *pe; + + edgespace = CC_SAFE_MALLOC (G->nnodes + (G->nedges * 2) + 1000, panedge *); + degrees = CC_SAFE_MALLOC (G->nnodes + 1000, int); + if (!edgespace || !degrees) { + fprintf (stderr, "out of memory in buildpadadjlist\n"); + exit (1); + } + panedgespace = edgespace; + + for (i = 0, pint = degrees; i < G->nnodes; i++) + *pint++ = 0; + + for (i = 0, pe = G->edgelist; i < G->nedges; i++, pe++) { + degrees[pe->ends[0] - G->nodelist]++; + degrees[pe->ends[1] - G->nodelist]++; + } + + for (i = 0, pint = degrees, pv = pannodelist; i < G->nnodes; + i++, pint++, pv++) { + if (*pint) { + pv->edgelist = pv->goodedge = edgespace; + edgespace += *pint + 1; + } else + pv->edgelist = pv->goodedge = (panedge **) NULL; + } + + for (i = 0, pa = panedgelist; i < G->nedges; i++, pa++) { + *(pa->ends[0]->goodedge++) = pa; + *(pa->ends[1]->goodedge++) = pa; + } + + for (i = 0, pv = pannodelist; i < G->nnodes; i++, pv++) + *(pv->goodedge) = (panedge *) NULL; + + CC_FREE (degrees, int); +} + +#ifdef CC_PROTOTYPE_ANSI +static void pancakemain (Xgraph *G) +#else +static void pancakemain (G) +Xgraph *G; +#endif +{ + initpancake (G); + buildfirsttree (G); + findbound (); + /* printf ("decompositiontree: %lf\n", findbound ()); */ +} + +#ifdef CC_PROTOTYPE_ANSI +static void initpancake (Xgraph *G) +#else +static void initpancake (G) +Xgraph *G; +#endif +{ + int i; + pannode *pn; + vaseknode *pv; + triomino *pt; + + vpannodes = CC_SAFE_MALLOC ((2 * G->nnodes) - 1 + 1000, vaseknode); + if (!vpannodes) { + fprintf (stderr, "out of memory in initpancake\n"); + exit (1); + } + + for (i = G->nnodes, pn = pannodelist, pv = vpannodes; i; i--, pn++, pv++) { + pv->parent = (vaseknode *) NULL; + pv->child = (vaseknode *) NULL; + pv->sibling = (vaseknode *) NULL; + pv->adj = (triomino *) NULL; + pv->n = 0; + pv->b = 1; + pv->anc = pv; + pv->junk = (panedge *) NULL; + pv->w = XBIGNEG; + pv->y = 0.0; + pn->vptr = pv; + } + + vnodestack = vpannodes + G->nnodes; + for (i = G->nnodes - 2, pv = vnodestack; i; i--, pv++) + pv->ptr = pv + 1; + pv->ptr = (vaseknode *) NULL; + + trisupply = CC_SAFE_MALLOC (2 * G->nedges + 1000, triomino); + if (!trisupply) { + fprintf (stderr, "out of memory in initpancake\n"); + exit (1); + } + + tristack = trisupply; + for (i = 2 * G->nedges - 1, pt = tristack; i; i--, pt++) + pt->next = pt + 1; + + VNODEALLOC (head); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xfreepancake (void) +#else +void Xfreepancake () +#endif +{ + CC_FREE (vpannodes, vaseknode); + CC_FREE (trisupply, triomino); + CC_FREE (vheap, panedge *); + CC_FREE (pannodelist, pannode); + CC_FREE (panedgelist, panedge); + CC_FREE (panedgespace, panedge *); +} + +#ifdef CC_PROTOTYPE_ANSI +static void buildfirsttree (Xgraph *G) +#else +static void buildfirsttree (G) +Xgraph *G; +#endif +{ + vaseknode *p; + double parw; + vaseknode *q; + + decompositiontree (G); + distribute (); + + + head->ptr = tail = root; + p = head; + do { + p = p->ptr; + parw = p->w; + for (q = p->child; q != (vaseknode *) NULL; q = q->sibling) { + q->mult = parw - q->w; + if (q->child != (vaseknode *) NULL) { + tail->ptr = q; + tail = q; + } + } + } while (p != tail); + root->mult = -root->w; + + magicrc (); +} + +#ifdef CC_PROTOTYPE_ANSI +static void decompositiontree (Xgraph *G) +#else +static void decompositiontree (G) +Xgraph *G; +#endif +{ + panedge *e; + int i; + double w, ub; + vaseknode *x, *y; + + initdecompositiontree (G); + + for (componentcount = G->nnodes - 2; componentcount;) { + for (;;) { + e = *vheap; + *vheap = vheap[vheapend--]; + trickledown (0); + x = anc (e->ends[0]->vptr); + y = anc (e->ends[1]->vptr); + if (x != y) + break; + drop (e, x); + } + + w = e->panweight; + throw (x, y, e); + + ub = w + 0.01; + + while (vheapend >= 0 && (e = *vheap)->panweight < ub) { + *vheap = vheap[vheapend--]; + trickledown (0); + x = anc (e->ends[0]->vptr); + y = anc (e->ends[1]->vptr); + if (x != y) + throw (x, y, e); + else + drop (e, x); + } + + for (; vnodehit != (vaseknode *) NULL; vnodehit = vnodehit->ptr) + if (vnodehit->n) + root = newcomp (vnodehit, w); + } + i = vheapend + 1; + while (i) + drop (vheap[--i], root); +} + +#ifdef CC_PROTOTYPE_ANSI +static void initdecompositiontree (Xgraph *G) +#else +static void initdecompositiontree (G) +Xgraph *G; +#endif +{ + int i; + panedge *pe, **ph; + pannode *pm; + + vnodehit = (vaseknode *) NULL; + work = (panedge *) NULL; + + for (i = G->nedges, pe = panedgelist; i; i--, pe++) + pe->tag = XFALSE; + + vheap = CC_SAFE_MALLOC (G->nedges + 1000, panedge *); + if (!vheap) { + fprintf (stderr, "out of memory in initdecompositiontree\n"); + exit (1); + } + + pm = pannodelist + XMAGICNODE; + for (i = G->nedges, pe = panedgelist, ph = vheap; i; i--, pe++) + if (pe->ends[0] != pm && pe->ends[1] != pm) + *(ph++) = pe; + else + pe->rc = pe->panweight; + + vheapend = (ph - vheap) - 1; + for (i = vheapend / 2; i >= 0; i--) + trickledown (i); +} + +#ifdef CC_PROTOTYPE_ANSI +static void drop (panedge *e, vaseknode *x) +#else +static void drop (e, x) +panedge *e; +vaseknode *x; +#endif +{ + e->a[0] = e->ends[0]->vptr; + e->a[1] = e->ends[1]->vptr; + e->roof = x; + e->rc = XPOSITIVE; + e->next = work; + work = e; +} + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void dumpwork (void) +#else +static void dumpwork () +#endif +{ + panedge *pe; + + printf ("WORK: "); + for (pe = work; pe != (panedge *) NULL; pe = pe->next) + printf ("(%d, %d) -> ", pe->ends[0] - pannodelist, + pe->ends[1] - pannodelist); + printf ("NULL\n"); + fflush (stdout); +} +#endif /* DEBUG */ + + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void dumpdecompositiontree (Xgraph *G) +#else +static void dumpdecompositiontree (G) +Xgraph *G; +#endif +{ + int i; + pannode *pn; + + printf ("Nodes of the decomposition tree:\n"); + for (i = 0, pn = pannodelist; i < G->nnodes; i++, pn++) + if (pn != pannodelist + XMAGICNODE) + dumpvaseknodes (G, pn->vptr); + printf ("\n"); + fflush (stdout); +} +#endif /* DEBUG */ + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void dumpvaseknodes (Xgraph *G, vaseknode *pv) +#else +static void dumpvaseknodes (G, pv) +Xgraph *G; +vaseknode *pv; +#endif +{ + /* dump vaseknodes whose smallest real pannode is v */ + + vaseknode *p; + + for (p = pv->parent; p != (vaseknode *) NULL && vsmall (G, p) == pv; + p = p->parent) { + printf ("Node %d: ", p - vpannodes); + printvaseknode (p); + printf ("\n"); + } + fflush (stdout); +} +#endif /* DEBUG */ + +#ifdef CC_PROTOTYPE_ANSI +static vaseknode *vsmall (Xgraph *G, vaseknode *p) +#else +static vaseknode *vsmall (G, p) +Xgraph *G; +vaseknode *p; +#endif +{ + vaseknode *p1, *p2, *psmall = vpannodes + G->nnodes; + + if (p->child == (vaseknode *) NULL) + return p; + for (p1 = p->child; p1 != (vaseknode *) NULL; p1 = p1->sibling) + if ((p2 = vsmall (G, p1)) < psmall) + psmall = p2; + return psmall; +} + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void printvaseknode (vaseknode *p) +#else +static void printvaseknode (p) +vaseknode *p; +#endif +{ + vaseknode *p1; + panedge *pe; + + if (p->child != (vaseknode *) NULL) { + for (p1 = p->child; p1 != (vaseknode *) NULL; p1 = p1->sibling) + printf ("%d ", p1 - vpannodes); + } else + printf ("%d ", p - vpannodes); + printf ("mult: %f ", p->mult); + printf ("parent: %d ", p->parent - vpannodes); + printf ("depth: %d ", p->d); + printf ("b: %d ", p->b); + printf ("junk: "); + for (pe = p->junk; pe != (panedge *) NULL; pe = pe->next) + printf ("(%d, %d) ", pe->ends[0] - pannodelist, + pe->ends[1] - pannodelist); + fflush (stdout); +} +#endif /* DEBUG */ + +#ifdef CC_PROTOTYPE_ANSI +static void throw (vaseknode *x, vaseknode *y, panedge *e) +#else +static void throw (x, y, e) +vaseknode *x, *y; +panedge *e; +#endif +{ + e->a[0] = x; + e->a[1] = y; + + e->rc = 0.0; + attach (e); + + if (!(x->n)) { + x->n = 1; + x->ptr = vnodehit; + vnodehit = x; + } + if (!(y->n)) { + y->n = 1; + y->ptr = vnodehit; + vnodehit = y; + } + e->next = work; + work = e; +} + +#ifdef CC_PROTOTYPE_ANSI +static vaseknode *anc (vaseknode *v) +#else +static vaseknode *anc (v) +vaseknode *v; +#endif +{ + vaseknode *hand, *va; + + hand = v; + while (hand != hand->anc) + hand = hand->anc; + + va = hand; + for (hand = v; hand != va; hand = hand->anc) + hand->anc = va; + + return va; +} + +#ifdef CC_PROTOTYPE_ANSI +static void trickledown (int i) +#else +static void trickledown (i) +int i; +#endif +{ + panedge *memo; + int k, minchild; + + memo = vheap[i]; + + while ((k = (2 * i) + 2) <= vheapend) { + minchild = (vheap[k - 1]->panweight <= vheap[k]->panweight ? k - 1 : k); + + if (memo->panweight > vheap[minchild]->panweight) { + vheap[i] = vheap[minchild]; + i = minchild; + } else { + vheap[i] = memo; + return; + } + } + if (k - 1 == vheapend && memo->panweight > vheap[vheapend]->panweight) { + vheap[i] = vheap[vheapend]; + i = vheapend; + } + vheap[i] = memo; +} + +#ifdef CC_PROTOTYPE_ANSI +static vaseknode *newcomp (vaseknode *v, double w) +#else +static vaseknode *newcomp (v, w) +vaseknode *v; +double w; +#endif +{ + vaseknode *new, *stack; + triomino *t; + + VNODEALLOC (new); + new->parent = (vaseknode *) NULL; + new->child = (vaseknode *) NULL; + new->sibling = (vaseknode *) NULL; + new->anc = new; + new->n = 0; + new->b = 0; + new->w = w; + new->adj = (triomino *) NULL; + new->junk = (panedge *) NULL; + new->tag = XFALSE; + + hookup (new, v); + v->qtr = (vaseknode *) NULL; + + do { + stack = v->qtr; + for (t = v->adj; t != (triomino *) NULL; t = t->next) { + t->edge->roof = new; + v = t->end; + if (v->n) { + v->qtr = stack; + stack = v; + hookup (new, v); + componentcount--; + } + } + } while ((v = stack) != (vaseknode *) NULL); + + return new; +} + +#ifdef CC_PROTOTYPE_ANSI +static void hookup (vaseknode *parent, vaseknode *child) +#else +static void hookup (parent, child) +vaseknode *parent, *child; +#endif +{ + child->n = 0; + child->parent = parent; + child->anc = parent; + child->sibling = parent->child; + parent->child = child; +} + +#ifdef CC_PROTOTYPE_ANSI +static void distribute (void) +#else +static void distribute () +#endif +{ + vaseknode *active; + panedge *e, *f; + + initdistribute (); + active = (vaseknode *) NULL; + root->n = 0; + + for (e = work, work = (panedge *) NULL; e != (panedge *) NULL; e = f) { + f = e->next; + e->top = root; + dealwith (e, &active); + } + + while (work) { + for (; active != (vaseknode *) NULL; active = active->ptr) + if (active->n < XFEW) + active->n = -1; + else { + active->n = 0; + split (active); + } + for (e = work, work = (panedge *) NULL; e != (panedge *) NULL; + e = f) { + f = e->next; + if (e->top->n >= 0) { + update (e); + dealwith (e, &active); + } else + bruteforce (e); + } + step = step / 2; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void initdistribute (void) +#else +static void initdistribute () +#endif +{ + vaseknode *stack, *finger, *x; + int maxd, twice, d; + + maxd = 0; + + root->d = 0; + root->ptr = (vaseknode *) NULL; + + for (finger = root; finger != (vaseknode *) NULL; finger = stack) { + stack = finger->ptr; + finger->anc = root; + if ((x = finger->child) != (vaseknode *) NULL) { + d = finger->d + 1; + do { + x->d = d; + x->ptr = stack; + stack = x; + x = x->sibling; + } while (x != (vaseknode *) NULL); + if (d > maxd) + maxd = d; + } + } + step = 1; + twice = 2; + while (twice < maxd) { + step = twice; + twice = step + step; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void split (vaseknode *a) +#else +static void split (a) +vaseknode *a; +#endif +{ + int mid, bot; + vaseknode *stack, *hand, *foot, *memo, *x; + + mid = step + a->d; + bot = step + mid; + + a->qtr = (vaseknode *) NULL; + for (hand = a; hand != (vaseknode *) NULL; hand = stack) { + stack = hand->qtr; + if (hand->d == mid) { + memo = hand->qtr; + hand->qtr = (vaseknode *) NULL; + for (foot = hand; foot != (vaseknode *) NULL; foot = stack) { + stack = foot->qtr; + foot->anc = hand; + if (foot->d != bot) { + for (x = foot->child; x != (vaseknode *) NULL; + x = x->sibling) { + x->qtr = stack; + stack = x; + } + } + } + hand->qtr = memo; + } else + for (x = hand->child; x != (vaseknode *) NULL; x = x->sibling) { + x->qtr = stack; + stack = x; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void bruteforce (panedge *e) +#else +static void bruteforce (e) +panedge *e; +#endif +{ + vaseknode *x, *y, *nx, *ny; + int dx, dy; + + x = e->a[0]; + y = e->a[1]; + + if (x == y) { + printf ("Tough luck Pal 1.\n"); + exit (1); + } + dx = x->d; + dy = y->d; + + while (dx > dy) { + x = x->parent; + dx--; + } + if (x == y) { + printf ("Tough luck Pal 2.\n"); + exit (1); + } + while (dy > dx) { + y = y->parent; + dy--; + } + if (x == y) { + printf ("Tough luck Pal 3.\n"); + exit (1); + } + nx = x->parent; + ny = y->parent; + while (nx != ny) { + x = nx; + y = ny; + nx = x->parent; + ny = y->parent; + } + + e->a[0] = x; + e->a[1] = y; + + e->roof = nx; + /* if (e->rc > 0.0) { e->next = nx->junk; nx->junk = e; } else { e->tag = + * XFALSE; attach (e); } */ + e->next = nx->junk; + nx->junk = e; +} + +#ifdef CC_PROTOTYPE_ANSI +static void update (panedge *e) +#else +static void update (e) +panedge *e; +#endif +{ + vaseknode *x, *y, *v; + + x = e->a[0]->anc; + y = e->a[1]->anc; + v = e->top; + + if (x == v) { + if (y != v) + e->a[1] = y; + } else if (y == v) + e->a[0] = x; + else if (x != y) { + e->a[0] = x; + e->a[1] = y; + } else { + e->top = x; + if (x->d > e->roof->d) + e->roof = x; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void dealwith (panedge *e, vaseknode **pa) +#else +static void dealwith (e, pa) +panedge *e; +vaseknode **pa; +#endif +{ + if ((e->roof->d) - (e->a[0]->d) < XSHORT && + (e->roof->d) - (e->a[1]->d) < XSHORT) + bruteforce (e); + else { + e->next = work; + work = e; + if (!e->top->n) { + e->top->ptr = *pa; + *pa = e->top; + } + (e->top->n)++; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void attach (panedge *e) +#else +static void attach (e) +panedge *e; +#endif +{ + triomino *cell; + + TRIALLOC (cell); + cell->edge = e; + cell->end = e->a[1]; + cell->next = e->a[0]->adj; + e->a[0]->adj = cell; + + TRIALLOC (cell); + cell->edge = e; + cell->end = e->a[0]; + cell->next = e->a[1]->adj; + e->a[1]->adj = cell; +} + +#ifdef CC_PROTOTYPE_ANSI +static void magicrc (void) +#else +static void magicrc () +#endif +{ + double a; + panedge **pee, *pe; + + a = min2 ((pannodelist + XMAGICNODE)->edgelist); + + for (pee = (pannodelist + XMAGICNODE)->edgelist; + (pe = *pee) != (panedge *) NULL; pee++) + pe->rc -= a; + + (pannodelist + XMAGICNODE)->vptr->y += a; +} + +#ifdef CC_PROTOTYPE_ANSI +static double min2 (panedge **elist) +#else +static double min2 (elist) +panedge **elist; +#endif +{ + double minweight, minweight2, td; + panedge *e; + + if (elist == (panedge **) NULL || elist[0] == (panedge *) NULL || + elist[1] == (panedge *) NULL) { + fprintf (stderr, "Vertex has degree < two\n"); + exit (1); + } + minweight = elist[0]->rc; + minweight2 = elist[1]->rc; + if (minweight > minweight2) { + SWAP (minweight, minweight2, td); + } + for (elist += 2; (e = *elist) != (panedge *) NULL; elist++) { + if (e->rc < minweight2) { + minweight2 = e->rc; + if (minweight > minweight2) { + SWAP (minweight, minweight2, td); + } + } + } + return minweight2; +} + +#ifdef CC_PROTOTYPE_ANSI +static double findbound (void) +#else +static double findbound () +#endif +{ + vaseknode *p, *q, *stack; + triomino *tri; + panedge **pee, *pe; + double tree_bound = 0.0; + double star_bound = 0.0; + double edge_bound = 0.0; + + root->ptr = (vaseknode *) NULL; + root->n = 1; + root->b = 0; + + + for (p = stack = root; p; p = stack) { + if (p->n) { + p->n = 0; + q = p->child; + if (q) + for (; q; q = q->sibling) { + q->ptr = stack; + stack = q; + q->n = 1; + q->b = 0; + } + else { + stack = p->ptr; + (p->parent->b)++; + star_bound += p->y; + } + for (tri = p->adj; tri; tri = tri->next) + edge_bound += tri->edge->rc; + } else { + stack = p->ptr; + if (stack) + (p->parent->b) += p->b; + tree_bound -= (p->mult) * ((p->b) - 1); + } + } + star_bound *= 2.0; + edge_bound /= 2.0; + + for (pee = ((pannodelist + XMAGICNODE)->edgelist); + (pe = *pee) != (panedge *) NULL; pee++) + if (pe->rc < 0.0) + edge_bound += pe->rc; + star_bound += (pannodelist + XMAGICNODE)->vptr->y * 2; + + return tree_bound + star_bound + edge_bound; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xblobsviolated (Xgraph *G, Xcplane **list) +#else +int Xblobsviolated (G, list) +Xgraph *G; +Xcplane **list; +#endif +{ + int hit = 0; + + blnode (G, list, root, &hit); + return hit; +} + +#ifdef CC_PROTOTYPE_ANSI +static double blnode (Xgraph *G, Xcplane **list, vaseknode *v, int *hit) +#else +static double blnode (G, list, v, hit) +Xgraph *G; +Xcplane **list; +vaseknode *v; +int *hit; +#endif +{ + double w = 0.0; + double t; + panedge *e; + vaseknode *c; + + if (!v->child) + return 0.0; + else { + for (e = v->junk; e; e = e->next) + w += (G->edgelist + (e - panedgelist))->x; + for (c = v->child; c; c = c->sibling) + w += blnode (G, list, c, hit); + t = v->b; + if (w > t - 1.0 + XCUTTOLERANCE) { + G->magicnum++; + labeler (G, v); + if (Xcutchecksout (G, G->magicnum)) { + Xloadcplane_cut (G, list, G->magicnum); + (*hit)++; + } else { + printf ("BAD BLOB"); + fflush (stdout); + } + } + return w; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void labeler (Xgraph *G, vaseknode *p) +#else +static void labeler (G, p) +Xgraph *G; +vaseknode *p; +#endif +{ + vaseknode *c; + + if (!p->child) + (G->nodelist + (p - vpannodes))->magiclabel = G->magicnum; + else + for (c = p->child; c; c = c->sibling) + labeler (G, c); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xshrinksmallblobs (Xgraph *G, int rnum, int biggest) +#else +void Xshrinksmallblobs (G, rnum, biggest) +Xgraph *G; +int rnum; +int biggest; +#endif +{ + int shrunk = 0; + + ssblob (G, root, rnum, biggest, &shrunk); +} + +#ifdef CC_PROTOTYPE_ANSI +static int ssblob (Xgraph *G, vaseknode *v, int rnum, int biggest, int *shrunk) +#else +static int ssblob (G, v, rnum, biggest, shrunk) +Xgraph *G; +vaseknode *v; +int rnum; +int biggest; +int *shrunk; +#endif +{ + int count = 0; + vaseknode *c; + static int s = 0; + + if (v->b < 3) + return 0; + else { + for (c = v->child; c; c = c->sibling) + count += ssblob (G, c, rnum, biggest, shrunk); + if (count) + return count; + else { + if (v->tag) { + if (v->b <= biggest && + (!rnum || (++s) % 2)) { + shrinkblob (G, v); + (*shrunk)++; + } + return 1; + } else + return 0; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void shrinkblob (Xgraph *G, vaseknode *v) +#else +static void shrinkblob (G, v) +Xgraph *G; +vaseknode *v; +#endif +{ + Xnode *first, *pn; + + G->magicnum++; + labeler (G, v); + first = G->pseudonodelist->next; + while (first->magiclabel != G->magicnum) + first = first->next; + for (pn = first->next; pn; pn = pn->next) + if (pn->magiclabel == G->magicnum) + Xsimpleshrink (G, first, pn); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xtightblobs (Xgraph *G) +#else +void Xtightblobs (G) +Xgraph *G; +#endif +{ + int count = 0; + + tblob (G, root, &count); + printf ("Number tight blobs: %d\n", count); +} + +#ifdef CC_PROTOTYPE_ANSI +static double tblob (Xgraph *G, vaseknode *v, int *count) +#else +static double tblob (G, v, count) +Xgraph *G; +vaseknode *v; +int *count; +#endif +{ + double w = 0.0; + double t; + panedge *e; + vaseknode *c; + + if (v->b < 3) + return 0.0; + else { + for (e = v->junk; e; e = e->next) + w += (G->edgelist + (e - panedgelist))->x; + for (c = v->child; c; c = c->sibling) + w += tblob (G, c, count); + t = v->b; + if (w > t - 1.0 - XEPSILON) { + v->tag = 1; + (*count)++; + } else + v->tag = 0; + return w; + } +} + diff --git a/contrib/blossom/concorde97/XSTUFF/Xblock.c b/contrib/blossom/concorde97/XSTUFF/Xblock.c new file mode 100644 index 0000000000000000000000000000000000000000..690d51ce8bdcfcbae44421ee4dd0e1f589a40551 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xblock.c @@ -0,0 +1,1825 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void */ +/* Xlocalshrink_a (), */ +/* Xlocalshrink_b (), */ +/* Xlocalshrink_c (), */ +/* Xadd_tooth (); */ +/* Xmarktooth (); */ +/* Xmarktoothend (); */ +/* */ +/* int */ +/* Xlocalcombs (), */ +/* Xglobalcombs (), */ +/* Xblockcombs (), */ +/* XTmark_components (), */ +/* Xrepeat_1_shrink (), */ +/* Xbasiccliques (), */ +/* Xsearchbasiccliques (), */ +/* Xbasicclique (); */ +/* */ +/* Xedge */ +/* *Xcurrentedge (Xnode *n1, Xnode *n2); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + +#define BLOTOLERANCE .01 + + +#ifdef CC_PROTOTYPE_ANSI + +static void + block_biconnect (Xgraph *G, Xnode *v, Xnode *u, int *lastnumber, + Xnode ***top_pointer, Xblock **tblock, Xcutnode **tcut, + int count_cut), + dfs_Tmark (Xnode *start, int t), + blockweight (Xgraph *G, Xblock *b), + blockone (Xgraph *G, Xblock *b), + buildcutnodes (Xgraph *G), + buildallneighbors (void), + buildneighbors (Xblock *b), + freeblocklist (void), + freecutnodelist (void), + handlesearch (Xgraph *G, Xcplane **cplanelist, double *x, + int *combcount, int *searchcount); + +static int + blockcombs_work (Xgraph *G, Xcplane **cplanelist, int pseudo, + double *x), + localcombs_work (Xgraph *G, Xcplane **cplanelist, + Xnode *startnode, double *x, int pseudo), + analyze_component (Xgraph *G, Xcplane **cplanelist, Xnode *n, + int first, Xnode **nodestack, double *x), + connectedhandles (Xgraph *G, Xcplane **cplanelist, double *x), + processhandle (Xgraph *G, Xcplane **cplanelist, double *x), + markblock (Xblock *b, Xcutnode *c, Xnodeptr **list), + component_basicclique (Xgraph *G, Xcplane **list, Xnode *n, int first, + Xnode **nodestack, double *x), + combslack (Xgraph *G, Xblock *handle, Xblock *fixtooth, double *slack, + Xnodeptrptr **teeth); + +static double + hoodweight (Xgraph *G, Xblock *b, Xnode *n); + +static Xnode + *globalshrink (Xgraph *G); + +#else + +static void + block_biconnect (), + dfs_Tmark (), + blockweight (), + blockone (), + buildcutnodes (), + buildallneighbors (), + buildneighbors (), + freeblocklist (), + freecutnodelist (), + handlesearch (); + +static int + blockcombs_work (), + localcombs_work (), + analyze_component (), + connectedhandles (), + processhandle (), + markblock (), + component_basicclique (), + combslack (); + +static double + hoodweight (); + +static Xnode + *globalshrink (); + +#endif + +#define FMPMAX 25 +#define SEARCHMAX 500 /* Was 5000 */ +static int nblocks, ncutnodes; +static Xblock *blocklist; +static Xcutnode *cutnodelist; + +#ifdef CC_PROTOTYPE_ANSI +int Xblockcombs (Xgraph *G, Xcplane **list, double *x) +#else +int Xblockcombs (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + return blockcombs_work (G, list, 0, x); +} + +#ifdef CC_PROTOTYPE_ANSI +int Xlocalcombs (Xgraph *G, Xcplane **list, double *x) +#else +int Xlocalcombs (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + return localcombs_work (G, list, (Xnode *) NULL, x, 0); + +} + +#ifdef CC_PROTOTYPE_ANSI +static int localcombs_work (Xgraph *G, Xcplane **cplanelist, + Xnode *startnode, double *x, int pseudo) +#else +static int localcombs_work (G, cplanelist, startnode, x, pseudo) +Xgraph *G; +Xcplane **cplanelist; +Xnode *startnode; +double *x; +int pseudo; +#endif +{ + int hit, component; + Xnode *n; + + /* printf ("localcombs...\n"); fflush (stdout); */ + + if (startnode) + component = startnode->Tmark; + else + component = 0; + if (x == (double *) NULL) { + printf ("need x vector for Xlocalcombs\n"); + return 0; + } + if (!pseudo) { + Xloadx (G, x); + Xbuildpseudonodelist (G, 0); + } + Xlocalshrink_a (G, component); + Xlocalshrink_b (G, component); + Xlocalshrink_c (G, component); + if (startnode == (Xnode *) NULL) + hit = blockcombs_work (G, cplanelist, 1, x); + else { + n = G->pseudonodelist->next; + while (n && n->Tmark != component) + n = n->next; + if (!n) { + hit = 0; + printf ("WHOOOPS, did not find the component\n"); + } else + hit = analyze_component (G, cplanelist, n, 0, (Xnode **) NULL, x); + } + if (!pseudo) + Xdestroypseudonodelist (G); + + return hit; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xglobalcombs (Xgraph *G, Xcplane **cplanelist, double *x) +#else +int Xglobalcombs (G, cplanelist, x) +Xgraph *G; +Xcplane **cplanelist; +double *x; +#endif +{ + int count = 0; + Xnode *n, **nodestack; + + Xloadx (G, x); + Xbuildpseudonodelist (G, 0); + nodestack = CC_SAFE_MALLOC (G->npseudonodes, Xnode *); + if (!nodestack) { + fprintf (stderr, "out of memory on globalcombs\n"); + exit (1); + } + + while ((n = globalshrink (G)) != (Xnode *) NULL) { + /* printf ("N: %d ", n - G->nodelist); fflush (stdout); */ + XTmark_components (G); + count += analyze_component (G, cplanelist, n, 0, nodestack, x); + count += localcombs_work (G, cplanelist, n, x, 1); + /* printf ("\n"); fflush (stdout); */ + } + +/* + printf ("%d globalcombs\n", count); +*/ + + CC_FREE (nodestack, Xnode *); + Xdestroypseudonodelist (G); + + return count; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xlocalshrink_a (Xgraph *G, int component) +#else +void Xlocalshrink_a (G, component) +Xgraph *G; +int component; +#endif +{ + int i; + Xedge *e; + Xnode *u, *v; + + /* printf ("localshrink_a (%d)...\n", component); */ + if (!component) { + for (e = G->edgelist, i = G->nedges; i; e++, i--) + if (e->stay && e->x == 1.0) { + u = e->cends[0]; + v = e->cends[1]; + Xrepeat_1_shrink (G, u, e); + Xrepeat_1_shrink (G, v, e); + } + } else { + for (e = G->edgelist, i = G->nedges; i; e++, i--) + if (e->stay && e->x == 1.0 && + (e->cends[0]->Tmark == component || + e->cends[1]->Tmark == component)) { + Xrepeat_1_shrink (G, e->cends[0], e); + Xrepeat_1_shrink (G, e->cends[1], e); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xlocalshrink_b (Xgraph *G, int component) +#else +void Xlocalshrink_b (G, component) +Xgraph *G; +int component; +#endif +{ + int i, hit; + Xedge *e, *f, *g; + Xedgeptr *ep; + Xnode *u, *v, *w; + + for (e = G->edgelist, i = G->nedges; i; e++, i--) { + if (e->stay && e->x == 1.0 && (!component || + (e->cends[0]->Tmark == component && + e->cends[1]->Tmark == component))) { + u = e->cends[0]; + v = e->cends[1]; + hit = 0; + for (ep = u->cadj.head; ep && !hit; ep = ep->next) { + f = ep->this; + w = OTHERCURRENTEND (f, u); + if ((g = Xcurrentedge (v, w)) != (Xedge *) NULL) + if (f->x + g->x > 1.0 - XEPSILON) { + hit = 1; + Xsimpleshrink (G, u, v); + } + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xlocalshrink_c (Xgraph *G, int component) +#else +void Xlocalshrink_c (G, component) +Xgraph *G; +int component; +#endif +{ + int i, hit; + Xedge *c, *d, *e, *f, *g, *h; + Xedgeptr *ep, *tp; + Xnode *u, *v, *w, *t; + + for (e = G->edgelist, i = G->nedges; i; e++, i--) + if (e->stay && (!component || (e->cends[0]->Tmark == component + && e->cends[1]->Tmark == component))) { + u = e->cends[0]; + v = e->cends[1]; + hit = 0; + for (ep = u->cadj.head; ep && !hit; ep = ep->next) { + f = ep->this; + if (f == e) + continue; + w = OTHERCURRENTEND (f, u); + if (((g = Xcurrentedge (w, v)) != (Xedge *) NULL) && + e->x + f->x + g->x > 2.0 - XEPSILON) { + for (tp = u->cadj.head; tp && !hit; + tp = tp->next) { + h = tp->this; + if (h == e || h == f || h == g) + continue; + t = OTHERCURRENTEND (h, u); + if (((c = Xcurrentedge (t, v)) != (Xedge *) NULL) && + ((d = Xcurrentedge (t, w)) != (Xedge *) NULL) && + h->x + c->x + d->x > + 1.0 - XEPSILON) { + hit = 1; + Xsimpleshrink (G, u, v); + Xsimpleshrink (G, u, w); + } + } + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static Xnode *globalshrink (Xgraph *G) +#else +static Xnode *globalshrink (G) +Xgraph *G; +#endif +{ + Xedge *e, *f, *g, *h; + Xedgeptr *ep, *ep2; + Xnode *u, *v, *w, *x; + int i; + + XTmark_components (G); + for (e = G->edgelist, i = G->nedges; i; i--, e++) + if (e->stay && e->x == 1.0 && (u = e->cends[0])->Tmark + != (w = e->cends[1])->Tmark) + for (ep = u->cadj.head; ep; ep = ep->next) { + f = ep->this; + if (f == e) + continue; + v = OTHERCURRENTEND (f, u); + for (ep2 = w->cadj.head; ep2; ep2 = ep2->next) { + g = ep2->this; + if (g == e) + continue; + x = OTHERCURRENTEND (g, w); + if (x != v && + f->x + g->x > 1.0 - XEPSILON && + (h = Xcurrentedge (v, x)) != (Xedge *) NULL && + h->x == 1.0) { + Xsimpleshrink (G, u, w); + Xsimpleshrink (G, v, x); + /* printf ("SHRINK\n"); fflush (stdout); */ + return u; + } + } + } + return (Xnode *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static int blockcombs_work (Xgraph *G, Xcplane **cplanelist, int pseudo, + double *x) +#else +static int blockcombs_work (G, cplanelist, pseudo, x) +Xgraph *G; +Xcplane **cplanelist; +int pseudo; +double *x; +#endif +{ + Xnode *n, **nodestack, **top; + int lastnumber = 1, oldlast, combcount = 0; + + /* printf ("blockcombs....\n"); fflush (stdout); */ + + if (x == (double *) NULL) { + printf ("Need x vector of Xblockcombs\n"); + return 0; + } + if (!pseudo) { + Xloadx (G, x); + Xbuildpseudonodelist (G, 0); + } + for (n = G->pseudonodelist->next; n; n = n->next) { + n->active = 0; + n->mark = G->npseudonodes; + } + + nodestack = CC_SAFE_MALLOC (G->npseudonodes, Xnode *); + if (!nodestack) { + fprintf (stderr, "out of memory in blockcombs\n"); + exit (1); + } + for (n = G->pseudonodelist->next; n; n = n->next) { + if (!n->active) { + *nodestack = n; + top = nodestack + 1; + oldlast = lastnumber; + block_biconnect (G, n, (Xnode *) NULL, &lastnumber, &top, + (Xblock **) NULL, (Xcutnode **) NULL, 0); + if (lastnumber - oldlast >= 3) + combcount += analyze_component (G, cplanelist, + n, oldlast, nodestack, x); + } + if (combcount >= FMPMAX) + break; + } + CC_FREE (nodestack, Xnode *); + + if (!pseudo) + Xdestroypseudonodelist (G); +/* + if (report) + printf ("%d blockcombs\n", combcount); +*/ + + return combcount; +} + +#ifdef CC_PROTOTYPE_ANSI +static void block_biconnect (Xgraph *G, Xnode *v, Xnode *u, int *lastnumber, + Xnode ***top_pointer, Xblock **tblock, Xcutnode **tcut, int count_cut) +#else +static void block_biconnect (G, v, u, lastnumber, top_pointer, tblock, tcut, + count_cut) +Xgraph *G; +Xnode *v, *u; +int *lastnumber; +Xnode ***top_pointer; +Xblock **tblock; +Xcutnode **tcut; +int count_cut; +#endif +{ + Xedge *e; + Xedgeptr *ep; + Xnode *w, **top = *top_pointer; + Xnodeptr *np; + + v->mark = v->active = (*lastnumber)++; + for (ep = v->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->x > 1.0 - XEPSILON) + continue; + w = OTHERCURRENTEND (e, v); + if (!w->active) { + *top = w; + top++; + block_biconnect (G, w, v, lastnumber, &top, tblock, tcut, + count_cut); + if (w->mark < v->mark) + v->mark = w->mark; + if (w->mark >= v->active) { + if (count_cut) + nblocks++; + if (count_cut && v->magiclabel != G->magicnum) { + if (v->magiclabel == G->magicnum - 1) + v->magiclabel--; + else { + ncutnodes++; + v->magiclabel = G->magicnum; + if (tcut != (Xcutnode **) NULL) { + (*tcut)->name = v; + (*tcut)++; + } + } + } + if (tblock) { + np = Xnodeptralloc (); + np->this = v; + np->next = (Xnodeptr *) NULL; + (*tblock)->members = np; + } + while (*(top - 1) != v) { + if (tblock) { + np = Xnodeptralloc (); + np->this = *(top - 1); + np->next = (*tblock)->members; + (*tblock)->members = np; + } + top--; + } + if (tblock) + (*tblock)++; + } + } else if (w->active < v->mark && w != u) { + if (w->mark < v->mark) + v->mark = w->mark; + } + } + *top_pointer = top; +} + +#ifdef CC_PROTOTYPE_ANSI +int XTmark_components (Xgraph *G) +#else +int XTmark_components (G) +Xgraph *G; +#endif +{ + int ccount = 1; + Xnode *n; + + for (n = G->pseudonodelist->next; n; n = n->next) + n->Tmark = 0; + + for (n = G->pseudonodelist->next; n; n = n->next) { + if (!n->Tmark) { + dfs_Tmark (n, ccount); + ccount++; + } + } + /* printf ("NUMBER OF COMPONENTS: %d\n", ccount - 1); */ + return ccount; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dfs_Tmark (Xnode *start, int t) +#else +static void dfs_Tmark (start, t) +Xnode *start; +int t; +#endif +{ + Xedgeptr *ep; + Xnode *n, *v; + Xnodeptr *next, *queue = (Xnodeptr *) NULL; + + start->Tmark = t; + Xadd_nodeptr (&queue, start); + + while (queue) { + n = queue->this; + next = queue->next; + Xnodeptrfree (queue); + queue = next; + for (ep = n->cadj.head; ep; ep = ep->next) { + if (ep->this->x > 1.0 - XEPSILON) + continue; + if (!(v = OTHERCURRENTEND (ep->this, n))->Tmark) { + v->Tmark = t; + Xadd_nodeptr (&queue, v); + } + } + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static int analyze_component (Xgraph *G, Xcplane **cplanelist, Xnode *n, + int first, Xnode **nodestack, double *x) +#else +static int analyze_component (G, cplanelist, n, first, nodestack, x) +Xgraph *G; +Xcplane **cplanelist; +Xnode *n; +int first; +Xnode **nodestack; +double *x; +#endif +{ + int i, fake, combcount = 0, newstack = 0; + Xnode *v, **top; + Xblock *topblock, *b; + Xcutnode *topcutnode; + + /* + printf ("analyze_component (blocks: %d cuts: %d)...\n", + nblocks, ncutnodes); + fflush (stdout); + */ + + if (!nodestack) { + nodestack = CC_SAFE_MALLOC (G->npseudonodes, Xnode *); + if (!nodestack) { + fprintf (stderr, "out of memory in analyze_component\n"); + exit (1); + } + newstack = 1; + } + *nodestack = n; + top = nodestack + 1; + if (first) { + for (v = G->pseudonodelist->next; v; v = v->next) + if (v->active >= first) + v->active = 0; + } else { + for (v = G->pseudonodelist->next; v; v = v->next) { + v->active = 0; + v->mark = G->npseudonodes; + } + first = 1; + } + + nblocks = ncutnodes = 0; + G->magicnum += 2; + n->magiclabel = G->magicnum - 1; + fake = first; + block_biconnect (G, n, (Xnode *) NULL, &fake, &top, (Xblock **) NULL, + (Xcutnode **) NULL, 1); + + if (nblocks > 0) { + blocklist = CC_SAFE_MALLOC (nblocks, Xblock); + if (!blocklist) { + fprintf (stderr, "out of memory in analyze_component\n"); + exit (1); + } + } else + blocklist = (Xblock *) NULL; + + if (ncutnodes) { + cutnodelist = CC_SAFE_MALLOC (ncutnodes, Xcutnode); + if (!cutnodelist) { + fprintf (stderr, "out of memory in analyze_component\n"); + exit (1); + } + } else + cutnodelist = (Xcutnode *) NULL; + + for (i = 0; i < nblocks; i++) { + blocklist[i].members = (Xnodeptr *) NULL; + blocklist[i].neighbors = (Xblockptr *) NULL; + blocklist[i].one = (Xedgeptr *) NULL; + blocklist[i].cutnodes = (Xcutnodeptr *) NULL; + } + + for (i = 0; i < ncutnodes; i++) + cutnodelist[i].blocks = (Xblockptr *) NULL; + + topblock = blocklist; + topcutnode = cutnodelist; + + for (v = G->pseudonodelist->next; v; v = v->next) + if (v->active >= first) + v->active = 0; + + *nodestack = n; + top = nodestack + 1; + nblocks = ncutnodes = 0; + G->magicnum += 2; + n->magiclabel = G->magicnum - 1; + fake = first; + block_biconnect (G, n, (Xnode *) NULL, &fake, &top, &topblock, + &topcutnode, 1); + for (i = nblocks, b = blocklist; i; i--, b++) { + blockweight (G, b); + blockone (G, b); + } + buildcutnodes (G); + buildallneighbors (); + combcount += connectedhandles (G, cplanelist, x); + + /* + printf ("ALL CUTNODES: "); + fflush (stdout); + for (i = ncutnodes, topcutnode = cutnodelist; i; i--, topcutnode++) + printf ("%d ", topcutnode->name - G->nodelist); + printf ("\n"); + printf ("BLOCKS:\n"); + for (i = 0, topblock = blocklist; i < nblocks; i++, topblock++) { + printf ("%d: ", i); + fflush (stdout); + for (np = topblock->members; np; np = np->next) + printf (" %d", np->this - nodelist); + printf ("\nWeight: %lf\n", topblock->weight); + printf ("ONE: "); + fflush (stdout); + for (ep = topblock->one; ep; ep = ep->next) { + printf ("(%d, %d) ", ep->this->cends[0] - G->nodelist, + ep->this->cends[1] - G->nodelist); + fflush (stdout); + } + printf ("\n"); + printf ("CUTNODES: "); + fflush (stdout); + for (cp = topblock->cutnodes; cp; cp = cp->next) + printf (" %d", cp->this->name - G->nodelist); + printf ("\n"); + } + printf ("done\n"); + fflush (stdout); + */ + + freeblocklist (); + freecutnodelist (); + if (newstack) + CC_FREE (nodestack, Xnode *); + return combcount; +} + +#ifdef CC_PROTOTYPE_ANSI +static void blockweight (Xgraph *G, Xblock *b) +#else +static void blockweight (G, b) +Xgraph *G; +Xblock *b; +#endif +{ + int count = 0; + double inside = 0.0; + Xnode *n; + Xedge *e; + Xnodeptr *np; + Xedgeptr *ep; + + G->magicnum++; + for (np = b->members; np; np = np->next) { + np->this->magiclabel = G->magicnum; + count++; + } + + for (np = b->members; np; np = np->next) { + n = np->this; + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (OTHERCURRENTEND (e, n)->magiclabel == G->magicnum) + inside += e->x; + } + } + inside /= 2.0; + b->x = inside; + b->weight = inside + 2.0 - count; +} + +#ifdef CC_PROTOTYPE_ANSI +static void blockone (Xgraph *G, Xblock *b) +#else +static void blockone (G, b) +Xgraph *G; +Xblock *b; +#endif +{ + Xnode *n; + Xedge *e; + Xnodeptr *np; + Xedgeptr *ep, *tp; + + G->magicnum++; + for (np = b->members; np; np = np->next) + np->this->magiclabel = G->magicnum; + + for (np = b->members; np; np = np->next) { + n = np->this; + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->x == 1.0 && OTHERCURRENTEND (e, n)->magiclabel + != G->magicnum) { + tp = Xedgeptralloc (); + tp->this = e; + tp->next = b->one; + b->one = tp; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void buildcutnodes (Xgraph *G) +#else +static void buildcutnodes (G) +Xgraph *G; +#endif +{ + Xcutnode *c; + Xnode *nc; + Xnodeptr *np; + Xcutnodeptr *cp; + Xblock *b; + Xblockptr *bp; + int i, j, hit; + + for (i = ncutnodes, c = cutnodelist; i; i--, c++) { + nc = c->name; + for (j = nblocks, b = blocklist; j; j--, b++) { + hit = 0; + for (np = b->members; np && !hit; np = np->next) + if (np->this == nc) { + cp = Xcutnodeptralloc (); + cp->this = c; + cp->next = b->cutnodes; + b->cutnodes = cp; + + bp = Xblockptralloc (); + bp->this = b; + bp->next = c->blocks; + c->blocks = bp; + bp->hood_weight = hoodweight (G, b, nc); + hit++; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void buildallneighbors (void) +#else +static void buildallneighbors () +#endif +{ + int i; + Xblock *b; + + for (i = nblocks, b = blocklist; i; i--, b++) + buildneighbors (b); +} + +#ifdef CC_PROTOTYPE_ANSI +static void buildneighbors (Xblock *b) +#else +static void buildneighbors (b) +Xblock *b; +#endif +{ + int i; + Xblock *d; + Xblockptr *bp; + Xcutnodeptr *cp; + + for (i = nblocks, d = blocklist; i; i--, d++) + d->mark = 0; + + for (cp = b->cutnodes; cp; cp = cp->next) + for (bp = cp->this->blocks; bp; bp = bp->next) + if (bp->this != b) + bp->this->mark = 1; + + for (i = nblocks, d = blocklist; i; i--, d++) + if (d->mark) { + bp = Xblockptralloc (); + bp->this = d; + bp->next = b->neighbors; + b->neighbors = bp; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static double hoodweight (Xgraph *G, Xblock *b, Xnode *n) +#else +static double hoodweight (G, b, n) +Xgraph *G; +Xblock *b; +Xnode *n; +#endif +{ + Xnode *m; + Xnodeptr *np; + Xedgeptr *ep, *tp; + Xedge *e; + double inside = 0.0; + int count = 1; + + G->magicnum++; + for (np = b->members; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (ep = n->cadj.head; ep; ep = ep->next) + OTHERCURRENTEND (ep->this, n)->magiclabel++; + n->magiclabel++; + G->magicnum++; + for (ep = n->cadj.head; ep; ep = ep->next) { + m = OTHERCURRENTEND (ep->this, n); + if (m->magiclabel == G->magicnum) { + count++; + inside += ep->this->x; + for (tp = m->cadj.head; tp; tp = tp->next) { + e = tp->this; + if (OTHERCURRENTEND (e, m)->magiclabel == G->magicnum) + inside += e->x; + } + } + } + inside /= 2.0; + + return inside + 2.0 - count; +} + +#ifdef CC_PROTOTYPE_ANSI +static void freeblocklist (void) +#else +static void freeblocklist () +#endif +{ + Xblock *b; + Xnodeptr *np, *next; + Xblockptr *bp, *bext; + Xcutnodeptr *cp, *cext; + Xedgeptr *ep, *eext; + int i; + + for (b = blocklist, i = nblocks; i; i--, b++) { + for (np = b->members; np; np = next) { + next = np->next; + Xnodeptrfree (np); + } + for (bp = b->neighbors; bp; bp = bext) { + bext = bp->next; + Xblockptrfree (bp); + } + for (cp = b->cutnodes; cp; cp = cext) { + cext = cp->next; + Xcutnodeptrfree (cp); + } + for (ep = b->one; ep; ep = eext) { + eext = ep->next; + Xedgeptrfree (ep); + } + } + if (blocklist) { + CC_FREE (blocklist, Xblock); + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static void freecutnodelist (void) +#else +static void freecutnodelist () +#endif +{ + Xcutnode *c; + Xblockptr *bp, *next; + int i; + + if (ncutnodes) { + for (c = cutnodelist, i = ncutnodes; i; i--, c++) + for (bp = c->blocks; bp; bp = next) { + next = bp->next; + Xblockptrfree (bp); + } + CC_FREE (cutnodelist, Xcutnode); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int connectedhandles (Xgraph *G, Xcplane **cplanelist, double *x) +#else +static int connectedhandles (G, cplanelist, x) +Xgraph *G; +Xcplane **cplanelist; +double *x; +#endif +{ + int i, combcount = 0, searchcount = 0; + Xblock *b; + + for (i = nblocks, b = blocklist; i; i--, b++) + b->mark = 0; + + for (i = nblocks, b = blocklist; i; i--, b++) { + b->mark = 1; + if (processhandle (G, cplanelist, x)) + combcount++; + if (combcount >= FMPMAX) + return combcount; + + b->mark = 0; + } + + handlesearch (G, cplanelist, x, &combcount, &searchcount); + + /* printf ("(%d) ", searchcount); fflush (stdout); */ + + return combcount; +} + +#ifdef CC_PROTOTYPE_ANSI +static void handlesearch (Xgraph *G, Xcplane **cplanelist, double *x, + int *combcount, int *searchcount) +#else +static void handlesearch (G, cplanelist, x, combcount, searchcount) +Xgraph *G; +Xcplane **cplanelist; +double *x; +int *combcount, *searchcount; +#endif +{ + int i, k; + Xblock *b, *winner = (Xblock *) NULL, *runnerup = (Xblock *) NULL; + Xblockptr *bp; + + for (i = nblocks, b = blocklist; i && !winner; i--, b++) { + if (!b->mark) { + for (k = 0, bp = b->neighbors; bp && k < 2; bp = bp->next) + if (!bp->this->mark) + k++; + if (k == 1) { + winner = b; + for (bp = b->neighbors; bp; bp = bp->next) + if (!bp->this->mark) { + runnerup = bp->this; + break; + } + winner->mark = 1; + runnerup->mark = 1; + } + } + } + if (!winner) + return; + (*searchcount)++; + if (processhandle (G, cplanelist, x)) + (*combcount)++; + if (*combcount >= FMPMAX || *searchcount >= SEARCHMAX) + return; + + winner->mark = -1; + runnerup->mark = 0; + handlesearch (G, cplanelist, x, combcount, searchcount); +} + +#ifdef CC_PROTOTYPE_ANSI +static int processhandle (Xgraph *G, Xcplane **cplanelist, double *x) +#else +static int processhandle (G, cplanelist, x) +Xgraph *G; +Xcplane **cplanelist; +double *x; +#endif +{ + int i, nteeth = 0, handlecount = 0, midtake = 0, test; + double total = 0.0, midval = 2.0, mid = 0, handleweight = 0.0, max; + Xcutnode *c; + Xnode *n; + Xnodeptr *np, *nnp; + Xcutnodeptr *cp; + Xblock *b, *d, *bestblock = (Xblock *) NULL; + Xblockptr *bp; + Xedgeptr *ep; + Xedge *e; + int gotmid, besttype = 0, hit; + Xnodeptr *handle, *tooth; + Xnodeptrptr *teeth, *ntp; + int countcheck = 0; + + /* + printf ("PH: "); + for (i = nblocks, b = blocklist; i; i--, b++) + if (b->mark == 1) + printf ("%d ", b - blocklist); + printf ("\n"); + */ + G->magicnum++; + for (n = G->pseudonodelist->next; n; n = n->next) + n->stacklabel = 0; + for (i = ncutnodes, c = cutnodelist; i; i--, c++) + c->mark = 0; + for (i = nblocks, b = blocklist; i; i--, b++) { + if (b->mark == 1) { + for (np = b->members; np; np = np->next) + np->this->stacklabel = 1; + for (cp = b->cutnodes; cp; cp = cp->next) + cp->this->mark = 1; + } + } + for (i = nblocks, b = blocklist; i; i--, b++) { + if (b->mark == 1) { + for (ep = b->one; ep; ep = ep->next) { + e = ep->this; + if ((e->cends[0]->stacklabel != + e->cends[1]->stacklabel) && + (e->cends[0]->magiclabel != G->magicnum || + e->cends[1]->magiclabel != G->magicnum)) { + e->cends[0]->magiclabel = G->magicnum; + e->cends[1]->magiclabel = G->magicnum; + nteeth++; + total += 1.0; + midtake = 1; + mid = 1.0; + midval = 0.5; + } + } + } + } + + for (i = G->nedges, e = G->edgelist; i; i--, e++) { + if (e->stay && e->cends[0]->stacklabel && + e->cends[1]->stacklabel) + handleweight += e->x; + } + + for (n = G->pseudonodelist->next; n; n = n->next) { + if (n->stacklabel) + handlecount++; + } + + for (i = ncutnodes, c = cutnodelist; i; i--, c++) { + if (c->mark && c->name->magiclabel != G->magicnum) { + hit = 0; + max = 0.0; + for (bp = c->blocks; bp; bp = bp->next) { + d = bp->this; + if (d->mark != 1) { + hit = 1; + if (d->weight > max) + max = d->weight; + if (bp->hood_weight > max) + max = bp->hood_weight; + } + } + if (max >= 0.5) { + nteeth++; + total += max; + if (midval > max - 0.5) { + midval = max - 0.5; + mid = max; + midtake = 1; + } + } else if (hit && midval > 0.5 - max) { + midval = 0.5 - max; + mid = max; + midtake = 0; + } + } + } + if (nteeth < 2) { + return 0; + } + if (nteeth % 2 == 0) { + gotmid = 0; + if (!midtake) { + total += mid; + nteeth++; + } else { + total -= mid; + nteeth--; + } + } else + gotmid = 1; + + + total += handleweight + 2.0 - handlecount; + if (nteeth < 3 || total <= 1.5 + (0.5 * nteeth) + BLOTOLERANCE) + return 0; + + G->magicnum++; + for (i = nblocks, b = blocklist; i; i--, b++) + if (b->mark == 1) + for (np = b->members; np; np = np->next) + for (nnp = np->this->base.head; nnp; + nnp = nnp->next) + nnp->this->magiclabel = G->magicnum; + + handle = (Xnodeptr *) NULL; + for (i = G->nnodes, n = G->nodelist; i; i--, n++) + if (n->magiclabel == G->magicnum) { + np = Xnodeptralloc (); + np->this = n; + np->next = handle; + handle = np; + } + nteeth = 0; + teeth = (Xnodeptrptr *) NULL; + + G->magicnum++; + for (i = nblocks, b = blocklist; i; i--, b++) + if (b->mark == 1) + for (ep = b->one; ep; ep = ep->next) { + e = ep->this; + if ((e->cends[0]->stacklabel != + e->cends[1]->stacklabel) && + (e->cends[0]->magiclabel != G->magicnum || + e->cends[1]->magiclabel != G->magicnum)) { + e->cends[0]->magiclabel = G->magicnum; + e->cends[1]->magiclabel = G->magicnum; + if (!gotmid && mid == 1.0) + gotmid = 1; + else { + nteeth++; + tooth = (Xnodeptr *) NULL; + Xmarktooth (ep->this, &tooth); + Xadd_nodeptrptr (&teeth, tooth); + } + } + } + + for (i = ncutnodes, c = cutnodelist; i; i--, c++) + if (c->mark && c->name->magiclabel != G->magicnum) { + max = 0.0; + hit = 0; + for (bp = c->blocks; bp; bp = bp->next) { + d = bp->this; + if (d->mark != 1) { + hit = 1; + if (d->weight > max) { + bestblock = d; + besttype = 0; + max = d->weight; + } + if (bp->hood_weight > max) { + bestblock = d; + besttype = 1; + max = bp->hood_weight; + } + } + } + if (max >= 0.5) { + if (!gotmid && max == mid) + gotmid = 1; + else { + nteeth++; + tooth = (Xnodeptr *) NULL; + if (besttype) + markblock (bestblock, c, + &tooth); + else + markblock (bestblock, (Xcutnode *) NULL, + &tooth); + Xadd_nodeptrptr (&teeth, tooth); + } + } else if (hit && !gotmid && max == mid) { + gotmid = 1; + nteeth++; + tooth = (Xnodeptr *) NULL; + if (besttype) + markblock (bestblock, c, + &tooth); + else + markblock (bestblock, (Xcutnode *) NULL, + &tooth); + Xadd_nodeptrptr (&teeth, tooth); + } + } + Xcleancomb (G, &handle, &teeth, &nteeth, x); + if (!Xtemp_combfluff (G, &handle, &teeth)) + return 0; + test = Xtemp_combcheck (G, handle, teeth) && + Xloadcplane (cplanelist, handle, (Xnodeptrptr *) NULL, teeth, + countcheck); + if (!test) { + Xnodeptr_list_free (handle); + for (ntp = teeth; ntp; ntp = ntp->next) + Xnodeptr_list_free (ntp->this); + Xnodeptrptr_list_free (teeth); + } + return test; +} + +#ifdef CC_PROTOTYPE_ANSI +static int markblock (Xblock *b, Xcutnode *c, Xnodeptr **list) +#else +static int markblock (b, c, list) +Xblock *b; +Xcutnode *c; +Xnodeptr **list; +#endif +{ + Xnode *n, *m; + Xnodeptr *np, *nnp; + Xedgeptr *ep; + int count = 0, hit; + + *list = (Xnodeptr *) NULL; + if (c == (Xcutnode *) NULL) + for (np = b->members; np; np = np->next) { + n = np->this; + for (nnp = n->base.head; nnp; nnp = nnp->next) { + Xadd_tooth (nnp->this, list); + count++; + } + } + else + for (np = b->members; np; np = np->next) { + n = np->this; + if (n == c->name) + hit = 1; + else + hit = 0; + for (ep = c->name->cadj.head; ep && !hit; ep = ep->next) { + m = OTHERCURRENTEND (ep->this, c->name); + if (m == n) + hit = 1; + } + if (hit) { + for (nnp = n->base.head; nnp; nnp = nnp->next) { + Xadd_tooth (nnp->this, list); + count++; + } + } + } + return count; +} + +#ifdef CC_PROTOTYPE_ANSI +Xedge *Xcurrentedge (Xnode *n1, Xnode *n2) +#else +Xedge *Xcurrentedge (n1, n2) +Xnode *n1, *n2; +#endif +{ + Xedgeptr *ep; + + for (ep = n1->cadj.head; ep; ep = ep->next) + if (OTHERCURRENTEND (ep->this, n1) == n2) + return ep->this; + + return (Xedge *) NULL; +} + + +#ifdef CC_PROTOTYPE_ANSI +void Xadd_tooth (Xnode *t, Xnodeptr **list) +#else +void Xadd_tooth (t, list) +Xnode *t; +Xnodeptr **list; +#endif +{ + Xnodeptr *np; + + np = Xnodeptralloc (); + np->this = t; + np->next = *list; + *list = np; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xmarktooth (Xedge *e, Xnodeptr **list) +#else +int Xmarktooth (e, list) +Xedge *e; +Xnodeptr **list; +#endif +{ + int count; + + *list = (Xnodeptr *) NULL; + count = Xmarktoothend (e->cends[0], list) + + Xmarktoothend (e->cends[1], list); + + return count; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xmarktoothend (Xnode *n, Xnodeptr **list) +#else +int Xmarktoothend (n, list) +Xnode *n; +Xnodeptr **list; +#endif +{ + Xnodeptr *np; + int count = 0; + + for (np = n->base.head; np; np = np->next) { + count++; + Xadd_tooth (np->this, list); + } + + return count; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xrepeat_1_shrink (Xgraph *G, Xnode *n, Xedge *e) +#else +int Xrepeat_1_shrink (G, n, e) +Xgraph *G; +Xnode *n; +Xedge *e; +#endif +{ + int hit, count = 0; + Xedgeptr *ep; + Xedge *f; + + do { + for (ep = n->cadj.head, hit = 0; ep && !hit; ep = ep->next) { + f = ep->this; + if (f->x == 1.0 && f != e) { + Xsimpleshrink (G, n, OTHERCURRENTEND (f, n)); + hit = 1; + count++; + } + } + } while (hit); + + return count; +} + + + +/*********************** New Clique Tree Stuff *********************/ + +#ifdef CC_PROTOTYPE_ANSI +int Xbasiccliques (Xgraph *G, Xcplane **list, double *x) +#else +int Xbasiccliques (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + return Xsearchbasiccliques (G, list, 0, x); +} + +#ifdef CC_PROTOTYPE_ANSI +int Xsearchbasiccliques (Xgraph *G, Xcplane **list, int pseudo, double *x) +#else +int Xsearchbasiccliques (G, list, pseudo, x) +Xgraph *G; +Xcplane **list; +int pseudo; +double *x; +#endif +{ + int lastnumber = 1, oldlast, cliquecount = 0; + Xnode *n, **nodestack, **top; + +/* + printf ("searchbasiccliques ...\n"); + fflush (stdout); +*/ + + if (x == (double *) NULL) { + printf ("need x vector of Xsearchbasiccliques\n"); + return 0; + } + if (!pseudo) { + Xloadx (G, x); + Xbuildpseudonodelist (G, 0); + } + for (n = G->pseudonodelist->next; n; n = n->next) { + n->active = 0; + n->mark = G->npseudonodes; + } + + nodestack = CC_SAFE_MALLOC (G->npseudonodes, Xnode *); + if (!nodestack) { + fprintf (stderr, "out of memory in Xsearchbasiccliques\n"); + exit (1); + } + for (n = G->pseudonodelist->next; n; n = n->next) { + if (!n->active) { + *nodestack = n; + top = nodestack + 1; + oldlast = lastnumber; + block_biconnect (G, n, (Xnode *) NULL, &lastnumber, &top, + (Xblock **) NULL, (Xcutnode **) NULL, 0); + if (lastnumber - oldlast >= 3) + cliquecount += component_basicclique (G, list, + n, oldlast, nodestack, x); + } + if (cliquecount >= FMPMAX) + break; + } + CC_FREE (nodestack, Xnode *); + + if (!pseudo) + Xdestroypseudonodelist (G); + + /* printf ("%d potential new cliquetrees\n", cliquecount); */ + + return cliquecount; +} + +#ifdef CC_PROTOTYPE_ANSI +static int component_basicclique (Xgraph *G, Xcplane **list, Xnode *n, + int first, Xnode **nodestack, double *x) +#else +static int component_basicclique (G, list, n, first, nodestack, x) +Xgraph *G; +Xcplane **list; +Xnode *n; +int first; +Xnode **nodestack; +double *x; +#endif +{ + int i, fake, cliquecount = 0, newstack = 0; + Xnode *v, **top; + Xblock *topblock, *b; + Xcutnode *topcutnode; + + if (!nodestack) { + nodestack = CC_SAFE_MALLOC (G->npseudonodes, Xnode *); + if (!nodestack) { + fprintf (stderr, "out of memory in component_basicclique\n"); + exit (1); + } + newstack = 1; + } + *nodestack = n; + top = nodestack + 1; + if (first) { + for (v = G->pseudonodelist->next; v; v = v->next) + if (v->active >= first) + v->active = 0; + } else { + for (v = G->pseudonodelist->next; v; v = v->next) { + v->active = 0; + v->mark = G->npseudonodes; + } + first = 1; + } + + nblocks = ncutnodes = 0; + G->magicnum += 2; + n->magiclabel = G->magicnum - 1; + fake = first; + block_biconnect (G, n, (Xnode *) NULL, &fake, &top, (Xblock **) NULL, + (Xcutnode **) NULL, 1); + + if (nblocks > 0) { + blocklist = CC_SAFE_MALLOC (nblocks, Xblock); + if (!blocklist) { + fprintf (stderr, "out of memory in component_basicclique\n"); + exit (1); + } + } else + blocklist = (Xblock *) NULL; + + if (ncutnodes > 0) { + cutnodelist = CC_SAFE_MALLOC (ncutnodes, Xcutnode); + if (!cutnodelist) { + fprintf (stderr, "out of memory in component_basicclique\n"); + exit (1); + } + } else + cutnodelist = (Xcutnode *) NULL; + + for (i = 0; i < nblocks; i++) { + blocklist[i].members = (Xnodeptr *) NULL; + blocklist[i].neighbors = (Xblockptr *) NULL; + blocklist[i].one = (Xedgeptr *) NULL; + blocklist[i].cutnodes = (Xcutnodeptr *) NULL; + } + + for (i = 0; i < ncutnodes; i++) + cutnodelist[i].blocks = (Xblockptr *) NULL; + + topblock = blocklist; + topcutnode = cutnodelist; + + for (v = G->pseudonodelist->next; v; v = v->next) + if (v->active >= first) + v->active = 0; + + *nodestack = n; + top = nodestack + 1; + nblocks = ncutnodes = 0; + G->magicnum += 2; + n->magiclabel = G->magicnum - 1; + fake = first; + block_biconnect (G, n, (Xnode *) NULL, &fake, &top, &topblock, + &topcutnode, 1); + for (i = nblocks, b = blocklist; i; i--, b++) { + blockweight (G, b); + blockone (G, b); + } + buildcutnodes (G); + buildallneighbors (); + + for (i = nblocks, b = blocklist; i; i--, b++) + cliquecount += Xbasicclique (G, list, x, b); + + + freeblocklist (); + freecutnodelist (); + if (newstack) + CC_FREE (nodestack, Xnode *); + return cliquecount; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xbasicclique (Xgraph *G, Xcplane **list, double *x, Xblock *bigtooth) +#else +int Xbasicclique (G, list, x, bigtooth) +Xgraph *G; +Xcplane **list; +double *x; +Xblock *bigtooth; +#endif +{ + Xblockptr *bp, *bnext, *combs; + Xblock *b, *minb = (Xblock *) NULL; + Xcutnode *c; + Xcutnodeptr *cp; + double min, t, slack, toothslack; + int count, goodcount, nhandles; + Xnodeptr *np, *tooth, *handle; + Xnodeptrptr *teeth, *handles; + int test; + + /* printf ("basiclique (%d)\n", bigtooth - blocklist); fflush (stdout); */ + + toothslack = -(bigtooth->weight) + 1.0; + + if (toothslack <= 0.001) + return 0; + for (count = 0, np = bigtooth->members; np; np = np->next) + count++; + if (count < 3) + return 0; + + + combs = (Xblockptr *) NULL; + for (cp = bigtooth->cutnodes; cp; cp = cp->next) { + c = cp->this; + min = 100.0; + minb = (Xblock *) NULL; + for (bp = c->blocks; bp; bp = bp->next) { + b = bp->this; + if (b == bigtooth) + continue; + if (combslack (G, b, bigtooth, &t, (Xnodeptrptr **) NULL)) + if (t < min) { + min = t; + minb = b; + } + } + if (minb) { + bp = Xblockptralloc (); + bp->this = minb; + bp->hood_weight = min; + bp->next = combs; + combs = bp; + } + } + goodcount = 0; + for (count = 0, bp = combs; bp; bp = bp->next) { + if (bp->hood_weight >= toothslack) + bp->this->mark = 0; + else { + bp->this->mark = 1; + goodcount++; + } + count++; + } + + if (count <= 1) { + for (bp = combs; bp; bp = bnext) { + bnext = bp->next; + Xblockptrfree (bp); + } + return 0; + } else if (goodcount == 1) { + min = 100.0; + for (bp = combs; bp; bp = bp->next) + if (!bp->this->mark && bp->hood_weight < min) { + min = bp->hood_weight; + minb = bp->this; + } + minb->mark = 1; + } else if (goodcount == 0) { + min = 100.0; + for (bp = combs; bp; bp = bp->next) + if (!bp->this->mark && bp->hood_weight < min) { + min = bp->hood_weight; + minb = bp->this; + } + minb->mark = 1; + min = 100.0; + for (bp = combs; bp; bp = bp->next) + if (!bp->this->mark && bp->hood_weight < min) { + min = bp->hood_weight; + minb = bp->this; + } + minb->mark = 1; + } + for (slack = 0.0, nhandles = 0, bp = combs; bp; bp = bp->next) + if (bp->this->mark) { + nhandles++; + slack += bp->hood_weight; + } + slack -= ((nhandles - 1) * toothslack); + +/* + printf ("NEW CLIQUE SLACK: %f\n", slack); + fflush (stdout); +*/ + + if (slack >= -BLOTOLERANCE) { + for (bp = combs; bp; bp = bnext) { + bnext = bp->next; + Xblockptrfree (bp); + } + return 0; + } + teeth = (Xnodeptrptr *) NULL; + handles = (Xnodeptrptr *) NULL; + markblock (bigtooth, (Xcutnode *) NULL, &tooth); + Xadd_nodeptrptr (&teeth, tooth); + + for (bp = combs; bp; bp = bp->next) + if (bp->this->mark) { + markblock (bp->this, (Xcutnode *) NULL, &handle); + Xadd_nodeptrptr (&handles, handle); + combslack (G, bp->this, bigtooth, &t, &teeth); + } + for (bp = combs; bp; bp = bnext) { + bnext = bp->next; + Xblockptrfree (bp); + } + if (!Xcliquefluff (G, &handles, &teeth)) { + printf ("DE FLUFFED TO 0\n"); + fflush (stdout); + return 0; + } + if (!Xviolated_clique_flow (G, handles, teeth, x)) { + printf ("BANG!\n"); + fflush (stdout); + Xfreeteeth (handles); + Xfreeteeth (teeth); + return 0; + } else { + test = Xloadcplane (list, (Xnodeptr *) NULL, handles, teeth, 0); + if (!test) { + Xfreeteeth (handles); + Xfreeteeth (teeth); + } + return test; + } + +} + +#ifdef CC_PROTOTYPE_ANSI +static int combslack (Xgraph *G, Xblock *handle, Xblock *fixtooth, + double *slack, Xnodeptrptr **teeth) +#else +static int combslack (G, handle, fixtooth, slack, teeth) +Xgraph *G; +Xblock *handle, *fixtooth; +double *slack; +Xnodeptrptr **teeth; +#endif +{ + int nteeth, hood = 0; + double max, total; + Xedge *e; + Xedgeptr *ep; + Xnode *n; + Xnodeptr *np; + Xcutnode *c; + Xcutnodeptr *cp; + Xblock *b, *maxb = (Xblock *) NULL; + Xblockptr *bp; + Xnodeptr *tooth; + + /* + printf ("combslack (%d, %d) ... \n", handle - blocklist, + fixtooth - * blocklist); + fflush (stdout); + */ + + nteeth = 1; + total = fixtooth->weight + handle->weight; + + for (n = G->pseudonodelist->next; n; n = n->next) + n->stacklabel = 0; + for (np = fixtooth->members; np; np = np->next) + np->this->stacklabel = 1; + for (bp = fixtooth->neighbors; bp; bp = bp->next) + for (np = bp->this->members; np; np = np->next) + np->this->stacklabel = 1; + + G->magicnum++; + for (ep = handle->one; ep; ep = ep->next) { + e = ep->this; + if (e->cends[0]->stacklabel != e->cends[1]->stacklabel) { + e->cends[0]->magiclabel = G->magicnum; + e->cends[1]->magiclabel = G->magicnum; + nteeth++; + total += 1.0; + if (teeth) { + Xmarktooth (e, &tooth); + Xadd_nodeptrptr (teeth, tooth); + } + } + } + for (np = fixtooth->members; np; np = np->next) + np->this->magiclabel = G->magicnum; + + for (cp = handle->cutnodes; cp; cp = cp->next) { + c = cp->this; + if (c->name->magiclabel != G->magicnum) { + max = 0.0; + for (bp = c->blocks; bp; bp = bp->next) { + b = bp->this; + if (b != handle) { + if (b->weight > max) { + hood = 0; + maxb = b; + max = b->weight; + } + if (bp->hood_weight > max) { + hood = 1; + maxb = b; + max = bp->hood_weight; + } + } + } + if (max >= 0.5) { + nteeth++; + total += max; + if (teeth) { + if (hood) + markblock (maxb, c, &tooth); + else + markblock (maxb, (Xcutnode *) NULL, &tooth); + Xadd_nodeptrptr (teeth, tooth); + } + } + } + } + + if (!(nteeth % 2)) + return 0; + else { + *slack = 1.5 + (0.5 * nteeth) - total; + return 1; + } +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xblossom.c b/contrib/blossom/concorde97/XSTUFF/Xblossom.c new file mode 100644 index 0000000000000000000000000000000000000000..376b5d8008314deef0e68f75930587c04803144f --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xblossom.c @@ -0,0 +1,1028 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int */ +/* Xexactblossoms_run (Xgraph *G, Xcplane **list, double *x), */ +/* Xexactblossomcheck (Xgraph *G, Xcplane **list, int pseudo, */ +/* double *x), */ +/* Xolaf (Xgraph *G, int olaf_select); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + buildcadj_from_pseudoedgelist (Xgraph *G), + buildcadj_from_edgelist (Xgraph *G), + buildpseudonodelist_from_scratch (Xgraph *G), + removedegreezero (Xgraph *G), + splitem (Xgraph *G, Xnode *n), + splitedge (Xgraph *G, Xedge *e, Xnode *n), + destroysplitgraph (Xgraph *G), + freesplitcadj (Xgraph *G), + freesplitedges (Xgraph *G), + freesplitters (Xgraph *G), + markcuttree_cut (Xcuttree_node *n, int v, int pseudo), + marknode (Xnode *n, int v), + dumpchildren (Xgraph *G, Xcuttree_node *n), + dump_cuttree (Xcuttree_node *t, Xnode *n), + T1 (Xgraph *G), + T2 (Xgraph *G), + T3 (Xgraph *G), + T4 (Xgraph *G), + T5 (Xgraph *G); + +static int + checkcuttree (Xgraph *G, Xcplane **cplanelist, Xcuttree_node *root, + int pseudo, double *x), + searchtree (Xgraph *G, Xcplane **cplanelist, Xcuttree_node *n, + int pseudo, double *x, double *val_last, int *n_last), + loadcuttree_blossom (Xgraph *G, Xcplane **cplanelist, int v), + loadcuttree_comb (Xgraph *G, Xcplane **list, int v, double *x), + cuttree_tooth (Xedge *e, int v), + isita_fattooth (Xedge *e), + oneend (Xedge *e, int v); + +#else + +static void + buildcadj_from_pseudoedgelist (), + buildcadj_from_edgelist (), + buildpseudonodelist_from_scratch (), + removedegreezero (), + splitem (), + splitedge (), + destroysplitgraph (), + freesplitcadj (), + freesplitedges (), + freesplitters (), + markcuttree_cut (), + marknode (), + dumpchildren (), + dump_cuttree (), + T1 (), + T2 (), + T3 (), + T4 (), + T5 (); + +static int + checkcuttree (), + searchtree (), + loadcuttree_blossom (), + loadcuttree_comb (), + cuttree_tooth (), + isita_fattooth (), + oneend (); + +#endif + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void + dumpsplitgraph (Xgraph *G); +#else +static void + dumpsplitgraph (); +#endif +#endif + + +#define ONEMINUS 0.999999 +#define ZEROPLUS 0.000001 + +static int npseudoedges; + +#ifdef CC_PROTOTYPE_ANSI +int Xexactblossoms_run (Xgraph *G, Xcplane **list, double *x) +#else +int Xexactblossoms_run (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + return Xexactblossomcheck (G, list, 0, x); +} + +#ifdef CC_PROTOTYPE_ANSI +int Xexactblossomcheck (Xgraph *G, Xcplane **cplanelist, int pseudo, double *x) +#else +int Xexactblossomcheck (G, cplanelist, pseudo, x) +Xgraph *G; +Xcplane **cplanelist; +int pseudo; +double *x; +#endif +{ + int i, j, npseudo_save = 0; + Xnode *n, **pseudo_save = (Xnode **) NULL, **p; + Xedge *e; + static Xedge pseudoedgedummy; + Xcuttree_node *root; + + if (!pseudo) { + Xloadx (G, x); + buildpseudonodelist_from_scratch (G); + for (i = G->nedges, e = G->edgelist; i; i--, e++) { + e->cends[0] = e->ends[0]; + e->cends[1] = e->ends[1]; + e->stay = 1; + } + buildcadj_from_edgelist (G); + } else { + pseudo_save = CC_SAFE_MALLOC (G->npseudonodes, Xnode *); + if (!pseudo_save) { + fprintf (stderr, "out of memory in Xexactblossomcheck\n"); + exit (1); + } + for (n = G->pseudonodelist->next, p = pseudo_save; n; n = n->next, p++) + *p = n; + npseudo_save = G->npseudonodes; + } + + for (n = G->pseudonodelist->next; n; n = n->next) { + n->pe = (Xedge *) NULL; + n->mark = 0; + } + for (i = G->nedges, e = G->edgelist; i; i--, e++) { + if (!e->stay) { + continue; + } else if (e->x > ONEMINUS) { + e->splitter = G->nodelist; /* just to kill the edge */ + e->cends[0]->mark = 1 - e->cends[0]->mark; + e->cends[1]->mark = 1 - e->cends[1]->mark; + } else if (e->x < ZEROPLUS) { + e->splitter = G->nodelist; + } else { + e->splitter = (Xnode *) NULL; + } + } + + + G->pseudoedgelist = &pseudoedgedummy; + G->pseudoedgelist->next = (Xedge *) NULL; + npseudoedges = 0; + + G->magicnum++; + for (n = G->pseudonodelist->next; n; n = n->next) + if (n->magiclabel != G->magicnum) + splitem (G, n); + + freesplitcadj (G); + buildcadj_from_pseudoedgelist (G); + removedegreezero (G); + + root = Xgomory_hu (G); + + if (root) { + j = checkcuttree (G, cplanelist, root, pseudo, x); +/* + printf ("%d exact blossoms\n", j); + fflush (stdout); +*/ + Xcuttree_free (root); + } else + j = 0; + + destroysplitgraph (G); + if (pseudo) { + G->npseudonodes = npseudo_save; + n = G->pseudonodelist; + for (i = npseudo_save, p = pseudo_save; i; i--, p++) { + n->next = *p; + n->next->prev = n; + n = n->next; + } + n->next = (Xnode *) NULL; + CC_FREE (pseudo_save, Xnode *); + buildcadj_from_edgelist (G); + } + return j; +} + +#ifdef CC_PROTOTYPE_ANSI +static void buildcadj_from_pseudoedgelist (Xgraph *G) +#else +static void buildcadj_from_pseudoedgelist (G) +Xgraph *G; +#endif +{ + Xedge *e; + Xedgeptr *ep; + + for (e = G->pseudoedgelist->next; e; e = e->next) { + ep = Xedgeptralloc (); + ep->next = (e->cends[0])->cadj.head; + ep->this = e; + (e->cends[0])->cadj.head = ep; + if ((e->cends[0])->cadj.tail == (Xedgeptr *) NULL) + (e->cends[0])->cadj.tail = ep; + ep = Xedgeptralloc (); + ep->next = (e->cends[1])->cadj.head; + ep->this = e; + (e->cends[1])->cadj.head = ep; + if ((e->cends[1])->cadj.tail == (Xedgeptr *) NULL) + (e->cends[1])->cadj.tail = ep; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void buildcadj_from_edgelist (Xgraph *G) +#else +static void buildcadj_from_edgelist (G) +Xgraph *G; +#endif +{ + Xedge *e; + Xedgeptr *ep; + int i; + + for (i = G->nedges, e = G->edgelist; i; i--, e++) { + if (!e->stay) + continue; + ep = Xedgeptralloc (); + ep->next = (e->cends[0])->cadj.head; + ep->this = e; + (e->cends[0])->cadj.head = ep; + if ((e->cends[0])->cadj.tail == (Xedgeptr *) NULL) + (e->cends[0])->cadj.tail = ep; + ep = Xedgeptralloc (); + ep->next = (e->cends[1])->cadj.head; + ep->this = e; + (e->cends[1])->cadj.head = ep; + if ((e->cends[1])->cadj.tail == (Xedgeptr *) NULL) + (e->cends[1])->cadj.tail = ep; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void buildpseudonodelist_from_scratch (Xgraph *G) +#else +static void buildpseudonodelist_from_scratch (G) +Xgraph *G; +#endif +{ + static Xnode pseudonodedummy; + int i; + Xnode *n; + + G->pseudonodelist = &pseudonodedummy; + pseudonodedummy.prev = (Xnode *) NULL; + pseudonodedummy.next = G->nodelist; + for (i = 0, n = G->nodelist; i < G->nnodes; i++, n++) { + n->cadj.head = n->cadj.tail = (Xedgeptr *) NULL; + n->prev = n - 1; + n->next = n + 1; + } + G->nodelist->prev = G->pseudonodelist; + G->nodelist[G->nnodes - 1].next = (Xnode *) NULL; + G->npseudonodes = G->nnodes; +} + +#ifdef CC_PROTOTYPE_ANSI +static void removedegreezero (Xgraph *G) +#else +static void removedegreezero (G) +Xgraph *G; +#endif +{ + Xnode *n, *next; + + for (n = G->pseudonodelist->next; n; n = next) + if (n->cadj.head == (Xedgeptr *) NULL) { + if ((next = n->next) != (Xnode *) NULL) { + n->next->prev = n->prev; + n->prev->next = n->next; + } else + n->prev->next = (Xnode *) NULL; + G->npseudonodes--; + } else + next = n->next; +} + +#ifdef CC_PROTOTYPE_ANSI +static void splitem (Xgraph *G, Xnode *n) +#else +static void splitem (G, n) +Xgraph *G; +Xnode *n; +#endif +{ + Xedgeptr *ep; + Xedge *e, *last; + Xnode *child; + + n->magiclabel = G->magicnum; + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (!e->splitter) { + child = OTHERCURRENTEND (e, n); + if (child->magiclabel != G->magicnum) + splitem (G, child); + } + } + for (ep = n->cadj.head, last = (Xedge *) NULL; ep; ep = ep->next) { + e = ep->this; + if (!e->splitter) { + if (last) + splitedge (G, last, n); + last = e; + } + } + + if (last) { + if (n->mark) + splitedge (G, last, n); + else + splitedge (G, last, OTHERCURRENTEND (last, n)); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void splitedge (Xgraph *G, Xedge *e, Xnode *n) +#else +static void splitedge (G, e, n) +Xgraph *G; +Xedge *e; +Xnode *n; +#endif +{ + Xnode *n1; + Xedge *e1; + + n->mark = 1 - n->mark; + + n1 = Xnodealloc (); + n1->magiclabel = 0; + n1->stacklabel = 0; + e->splitter = n1; + n1->pe = e; + n1->snext = n; /* points to the end which is marked odd */ + n1->mark = 1; + n1->cadj.head = n1->cadj.tail = (Xedgeptr *) NULL; + + n1->base.head = Xnodeptralloc (); + n1->base.tail = n1->base.head; + n1->base.head->next = (Xnodeptr *) NULL; + n1->base.head->this = n1; + + n1->next = G->pseudonodelist->next; + n1->prev = G->pseudonodelist; + G->pseudonodelist->next->prev = n1; + G->pseudonodelist->next = n1; + G->npseudonodes++; + + + e1 = Xedgealloc (); + e1->cends[0] = n; + e1->cends[1] = n1; + e1->stay = 1; + e1->x = 1.0 - e->x; + e1->next = G->pseudoedgelist->next; + G->pseudoedgelist->next = e1; + npseudoedges++; + + + e1 = Xedgealloc (); + e1->cends[0] = OTHERCURRENTEND (e, n); + e1->cends[1] = n1; + e1->stay = 1; + e1->x = e->x; + e1->next = G->pseudoedgelist->next; + G->pseudoedgelist->next = e1; + npseudoedges++; +} + +#ifdef CC_PROTOTYPE_ANSI +static void destroysplitgraph (Xgraph *G) +#else +static void destroysplitgraph (G) +Xgraph *G; +#endif +{ + freesplitcadj (G); + freesplitedges (G); + freesplitters (G); +} + +#ifdef CC_PROTOTYPE_ANSI +static void freesplitcadj (Xgraph *G) +#else +static void freesplitcadj (G) +Xgraph *G; +#endif +{ + Xnode *n; + Xedgeptr *e, *enext; + + for (n = G->pseudonodelist->next; n; n = n->next) { + for (e = n->cadj.head; e; e = enext) { + enext = e->next; + Xedgeptrfree (e); + } + n->cadj.head = n->cadj.tail = (Xedgeptr *) NULL; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void freesplitedges (Xgraph *G) +#else +static void freesplitedges (G) +Xgraph *G; +#endif +{ + Xedge *e, *enext; + + for (e = G->pseudoedgelist->next; e; e = enext) { + enext = e->next; + Xedgefree (e); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void freesplitters (Xgraph *G) +#else +static void freesplitters (G) +Xgraph *G; +#endif +{ + Xnode *n, *nnext, *prev; + Xnodeptr *np, *npnext; + + for (n = G->pseudonodelist->next, prev = G->pseudonodelist; n; n = nnext) { + nnext = n->next; + if (n->pe) { + prev->next = nnext; + if (nnext) + nnext->prev = prev; + for (np = n->base.head; np; np = npnext) { + npnext = np->next; + Xnodeptrfree (np); + } + Xnodefree (n); + } else + prev = n; + } +} + + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void dumpsplitgraph (Xgraph *G) +#else +static void dumpsplitgraph (G) +Xgraph *G; +#endif +{ + Xnode *n; + Xedge *e; + int i; + + printf ("NODES: %d\n", G->npseudonodes); + for (n = G->pseudonodelist->next; n; n = n->next) { + printf ("NODE %d mark = %d", n - G->nodelist, n->mark); + if (n->pe) + printf (" from %d\n", n->pe - G->edgelist); + else + printf ("\n"); + } + + printf ("EDGES: %d\n", npseudoedges); + for (i = 0, e = G->pseudoedgelist->next; e; e = e->next, i++) { + printf ("(%d %d %f) ", e->cends[0] - G->nodelist, + e->cends[1] - G->nodelist, + e->x); + if (i % 10 == 9) + printf ("\n"); + } + if (i % 10) + printf ("\n"); + fflush (stdout); +} +#endif /* DEBUG */ + + + +/***********************************************************************/ + + +#ifdef CC_PROTOTYPE_ANSI +static int checkcuttree (Xgraph *G, Xcplane **cplanelist, Xcuttree_node *root, + int pseudo, double *x) +#else +static int checkcuttree (G, cplanelist, root, pseudo, x) +Xgraph *G; +Xcplane **cplanelist; +Xcuttree_node *root; +int pseudo; +double *x; +#endif +{ + int nviolated; + int n_last = 0; + double val_last = 1.0; + + if (x == (double *) NULL) { + printf ("need x vector in checkcuttree\n"); + fflush (stdout); + return 0; + } + + nviolated = searchtree (G, cplanelist, root, pseudo, x, &val_last, &n_last); + return nviolated; +} + + +#ifdef CC_PROTOTYPE_ANSI +static int searchtree (Xgraph *G, Xcplane **cplanelist, Xcuttree_node *n, + int pseudo, double *x, double *val_last, int *n_last) +#else +static int searchtree (G, cplanelist, n, pseudo, x, val_last, n_last) +Xgraph *G; +Xcplane **cplanelist; +Xcuttree_node *n; +int pseudo; +double *x; +double *val_last; /* these guys are a hack to try to stop + * repeats */ +int *n_last; +#endif +{ + Xcuttree_node *c; + int i = 0; + + if (n->ndescendants % 2 == 1 && n->ndescendants > 1 ) { + if (n->cutval < 1.0 - XBLOTOLERANCE) { + G->magicnum++; + markcuttree_cut (n, G->magicnum, pseudo); + if (pseudo) { + i += loadcuttree_comb (G, cplanelist, G->magicnum, x); + } else + i += loadcuttree_blossom (G, cplanelist, G->magicnum); + } + } + for (c = n->child; c; c = c->sibling) + i += searchtree (G, cplanelist, c, pseudo, x, val_last, n_last); + + return i; +} + + +#ifdef CC_PROTOTYPE_ANSI +static void markcuttree_cut (Xcuttree_node *n, int v, int pseudo) +#else +static void markcuttree_cut (n, v, pseudo) +Xcuttree_node *n; +int v, pseudo; +#endif +{ + Xcuttree_node *c; + Xnodeptr *np; + + for (np = n->nlist.head; np; np = np->next) + if (pseudo) { + marknode (np->this, v); + } else + np->this->magiclabel = v; + + for (c = n->child; c; c = c->sibling) + markcuttree_cut (c, v, pseudo); +} + +#ifdef CC_PROTOTYPE_ANSI +static int loadcuttree_blossom (Xgraph *G, Xcplane **cplanelist, int v) +#else +static int loadcuttree_blossom (G, cplanelist, v) +Xgraph *G; +Xcplane **cplanelist; +int v; +#endif +{ + int i, test; + Xedge *e; + Xnode *n; + Xnodeptr *handle, *np; + Xedgeptr *teeth, *ep; + + teeth = (Xedgeptr *) NULL; + for (i = G->nedges, e = G->edgelist; i; i--, e++) + if (oneend (e, v) && cuttree_tooth (e, v)) { + ep = Xedgeptralloc (); + ep->this = e; + ep->next = teeth; + teeth = ep; + } + handle = (Xnodeptr *) NULL; + for (i = G->nnodes, n = G->nodelist; i; i--, n++) + if (n->magiclabel == v) { + np = Xnodeptralloc (); + np->this = n; + np->next = handle; + handle = np; + } + test = Xtemp_doblossom (G, cplanelist, handle, teeth); + Xedgeptr_list_free (teeth); + return test; +} + +#ifdef CC_PROTOTYPE_ANSI +static int loadcuttree_comb (Xgraph *G, Xcplane **cplanelist, int v, double *x) +#else +static int loadcuttree_comb (G, cplanelist, v, x) +Xgraph *G; +Xcplane **cplanelist; +int v; +double *x; +#endif +{ + int i, nteeth, test, hit = 0, countcheck = 1; + Xnode *n; + Xedge *e; + Xnodeptr *np, *handle; + Xnodeptrptr *teeth, *ntp; + + + for (i = G->nedges, e = G->edgelist; i; i--, e++) { + if (e->stay && oneend (e, v) && + cuttree_tooth (e, v) && isita_fattooth (e)) { + hit = 1; + break; + } + } + if (!hit) + return 0; + + handle = (Xnodeptr *) NULL; + for (i = G->nnodes, n = G->nodelist; i; i--, n++) + if (n->magiclabel == v) { + np = Xnodeptralloc (); + np->this = n; + np->next = handle; + handle = np; + } + teeth = (Xnodeptrptr *) NULL; + for (nteeth = 0, i = G->nedges, e = G->edgelist; i; i--, e++) { + if (!e->stay) + continue; + if (oneend (e, v) && cuttree_tooth (e, v)) { + nteeth++; + ntp = Xnodeptrptralloc (); + ntp->this = (Xnodeptr *) NULL; + ntp->next = teeth; + teeth = ntp; + Xmarktooth (e, &(ntp->this)); + } + } + + Xcleancomb (G, &handle, &teeth, &nteeth, x); + if (!Xtemp_combfluff (G, &handle, &teeth)) + return 0; + test = Xloadcplane (cplanelist, handle, (Xnodeptrptr *) NULL, teeth, + countcheck); + if (!test) { + Xnodeptr_list_free (handle); + for (ntp = teeth; ntp; ntp = ntp->next) + Xnodeptr_list_free (ntp->this); + Xnodeptrptr_list_free (teeth); + } + return test; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cuttree_tooth (Xedge *e, int v) +#else +static int cuttree_tooth (e, v) +Xedge *e; +int v; +#endif +{ + if (e->x > ONEMINUS) + return 1; + if (e->x < ZEROPLUS) + return 0; + + if (e->splitter->magiclabel == v) { + if (e->splitter->snext->magiclabel == v) + return 0; + else + return 1; + } else { + if (e->splitter->snext->magiclabel == v) + return 1; + else + return 0; + } + + /* David: is this the same as return (e->splitter->magiclabel == v) ^ + * (e->splitter->snext->magiclabel == v) */ +} + +#ifdef CC_PROTOTYPE_ANSI +static int isita_fattooth (Xedge *e) +#else +static int isita_fattooth (e) +Xedge *e; +#endif +{ + return (e->cends[0]->base.head->next || + e->cends[1]->base.head->next); +} + +#ifdef CC_PROTOTYPE_ANSI +static int oneend (Xedge *e, int v) +#else +static int oneend (e, v) +Xedge *e; +int v; +#endif +{ + if ((e->ends[0]->magiclabel == v && e->ends[1]->magiclabel != v) || + (e->ends[0]->magiclabel != v && e->ends[1]->magiclabel == v)) + return 1; + else + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void marknode (Xnode *n, int v) +#else +static void marknode (n, v) +Xnode *n; +int v; +#endif +{ + Xnodeptr *np; + + n->magiclabel = v; + for (np = n->base.head; np; np = np->next) { + np->this->magiclabel = v; + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static void dumpchildren (Xgraph *G, Xcuttree_node *n) +#else +static void dumpchildren (G, n) +Xgraph *G; +Xcuttree_node *n; +#endif +{ + Xcuttree_node *c; + Xnodeptr *cp; + + for (cp = n->nlist.head; cp; cp = cp->next) { + printf ("%d ", (int) (cp->this - G->nodelist)); + if (cp->this->pe) + printf ("splits %d = (%d %d) ", + (int) (cp->this->pe - G->edgelist), + (int) (cp->this->pe->ends[0] - G->nodelist), + (int) (cp->this->pe->ends[1] - G->nodelist)); + } + printf ("Special: %d\n", (int) (n->special - G->nodelist)); + for (c = n->child; c; c = c->sibling) + dumpchildren (G, c); + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_cuttree (Xcuttree_node *t, Xnode *n) +#else +static void dump_cuttree (t, n) +Xcuttree_node *t; +Xnode *n; +#endif +{ + Xcuttree_node *p; + Xnodeptr *pn; + + printf ("(%f, %d, %d, <", t->cutval, t->ndescendants, + (int) (t->special - n)); + for (pn = t->nlist.head; pn; pn = pn->next) + printf ("%d ", (int) (pn->this - n)); + printf ("> )\n"); + for (p = t->child; p; p = p->sibling) + dump_cuttree (p, n); + printf ("*"); + fflush (stdout); +} + +/**********************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI +int Xolaf (Xgraph *G, int olaf_select) +#else +int Xolaf (G, olaf_select) +Xgraph *G; +int olaf_select; +#endif +{ + Xnode *n; + int oldpseudonodes = G->npseudonodes; + + for (n = G->pseudonodelist->next; n; n = n->next) + n->Tmark = 0; + + switch (olaf_select) { + case 1: + T1 (G); + T2 (G); + T3 (G); + break; + case 2: + T1 (G); + T4 (G); + T3 (G); + break; + case 3: + T1 (G); + T5 (G); + T3 (G); + break; + case 4: + T1 (G); + T4 (G); + T5 (G); + break; + default: + printf ("Hey pal, don't call olaf with %d\n", olaf_select); + break; + } + return oldpseudonodes - G->npseudonodes; +} + +#ifdef CC_PROTOTYPE_ANSI +static void T1 (Xgraph *G) +#else +static void T1 (G) +Xgraph *G; +#endif +{ + int i; + Xedge *e; + Xnode *u, *v; + + for (e = G->edgelist, i = G->nedges; i; e++, i--) { + if (e->stay && e->x == 1.0) { + u = e->cends[0]; + v = e->cends[1]; + if (Xrepeat_1_shrink (G, u, e) + Xrepeat_1_shrink (G, v, e)) { + u->Tmark = 1; + v->Tmark = 1; + } + } + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static void T2 (Xgraph *G) +#else +static void T2 (G) +Xgraph *G; +#endif +{ + int i; + Xedge *e, *f, *g; + Xedgeptr *ep; + Xnode *u, *v, *w; + + for (e = G->edgelist, i = G->nedges; i; e++, i--) { + if (e->stay && e->x == 1.0 && !(u = e->cends[0])->Tmark + && !(v = e->cends[1])->Tmark) { + for (ep = u->cadj.head; ep && !u->Tmark; ep = ep->next) { + f = ep->this; + w = OTHERCURRENTEND (f, u); + if (!w->Tmark && (g = Xcurrentedge (v, w)) != (Xedge *) NULL) + if (f->x + g->x > 1.0 - XEPSILON) { + Xsimpleshrink (G, u, v); + u->Tmark = 1; + w->Tmark = 1; + } + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void T3 (Xgraph *G) +#else +static void T3 (G) +Xgraph *G; +#endif +{ + int i; + Xedge *c, *d, *e, *f, *g, *h; + Xedgeptr *ep, *ep2; + Xnode *u, *v, *w, *x; + + for (e = G->edgelist, i = G->nedges; i; e++, i--) { + /* e->x == 1 remove */ + if (e->stay && !(u = e->cends[0])->Tmark + && !(w = e->cends[1])->Tmark) { + for (ep = u->cadj.head; ep && !u->Tmark; ep = ep->next) { + f = ep->this; + v = OTHERCURRENTEND (f, u); + if (!v->Tmark) { + for (ep2 = w->cadj.head; ep2 && + !w->Tmark; ep2 = ep2->next) { + g = ep2->this; + x = OTHERCURRENTEND (g, w); + if (!x->Tmark && + x != v && + (h = Xcurrentedge (v, x)) != (Xedge *) NULL && + (d = Xcurrentedge (u, x)) != (Xedge *) NULL && + (c = Xcurrentedge (w, v)) != (Xedge *) NULL && + c->x + d->x + e->x + f->x + g->x + h->x >= + 3.0 - XEPSILON) { + Xsimpleshrink (G, u, w); + Xsimpleshrink (G, u, v); + Xsimpleshrink (G, u, x); + u->Tmark = 1; + w->Tmark = 1; + v->Tmark = 1; + x->Tmark = 1; + } + } + } + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void T4 (Xgraph *G) +#else +static void T4 (G) +Xgraph *G; +#endif +{ + int i; + Xedge *e, *f, *g, *h; + Xedgeptr *ep, *ep2; + Xnode *u, *v, *w, *x; + + for (e = G->edgelist, i = G->nedges; i; e++, i--) { + if (e->stay && e->x == 1.0 && !(u = e->cends[0])->Tmark + && !(w = e->cends[1])->Tmark) { + for (ep = u->cadj.head; ep && !u->Tmark; ep = ep->next) { + f = ep->this; + v = OTHERCURRENTEND (f, u); + if (!v->Tmark) { + for (ep2 = w->cadj.head; ep2 && + !w->Tmark; ep2 = ep2->next) { + g = ep2->this; + x = OTHERCURRENTEND (g, w); + if (!x->Tmark && + x != v && + f->x + g->x == 1.0 && + (h = Xcurrentedge (v, x)) != (Xedge *) NULL && + h->x == 1.0) { + Xsimpleshrink (G, u, w); + Xsimpleshrink (G, v, x); + u->Tmark = 1; + w->Tmark = 1; + v->Tmark = 1; + x->Tmark = 1; + } + } + } + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void T5 (Xgraph *G) +#else +static void T5 (G) +Xgraph *G; +#endif +{ + int i; + Xedge *e, *f, *g; + Xedgeptr *ep; + Xnode *u, *v, *w; + + for (e = G->edgelist, i = G->nedges; i; e++, i--) { + if (e->stay && e->x == 1.0 && !(u = e->cends[0])->Tmark + && !(v = e->cends[1])->Tmark) { + for (ep = u->cadj.head; ep && !u->Tmark; ep = ep->next) { + f = ep->this; + w = OTHERCURRENTEND (f, u); + if (!w->Tmark && (g = Xcurrentedge (v, w)) != (Xedge *) NULL) + if (f->x + g->x <= 0.5 + XEPSILON) { + Xsimpleshrink (G, u, v); + u->Tmark = 1; + w->Tmark = 1; + } + } + } + } +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xcclean.c b/contrib/blossom/concorde97/XSTUFF/Xcclean.c new file mode 100644 index 0000000000000000000000000000000000000000..bd70f9991451d340a61729a5976c22c7df62e3ad --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xcclean.c @@ -0,0 +1,1348 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void */ +/* cleancomb (); */ +/* */ +/* int */ +/* checkcomb (), */ +/* cliquefluff (), */ +/* temp_combfluff (), */ +/* combfluff (), */ +/* histok (), */ +/* checkclique (); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + + +#ifdef CC_PROTOTYPE_ANSI + +static void + complement_nodeptrlist (Xgraph *G, Xnodeptr *list, Xnodeptr **new), + get_smaller_cliquetree (Xgraph *G, Xnodeptrptr **newhandles, + Xnodeptrptr **newteeth, Xnodeptrptr *handles, Xnodeptrptr *teeth, + Xnodeptr *specialhandle), + clean_handle (Xgraph *G, Xnodeptr **handle, Xnodeptrptr **teeth, + int *nteeth, int *degree, double *x), + clean_stretch (Xgraph *G, Xnode *a, Xnode *b, Xnodeptr **toss, + Xnodeptr **tooth, int *degree, double *x), + clean_tooth (Xgraph *G, Xnodeptr *handle, Xnodeptr *tooth, + Xnodeptr **newtooth, double *x, int *degree), + process_clean_tooth_node (Xgraph *G, Xnode *n, double *x, int *degree, + Xnodeptr **toss), + clean_handle_connect_dfs (Xgraph *G, Xnode *n, double *x, int k); + +static int + checkclique_work (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth, + int flipped), + check_for_intersecting_teeth (Xgraph *G, Xnodeptr *handle, + Xnodeptrptr *teeth), + setmarks (Xgraph *G, int *vec, Xnodeptr *p, int from, int to), + check_cavity (Xgraph *G, Xnodeptr *p, int *vec), + verify_13 (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth), + clean_handle_connect (Xgraph *G, Xnodeptr *handle, double *x); + +#else + +static void + complement_nodeptrlist (), + get_smaller_cliquetree (), + clean_handle (), + clean_stretch (), + clean_tooth (), + process_clean_tooth_node (), + clean_handle_connect_dfs (); + +static int + checkclique_work (), + check_for_intersecting_teeth (), + setmarks (), + check_cavity (), + verify_13 (), + clean_handle_connect (); + +#endif + + +#ifdef CC_PROTOTYPE_ANSI +int Xcheckcomb (Xgraph *G, Xnodeptr *handle, Xnodeptrptr *teeth) +#else +int Xcheckcomb (G, handle, teeth) +Xgraph *G; +Xnodeptr *handle; +Xnodeptrptr *teeth; +#endif +{ + int nteeth, count, in, out; + Xnodeptr *np; + Xnodeptrptr *ntp; + + for (nteeth = 0, ntp = teeth; ntp; ntp = ntp->next) + nteeth++; + if (nteeth % 2 == 0) { + return 0; + } + G->magicnum++; + for (count = 0, np = handle; np; np = np->next, count++) + np->this->magiclabel = G->magicnum; + + if (count < 3) { + return 0; + } + for (count = 0, ntp = teeth; count < nteeth; ntp = ntp->next, count++) { + in = out = 0; + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) + in = 1; + else + out = 1; + if (!in || !out) { + return 0; + } + } + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xcliquefluff (Xgraph *G, Xnodeptrptr **handles, Xnodeptrptr **teeth) +#else +int Xcliquefluff (G, handles, teeth) +Xgraph *G; +Xnodeptrptr **handles, **teeth; +#endif +{ + /* Returns 1 if new clique-tree is loaded in handles and teeth */ + /* Returns 0 if clique-tree should be killed, wiping out the cut. */ + + int nteeth, nhandles, nonpendant, hit, hit1, hit2, cavity; + Xnodeptrptr *ntp, *mtp; + Xnodeptrptr *nonpendant_teeth, *pendant_teeth; + Xnodeptrptr *handle1_teeth, *handle2_teeth; + Xnodeptrptr *handle1, *handle2; + Xnodeptr *np; + + for (nhandles = 0, ntp = *handles; ntp; ntp = ntp->next) + nhandles++; + for (nteeth = 0, ntp = *teeth; ntp; ntp = ntp->next) + nteeth++; + + if (nhandles == 1) + return Xcombfluff (G, handles, teeth, 0); + + if (nteeth % 2 == 0 || nteeth < 3 || nhandles != 2) { + Xfreeteeth (*teeth); + Xfreeteeth (*handles); + /* printf ("FF Wrong Number of Handles or Teeth\n"); */ + return 0; + } + /* COLLECT NONPENDANT TEETH */ + + nonpendant_teeth = (Xnodeptrptr *) NULL; + pendant_teeth = (Xnodeptrptr *) NULL; + nonpendant = 0; + for (ntp = *teeth; ntp; ntp = ntp->next) { + G->magicnum++; + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (mtp = *handles, hit = 0; mtp && hit < 2; mtp = mtp->next) + for (np = mtp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + hit++; + break; + } + if (hit >= 2) { + nonpendant++; + Xadd_nodeptrptr (&nonpendant_teeth, ntp->this); + } else + Xadd_nodeptrptr (&pendant_teeth, ntp->this); + } + + if (nonpendant != 1) { + Xnodeptrptr_list_free (nonpendant_teeth); + Xnodeptrptr_list_free (pendant_teeth); + Xfreeteeth (*teeth); + Xfreeteeth (*handles); + return 0; + } + /* DO NOT ALLOW NONPENDANT TEETH TO MEET ANY OTHER TEETH */ + + G->magicnum++; + for (ntp = pendant_teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (ntp = nonpendant_teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + Xnodeptrptr_list_free (nonpendant_teeth); + Xnodeptrptr_list_free (pendant_teeth); + Xfreeteeth (*teeth); + Xfreeteeth (*handles); + /* printf ("FF Nonpendant Teeth Meet\n"); */ + return 0; + } else + np->this->magiclabel = G->magicnum; + + /* DIVIDE THE NONPENDANT TEETH AMONGST THE TWO HANDLES */ + + G->magicnum++; + handle1 = (Xnodeptrptr *) NULL; + Xadd_nodeptrptr (&handle1, (*handles)->this); + handle1_teeth = (Xnodeptrptr *) NULL; + for (np = handle1->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (ntp = pendant_teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + Xadd_nodeptrptr (&handle1_teeth, ntp->this); + break; + } + G->magicnum++; + handle2 = (Xnodeptrptr *) NULL; + Xadd_nodeptrptr (&handle2, (*handles)->next->this); + handle2_teeth = (Xnodeptrptr *) NULL; + for (np = handle2->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (ntp = pendant_teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + Xadd_nodeptrptr (&handle2_teeth, ntp->this); + break; + } + /* WE NO LONGER NEED THE ORIGINAL HANDLE & TEETH LISTS */ + + Xnodeptrptr_list_free (*handles); + Xnodeptrptr_list_free (*teeth); + Xnodeptrptr_list_free (pendant_teeth); + + /* DON'T ALLOW ANY TOOTH TO MEET A TOOTH HITTING THE OTHER HANDLE */ + + G->magicnum++; + for (ntp = handle1_teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (ntp = handle2_teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + Xfreeteeth (handle1_teeth); + Xfreeteeth (handle2_teeth); + Xfreeteeth (handle1); + Xfreeteeth (handle2); + Xfreeteeth (nonpendant_teeth); + /* printf ("FF Cross Teeth Meet\n"); */ + return 0; + } + + /* USE THE COMB CODE TO CLEAN THE TEETH MEETING EACH HANDLE */ + + if (!Xcombfluff (G, &handle1, &handle1_teeth, 1)) { + Xfreeteeth (handle2); + Xfreeteeth (handle2_teeth); + Xfreeteeth (nonpendant_teeth); + /* printf ("FF Comb Fluff of First Handle Failed\n"); */ + return 0; + } else if (!Xcombfluff (G, &handle2, &handle2_teeth, 1)) { + Xfreeteeth (handle1); + Xfreeteeth (handle1_teeth); + Xfreeteeth (nonpendant_teeth); + /* printf ("FF Comb Fluff of Second Handle Failed\n"); */ + return 0; + } + if (!handle1 || !handle2 || !handle1_teeth || !handle2_teeth) { + /* printf ("OH OH IN FLUFF\n"); */ + return 0; + } + + /* CHECK THAT NEW HANDLES DO NOT MEET */ + + G->magicnum++; + for (np = handle1->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + G->magicnum++; + for (np = handle2->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum - 1) { + Xfreeteeth (handle1); + Xfreeteeth (handle2); + Xfreeteeth (handle1_teeth); + Xfreeteeth (handle2_teeth); + Xfreeteeth (nonpendant_teeth); + /* printf ("FF New Handles Meet\n"); */ + return 0; + } else + np->this->magiclabel = G->magicnum; + + /* CHECK THAT NONPENDANT TOOTH HAS A CAVITY */ + + for (np = nonpendant_teeth->this, hit1 = 0, hit2 = 0, cavity = 0; np; + np = np->next) { + if (np->this->magiclabel == G->magicnum - 1) + hit1++; + else if (np->this->magiclabel == G->magicnum) + hit2++; + else + cavity++; + } + + if (!hit1 || !hit2 || !cavity) { + Xfreeteeth (handle1); + Xfreeteeth (handle2); + Xfreeteeth (handle1_teeth); + Xfreeteeth (handle2_teeth); + Xfreeteeth (nonpendant_teeth); + /* printf ("FF Nonpendant Tooth No Longer Has a Cavity\n"); */ + return 0; + } + + /* PUT THE NEW CLIQUE TREE TOGETHER */ + + handle1->next = handle2; + *handles = handle1; + + ntp = handle1_teeth; + while (ntp->next) + ntp = ntp->next; + if (!ntp) { + /* printf ("OH OH 2 IN FLUFF\n"); */ + return 0; + } + ntp->next = handle2_teeth; + nonpendant_teeth->next = handle1_teeth; + *teeth = nonpendant_teeth; + + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xtemp_combfluff (Xgraph *G, Xnodeptr **handle, Xnodeptrptr **teeth) +#else +int Xtemp_combfluff (G, handle, teeth) +Xgraph *G; +Xnodeptr **handle; +Xnodeptrptr **teeth; +#endif +{ + Xnodeptrptr *temphandle; + + temphandle = (Xnodeptrptr *) NULL; + Xadd_nodeptrptr (&temphandle, *handle); + if (!Xcliquefluff (G, &temphandle, teeth)) { + return 0; + } else { + *handle = temphandle->this; + Xnodeptrptrfree (temphandle); + return 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int Xtemp_combcheck (Xgraph *G, Xnodeptr *handle, Xnodeptrptr *teeth) +#else +int Xtemp_combcheck (G, handle, teeth) +Xgraph *G; +Xnodeptr *handle; +Xnodeptrptr *teeth; +#endif +{ + int rval; + Xnodeptrptr *temphandle; + + temphandle = (Xnodeptrptr *) NULL; + Xadd_nodeptrptr (&temphandle, handle); + + rval = Xcheckclique (G, temphandle, teeth); + Xnodeptrptrfree (temphandle); + return rval; +} + +#define SET_NOTEST -2 + +#ifdef CC_PROTOTYPE_ANSI +int Xcombfluff (Xgraph *G, Xnodeptrptr **handles, Xnodeptrptr **teeth, + int cliquetest) +#else +int Xcombfluff (G, handles, teeth, cliquetest) +Xgraph *G; +Xnodeptrptr **handles; +Xnodeptrptr **teeth; +int cliquetest; +#endif +{ + int *in_hand; + int *in_tooth; + int i, j; + int nhand; + int nteeth; + int newteeth; + Xnodeptr **teeth_array; + Xnodeptr *p; + Xnodeptrptr *np; + int v; + + for (np = *handles, nhand = 0; np; np = np->next) + nhand++; + for (np = *teeth, nteeth = 0; np; np = np->next) + nteeth++; + if (nhand != 1) { + /* + printf ("FF Fluff Comb called with more (or less) than one handle\n"); + */ + Xfreeteeth (*handles); + Xfreeteeth (*teeth); + return 0; + } + if (nteeth == 3 && !cliquetest) { + if (verify_13 (G, *handles, *teeth)) { + return 1; + } else { + for (np = *handles; np; np = np->next) { + Xnodeptr_list_free (np->this); + } + for (np = *teeth; np; np = np->next) { + Xnodeptr_list_free (np->this); + } + Xnodeptrptr_list_free (*handles); + Xnodeptrptr_list_free (*teeth); + *handles = (Xnodeptrptr *) NULL; + *teeth = (Xnodeptrptr *) NULL; + /* printf ("FF Fluff Comb\n"); */ + return 0; + } + } + in_hand = CC_SAFE_MALLOC (G->nnodes, int); + in_tooth = CC_SAFE_MALLOC (G->nnodes, int); + if (!in_hand || !in_tooth) { + fprintf (stderr, "out of memory in Xcombfluff\n"); + exit (1); + } + + for (i = 0; i < G->nnodes; i++) { + in_hand[i] = 0; + in_tooth[i] = -1; + } + + if (setmarks (G, in_hand, (*handles)->this, 0, 1) != SET_NOTEST) { + fprintf (stderr, "A setmarks failed\n"); + exit (1); + } + Xnodeptr_list_free ((*handles)->this); + + teeth_array = CC_SAFE_MALLOC (nteeth, Xnodeptr *); + if (!teeth_array) { + fprintf (stderr, "out of memory in Xcombfluff\n"); + exit (1); + } + + for (np = *teeth, i = 0; np; np = np->next, i++) { + teeth_array[i] = np->this; + } + Xnodeptrptr_list_free (*teeth); + + for (i = 0; i < nteeth; i++) { + v = setmarks (G, in_tooth, teeth_array[i], -1, i); + if (v != SET_NOTEST) { + j = in_tooth[v]; + if (setmarks (G, in_tooth, teeth_array[i], i, -1) != v || + setmarks (G, in_tooth, teeth_array[j], j, -1) != SET_NOTEST) { + fprintf (stderr, "B setmarks failed\n"); + exit (1); + } + if (in_hand[v]) { + setmarks (G, in_hand, teeth_array[i], SET_NOTEST, 0); + setmarks (G, in_hand, teeth_array[j], SET_NOTEST, 0); + } else { + setmarks (G, in_hand, teeth_array[i], SET_NOTEST, 1); + setmarks (G, in_hand, teeth_array[j], SET_NOTEST, 1); + } + Xnodeptr_list_free (teeth_array[i]); + Xnodeptr_list_free (teeth_array[j]); + teeth_array[i] = (Xnodeptr *) NULL; + teeth_array[j] = (Xnodeptr *) NULL; + } + } + *teeth = (Xnodeptrptr *) NULL; + for (i = 0, newteeth = 0; i < nteeth; i++) { + if (teeth_array[i]) { + if (check_cavity (G, teeth_array[i], in_hand)) { + newteeth++; + Xadd_nodeptrptr (teeth, teeth_array[i]); + } else { + Xnodeptr_list_free (teeth_array[i]); + teeth_array[i] = (Xnodeptr *) NULL; + } + } + } + + if (newteeth > 1 && (((!cliquetest && (newteeth & 1) == 1)) || + (cliquetest && (newteeth & 1) == 0))) { + p = (Xnodeptr *) NULL; + for (i = 0; i < G->nnodes; i++) { + if (in_hand[i]) { + Xadd_nodeptr (&p, &(G->nodelist[i])); + } + } + *handles = (Xnodeptrptr *) NULL; + Xadd_nodeptrptr (handles, p); + CC_FREE (in_hand, int); + CC_FREE (in_tooth, int); + CC_FREE (teeth_array, Xnodeptr *); + return 1; + } else { + for (np = *teeth; np; np = np->next) { + Xnodeptr_list_free (np->this); + } + Xnodeptrptr_list_free (*teeth); + *teeth = (Xnodeptrptr *) NULL; + *handles = (Xnodeptrptr *) NULL; + CC_FREE (in_hand, int); + CC_FREE (in_tooth, int); + CC_FREE (teeth_array, Xnodeptr *); + /* printf ("FF Fluff Comb\n"); */ + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int setmarks (Xgraph *G, int *vec, Xnodeptr *p, int from, int to) +#else +static int setmarks (G, vec, p, from, to) +Xgraph *G; +int *vec; +Xnodeptr *p; +int from, to; +#endif +{ + if (from == SET_NOTEST) { + while (p) { + vec[p->this - G->nodelist] = to; + p = p->next; + } + } else { + while (p) { + if (vec[p->this - G->nodelist] != from) { + return p->this - G->nodelist; + } + vec[p->this - G->nodelist] = to; + p = p->next; + } + } + return SET_NOTEST; +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_cavity (Xgraph *G, Xnodeptr *p, int *vec) +#else +static int check_cavity (G, p, vec) +Xgraph *G; +Xnodeptr *p; +int *vec; +#endif +{ + int got_hand = 0; + int got_cavity = 0; + + while (p) { + if (vec[p->this - G->nodelist]) { + if (got_cavity) + return 1; + got_hand++; + } else { + if (got_hand) + return 1; + got_cavity++; + } + p = p->next; + } + return 0; +} + +#define HANDLE 1 +#define TOOTH1 2 +#define TOOTH2 4 +#define TOOTH3 8 +#define NREGIONS 16 + +#ifdef CC_PROTOTYPE_ANSI +static int verify_13 (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth) +#else +static int verify_13 (G, handles, teeth) +Xgraph *G; +Xnodeptrptr *handles; +Xnodeptrptr *teeth; +#endif +{ + unsigned int *node_stat; + unsigned int flip; + unsigned int hist[NREGIONS]; + unsigned int hist2[NREGIONS]; + int i; + Xnodeptr *p; + Xnodeptrptr *pp; + int nhand; + int nteeth; + + node_stat = CC_SAFE_MALLOC (G->nnodes, unsigned int); + if (!node_stat) { + fprintf (stderr, "out of memory in verify_13\n"); + exit (1); + } + + for (i = 0; i < G->nnodes; i++) { + node_stat[i] = 0; + } + for (pp = handles, nhand = 0; pp; pp = pp->next, nhand++) { + for (p = pp->this; p; p = p->next) { + node_stat[p->this - G->nodelist] |= (1 << nhand); + } + } + for (pp = teeth, nteeth = 0; pp; pp = pp->next, nteeth++) { + for (p = pp->this; p; p = p->next) { + node_stat[p->this - G->nodelist] |= 1 << (nhand + nteeth); + } + } + if (nhand != 1 || nteeth != 3) { + CC_FREE (node_stat, unsigned int); + return 0; + } + for (i = 0; i < NREGIONS; i++) { + hist[i] = 0; + } + for (i = 0; i < G->nnodes; i++) { + hist[node_stat[i]]++; + } + for (flip = 0; flip < NREGIONS; flip++) { + for (i = 0; i < NREGIONS; i++) { + hist2[i] = hist[i ^ flip]; + } + if (Xhistok (hist2)) { + CC_FREE (node_stat, unsigned int); + return 1; + } + } + CC_FREE (node_stat, unsigned int); + /* printf ("CC Verify special failed to find a good flip\n"); */ + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xhistok (unsigned int *hist) +#else +int Xhistok (hist) +unsigned int *hist; +#endif +{ + if (!hist[TOOTH1]) + return 0; /* tooth 1 has a cavity */ + if (!hist[TOOTH2]) + return 0; /* tooth 2 has a cavity */ + if (!hist[TOOTH3]) + return 0; /* tooth 3 has a cavity */ + if (!hist[TOOTH1 | HANDLE]) + return 0; /* tooth 1 intersects the handle */ + if (!hist[TOOTH2 | HANDLE]) + return 0; /* tooth 1 intersects the handle */ + if (!hist[TOOTH3 | HANDLE]) + return 0; /* tooth 1 intersects the handle */ + if (hist[TOOTH1 | TOOTH2] ||/* Nothing else happens */ + hist[TOOTH1 | TOOTH3] || + hist[TOOTH2 | TOOTH3] || + hist[TOOTH1 | TOOTH2 | TOOTH3] || + hist[TOOTH1 | TOOTH2 | HANDLE] || + hist[TOOTH1 | TOOTH3 | HANDLE] || + hist[TOOTH2 | TOOTH3 | HANDLE] || + hist[TOOTH1 | TOOTH2 | TOOTH3 | HANDLE]) { + return 0; + } + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xcheckclique (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth) +#else +int Xcheckclique (G, handles, teeth) +Xgraph *G; +Xnodeptrptr *handles, *teeth; +#endif +{ + return checkclique_work (G, handles, teeth, 0); +} + +#ifdef CC_PROTOTYPE_ANSI +static int checkclique_work (Xgraph *G, Xnodeptrptr *handles, + Xnodeptrptr *teeth, int flipped) +#else +static int checkclique_work (G, handles, teeth, flipped) +Xgraph *G; +Xnodeptrptr *handles, *teeth; +int flipped; +#endif +{ + int nteeth, nhandles, nonpendant, hit, cavity, inhit; + Xnodeptr *np, *mp, *newtooth; + Xnodeptrptr *ntp, *mtp, *nonpendant_teeth, *pendant_teeth; + Xnodeptrptr *newhandles, *newteeth; + int special13, rval; + + for (nteeth = 0, ntp = teeth; ntp; ntp = ntp->next) + nteeth++; + if (nteeth % 2 == 0) { + /* printf ("CC Even Number of Teeth: %d\n", nteeth); */ + return 0; + } + for (nhandles = 0, ntp = handles; ntp; ntp = ntp->next) + nhandles++; + + if (nhandles == 0) { + /* printf ("CC No Handles\n"); */ + return 0; + } + if (nhandles == 1 && nteeth == 3) + special13 = 1; + else + special13 = 0; + + + /* EASY STUFF - Emtpy cliques, bad node numbers, etc. */ + + for (ntp = handles; ntp; ntp = ntp->next) { + if (!ntp->this) { + /* printf ("CC Empty Handle\n"); */ + return 0; + } + for (hit = 0, np = ntp->this; np; np = np->next) { + if ((np->this - G->nodelist) < 0 || + (np->this - G->nodelist) >= G->nnodes) { + /* printf ("CC Invalid node number in handle\n"); */ + return 0; + } else + hit++; + } + if (hit >= G->nnodes) { + /* printf ("CC Handle is entire graph\n"); */ + return 0; + } + } + + for (ntp = teeth; ntp; ntp = ntp->next) { + if (!ntp->this) { + /* printf ("CC Empty Tooth\n"); */ + return 0; + } + for (hit = 0, np = ntp->this; np; np = np->next) { + if ((np->this - G->nodelist) < 0 || + (np->this - G->nodelist) >= G->nnodes) { + /* printf ("CC Invalid node number in tooth\n"); */ + return 0; + } else + hit++; + } + if (hit >= G->nnodes) { + /* printf ("CC Tooth is entire graph\n"); */ + return 0; + } + } + + /* HANDLES SHOULD NEVER INTERSECT */ + + G->magicnum++; + for (ntp = handles; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + if (special13) + return verify_13 (G, handles, teeth); + else { + /* printf ("CC Handles Meet\n"); */ + return 0; + } + } else + np->this->magiclabel = G->magicnum; + + + /* INSIST THAT EVERY TOOTH HAVE A CAVITY, UNLESS WE HAVE THE 1-3 */ + /* CASE, WHERE WE ALLOW THE INVERTED TOOTH TO HAVE NO CAVITY. */ + + for (ntp = teeth; ntp; ntp = ntp->next) { + cavity = inhit = 0; + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel != G->magicnum) + cavity++; + else + inhit++; + if (!cavity || !inhit) { + if (special13) + return verify_13 (G, handles, teeth); + else { + /* printf ("CC Tooth has no cavity\n"); */ + return 0; + } + } + } + + /* EVERY HANDLE HITS AN ODD NUMBER OF TEETH */ + + for (ntp = handles; ntp; ntp = ntp->next) { + G->magicnum++; + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (hit = 0, mtp = teeth; mtp; mtp = mtp->next) + for (mp = mtp->this; mp; mp = mp->next) + if (mp->this->magiclabel == G->magicnum) { + hit++; + break; + } + if (hit % 2 == 0) { + if (special13) + return verify_13 (G, handles, teeth); + else { + /* printf ("CC Handle hits even num of teeth\n"); */ + return 0; + } + } + } + + /* TEETH IN COMBS CANNOT INTERSECT UNLESS 1-3 CASE */ + + if (nhandles == 1) { + G->magicnum++; + for (ntp = teeth; ntp; ntp = ntp->next) { + for (np = ntp->this; np; np = np->next) { + if (np->this->magiclabel == G->magicnum) { + if (special13) + return verify_13 (G, handles, teeth); + else { + /* printf ("CC Teeth in Comb\n"); */ + return 0; + } +/* + } +*/ + + } else { + np->this->magiclabel = G->magicnum; + } + + +/******************** BUG ************************************* + SHOULD HAVE: } else { + np->this->magiclabel = G->magicnum; + } +**************************************************************/ + + } + } + return 1; + } + /* Deal with a multihandled cliquetree by finding a handle to */ + /* delete and check that the remainder is a valid cliquetree. */ + + + nonpendant_teeth = (Xnodeptrptr *) NULL; + pendant_teeth = (Xnodeptrptr *) NULL; + nonpendant = 0; + for (ntp = teeth; ntp; ntp = ntp->next) { + G->magicnum++; + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (mtp = handles, hit = 0; mtp && hit < 2; mtp = mtp->next) + for (np = mtp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + hit++; + break; + } + if (hit >= 2) { + nonpendant++; + Xadd_nodeptrptr (&nonpendant_teeth, ntp->this); + } else + Xadd_nodeptrptr (&pendant_teeth, ntp->this); + } + + if (nonpendant > nhandles - 1) { + /* + printf ("CC %d handles, but %d nonpendant teeth\n", + nhandles, nonpendant); + */ + Xnodeptrptr_list_free (nonpendant_teeth); + Xnodeptrptr_list_free (pendant_teeth); + Xprintcliquetree (G, handles, teeth); + return 0; + } + for (ntp = handles; ntp; ntp = ntp->next) { + G->magicnum++; + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (mtp = nonpendant_teeth, hit = 0; mtp && hit < 2; mtp = mtp->next) + for (np = mtp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + hit++; + break; + } + if (!hit) { + /* printf ("CC Handle meets no nonpendant tooth\n"); */ + Xnodeptrptr_list_free (nonpendant_teeth); + Xnodeptrptr_list_free (pendant_teeth); + return 0; + } else if (hit == 1) { + if (check_for_intersecting_teeth (G, ntp->this, teeth)) { + get_smaller_cliquetree (G, &newhandles, &newteeth, + handles, teeth, ntp->this); + rval = checkclique_work (G, newhandles, newteeth, flipped); + Xnodeptrptr_list_free (nonpendant_teeth); + Xnodeptrptr_list_free (pendant_teeth); + Xnodeptrptr_list_free (newhandles); + Xnodeptrptr_list_free (newteeth); + if (!rval) { + printf ("CC Bad Recursion\n"); + Xprintcliquetree (G, handles, teeth); + fflush (stdout); + } + return rval; + } + } + } + + if (nhandles > 2) { + /* printf ("CC No good handle (%d) to reduce\n", nhandles); */ + } + + /* TRY FLIPPING THE NONPENDANT TOOTH IN TWO HANDLED CASE */ + + if (nhandles == 2 && !flipped) { + complement_nodeptrlist (G, nonpendant_teeth->this, &newtooth); + Xadd_nodeptrptr (&pendant_teeth, newtooth); + rval = checkclique_work (G, handles, pendant_teeth, 1); + Xnodeptr_list_free (newtooth); + Xnodeptrptr_list_free (nonpendant_teeth); + Xnodeptrptr_list_free (pendant_teeth); + if (rval) { + /* printf ("CC Needed to Flip the nonpendant tooth.\n"); */ + } else { + /* printf ("CC FLIP DID NOT HELP\n"); */ + } + return rval; + } else { + Xnodeptrptr_list_free (nonpendant_teeth); + Xnodeptrptr_list_free (pendant_teeth); + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void complement_nodeptrlist (Xgraph *G, Xnodeptr *list, Xnodeptr **new) +#else +static void complement_nodeptrlist (G, list, new) +Xgraph *G; +Xnodeptr *list, **new; +#endif +{ + Xnodeptr *np; + int i; + Xnode *n; + + *new = (Xnodeptr *) NULL; + G->magicnum++; + for (np = list; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (i = G->nnodes, n = G->nodelist; i; i--, n++) + if (n->magiclabel != G->magicnum) + Xadd_nodeptr (new, n); +} + +#ifdef CC_PROTOTYPE_ANSI +static void get_smaller_cliquetree (Xgraph *G, Xnodeptrptr **newhandles, + Xnodeptrptr **newteeth, Xnodeptrptr *handles, Xnodeptrptr *teeth, + Xnodeptr *specialhandle) +#else +static void get_smaller_cliquetree (G, newhandles, newteeth, handles, + teeth, specialhandle) +Xgraph *G; +Xnodeptrptr **newhandles, **newteeth, *handles, *teeth; +Xnodeptr *specialhandle; +#endif +{ + Xnodeptrptr *ntp, *mtp; + Xnodeptr *np; + int hit; + + *newhandles = (Xnodeptrptr *) NULL; + for (ntp = handles; ntp; ntp = ntp->next) + if (ntp->this != specialhandle) + Xadd_nodeptrptr (newhandles, ntp->this); + *newteeth = (Xnodeptrptr *) NULL; + for (ntp = teeth; ntp; ntp = ntp->next) { + G->magicnum++; + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (mtp = *newhandles, hit = 0; mtp && !hit; mtp = mtp->next) { + for (np = mtp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + hit++; + break; + } + } + if (hit) + Xadd_nodeptrptr (newteeth, ntp->this); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_for_intersecting_teeth (Xgraph *G, Xnodeptr *handle, + Xnodeptrptr *teeth) +#else +static int check_for_intersecting_teeth (G, handle, teeth) +Xgraph *G; +Xnodeptr *handle; +Xnodeptrptr *teeth; +#endif +{ + Xnodeptrptr *ntp; + Xnodeptr *np; + Xnodeptrptr *handle_teeth; + + G->magicnum++; + for (np = handle; np; np = np->next) + np->this->magiclabel = G->magicnum; + handle_teeth = (Xnodeptrptr *) NULL; + for (ntp = teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + Xadd_nodeptrptr (&handle_teeth, ntp->this); + break; + } + G->magicnum++; + for (ntp = handle_teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + if (np->this->magiclabel == G->magicnum) { + Xnodeptrptr_list_free (handle_teeth); + return 0; + } else + np->this->magiclabel = G->magicnum; + + Xnodeptrptr_list_free (handle_teeth); + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcleancomb (Xgraph *G, Xnodeptr **handle, Xnodeptrptr **teeth, + int *nteeth, double *x) +#else +void Xcleancomb (G, handle, teeth, nteeth, x) +Xgraph *G; +Xnodeptr **handle; +Xnodeptrptr **teeth; +int *nteeth; +double *x; +#endif +{ + int *degree; + Xnodeptrptr *newteeth, *ntp, *newtp; + + /* The cleaned comb goes back into handle and teeth. */ + + if (x == (double *) NULL) + return; + + newteeth = (Xnodeptrptr *) NULL; + + degree = CC_SAFE_MALLOC (G->nnodes, int); + if (!degree) { + fprintf (stderr, "out of memory in cleancomb\n"); + exit (1); + } + for (ntp = *teeth; ntp; ntp = ntp->next) { + newtp = Xnodeptrptralloc (); + newtp->this = (Xnodeptr *) NULL; + newtp->next = newteeth; + newteeth = newtp; + clean_tooth (G, *handle, ntp->this, &(newtp->this), x, degree); + } + + Xfreeteeth (*teeth); + + *teeth = newteeth; + + clean_handle (G, handle, teeth, nteeth, degree, x); + + CC_FREE (degree, int); +} + +#ifdef CC_PROTOTYPE_ANSI +static void clean_handle (Xgraph *G, Xnodeptr **handle, Xnodeptrptr **teeth, + int *nteeth, int *degree, double *x) +#else +static void clean_handle (G, handle, teeth, nteeth, degree, x) +Xgraph *G; +Xnodeptr **handle; +Xnodeptrptr **teeth; +int *nteeth, *degree; +double *x; +#endif +{ + Xnodeptr *np, *toss = (Xnodeptr *) NULL; + Xnodeptrptr *ntp; + Xnodeptr *tooth1, *tooth2, *newhandle; + Xnode *n, *n1; + Xedgeptr *ep; + Xedge *e; + + if (!clean_handle_connect (G, *handle, x)) + return; + + G->magicnum++; + for (np = *handle; np; np = np->next) { + np->this->magiclabel = G->magicnum; + degree[np->this - G->nodelist] = 0; + } + for (np = *handle; np; np = np->next) { + n = np->this; + for (ep = n->adj.head; ep; ep = ep->next) { + e = ep->this; + if (x[e - G->edgelist] > .9999 && + e->ends[0]->magiclabel == G->magicnum && + e->ends[1]->magiclabel == G->magicnum) + (degree[n - G->nodelist])++; + } + } + for (ntp = *teeth; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum - 1; + + for (np = *handle; np; np = np->next) { + n = np->this; + if (degree[n - G->nodelist] != 2 || n->magiclabel != G->magicnum) + continue; + for (ep = n->adj.head; ep; ep = ep->next) { + e = ep->this; + n1 = OTHEREND (e, n); + if (x[e - G->edgelist] > .9999 && + n1->magiclabel == G->magicnum && + degree[n1 - G->nodelist] == 2) { + Xadd_nodeptr (&toss, n); + Xadd_nodeptr (&toss, n1); + degree[n - G->nodelist] = 0; + degree[n1 - G->nodelist] = 0; + clean_stretch (G, n, n1, &toss, &tooth1, degree, x); + clean_stretch (G, n1, n, &toss, &tooth2, degree, x); + Xadd_nodeptrptr (teeth, tooth1); + Xadd_nodeptrptr (teeth, tooth2); + (*nteeth) += 2; + break; + } + } + } + G->magicnum++; + for (np = toss; np; np = np->next) + np->this->magiclabel = G->magicnum; + + Xnodeptr_list_free (toss); + + newhandle = (Xnodeptr *) NULL; + for (np = *handle; np; np = np->next) + if (np->this->magiclabel != G->magicnum) + Xadd_nodeptr (&newhandle, np->this); + Xnodeptr_list_free (*handle); + *handle = newhandle; +} + +#ifdef CC_PROTOTYPE_ANSI +static void clean_stretch (Xgraph *G, Xnode *a, Xnode *b, Xnodeptr **toss, + Xnodeptr **tooth, int *degree, double *x) +#else +static void clean_stretch (G, a, b, toss, tooth, degree, x) +Xgraph *G; +Xnode *a, *b; +Xnodeptr **toss, **tooth; +int *degree; +double *x; +#endif +{ + Xnode *c; + Xedgeptr *ep; + Xedge *e; + + for (ep = a->adj.head; ep; ep = ep->next) { + e = ep->this; + if (x[e - G->edgelist] > .9999 && ((c = OTHEREND (e, a)) != b)) { + if (degree[c - G->nodelist] == 2 && + c->magiclabel == G->magicnum) { + Xadd_nodeptr (toss, c); + degree[c - G->nodelist] = 0; + clean_stretch (G, c, a, toss, tooth, degree, x); + } else { + *tooth = (Xnodeptr *) NULL; + Xadd_nodeptr (tooth, a); + Xadd_nodeptr (tooth, c); + } + return; + } + } + printf ("ERROR IN CLEAN_STRETCH\n"); + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +static void clean_tooth (Xgraph *G, Xnodeptr *handle, Xnodeptr *tooth, + Xnodeptr **newtooth, double *x, int *degree) +#else +static void clean_tooth (G, handle, tooth, newtooth, x, degree) +Xgraph *G; +Xnodeptr *handle, *tooth, **newtooth; +double *x; +int *degree; +#endif +{ + Xnodeptr *np, *np1, *toss; + Xnode *n; + Xedgeptr *ep; + Xedge *e; + + G->magicnum++; + for (np = tooth; np; np = np->next) { + degree[np->this - G->nodelist] = 0; + np->this->magiclabel = G->magicnum; + } + + for (np = tooth; np; np = np->next) { + n = np->this; + for (ep = n->adj.head; ep; ep = ep->next) { + e = ep->this; + if (x[e - G->edgelist] > XEPSILON && + e->ends[0]->magiclabel == e->ends[1]->magiclabel) + (degree[n - G->nodelist])++; + } + } + + G->magicnum++; + for (np = handle; np; np = np->next) { + np->this->magiclabel = G->magicnum; + } + + toss = (Xnodeptr *) NULL; + + for (np = tooth; np; np = np->next) { + n = np->this; + if (n->magiclabel == G->magicnum - 1 && degree[n - G->nodelist] == 1) + process_clean_tooth_node (G, n, x, degree, &toss); + } + G->magicnum++; + + for (np = toss; np; np = np->next) + np->this->magiclabel = G->magicnum; + + Xnodeptr_list_free (toss); + + *newtooth = (Xnodeptr *) NULL; + for (np = tooth; np; np = np->next) + if (np->this->magiclabel != G->magicnum) { + np1 = Xnodeptralloc (); + np1->this = np->this; + np1->next = *newtooth; + *newtooth = np1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void process_clean_tooth_node (Xgraph *G, Xnode *n, double *x, + int *degree, Xnodeptr **toss) +#else +static void process_clean_tooth_node (G, n, x, degree, toss) +Xgraph *G; +Xnode *n; +double *x; +int *degree; +Xnodeptr **toss; +#endif +{ + Xedgeptr *ep; + Xedge *e; + Xnodeptr *np; + Xnode *n1; + double t; + + for (ep = n->adj.head; ep; ep = ep->next) { + e = ep->this; + t = x[e - G->edgelist]; + if (t > XEPSILON && + e->ends[0]->magiclabel == e->ends[1]->magiclabel) { + if (t > 0.9999) { + np = Xnodeptralloc (); + np->this = n; + np->next = *toss; + *toss = np; + n->magiclabel = G->magicnum - 2; + n1 = OTHEREND (e, n); + if (degree[n1 - G->nodelist] == 2) + process_clean_tooth_node (G, n1, x, degree, toss); + } + return; + } + } + return; +} + +#ifdef CC_PROTOTYPE_ANSI +static int clean_handle_connect (Xgraph *G, Xnodeptr *handle, double *x) +#else +static int clean_handle_connect (G, handle, x) +Xgraph *G; +Xnodeptr *handle; +double *x; +#endif +{ + Xnodeptr *np; + + if (handle == (Xnodeptr *) NULL) + return 0; + + G->magicnum++; + for (np = handle; np; np = np->next) + np->this->magiclabel = G->magicnum; + + clean_handle_connect_dfs (G, handle->this, x, G->magicnum); + + for (np = handle; np; np = np->next) + if (np->this->magiclabel == G->magicnum) + return 0; + + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static void clean_handle_connect_dfs (Xgraph *G, Xnode *start, double *x, int k) +#else +static void clean_handle_connect_dfs (G, start, x, k) +Xgraph *G; +Xnode *start; +double *x; +int k; +#endif +{ + Xedgeptr *ep; + Xedge *e; + Xnode *n, *n1; + Xnodeptr *next, *queue = (Xnodeptr *) NULL; + + start->magiclabel = k - 1; + Xadd_nodeptr (&queue, start); + + while (queue) { + n = queue->this; + next = queue->next; + Xnodeptrfree (queue); + queue = next; + + for (ep = n->adj.head; ep; ep = ep->next) { + e = ep->this; + if (x[e - G->edgelist] > 0.005) { + n1 = OTHEREND (e, n); + if (n1->magiclabel == k) { + n1->magiclabel = k - 1; + Xadd_nodeptr (&queue, n1); + } + } + } + } +} + diff --git a/contrib/blossom/concorde97/XSTUFF/Xclique.c b/contrib/blossom/concorde97/XSTUFF/Xclique.c new file mode 100644 index 0000000000000000000000000000000000000000..a89741e0863c65d52da9832800d94520d15024fc --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xclique.c @@ -0,0 +1,1174 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int */ +/* Xcliquetree (Xgraph *G, Xcplane **list, double *x), */ +/* Xcliquetree_work (Xgraph *G, Xcplane **list, int pseudo, */ +/* double *x, int type_of_grow) */ +/* */ +/**************************************************************************/ + + +#include "machdefs.h" +#include "Xsubtour.h" + + +#ifdef CC_PROTOTYPE_ANSI + +static void + split_T (Xgraph *G, Xnodeptr *T, Xnodeptr *U, Xnodeptr **u1, + Xnodeptr **u2, Xnodeptr **u3, Xnodeptr **u4, Xnodeptr **u5), + clique_dfs (Xgraph *G, Xnode *start, int z, int storenodes, + Xnodeptr **list), + unscan_remove (Xgraph *G, Xedgeptr **unscan, Xnodeptr *T), + remove_from_nodeptr (Xnode *n, Xnodeptr **list), + add_nodeptr_list (Xnodeptr **addto, Xnodeptr *takefrom), + label_nodeptr_list (Xnodeptr *list, int z), + pseudonodelist_to_nodelist (Xnodeptr *p, Xnodeptr **l); + +static int + clique_setup (Xgraph *G, int ct, Xnodeptr **u1, Xnodeptr **u2, + Xnodeptr **u3, Xnodeptr **u4, Xnodeptr **u5, int type_of_grow), + process_T (Xgraph *G, Xnodeptr **T, Xedge *e, Xnodeptr *U, + Xnodeptr **u1, Xnodeptr **u2, int type_of_grow), + grow (Xgraph *G, Xnodeptr **T, Xedge *e, Xnodeptr *U), + grow2 (Xgraph *G, Xnodeptr **T, Xedge *e, Xnodeptr *U), + grabcomponents (Xgraph *G, int z, Xnodeptr *T, Xnodeptr *U, + Xnodeptr **u1, Xnodeptr **u2), + improve (Xgraph *G, Xnodeptr **u1, Xnodeptr **u2, Xnodeptr **u3, + Xnodeptr **u4, Xnodeptr **u5), + grab_from_u5 (Xgraph *G, Xnodeptr *u1, Xnodeptr *u2, Xnodeptr *u3, + Xnodeptr *u4, Xnodeptr *u5, Xnodeptr **pick, Xnode **v), + grab_from_mate (Xgraph *G, Xnodeptr *mate, Xnodeptr *u3, + Xnodeptr *u4, Xnodeptr *u5, Xnode **w), + clique_violated (Xgraph *G, Xnodeptr *u1, Xnodeptr *u2, + Xnodeptr *u3, Xnodeptr *u4, Xnodeptr *u5), + clique_fringe (Xnode *n, int ct), + check_special_cliquetree (Xgraph *G, Xnodeptr *u1, Xnodeptr *u2, + Xnodeptr *u3, Xnodeptr *u4, Xnodeptr *u5, Xcplane **list, double *x), + load_special_cliquetree (Xgraph *G, Xnodeptr *H1, Xnodeptr *H2, + Xnodeptr *T, Xedgeptr *pteeth, Xcplane **list, double *x); + +static double + crossvalue (Xgraph *G, Xnodeptr *s1, Xnodeptr *s2, Xnodeptr *s3), + single_crossvalue (Xgraph *G, Xnode *v, Xnodeptr *s1, + Xnodeptr *s2, Xnodeptr *s3), + clique_slack (Xgraph *G, Xnodeptr *s); + +static Xnode + *best_w (Xgraph *G, Xnodeptr *T, Xnodeptr *ui, Xnode *hitter); + +#else + +static void + split_T (), + clique_dfs (), + unscan_remove (), + remove_from_nodeptr (), + add_nodeptr_list (), + label_nodeptr_list (), + pseudonodelist_to_nodelist (); + +static int + clique_setup (), + process_T (), + grow (), + grow2 (), + grabcomponents (), + improve (), + grab_from_u5 (), + grab_from_mate (), + clique_violated (), + clique_fringe (), + check_special_cliquetree (), + load_special_cliquetree (); + +static double + crossvalue (), + single_crossvalue (), + clique_slack (); + +static Xnode + *best_w (); + +#endif + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void + nodeptr_print (Xgraph *G, Xnodeptr *s), + dump_special_cliquetree (Xgraph *G, Xnodeptr *u1, Xnodeptr *u2, + Xnodeptr *u3, Xnodeptr *u4, Xnodeptr *u5); +#else +static void + nodeptr_print (), + dump_special_cliquetree (); +#endif +#endif + +#define ONEMINUS 0.999999 + +#ifdef CC_PROTOTYPE_ANSI +int Xcliquetree (Xgraph *G, Xcplane **list, double *x) +#else +int Xcliquetree (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + int hit = 0; + + hit += Xcliquetree_work (G, list, 0, x, 0); + if (hit < XCUTNUM) + hit += Xcliquetree_work (G, list, 0, x, 1); + + return hit; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xcliquetree_work (Xgraph *G, Xcplane **list, int pseudo, double *x, + int type_of_grow) +#else +int Xcliquetree_work (G, list, pseudo, x, type_of_grow) +Xgraph *G; +Xcplane **list; +int pseudo; +double *x; +int type_of_grow; +#endif +{ + int ncomponents, ct, hit, roll, realcount = 0; + Xnodeptr *u1, *u2, *u3, *u4, *u5; + + if (!pseudo) { + Xloadx (G, x); + Xbuildpseudonodelist (G, 0); + } + ncomponents = XTmark_components (G); + for (ct = 1; ct <= ncomponents; ct++) { + u1 = u2 = u3 = u4 = u5 = (Xnodeptr *) NULL; + if (!clique_setup (G, ct, &u1, &u2, &u3, &u4, &u5, type_of_grow)) + continue; + hit = 0; + do { + roll = improve (G, &u1, &u2, &u3, &u4, &u5); + if (clique_violated (G, u1, u2, u3, u4, u5)) + hit = 1; + } while (!hit && roll); + if (hit) { + realcount += + check_special_cliquetree (G, u1, u2, u3, u4, u5, list, x); + } + Xnodeptr_list_free (u1); + Xnodeptr_list_free (u2); + Xnodeptr_list_free (u3); + Xnodeptr_list_free (u4); + Xnodeptr_list_free (u5); + } + + if (!pseudo) { + Xdestroypseudonodelist (G); + /* printf ("%d clique trees\n", realcount); */ + } + + return realcount; +} + +#ifdef CC_PROTOTYPE_ANSI +static int clique_setup (Xgraph *G, int ct, Xnodeptr **u1, Xnodeptr **u2, + Xnodeptr **u3, Xnodeptr **u4, Xnodeptr **u5, int type_of_grow) +#else +static int clique_setup (G, ct, u1, u2, u3, u4, u5, type_of_grow) +Xgraph *G; +int ct; +Xnodeptr **u1, **u2, **u3, **u4, **u5; +int type_of_grow; +#endif +{ + Xnodeptr *np, *tp, *U = (Xnodeptr *) NULL, *T; + Xnode *n; + Xedgeptr *ep, *unscan = (Xedgeptr *) NULL; + Xedge *e; + int i, k; + + for (n = G->pseudonodelist->next; n; n = n->next) { + n->mark = 0; + if (n->Tmark == ct || clique_fringe (n, ct)) { + tp = Xnodeptralloc (); + tp->this = n; + tp->next = U; + U = tp; + } + } + G->magicnum++; + for (k = 0, np = U; np; np = np->next) { + np->this->magiclabel = G->magicnum; + k++; + } + if (k < 7) { + Xnodeptr_list_free (U); + return 0; + } + for (k = 0, np = U; np; np = np->next) { + n = np->this; + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->x > ONEMINUS && + OTHERCURRENTEND (e, n)->magiclabel != G->magicnum) { + n->mark = 1; + k++; + } + } + } + + if (k < 4) { + Xnodeptr_list_free (U); + return 0; + } + if (k % 2) { + Xnodeptr_list_free (U); + return 0; + } + for (i = G->nedges, e = G->edgelist; i; i--, e++) + if (e->stay && e->cends[0]->magiclabel == G->magicnum && + e->cends[1]->magiclabel == G->magicnum && + e->cends[0]->mark == 0 && + e->cends[1]->mark == 0) { + ep = Xedgeptralloc (); + ep->this = e; + ep->next = unscan; + unscan = ep; + } + while (unscan) { + e = unscan->this; + ep = unscan; + unscan = unscan->next; + Xedgeptrfree (ep); + if (process_T (G, &T, e, U, u1, u2, type_of_grow)) { + split_T (G, T, U, u1, u2, u3, u4, u5); + Xnodeptr_list_free (U); + Xnodeptr_list_free (T); + Xedgeptr_list_free (unscan); + return 1; + } else { + unscan_remove (G, &unscan, T); + Xnodeptr_list_free (T); + } + } + Xnodeptr_list_free (U); + Xedgeptr_list_free (unscan); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void split_T (Xgraph *G, Xnodeptr *T, Xnodeptr *U, Xnodeptr **u1, + Xnodeptr **u2, Xnodeptr **u3, Xnodeptr **u4, Xnodeptr **u5) +#else +static void split_T (G, T, U, u1, u2, u3, u4, u5) +Xgraph *G; +Xnodeptr *T, *U, **u1, **u2, **u3, **u4, **u5; +#endif +{ + Xnodeptr *np, *tp, *next; + Xnode *n, *w1, *w2; + + G->magicnum++; + for (np = T; np; np = np->next) + np->this->magiclabel = G->magicnum; + + for (np = *u1, *u1 = (Xnodeptr *) NULL; np; np = next) { + next = np->next; + if (np->this->magiclabel == G->magicnum) + Xnodeptrfree (np); + else { + np->next = *u1; + *u1 = np; + } + } + for (np = *u2, *u2 = (Xnodeptr *) NULL; np; np = next) { + next = np->next; + if (np->this->magiclabel == G->magicnum) + Xnodeptrfree (np); + else { + np->next = *u2; + *u2 = np; + } + } + + w1 = best_w (G, T, *u1, (Xnode *) NULL); + np = Xnodeptralloc (); + np->this = w1; + np->next = (Xnodeptr *) NULL; + *u3 = np; + + w2 = best_w (G, T, *u2, w1); + np = Xnodeptralloc (); + np->this = w2; + np->next = (Xnodeptr *) NULL; + *u4 = np; + + G->magicnum++; + for (np = *u1; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (np = *u2; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (np = *u3; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (np = *u4; np; np = np->next) + np->this->magiclabel = G->magicnum; + + *u5 = (Xnodeptr *) NULL; + for (np = U; np; np = np->next) { + n = np->this; + if (n->magiclabel != G->magicnum) { + tp = Xnodeptralloc (); + tp->this = n; + tp->next = *u5; + *u5 = tp; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static Xnode *best_w (Xgraph *G, Xnodeptr *T, Xnodeptr *ui, Xnode *hitter) +#else +static Xnode *best_w (G, T, ui, hitter) +Xgraph *G; +Xnodeptr *T, *ui; +Xnode *hitter; +#endif +{ + Xnodeptr *np; + Xnode *n, *w = (Xnode *) NULL; + Xedgeptr *ep; + Xedge *e; + double adj, bestadj = -1.0; + + G->magicnum++; + for (np = ui; np; np = np->next) + np->this->magiclabel = G->magicnum; + + for (np = T; np; np = np->next) { + n = np->this; + if (n == hitter) + continue; + adj = 0.0; + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (OTHERCURRENTEND (e, n)->magiclabel == + G->magicnum) + adj += e->x; + } + if (adj > bestadj) { + bestadj = adj; + w = n; + } + } + return w; +} + +#ifdef CC_PROTOTYPE_ANSI +static int process_T (Xgraph *G, Xnodeptr **T, Xedge *e, Xnodeptr *U, + Xnodeptr **u1, Xnodeptr **u2, int type_of_grow) +#else +static int process_T (G, T, e, U, u1, u2, type_of_grow) +Xgraph *G; +Xnodeptr **T; +Xedge *e; +Xnodeptr *U, **u1, **u2; +int type_of_grow; +#endif +{ + Xnodeptr *np; + Xnode *n; + Xedgeptr *ep; + Xedge *f; + int iU; + + if (!type_of_grow) { + if (grow (G, T, e, U) < 3) + return 0; + } else { + if (grow2 (G, T, e, U) < 3) + return 0; + } + + iU = ++(G->magicnum); + for (np = U; np; np = np->next) + np->this->magiclabel = G->magicnum; + G->magicnum++; + for (np = *T; np; np = np->next) + np->this->magiclabel = G->magicnum; + + G->magicedgenum++; + for (np = U; np; np = np->next) { + n = np->this; + if (n->magiclabel == G->magicnum) + continue; + for (ep = n->cadj.head; ep; ep = ep->next) { + f = ep->this; + if ((OTHERCURRENTEND (f, n))->magiclabel >= iU) + f->magiclabel = G->magicedgenum; + } + } + if (grabcomponents (G, G->magicedgenum, *T, U, u1, u2)) + return 1; + + iU = ++(G->magicnum); + for (np = U; np; np = np->next) + np->this->magiclabel = G->magicnum; + G->magicnum++; + for (np = *T; np; np = np->next) + np->this->magiclabel = G->magicnum; + + G->magicedgenum++; + for (np = U; np; np = np->next) { + n = np->this; + if (n->magiclabel == G->magicnum) + continue; + for (ep = n->cadj.head; ep; ep = ep->next) { + f = ep->this; + if ((OTHERCURRENTEND (f, n))->magiclabel == iU) + f->magiclabel = G->magicedgenum; + } + } + + if (grabcomponents (G, G->magicedgenum, *T, U, u1, u2)) + return 1; + else + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int grow (Xgraph *G, Xnodeptr **T, Xedge *e, Xnodeptr *U) +#else +static int grow (G, T, e, U) +Xgraph *G; +Xnodeptr **T; +Xedge *e; +Xnodeptr *U; +#endif +{ + Xnodeptr *np, *tp; + Xnode *n; + Xedgeptr *ep; + Xedge *f; + int count, adcount, hit; + double adval; + + np = Xnodeptralloc (); + tp = Xnodeptralloc (); + np->this = e->cends[0]; + tp->this = e->cends[1]; + np->next = (Xnodeptr *) NULL; + tp->next = np; + *T = tp; + count = 2; + + G->magicnum++; + e->cends[0]->magiclabel = G->magicnum; + e->cends[1]->magiclabel = G->magicnum; + + do { + hit = 0; + for (np = U; np; np = np->next) { + n = np->this; + if (n->magiclabel != G->magicnum && n->mark == 0) { + adcount = 0; + adval = 0.0; + for (ep = n->cadj.head; ep; ep = ep->next) { + f = ep->this; + if (OTHERCURRENTEND (f, n)->magiclabel + == G->magicnum) { + adcount++; + adval += f->x; + } + } + if (adcount >= 2 && adval >= 1.0) { + tp = Xnodeptralloc (); + tp->this = n; + tp->next = *T; + *T = tp; + n->magiclabel = G->magicnum; + hit++; + } + } + } + count += hit; + } while (hit); + + return count; +} + +#ifdef CC_PROTOTYPE_ANSI +static int grow2 (Xgraph *G, Xnodeptr **T, Xedge *e, Xnodeptr *U) +#else +static int grow2 (G, T, e, U) +Xgraph *G; +Xnodeptr **T; +Xedge *e; +Xnodeptr *U; +#endif +{ + Xnodeptr *np, *tp; + Xnode *n; + Xedgeptr *ep; + Xedge *f; + int count, hit; + double adval, slack; + + np = Xnodeptralloc (); + tp = Xnodeptralloc (); + np->this = e->cends[0]; + tp->this = e->cends[1]; + np->next = (Xnodeptr *) NULL; + tp->next = np; + *T = tp; + count = 2; + + G->magicnum++; + e->cends[0]->magiclabel = G->magicnum; + e->cends[1]->magiclabel = G->magicnum; + slack = 1.0 - e->x; + + do { + hit = 0; + for (np = U; np; np = np->next) { + n = np->this; + if (n->magiclabel != G->magicnum && n->mark == 0) { + adval = 0.0; + for (ep = n->cadj.head; ep; ep = ep->next) { + f = ep->this; + if (OTHERCURRENTEND (f, n)->magiclabel + == G->magicnum) { + adval += f->x; + } + } + if (slack + (1.0 - adval) < 0.5) { + tp = Xnodeptralloc (); + tp->this = n; + tp->next = *T; + *T = tp; + n->magiclabel = G->magicnum; + hit++; + slack += (1.0 - adval); + } + } + } + count += hit; + } while (hit); + + return count; +} + +#ifdef CC_PROTOTYPE_ANSI +static int grabcomponents (Xgraph *G, int z, Xnodeptr *T, Xnodeptr *U, + Xnodeptr **u1, Xnodeptr **u2) +#else +static int grabcomponents (G, z, T, U, u1, u2) +Xgraph *G; +int z; +Xnodeptr *T, *U, **u1, **u2; +#endif +{ + Xnodeptr *np, *tp, *all = (Xnodeptr *) NULL; + Xnode *n; + Xedgeptr *ep; + int componentcount, k; + + G->magicnum++; + label_nodeptr_list (T, G->magicnum); + + for (np = U; np; np = np->next) { + n = np->this; + if (n->magiclabel != G->magicnum) + Xadd_nodeptr (&all, n); + else + for (ep = n->cadj.head; ep; ep = ep->next) + if (ep->this->magiclabel == z) { + Xadd_nodeptr (&all, n); + break; + } + } + if (!all) { + printf ("Eak in grabcomponents\n"); + return 0; + } + G->magicnum++; + componentcount = 0; + for (np = all; componentcount <= 2 && np; np = np->next) + if (np->this->magiclabel != G->magicnum) { + clique_dfs (G, np->this, z, 0, (Xnodeptr **) NULL); + componentcount++; + } + if (componentcount != 2) { + Xnodeptr_list_free (all); + return 0; + } else { + G->magicnum++; + *u1 = (Xnodeptr *) NULL; + clique_dfs (G, all->this, z, 1, u1); + for (k = 0, tp = *u1; tp; tp = tp->next) { + if (tp->this->mark) + k++; + } + if (k < 2 || k % 2 != 0) { + Xnodeptr_list_free (all); + Xnodeptr_list_free (*u1); + *u1 = (Xnodeptr *) NULL; + return 0; + } + np = all->next; + while (np->this->magiclabel == G->magicnum) + np = np->next; + *u2 = (Xnodeptr *) NULL; + clique_dfs (G, np->this, z, 1, u2); + for (k = 0, tp = *u2; tp; tp = tp->next) + if (tp->this->mark) + k++; + if (k < 2 || k % 2 != 0) { + Xnodeptr_list_free (all); + Xnodeptr_list_free (*u1); + Xnodeptr_list_free (*u2); + *u1 = *u2 = (Xnodeptr *) NULL; + return 0; + } else { + Xnodeptr_list_free (all); + return 1; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void clique_dfs (Xgraph *G, Xnode *start, int z, int storenodes, + Xnodeptr **list) +#else +static void clique_dfs (G, start, z, storenodes, list) +Xgraph *G; +Xnode *start; +int z, storenodes; +Xnodeptr **list; +#endif +{ + Xedgeptr *ep; + Xnodeptr *np; + Xnode *n, *v; + Xnodeptr *next, *queue = (Xnodeptr *) NULL; + + start->magiclabel = G->magicnum; + Xadd_nodeptr (&queue, start); + + while (queue) { + n = queue->this; + next = queue->next; + Xnodeptrfree (queue); + queue = next; + if (storenodes) { + np = Xnodeptralloc (); + np->this = n; + np->next = *list; + *list = np; + } + for (ep = n->cadj.head; ep; ep = ep->next) { + if (ep->this->magiclabel == z) { + v = OTHERCURRENTEND (ep->this, n); + if (v->magiclabel != G->magicnum) { + v->magiclabel = G->magicnum; + Xadd_nodeptr (&queue, v); + } + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void unscan_remove (Xgraph *G, Xedgeptr **unscan, Xnodeptr *T) +#else +static void unscan_remove (G, unscan, T) +Xgraph *G; +Xedgeptr **unscan; +Xnodeptr *T; +#endif +{ + Xnodeptr *np; + Xedgeptr *ep, *next; + + G->magicnum++; + for (np = T; np; np = np->next) + np->this->magiclabel = G->magicnum; + + for (ep = *unscan, *unscan = (Xedgeptr *) NULL; ep; ep = next) { + next = ep->next; + if (ep->this->cends[0]->magiclabel == G->magicnum && + ep->this->cends[1]->magiclabel == G->magicnum) + Xedgeptrfree (ep); + else { + ep->next = *unscan; + *unscan = ep; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int improve (Xgraph *G, Xnodeptr **u1, Xnodeptr **u2, Xnodeptr **u3, + Xnodeptr **u4, Xnodeptr **u5) +#else +static int improve (G, u1, u2, u3, u4, u5) +Xgraph *G; +Xnodeptr **u1, **u2, **u3, **u4, **u5; +#endif +{ + int win, gotone = 0; + Xnodeptr *pick; + Xnode *v, *w; + + while ((*u5)->next != (Xnodeptr *) NULL) { + win = grab_from_u5 (G, *u1, *u2, *u3, *u4, *u5, &pick, &v); + if (!win) + return gotone; + gotone = 1; + if (pick == *u1) { + remove_from_nodeptr (v, u5); + Xadd_nodeptr (u3, v); + while ((*u3)->next != (Xnodeptr *) NULL && + grab_from_mate (G, *u3, *u3, *u4, *u5, &w)) { + remove_from_nodeptr (w, u3); + Xadd_nodeptr (u1, w); + } + } else { + remove_from_nodeptr (v, u5); + Xadd_nodeptr (u4, v); + while ((*u4)->next != (Xnodeptr *) NULL && + grab_from_mate (G, *u4, *u3, *u4, *u5, &w)) { + remove_from_nodeptr (w, u4); + Xadd_nodeptr (u2, w); + } + } + } + return gotone; +} + +#ifdef CC_PROTOTYPE_ANSI +static int grab_from_u5 (Xgraph *G, Xnodeptr *u1, Xnodeptr *u2, Xnodeptr *u3, + Xnodeptr *u4, Xnodeptr *u5, Xnodeptr **pick, Xnode **v) +#else +static int grab_from_u5 (G, u1, u2, u3, u4, u5, pick, v) +Xgraph *G; +Xnodeptr *u1, *u2, *u3, *u4, *u5, **pick; +Xnode **v; +#endif +{ + Xnodeptr *np; + Xnode *n; + double t, best = -1.0; + + for (np = u5; np; np = np->next) { + n = np->this; + t = single_crossvalue (G, n, u1, u3, (Xnodeptr *) NULL); + if (t > best) { + best = t; + *pick = u1; + *v = n; + } + t = single_crossvalue (G, n, u2, u4, (Xnodeptr *) NULL); + if (t > best) { + best = t; + *pick = u2; + *v = n; + } + } + + return (best >= 1.0); +} + +#ifdef CC_PROTOTYPE_ANSI +static int grab_from_mate (Xgraph *G, Xnodeptr *mate, Xnodeptr *u3, + Xnodeptr *u4, Xnodeptr *u5, Xnode **w) +#else +static int grab_from_mate (G, mate, u3, u4, u5, w) +Xgraph *G; +Xnodeptr *mate, *u3, *u4, *u5; +Xnode **w; +#endif +{ + Xnodeptr *np; + + for (np = mate; np; np = np->next) + if (single_crossvalue (G, np->this, u3, u4, u5) <= 1.0) { + *w = np->this; + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int clique_violated (Xgraph *G, Xnodeptr *u1, Xnodeptr *u2, + Xnodeptr *u3, Xnodeptr *u4, Xnodeptr *u5) +#else +static int clique_violated (G, u1, u2, u3, u4, u5) +Xgraph *G; +Xnodeptr *u1, *u2, *u3, *u4, *u5; +#endif +{ + double y; + + y = crossvalue (G, u1, (Xnodeptr *) NULL, u2) + crossvalue (G, u1, u2, u5) + + crossvalue (G, u1, (Xnodeptr *) NULL, u4) + + crossvalue (G, u2, (Xnodeptr *) NULL, u3) + + clique_slack (G, u3) + clique_slack (G, u4); + /* printf ("CLIQUE VALUE: %f\n", y); fflush (stdout); */ + return (y < 1.0 - XEPSILON); +} + +#ifdef CC_PROTOTYPE_ANSI +static double crossvalue (Xgraph *G, Xnodeptr *s1, Xnodeptr *s2, Xnodeptr *s3) +#else +static double crossvalue (G, s1, s2, s3) +Xgraph *G; +Xnodeptr *s1, *s2, *s3; +#endif +{ + double val = 0.0; + Xnodeptr *np; + Xnode *n; + Xedgeptr *ep; + Xedge *e; + + G->magicnum++; + for (np = s1; np; np = np->next) + np->this->magiclabel = G->magicnum; + if (s2) + for (np = s2; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (np = s3; np; np = np->next) { + n = np->this; + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (OTHERCURRENTEND (e, n)->magiclabel == G->magicnum) + val += e->x; + } + } + return val; +} + +#ifdef CC_PROTOTYPE_ANSI +static double single_crossvalue (Xgraph *G, Xnode *v, Xnodeptr *s1, + Xnodeptr *s2, Xnodeptr *s3) +#else +static double single_crossvalue (G, v, s1, s2, s3) +Xgraph *G; +Xnode *v; +Xnodeptr *s1, *s2, *s3; +#endif +{ + double val = 0.0; + Xnodeptr *np; + Xedgeptr *ep; + Xedge *e; + + G->magicnum++; + for (np = s1; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (np = s2; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (np = s3; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (ep = v->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (OTHERCURRENTEND (e, v)->magiclabel == G->magicnum) + val += e->x; + } + return val; +} + +#ifdef CC_PROTOTYPE_ANSI +static double clique_slack (Xgraph *G, Xnodeptr *s) +#else +static double clique_slack (G, s) +Xgraph *G; +Xnodeptr *s; +#endif +{ + double val = 0.0, c = 0.0; + Xnodeptr *np; + Xedgeptr *ep; + Xedge *e; + + G->magicnum++; + for (np = s; np; np = np->next) { + np->this->magiclabel = G->magicnum; + c += 1.0; + } + for (np = s; np; np = np->next) + for (ep = np->this->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->cends[0]->magiclabel == G->magicnum && + e->cends[1]->magiclabel == G->magicnum) + val += e->x; + } + val *= 0.5; + return c - 1.0 - val; +} + +#ifdef CC_PROTOTYPE_ANSI +static int clique_fringe (Xnode *n, int ct) +#else +static int clique_fringe (n, ct) +Xnode *n; +int ct; +#endif +{ + Xedgeptr *ep; + Xedge *e; + + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->x <= ONEMINUS || + OTHERCURRENTEND (e, n)->Tmark != ct) + return 0; + } + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static void remove_from_nodeptr (Xnode *n, Xnodeptr **list) +#else +static void remove_from_nodeptr (n, list) +Xnode *n; +Xnodeptr **list; +#endif +{ + Xnodeptr *np, *next; + + for (np = *list, *list = (Xnodeptr *) NULL; np; np = next) { + next = np->next; + if (np->this == n) + Xnodeptrfree (np); + else { + np->next = *list; + *list = np; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void add_nodeptr_list (Xnodeptr **addto, Xnodeptr *takefrom) +#else +static void add_nodeptr_list (addto, takefrom) +Xnodeptr **addto, *takefrom; +#endif +{ + Xnodeptr *np, *tp; + + for (np = takefrom; np; np = np->next) { + tp = Xnodeptralloc (); + tp->this = np->this; + tp->next = *addto; + *addto = tp; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void label_nodeptr_list (Xnodeptr *list, int z) +#else +static void label_nodeptr_list (list, z) +Xnodeptr *list; +int z; +#endif +{ + Xnodeptr *np; + + for (np = list; np; np = np->next) + np->this->magiclabel = z; +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_special_cliquetree (Xgraph *G, Xnodeptr *u1, Xnodeptr *u2, + Xnodeptr *u3, Xnodeptr *u4, Xnodeptr *u5, Xcplane **list, double *x) +#else +static int check_special_cliquetree (G, u1, u2, u3, u4, u5, list, x) +Xgraph *G; +Xnodeptr *u1, *u2, *u3, *u4, *u5; +Xcplane **list; +double *x; +#endif +{ + Xnodeptr *H1 = (Xnodeptr *) NULL, *H2 = (Xnodeptr *) NULL, + *T = (Xnodeptr *) NULL, *np; + Xedgeptr *ep, *et, *pteeth = (Xedgeptr *) NULL; + int nteeth = 0, test; + Xnode *n; + Xedge *e; + + add_nodeptr_list (&H1, u1); + add_nodeptr_list (&H1, u3); + + add_nodeptr_list (&H2, u2); + add_nodeptr_list (&H2, u4); + + add_nodeptr_list (&T, u3); + add_nodeptr_list (&T, u4); + add_nodeptr_list (&T, u5); + nteeth++; + + G->magicnum++; + label_nodeptr_list (u1, G->magicnum); + label_nodeptr_list (u2, G->magicnum); + label_nodeptr_list (u3, G->magicnum); + label_nodeptr_list (u4, G->magicnum); + label_nodeptr_list (u5, G->magicnum); + + for (np = u1; np; np = np->next) { + n = np->this; + if (n->mark) + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->x > ONEMINUS && + OTHERCURRENTEND (e, n)->magiclabel != G->magicnum) { + et = Xedgeptralloc (); + et->this = e; + et->next = pteeth; + pteeth = et; + nteeth++; + } + } + } + for (np = u2; np; np = np->next) { + n = np->this; + if (n->mark) + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->x > ONEMINUS && + OTHERCURRENTEND (e, n)->magiclabel != G->magicnum) { + et = Xedgeptralloc (); + et->this = e; + et->next = pteeth; + pteeth = et; + nteeth++; + } + } + } + if (nteeth % 2 == 0) { + printf ("Even number of teeth in a clique-tree\n"); + Xnodeptr_list_free (H1); + Xnodeptr_list_free (H2); + Xnodeptr_list_free (T); + Xedgeptr_list_free (pteeth); + return 0; + } else { + test = load_special_cliquetree (G, H1, H2, T, pteeth, list, x); + Xnodeptr_list_free (H1); + Xnodeptr_list_free (H2); + Xnodeptr_list_free (T); + Xedgeptr_list_free (pteeth); + return test; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int load_special_cliquetree (Xgraph *G, Xnodeptr *H1, Xnodeptr *H2, + Xnodeptr *T, Xedgeptr *pteeth, Xcplane **list, double *x) +#else +static int load_special_cliquetree (G, H1, H2, T, pteeth, list, x) +Xgraph *G; +Xnodeptr *H1, *H2, *T; +Xedgeptr *pteeth; +Xcplane **list; +double *x; +#endif +{ + int test; + Xnodeptr *tooth, *tH1, *tH2, *tT; + Xnodeptrptr *handles, *teeth; + Xedgeptr *ep; + + pseudonodelist_to_nodelist (H1, &tH1); + pseudonodelist_to_nodelist (H2, &tH2); + pseudonodelist_to_nodelist (T, &tT); + + handles = (Xnodeptrptr *) NULL; + Xadd_nodeptrptr (&handles, tH1); + Xadd_nodeptrptr (&handles, tH2); + + teeth = (Xnodeptrptr *) NULL; + Xadd_nodeptrptr (&teeth, tT); + for (ep = pteeth; ep; ep = ep->next) { + tooth = (Xnodeptr *) NULL; + Xmarktooth (ep->this, &(tooth)); + Xadd_nodeptrptr (&teeth, tooth); + } + + if (!Xcliquefluff (G, &handles, &teeth)) { + return 0; + } + if (!Xviolated_clique_flow (G, handles, teeth, x)) { + /* printf ("BANG!\n"); */ + Xfreeteeth (handles); + Xfreeteeth (teeth); + return 0; + } + test = Xloadcplane (list, (Xnodeptr *) NULL, handles, teeth, 0); + if (!test) { + Xfreeteeth (handles); + Xfreeteeth (teeth); + } + return test; +} + +#ifdef CC_PROTOTYPE_ANSI +static void pseudonodelist_to_nodelist (Xnodeptr *p, Xnodeptr **l) +#else +static void pseudonodelist_to_nodelist (p, l) +Xnodeptr *p, **l; +#endif +{ + Xnodeptr *mp, *np; + + (*l) = (Xnodeptr *) NULL; + for (np = p; np; np = np->next) + for (mp = np->this->base.head; mp; mp = mp->next) + Xadd_nodeptr (l, mp->this); +} + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void dump_special_cliquetree (Xgraph *G, Xnodeptr *u1, Xnodeptr *u2, + Xnodeptr *u3, Xnodeptr *u4, Xnodeptr *u5) +#else +static void dump_special_cliquetree (G, u1, u2, u3, u4, u5) +Xgraph *G; +Xnodeptr *u1, *u2, *u3, *u4, *u5; +#endif +{ + printf ("U1: "); + nodeptr_print (u1); + printf ("U2: "); + nodeptr_print (u2); + printf ("U3: "); + nodeptr_print (u3); + printf ("U4: "); + nodeptr_print (u4); + printf ("U5: "); + nodeptr_print (u5); +} +#endif /* DEBUG */ + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void nodeptr_print (Xgraph *G, Xnodeptr *s) +#else +static void nodeptr_print (G, s) +Xgraph *G; +Xnodeptr *s; +#endif +{ + Xnodeptr *np; + + for (np = s; np; np = np->next) + printf ("%3d%c ", np->this - G->nodelist, np->this->mark ? '*' : ' '); + printf ("\n"); +} +#endif /* DEBUG */ + diff --git a/contrib/blossom/concorde97/XSTUFF/Xcuthash.c b/contrib/blossom/concorde97/XSTUFF/Xcuthash.c new file mode 100644 index 0000000000000000000000000000000000000000..da2e6b05403880065a071cffc7143989bf214610 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xcuthash.c @@ -0,0 +1,122 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void */ +/* init_hash_values (); */ +/* */ +/* unsigned long */ +/* cut_hash_value (), */ +/* comb_hash_value (), */ +/* clique_hash_value (); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + + +/* + This code needs two fields added to a node. They are unsigned long rand1 + and unsigned long rand2. +*/ + +static unsigned long hashfunc1[256]; +static unsigned long hashfunc2[256]; +static unsigned long hashfunc3[256]; +static unsigned long hashfunc4[256]; + +#define TOOTHHASHFUNC(x) (hashfunc1[(x)&0xff] ^ hashfunc2[((x)>>8)&0xff] ^ \ + hashfunc3[((x)>>16)&0xff] ^ hashfunc4[((x)>>24)&0xff]) + +#ifdef CC_PROTOTYPE_ANSI +void Xinit_hash_values (Xgraph *G) +#else +void Xinit_hash_values (G) +Xgraph *G; +#endif +{ + int i; + + for (i = 0; i < G->nnodes; i++) { + G->nodelist[i].rand1 = (int) CCutil_lprand (); + G->nodelist[i].rand2 = (int) CCutil_lprand (); + } + for (i = 0; i < 256; i++) { + hashfunc1[i] = CCutil_lprand (); + hashfunc2[i] = CCutil_lprand (); + hashfunc3[i] = CCutil_lprand (); + hashfunc4[i] = CCutil_lprand (); + } +} + + +#ifdef CC_PROTOTYPE_ANSI +unsigned long Xcut_hash_value (Xnodeptr *h) +#else +unsigned long Xcut_hash_value (h) +Xnodeptr *h; +#endif +{ + Xnodeptr *p; + unsigned long hashval = 0; + + for (p = h; p; p = p->next) + hashval ^= p->this->rand1; + + return hashval; +} + +#ifdef CC_PROTOTYPE_ANSI +unsigned long Xcomb_hash_value (Xnodeptr *h, Xnodeptrptr *t) +#else +unsigned long Xcomb_hash_value (h, t) +Xnodeptr *h; +Xnodeptrptr *t; +#endif +{ + Xnodeptr *p; + Xnodeptrptr *q; + unsigned long hashval = 0; + unsigned long toothhash; + + for (p = h; p; p = p->next) + hashval ^= p->this->rand1; + for (q = t; q; q = q->next) { + toothhash = 0; + for (p = q->this; p; p = p->next) + toothhash ^= p->this->rand2; + hashval ^= TOOTHHASHFUNC (toothhash); + } + return hashval; +} + +#ifdef CC_PROTOTYPE_ANSI +unsigned long Xclique_hash_value (Xnodeptrptr *h, Xnodeptrptr *t) +#else +unsigned long Xclique_hash_value (h, t) +Xnodeptrptr *h; +Xnodeptrptr *t; +#endif +{ + Xnodeptr *p; + Xnodeptrptr *q; + unsigned long hashval = 0; + unsigned long toothhash; + unsigned long handlehash; + + for (q = h; q; q = q->next) { + handlehash = 0; + for (p = q->this; p; p = p->next) + handlehash ^= p->this->rand1; + hashval ^= TOOTHHASHFUNC (handlehash); + } + for (q = t; q; q = q->next) { + toothhash = 0; + for (p = q->this; p; p = p->next) + toothhash ^= p->this->rand2; + hashval ^= TOOTHHASHFUNC (toothhash); + } + return hashval; +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xcutload.c b/contrib/blossom/concorde97/XSTUFF/Xcutload.c new file mode 100644 index 0000000000000000000000000000000000000000..14e22541fd7e1bc67d4e360268da8a4140506698 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xcutload.c @@ -0,0 +1,295 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void */ +/* cliquetree_slack_rhs_flow (), */ +/* destroycutlinks (), */ +/* freecplanelist (); */ +/* int */ +/* cutchecksout (), */ +/* temp_doblossom (), */ +/* violated_clique_flow (), */ +/* loadcplane (), */ +/* loadcplane_cut (), */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI +int Xcutchecksout (Xgraph *G, int x) +#else +int Xcutchecksout (G, x) +Xgraph *G; +int x; +#endif +{ + double weight = 0.0; + int i; + Xedge *e; + + for (i = G->nedges, e = G->edgelist; i; i--, e++) + if ((e->ends[0]->magiclabel == x) != + (e->ends[1]->magiclabel == x)) + weight += e->x; + + return (weight <= 2.0 - XEPSILON); +} + +#ifdef CC_PROTOTYPE_ANSI +int Xtemp_doblossom (Xgraph *G, Xcplane **cplanelist, Xnodeptr *handle, + Xedgeptr *teeth) +#else +int Xtemp_doblossom (G, cplanelist, handle, teeth) +Xgraph *G; +Xcplane **cplanelist; +Xnodeptr *handle; +Xedgeptr *teeth; +#endif +{ + Xnodeptrptr *temp_teeth, *ntp; + Xedgeptr *ep; + int nteeth, i, returnval; + int countcheck = 1; + + for (nteeth = 0, ep = teeth; ep; ep = ep->next) + nteeth++; + + if (nteeth % 2 == 0) { + fprintf (stderr, "EVEN NUMBER OF TEETH on a blossom\n"); + Xnodeptr_list_free (handle); + return 0; + } + temp_teeth = (Xnodeptrptr *) NULL; + for (i = 0, ep = teeth; i < nteeth; i++, ep = ep->next) { + ntp = Xnodeptrptralloc (); + ntp->this = (Xnodeptr *) NULL; + ntp->next = temp_teeth; + temp_teeth = ntp; + + Xadd_nodeptr (&(ntp->this), ep->this->ends[0]); + Xadd_nodeptr (&(ntp->this), ep->this->ends[1]); + } + + if (!Xtemp_combfluff (G, &handle, &temp_teeth)) { + return 0; + } + + returnval = Xloadcplane (cplanelist, handle, (Xnodeptrptr *) NULL, + temp_teeth, countcheck); + if (!returnval) { + Xfreeteeth (temp_teeth); + Xnodeptr_list_free (handle); + return 0; + } + + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcliquetree_slack_rhs_flow (Xgraph *G, Xnodeptrptr *handles, + Xnodeptrptr *teeth, double *x, double *slack, double *rhs) +#else +void Xcliquetree_slack_rhs_flow (G, handles, teeth, x, slack, rhs) +Xgraph *G; +Xnodeptrptr *handles, *teeth; +double *x; +double *slack, *rhs; +#endif +{ + int i; + Xedge *e; + Xnodeptrptr *ntp, *mtp; + Xnodeptr *np; + int nteeth; + int H, T, TI; + double sum; + + /* Puts cliquetree coef on the flow variables, computes rhs of */ + /* the cliquetree, and computes slack if x is given. */ + + for (i = G->nedges, e = G->edgelist; i; i--, e++) + e->flow = 0.0; + + for (ntp = handles, H = 0; ntp; ntp = ntp->next) { + H += Xinduced_edges_flow (G, ntp->this); + } + for (ntp = teeth, nteeth = 0, T = 0; ntp; ntp = ntp->next) { + nteeth++; + T += Xinduced_edges_flow (G, ntp->this); + } + + /* TI will be the sum over all teeth of the number of handles */ + /* a given tooth meets. */ + + for (ntp = teeth, TI = 0; ntp; ntp = ntp->next) { + G->magicnum++; + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (mtp = handles; mtp; mtp = mtp->next) { + for (np = mtp->this; np; np = np->next) { + if (np->this->magiclabel == G->magicnum) { + TI++; + break; + } + } + } + } + + *rhs = H + T - TI - ((nteeth + 1) / 2); + + if (x) { + for (i = G->nedges, e = G->edgelist, sum = 0.0; i; i--, e++) + if (e->flow >= 1.0) + sum += (e->flow * x[e - G->edgelist]); + *slack = *rhs - sum; + } else { + *slack = 0.0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int Xviolated_clique_flow (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth, + double *x) +#else +int Xviolated_clique_flow (G, handles, teeth, x) +Xgraph *G; +Xnodeptrptr *handles; +Xnodeptrptr *teeth; +double *x; +#endif +{ + double slack, rhs; + + if (!Xcheckclique (G, handles, teeth)) + return 0; + + Xcliquetree_slack_rhs_flow (G, handles, teeth, x, &slack, &rhs); + + if (slack > -XEPSILON) { + return 0; + } else { + return 1; + } +} + +#define MAXCOMBSIZE 150 + +#ifdef CC_PROTOTYPE_ANSI +int Xloadcplane (Xcplane **list, Xnodeptr *h, Xnodeptrptr *H, + Xnodeptrptr *t, int countcheck) +#else +int Xloadcplane (list, h, H, t, countcheck) +Xcplane **list; +Xnodeptr *h; +Xnodeptrptr *H; +Xnodeptrptr *t; +int countcheck; +#endif +{ + unsigned long val; + Xcplane *c; + Xnodeptr *np; + Xnodeptrptr *ntp; + int count; + + if (t == (Xnodeptrptr *) NULL) + val = Xcut_hash_value (h); + else if (H == (Xnodeptrptr *) NULL) + val = Xcomb_hash_value (h, t); + else + val = Xclique_hash_value (H, t); + + for (c = *list; c; c = c->next) + if (c->val == val) + break; + if (c == (Xcplane *) NULL) { + if (t != (Xnodeptrptr *) NULL && h != (Xnodeptr *) NULL && countcheck) { + count = 0; + for (np = h; np; np = np->next) + count++; + for (ntp = t; ntp; ntp = ntp->next) + for (np = ntp->this; np; np = np->next) + count++; + if (count > MAXCOMBSIZE) + return 0; + } + c = Xcplanealloc (); + c->val = val; + c->handle = h; + c->handles = H; + c->teeth = t; + c->next = *list; + *list = c; + return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int Xloadcplane_cut (Xgraph *G, Xcplane **list, int num) +#else +int Xloadcplane_cut (G, list, num) +Xgraph *G; +Xcplane **list; +int num; +#endif +{ + Xnodeptr *handle, *np; + Xnode *n; + int i, cnt = 0, test, countcheck = 1; + + for (i = 0; i < G->nnodes; i++) + if (G->nodelist[i].magiclabel == num) + cnt++; + + if (cnt < 3 || cnt > G->nnodes - 2) + return 0; + + if (cnt <= G->nnodes / 2) { + for (handle = (Xnodeptr *) NULL, i = G->nnodes, n = G->nodelist; i; + n++, i--) { + if (n->magiclabel == num) { + np = Xnodeptralloc (); + np->this = n; + np->next = handle; + handle = np; + } + } + } else { + for (handle = (Xnodeptr *) NULL, i = G->nnodes, n = G->nodelist; i; + n++, i--) { + if (n->magiclabel != num) { + np = Xnodeptralloc (); + np->this = n; + np->next = handle; + handle = np; + } + } + } + test = Xloadcplane (list, handle, (Xnodeptrptr *) NULL, + (Xnodeptrptr *) NULL, countcheck); + if (!test) { + Xnodeptr_list_free (handle); + } + return test; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xfreecplanelist (Xcplane **list) +#else +void Xfreecplanelist (list) +Xcplane **list; +#endif +{ + Xcplane *c, *cnext; + + for (c = *list; c; c = cnext) { + cnext = c->next; + Xfreecplanestruct (c); + } + *list = (Xcplane *) NULL; +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xcutpool.h b/contrib/blossom/concorde97/XSTUFF/Xcutpool.h new file mode 100644 index 0000000000000000000000000000000000000000..984561542bdbf8658483a1b973483827831bc6e2 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xcutpool.h @@ -0,0 +1,17 @@ +#ifndef __XCUTPOOL_H +#define __XCUTPOOL_H + +typedef struct Xportablecut { + int nhandles; + int *handles; /* each handle terminated with a -1 */ + int nteeth; + int *teeth; /* each tooth terminated with a -1 */ +} Xportablecut; + +typedef struct Xportableclique { + int size; + int *nodes; + double cutval; +} Xportableclique; + +#endif /* __XCUTPOOL_H */ diff --git a/contrib/blossom/concorde97/XSTUFF/Xcuts.c b/contrib/blossom/concorde97/XSTUFF/Xcuts.c new file mode 100644 index 0000000000000000000000000000000000000000..73d07f65c90f44ee42b9a5c1154bc26278706210 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xcuts.c @@ -0,0 +1,141 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int */ +/* Xolaf_combs (Xgraph *G, Xcplane *list, double *x), */ +/* Xblobcuts (Xgraph *G, Xcplane **list, double *x); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI + +static int + run_olaf (Xgraph *G, Xcplane **list, double *x, int olaf_select, int count), + dfs (Xgraph *G, Xnode *start); + +#else + +static int + run_olaf (), + dfs (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +int Xolaf_combs (Xgraph *G, Xcplane **list, double *x) +#else +int Xolaf_combs (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + int cnt; + + cnt = run_olaf (G, list, x, 3, 4); + if (cnt >= XCUTNUM) + return cnt; + cnt += run_olaf (G, list, x, 1, 1); + if (cnt >= XCUTNUM) + return cnt; + cnt += run_olaf (G, list, x, 2, 1); + if (cnt >= XCUTNUM) + return cnt; + cnt += run_olaf (G, list, x, 4, 1); + + return cnt; +} + + +#ifdef CC_PROTOTYPE_ANSI +static int run_olaf (Xgraph *G, Xcplane **list, double *x, int olaf_select, + int count) +#else +static int run_olaf (G, list, x, olaf_select, count) +Xgraph *G; +Xcplane **list; +double *x; +int olaf_select, count; +#endif +{ + int hit, cuts, round; + + Xloadx (G, x); + hit = round = 0; + Xbuildpseudonodelist (G, 0); + while (round < count && hit < XCUTNUM && Xolaf (G, olaf_select)) { + hit += (cuts = Xexactblossomcheck (G, list, 1, x)); + printf (" [%d olaf(%d) combs]\n", cuts, olaf_select); + fflush (stdout); + round++; + } + Xdestroypseudonodelist (G); + return hit; +} + + +#ifdef CC_PROTOTYPE_ANSI +int Xblobcuts (Xgraph *G, Xcplane **list, double *x) +#else +int Xblobcuts (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + int i; + + if (dfs (G, &(G->nodelist[0])) != G->nnodes) { + printf (" cannot run blobcuts on disconnected graph\n"); + fflush (stdout); + return 0; + } + Xpancakex (G, x); + i = Xblobsviolated (G, list); + Xfreepancake (); + + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static int dfs (Xgraph *G, Xnode *start) +#else +static int dfs (G, start) +Xgraph *G; +Xnode *start; +#endif +{ + int i = 0; + Xedgeptr *epp; + Xedge *ep; + Xnode *n, *n1; + Xnodeptr *next, *queue = (Xnodeptr *) NULL; + + G->magicnum++; + start->magiclabel = G->magicnum; + Xadd_nodeptr (&queue, start); + + while (queue) { + i++; + n = queue->this; + next = queue->next; + Xnodeptrfree (queue); + queue = next; + for (epp = n->adj.head; epp; epp = epp->next) { + ep = epp->this; + n1 = ep->ends[0]; + if (n1 == n) + n1 = ep->ends[1]; + if (n1->magiclabel != G->magicnum) { + n1->magiclabel = G->magicnum; + Xadd_nodeptr (&queue, n1); + } + } + } + return i; +} + diff --git a/contrib/blossom/concorde97/XSTUFF/Xcututil.c b/contrib/blossom/concorde97/XSTUFF/Xcututil.c new file mode 100644 index 0000000000000000000000000000000000000000..9304be520bb623df5cc1228abd6fccc1e1e35109 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xcututil.c @@ -0,0 +1,613 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void */ +/* freecplanestruct (), */ +/* freeiplanestruct (), */ +/* cplane_to_iplane (), */ +/* iplane_to_cplane (), */ +/* portablecut_to_cplane (), */ +/* portablecut_to_handles_and_teeth (), */ +/* portablecut_to_iplane (), */ +/* freeteeth (), */ +/* printchvatalcomb (), */ +/* printcliquetree (), */ +/* dumpchvatalcomb (), */ +/* dumpcliquetree (); */ +/* */ +/* int */ +/* slackclique (), */ +/* induced_edges_flow (); */ +/* */ +/* NOT CALLED: portablecut_to_handles_and_teeth() */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI +int Xslackclique (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth, + double *slack) +#else +int Xslackclique (G, handles, teeth, slack) +Xgraph *G; +Xnodeptrptr *handles, *teeth; +double *slack; +#endif +{ + /* ASSUMES x VALUES ON THE EDGES */ + int hit, H, T, TI, nteeth; + Xedge *e, *lastedge = (G->edgelist) + G->nedges; + Xnodeptr *np; + Xnodeptrptr *ntp, *mtp; + double sum, rhs; + + for (e = G->edgelist; e != lastedge; e++) + e->flow = 0.0; + + for (ntp = handles, H = 0; ntp; ntp = ntp->next) { + H += Xinduced_edges_flow (G, ntp->this); + } + for (ntp = teeth, nteeth = 0, T = 0; ntp; ntp = ntp->next) { + nteeth++; + T += Xinduced_edges_flow (G, ntp->this); + } + + for (ntp = teeth, TI = 0; ntp; ntp = ntp->next) { + G->magicnum++; + for (np = ntp->this; np; np = np->next) + np->this->magiclabel = G->magicnum; + for (hit = 0, mtp = handles; mtp; mtp = mtp->next) { + for (np = mtp->this; np; np = np->next) { + if (np->this->magiclabel == G->magicnum) { + TI++; + hit++; + break; + } + } + } + if (!hit) { + fprintf (stderr, "Tooth doesn't meet handles\n"); + return 0; + } + } + + rhs = H + T - TI - ((nteeth + 1) / 2); + + for (e = G->edgelist, sum = 0.0; e != lastedge; e++) + if (e->flow >= 1.0) + sum += (e->flow * e->x); + + *slack = rhs - sum; + return 1; +} + + +#ifdef CC_PROTOTYPE_ANSI +int Xinduced_edges_flow (Xgraph *G, Xnodeptr *set) +#else +int Xinduced_edges_flow (G, set) +Xgraph *G; +Xnodeptr *set; +#endif +{ + Xnodeptr *np; + Xedgeptr *ep; + int count; + + G->magicnum++; + for (np = set, count = 0; np; count++, np = np->next) + np->this->magiclabel = G->magicnum; + for (np = set; np; np = np->next) + for (ep = np->this->adj.head; ep; ep = ep->next) + if (ep->this->ends[0]->magiclabel == + ep->this->ends[1]->magiclabel) + ep->this->flow += 0.5; + return count; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xfreecplanestruct (Xcplane *c) +#else +void Xfreecplanestruct (c) +Xcplane *c; +#endif +{ + if (c->handle != (Xnodeptr *) NULL) + Xnodeptr_list_free (c->handle); + if (c->handles != (Xnodeptrptr *) NULL) + Xfreeteeth (c->handles); + if (c->teeth != (Xnodeptrptr *) NULL) + Xfreeteeth (c->teeth); + Xcplanefree (c); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xfreeiplanestruct (Xiplane *c) +#else +void Xfreeiplanestruct (c) +Xiplane *c; +#endif +{ + Xintptrptr *itp; + + if (c->handle) + Xintptr_list_free (c->handle); + if (c->handles) { + for (itp = c->handles; itp; itp = itp->next) + Xintptr_list_free (itp->this); + Xintptrptr_list_free (c->handles); + } + if (c->teeth) { + for (itp = c->teeth; itp; itp = itp->next) + Xintptr_list_free (itp->this); + Xintptrptr_list_free (c->teeth); + } + Xiplanefree (c); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcplane_to_iplane (Xgraph *G, Xcplane *c, Xiplane **ipl) +#else +void Xcplane_to_iplane (G, c, ipl) +Xgraph *G; +Xcplane *c; +Xiplane **ipl; +#endif +{ + Xintptr *handle, *ip, *tooth, *h; + Xintptrptr *handles, *teeth; + Xnodeptr *np; + Xnodeptrptr *ntp; + + if (c->handle) { + handle = (Xintptr *) NULL; + for (np = c->handle; np; np = np->next) { + ip = Xintptralloc (); + ip->this = np->this - G->nodelist; + ip->next = handle; + handle = ip; + } + } else + handle = (Xintptr *) NULL; + + if (c->handles) { + handles = (Xintptrptr *) NULL; + for (ntp = c->handles; ntp; ntp = ntp->next) { + h = (Xintptr *) NULL; + for (np = ntp->this; np; np = np->next) { + ip = Xintptralloc (); + ip->this = np->this - G->nodelist; + ip->next = h; + h = ip; + } + Xadd_intptrptr (&handles, h); + } + } else + handles = (Xintptrptr *) NULL; + + if (c->teeth) { + teeth = (Xintptrptr *) NULL; + for (ntp = c->teeth; ntp; ntp = ntp->next) { + tooth = (Xintptr *) NULL; + for (np = ntp->this; np; np = np->next) { + ip = Xintptralloc (); + ip->this = np->this - G->nodelist; + ip->next = tooth; + tooth = ip; + } + Xadd_intptrptr (&teeth, tooth); + } + } else + teeth = (Xintptrptr *) NULL; + + *ipl = Xiplanealloc (); + (*ipl)->handle = handle; + (*ipl)->handles = handles; + (*ipl)->teeth = teeth; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xiplane_to_cplane (Xgraph *G, Xiplane *c, Xcplane **cpl) +#else +void Xiplane_to_cplane (G, c, cpl) +Xgraph *G; +Xiplane *c; +Xcplane **cpl; +#endif +{ + Xnodeptr *handle, *np, *tooth, *h; + Xnodeptrptr *handles, *teeth; + Xintptr *ip; + Xintptrptr *itp; + + if (c->handle) { + handle = (Xnodeptr *) NULL; + for (ip = c->handle; ip; ip = ip->next) { + np = Xnodeptralloc (); + np->this = ip->this + G->nodelist; + np->next = handle; + handle = np; + } + } else + handle = (Xnodeptr *) NULL; + + if (c->handles) { + handles = (Xnodeptrptr *) NULL; + for (itp = c->handles; itp; itp = itp->next) { + h = (Xnodeptr *) NULL; + for (ip = itp->this; ip; ip = ip->next) { + np = Xnodeptralloc (); + np->this = ip->this + G->nodelist; + np->next = h; + h = np; + } + Xadd_nodeptrptr (&handles, h); + } + } else + handles = (Xnodeptrptr *) NULL; + + if (c->teeth) { + teeth = (Xnodeptrptr *) NULL; + for (itp = c->teeth; itp; itp = itp->next) { + tooth = (Xnodeptr *) NULL; + for (ip = itp->this; ip; ip = ip->next) { + np = Xnodeptralloc (); + np->this = ip->this + G->nodelist; + np->next = tooth; + tooth = np; + } + Xadd_nodeptrptr (&teeth, tooth); + } + } else + teeth = (Xnodeptrptr *) NULL; + + *cpl = Xcplanealloc (); + (*cpl)->handle = handle; + (*cpl)->handles = handles; + (*cpl)->teeth = teeth; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xportablecut_to_cplane (Xgraph *G, Xportablecut *p, Xcplane **cpl) +#else +void Xportablecut_to_cplane (G, p, cpl) +Xgraph *G; +Xportablecut *p; +Xcplane **cpl; +#endif +{ + Xnodeptr *np, *tooth, *h; + Xnodeptrptr *handles, *teeth; + int i, k; + + handles = (Xnodeptrptr *) NULL; + for (i = 0, k = 0; i < p->nhandles; i++) { + h = (Xnodeptr *) NULL; + while (p->handles[k] != -1) { + np = Xnodeptralloc (); + np->this = p->handles[k++] + G->nodelist; + np->next = h; + h = np; + } + Xadd_nodeptrptr (&handles, h); + k++; + } + + teeth = (Xnodeptrptr *) NULL; + for (i = 0, k = 0; i < p->nteeth; i++) { + tooth = (Xnodeptr *) NULL; + while (p->teeth[k] != -1) { + np = Xnodeptralloc (); + np->this = p->teeth[k++] + G->nodelist; + np->next = tooth; + tooth = np; + } + Xadd_nodeptrptr (&teeth, tooth); + k++; + } + + *cpl = Xcplanealloc (); + (*cpl)->handle = (Xnodeptr *) NULL; + (*cpl)->handles = handles; + (*cpl)->teeth = teeth; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xportablecut_to_handles_and_teeth (Xgraph *G, Xportablecut *p, + Xnodeptrptr **handles, Xnodeptrptr **teeth) +#else +void Xportablecut_to_handles_and_teeth (G, p, handles, teeth) +Xgraph *G; +Xportablecut *p; +Xnodeptrptr **handles, **teeth; +#endif +{ + Xnodeptr *np, *tooth, *h; + int i, k; + + *handles = (Xnodeptrptr *) NULL; + for (i = 0, k = 0; i < p->nhandles; i++) { + h = (Xnodeptr *) NULL; + while (p->handles[k] != -1) { + np = Xnodeptralloc (); + np->this = p->handles[k++] + G->nodelist; + np->next = h; + h = np; + } + Xadd_nodeptrptr (handles, h); + k++; + } + + *teeth = (Xnodeptrptr *) NULL; + for (i = 0, k = 0; i < p->nteeth; i++) { + tooth = (Xnodeptr *) NULL; + while (p->teeth[k] != -1) { + np = Xnodeptralloc (); + np->this = p->teeth[k++] + G->nodelist; + np->next = tooth; + tooth = np; + } + Xadd_nodeptrptr (teeth, tooth); + k++; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xportablecut_to_iplane (Xportablecut *p, Xiplane **ipl) +#else +void Xportablecut_to_iplane (p, ipl) +Xportablecut *p; +Xiplane **ipl; +#endif +{ + Xintptr *ip, *tooth, *h; + Xintptrptr *handles, *teeth; + int i, k; + + handles = (Xintptrptr *) NULL; + for (i = 0, k = 0; i < p->nhandles; i++) { + h = (Xintptr *) NULL; + while (p->handles[k] != -1) { + ip = Xintptralloc (); + ip->this = p->handles[k++]; + ip->next = h; + h = ip; + } + Xadd_intptrptr (&handles, h); + k++; + } + + teeth = (Xintptrptr *) NULL; + for (i = 0, k = 0; i < p->nteeth; i++) { + tooth = (Xintptr *) NULL; + while (p->teeth[k] != -1) { + ip = Xintptralloc (); + ip->this = p->teeth[k++]; + ip->next = tooth; + tooth = ip; + } + Xadd_intptrptr (&teeth, tooth); + k++; + } + + *ipl = Xiplanealloc (); + (*ipl)->handle = (Xintptr *) NULL; + (*ipl)->handles = handles; + (*ipl)->teeth = teeth; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xiplane_to_portablecut (Xiplane *c, Xportablecut *p) +#else +void Xiplane_to_portablecut (c, p) +Xiplane *c; +Xportablecut *p; +#endif +{ + int hands, handcount; + int teeth, teethcount; + int k; + Xintptr *ip; + Xintptrptr *ipp; + + if (c->handle) { + p->nhandles = 1; + for (ip = c->handle, handcount = 0; ip; ip = ip->next) + handcount++; + handcount++; + p->handles = CC_SAFE_MALLOC (handcount, int); + if (!p->handles) { + fprintf (stderr, "out of memory in iplane_to_portablecut\n"); + exit (1); + } + for (ip = c->handle, k = 0; ip; ip = ip->next) + p->handles[k++] = ip->this; + p->handles[k] = -1; + } else { + for (ipp = c->handles, hands = 0; ipp; ipp = ipp->next) + hands++; + p->nhandles = hands; + for (ipp = c->handles, handcount = 0; ipp; ipp = ipp->next) { + for (ip = ipp->this; ip; ip = ip->next) + handcount++; + handcount++; + } + p->handles = CC_SAFE_MALLOC (handcount, int); + if (!p->handles) { + fprintf (stderr, "out of memory in iplane_to_portablecut\n"); + exit (1); + } + for (ipp = c->handles, k = 0; ipp; ipp = ipp->next) { + for (ip = ipp->this; ip; ip = ip->next) + p->handles[k++] = ip->this; + p->handles[k++] = -1; + } + } + + for (ipp = c->teeth, teeth = 0; ipp; ipp = ipp->next) + teeth++; + p->nteeth = teeth; + for (ipp = c->teeth, teethcount = 0; ipp; ipp = ipp->next) { + for (ip = ipp->this; ip; ip = ip->next) + teethcount++; + teethcount++; + } + p->teeth = CC_SAFE_MALLOC (teethcount, int); + if (!p->teeth) { + fprintf (stderr, "out of memory in iplane_to_portablecut\n"); + exit (1); + } + + for (ipp = c->teeth, k = 0; ipp; ipp = ipp->next) { + for (ip = ipp->this; ip; ip = ip->next) + p->teeth[k++] = ip->this; + p->teeth[k++] = -1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xfreeteeth (Xnodeptrptr *teeth) +#else +void Xfreeteeth (teeth) +Xnodeptrptr *teeth; +#endif +{ + Xnodeptrptr *ntp; + + for (ntp = teeth; ntp; ntp = ntp->next) + Xnodeptr_list_free (ntp->this); + Xnodeptrptr_list_free (teeth); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xprintchvatalcomb (Xgraph *G, Xnodeptr *h, Xnodeptrptr *t) +#else +void Xprintchvatalcomb (G, h, t) +Xgraph *G; +Xnodeptr *h; +Xnodeptrptr *t; +#endif +{ + Xnodeptr *np; + Xnodeptrptr *ntp; + int i; + + printf ("HANDLE: "); + fflush (stdout); + for (np = h; np; np = np->next) { + printf ("%d ", (int) (np->this - G->nodelist)); + fflush (stdout); + } + printf ("\n"); + for (i = 0, ntp = t; ntp; ntp = ntp->next, i++) { + printf ("TOOTH[%d]: ", i); + fflush (stdout); + for (np = ntp->this; np; np = np->next) { + printf ("%d ", (int) (np->this - G->nodelist)); + fflush (stdout); + } + printf ("\n"); + } + printf ("\n"); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xprintcliquetree (Xgraph *G, Xnodeptrptr *h, Xnodeptrptr *t) +#else +void Xprintcliquetree (G, h, t) +Xgraph *G; +Xnodeptrptr *h, *t; +#endif +{ + Xnodeptr *np; + Xnodeptrptr *ntp; + int i; + + for (i = 0, ntp = h; ntp; ntp = ntp->next, i++) { + printf ("HANDLE[%d]: ", i); + fflush (stdout); + for (np = ntp->this; np; np = np->next) { + printf ("%d ", (int) (np->this - G->nodelist)); + fflush (stdout); + } + printf ("\n"); + } + for (i = 0, ntp = t; ntp; ntp = ntp->next, i++) { + printf ("TOOTH[%d]: ", i); + fflush (stdout); + for (np = ntp->this; np; np = np->next) { + printf ("%d ", (int) (np->this - G->nodelist)); + fflush (stdout); + } + printf ("\n"); + } + printf ("\n"); +} + +/* Format #handles #teeth (handle) -1 (handle) -1 ... (tooth) -1 ... */ + +#ifdef CC_PROTOTYPE_ANSI +void Xdumpchvatalcomb (FILE *out, Xintptr *h, Xintptrptr *t) +#else +void Xdumpchvatalcomb (out, h, t) +FILE *out; +Xintptr *h; +Xintptrptr *t; +#endif +{ + Xintptr *ip; + Xintptrptr *itp; + int nteeth; + + for (nteeth = 0, itp = t; itp; itp = itp->next) + nteeth++; + + fprintf (out, "1 %d ", nteeth); + for (ip = h; ip; ip = ip->next) + fprintf (out, "%d ", ip->this); + fprintf (out, "%d ", -1); + for (itp = t; itp; itp = itp->next) { + for (ip = itp->this; ip; ip = ip->next) + fprintf (out, "%d ", ip->this); + fprintf (out, "%d ", -1); + } + fprintf (out, "\n"); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xdumpcliquetree (FILE *out, Xintptrptr *h, Xintptrptr *t) +#else +void Xdumpcliquetree (out, h, t) +FILE *out; +Xintptrptr *h; +Xintptrptr *t; +#endif +{ + Xintptr *ip; + Xintptrptr *itp; + int nteeth, nhandles; + + for (nhandles = 0, itp = h; itp; itp = itp->next) + nhandles++; + for (nteeth = 0, itp = t; itp; itp = itp->next) + nteeth++; + + fprintf (out, "%d ", nhandles); + fprintf (out, "%d ", nteeth); + for (itp = h; itp; itp = itp->next) { + for (ip = itp->this; ip; ip = ip->next) + fprintf (out, "%d ", ip->this); + fprintf (out, "%d ", -1); + } + for (itp = t; itp; itp = itp->next) { + for (ip = itp->this; ip; ip = ip->next) + fprintf (out, "%d ", ip->this); + fprintf (out, "%d ", -1); + } + fprintf (out, "\n"); +} + diff --git a/contrib/blossom/concorde97/XSTUFF/Xflow.c b/contrib/blossom/concorde97/XSTUFF/Xflow.c new file mode 100644 index 0000000000000000000000000000000000000000..2e563776bcac5b0013891665182929321a40c3fd --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xflow.c @@ -0,0 +1,536 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTION: */ +/* */ +/* double flow (); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + relabel (Xnode *), + setlabels (Xgraph *G, Xnode *, Xnode *), + backwards_bfs (Xnode *, int), + addtoq (Xnodeset *, Xnode *), + dfs2 (Xgraph *G, Xnode *start), + marknode (Xnode *n, int v); + +static int + subtourcuts (Xgraph *G, Xcplane **list), + connectcuts (Xgraph *G, Xcplane **list), + dfs (Xgraph *G, Xnode *start); + +static Xnode + *push (Xnode *, Xedge *), + *popfromq (Xnodeset *); + +#else + +static void + relabel (), + setlabels (), + backwards_bfs (), + addtoq (), + dfs2 (), + marknode (); + +static int + subtourcuts (), + connectcuts (), + dfs (); + +static Xnode + *push (), + *popfromq (); + +#endif + +#define INFINITY (1<<30) + +#ifdef CC_PROTOTYPE_ANSI +double Xflow (Xgraph *G, Xnode *s, Xnode *t, double bound) +#else +double Xflow (G, s, t, bound) +Xgraph *G; +Xnode *s, *t; +double bound; +#endif +{ + Xnodeset q; + Xnode *n, *n1; + Xedge *e; + int savelabel; + Xedgeptr *ep; + int count, round; + + q.head = q.tail = (Xnodeptr *) NULL; + for (n = G->pseudonodelist->next; n; n = n->next) { + n->excess = 0.0; + n->active = 0; + n->current = n->cadj.head; + n->flowlabel = 0; + for (ep = n->cadj.head; ep; ep = ep->next) + ep->this->flow = 0.0; + } + setlabels (G, s, t); + t->active = 1; /* a lie, which keeps t off the active queue */ + for (ep = s->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (!e->stay) + continue; + if (e->cends[0] == s) { + e->flow = e->x; + if (e->x > 0.0) { + e->cends[1]->excess += e->x; + addtoq (&q, e->cends[1]); + } + } else { + e->flow = -e->x; + if (e->x > 0.0) { + e->cends[0]->excess += e->x; + addtoq (&q, e->cends[0]); + } + } + } + count = 0; + round = G->npseudonodes / 2; + while (q.head && t->excess < bound) { + if (count == round) { + setlabels (G, s, t); + count = 0; + } else + count++; + n = popfromq (&q); + n->active = 0; + savelabel = n->flowlabel; + do { + ep = n->current; + if ((n1 = push (n, ep->this)) != (Xnode *) NULL) + addtoq (&q, n1); + else { + n->current = ep->next; + if (!n->current) { + n->current = n->cadj.head; + relabel (n); + } + } + } while (n->excess > 0.0 && n->flowlabel == savelabel); + if (n->excess > 0.0 && n->flowlabel < G->npseudonodes) + addtoq (&q, n); + } + + while (q.head) { + popfromq (&q); + } + + return t->excess; +} + +#ifdef CC_PROTOTYPE_ANSI +static void relabel (Xnode *n) +#else +static void relabel (n) +Xnode *n; +#endif +{ + int m = INFINITY; + Xedgeptr *ep; + Xedge *e; + int t; + + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (n == e->cends[0]) { + if (e->x - e->flow > 0.0 && (t = e->cends[1]->flowlabel) < m) + m = t; + } else { + if (e->x + e->flow > 0.0 && (t = e->cends[0]->flowlabel) < m) + m = t; + } + } + n->flowlabel = m + 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static Xnode *push (Xnode *n, Xedge *e) +#else +static Xnode *push (n, e) +Xnode *n; +Xedge *e; +#endif +{ + Xnode *n1; + double rf; + + if (e->cends[0] == n) { + n1 = e->cends[1]; + rf = e->x - e->flow; + if (n->flowlabel == n1->flowlabel + 1 && rf > 0.0) { + if (n->excess < rf) + rf = n->excess; + n->excess -= rf; + e->flow += rf; + n1->excess += rf; + return n1; + } else + return 0; + } else { + n1 = e->cends[0]; + rf = e->x + e->flow; + if (n->flowlabel == n1->flowlabel + 1 && rf > 0.0) { + if (n->excess < rf) + rf = n->excess; + n->excess -= rf; + e->flow -= rf; + n1->excess += rf; + return n1; + } else + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void setlabels (Xgraph *G, Xnode *s, Xnode *t) +#else +static void setlabels (G, s, t) +Xgraph *G; +Xnode *s, *t; +#endif +{ + G->magicnum++; + t->flowlabel = 0; + backwards_bfs (t, G->magicnum); + s->flowlabel = G->npseudonodes; + + if (s->magiclabel == G->magicnum) + return; + else + backwards_bfs (s, G->magicnum); +} + +#ifdef CC_PROTOTYPE_ANSI +static void backwards_bfs (Xnode *s, int K) +#else +static void backwards_bfs (s, K) +Xnode *s; +int K; +#endif +{ + Xnode *this, *next, *tail; + Xedge *e; + Xedgeptr *ep; + int dist; + + s->magiclabel = K; + next = s; + s->tnext = (Xnode *) NULL; + do { + for (this = next, next = (Xnode *) NULL; this; this = this->tnext) { + dist = this->flowlabel + 1; + for (ep = this->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (this == e->cends[0]) { + tail = e->cends[1]; + if (tail->magiclabel != K && + e->x + e->flow > 0.0) { + tail->flowlabel = dist; + tail->tnext = next; + next = tail; + tail->magiclabel = K; + } + } else { + tail = e->cends[0]; + if (tail->magiclabel != K && + e->x - e->flow > 0.0) { + tail->flowlabel = dist; + tail->tnext = next; + next = tail; + tail->magiclabel = K; + } + } + } + } + } while (next); +} + +#ifdef CC_PROTOTYPE_ANSI +static void addtoq (Xnodeset *q, Xnode *n) +#else +static void addtoq (q, n) +Xnodeset *q; +Xnode *n; +#endif +{ + Xnodeptr *newn; + + if (!n->active) { + newn = Xnodeptralloc (); + newn->next = (Xnodeptr *) NULL; + newn->this = n; + if (q->tail) { + q->tail->next = newn; + } else { + q->head = newn; + } + q->tail = newn; + n->active = 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static Xnode *popfromq (Xnodeset *q) +#else +static Xnode *popfromq (q) +Xnodeset *q; +#endif +{ + Xnodeptr *newn = q->head; + Xnode *n = newn->this; + + q->head = newn->next; + if (!q->head) + q->tail = (Xnodeptr *) NULL; + Xnodeptrfree (newn); + return n; +} + +#ifdef CC_PROTOTYPE_ANSI +static int subtourcuts (Xgraph *G, Xcplane **list) +#else +static int subtourcuts (G, list) +Xgraph *G; +Xcplane **list; +#endif +{ + Xnode *n, *nnext; + int returnval = 0; + + for (n = G->pseudonodelist->next->next; n; n = nnext) { + /* printf ("o"); fflush (stdout); */ + + nnext = n->next; + if (Xflow (G, G->pseudonodelist->next, n, XCUTTWO) < XCUTTWO) { + G->magicnum++; + dfs2 (G, n); + returnval += Xloadcplane_cut (G, list, G->magicnum); + /* printf ("i"); fflush (stdout); */ + Xsimpleshrink (G, G->pseudonodelist->next, n); + } + } + /* printf ("\n"); */ + return returnval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dfs2 (Xgraph *G, Xnode *start) +#else +static void dfs2 (G, start) +Xgraph *G; +Xnode *start; +#endif +{ + Xedgeptr *epp; + Xedge *ep; + Xnodeptr *next, *queue = (Xnodeptr *) NULL; + Xnode *n; + + marknode (start, G->magicnum); + Xadd_nodeptr (&queue, start); + + while (queue) { + n = queue->this; + next = queue->next; + Xnodeptrfree (queue); + queue = next; + for (epp = n->cadj.head; epp; epp = epp->next) { + ep = epp->this; + if (ep->cends[0] == n) { + if (ep->x + ep->flow > 0.0 && + ep->cends[1]->magiclabel != G->magicnum) { + marknode (ep->cends[1], G->magicnum); + Xadd_nodeptr (&queue, ep->cends[1]); + } + } else { + if (ep->x - ep->flow > 0.0 && + ep->cends[0]->magiclabel != G->magicnum) { + marknode (ep->cends[0], G->magicnum); + Xadd_nodeptr (&queue, ep->cends[0]); + } + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void marknode (Xnode *n, int v) +#else +static void marknode (n, v) +Xnode *n; +int v; +#endif +{ + Xnodeptr *np; + + n->magiclabel = v; + for (np = n->base.head; np; np = np->next) { + np->this->magiclabel = v; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int Xexactcutcheck (Xgraph *G, Xcplane **list, double *x) +#else +int Xexactcutcheck (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + int i, hit; + + Xloadx (G, x); + Xbuildpseudonodelist (G, 0); + i = Xshrinkprocess (G, list); +/* + printf ("%d heavy-edge cut(s), np = %d\n", i, G->npseudonodes); + fflush (stdout); +*/ + if (i >= XCUTNUM) { + Xdestroypseudonodelist (G); + return i; + } + hit = i; + Xrebuildcadj (G); + + i = subtourcuts (G, list); + /* printf ("%d flow cut(s)\n", i); fflush (stdout); */ + Xdestroypseudonodelist (G); + + return hit + i; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xmincut (Xgraph *G, Xnode *s, Xnode *t, double bound, double *value, + int *label) +#else +int Xmincut (G, s, t, bound, value, label) +Xgraph *G; +Xnode *s, *t; +double bound, *value; +int *label; +#endif +{ + /* Uses the x field as capacities. If min cut from s to t has */ + /* value < bound it returns 1 and marks nodes in cut with */ + /* magiclabel equal to label. value get the capacity of cut. */ + + *value = Xflow (G, s, t, bound); + if (*value >= bound) + return 0; + else { + G->magicnum++; + dfs2 (G, t); + *label = G->magicnum; + return 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +int Xrunconnectcuts (Xgraph *G, Xcplane **list, double *x) +#else +int Xrunconnectcuts (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + int i; + + Xloadx (G, x); + Xbuildpseudonodelist (G, 0); + i = connectcuts (G, list); + Xdestroypseudonodelist (G); + + fflush (stdout); + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static int connectcuts (Xgraph *G, Xcplane **list) +#else +static int connectcuts (G, list) +Xgraph *G; +Xcplane **list; +#endif +{ + int val, ccount = 0, count, track = 1; + Xnode *n; + + val = ++(G->magicnum); + if ((count = dfs (G, G->pseudonodelist->next)) < G->npseudonodes) { + ccount += Xloadcplane_cut (G, list, G->magicnum); + n = G->pseudonodelist->next; + do { + track++; + n = n->next; + while (n->magiclabel >= val) + n = n->next; + G->magicnum++; + count += dfs (G, n); + } while (count < G->npseudonodes); + + if (track > 2) { + for (val++; val <= G->magicnum; val++) { + ccount += Xloadcplane_cut (G, list, val); + } + return ccount; + } else { + return ccount; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int dfs (Xgraph *G, Xnode *start) +#else +static int dfs (G, start) +Xgraph *G; +Xnode *start; +#endif +{ + int i = 0; + Xedgeptr *epp; + Xedge *ep; + Xnode *n, *n1; + Xnodeptr *next, *queue = (Xnodeptr *) NULL; + + marknode (start, G->magicnum); + Xadd_nodeptr (&queue, start); + + while (queue) { + i++; + n = queue->this; + next = queue->next; + Xnodeptrfree (queue); + queue = next; + for (epp = n->cadj.head; epp; epp = epp->next) { + ep = epp->this; + if (ep->stay) { + n1 = ep->cends[0]; + if (n1 == n) + n1 = ep->cends[1]; + if (n1->magiclabel != G->magicnum) { + marknode (n1, G->magicnum); + Xadd_nodeptr (&queue, n1); + } + } + } + } + return i; +} + diff --git a/contrib/blossom/concorde97/XSTUFF/Xgomhu.c b/contrib/blossom/concorde97/XSTUFF/Xgomhu.c new file mode 100644 index 0000000000000000000000000000000000000000..af8b4f685e365d2efdc3307e68cff73094aa9794 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xgomhu.c @@ -0,0 +1,699 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* Xcuttree_node */ +/* *Xgomory_hu (Xgraph *G); */ +/* */ +/* void */ +/* Xcuttree_free (Xcuttree_node *n); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + addtonodeset (Xnodeset *s, Xnode *n), + delfromnodeset (Xnodeset *s, Xnode *n), + delfromedgeset (Xedgeset *s, Xedge *e), + freenodeset (Xnodeset *s), + gh_work (Xgraph *G, Xcuttree_node *n, Xnodeset *nlist, Xnodeset *special), + splitset (Xnodeset *s, Xnodeset *a, Xnodeset *b, int n), + mergeset (Xnodeset *s, Xnodeset *a), + shrinkdown (Xnodeset *a, Xnode *pseudo, Xedgeset *esave, int num), + unshrink (Xnode *pseudo, Xedgeset *esave, int num), + paint (Xgraph *G, Xnode *n, int v); + +static int + countdescendants (Xcuttree_node *n), + myrandnum (int n); + +#else + +static void + addtonodeset (), + delfromnodeset (), + delfromedgeset (), + freenodeset (), + gh_work (), + splitset (), + mergeset (), + shrinkdown (), + unshrink (), + paint (); + +static int + countdescendants (), + myrandnum (); + +#endif + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void + dumpcutcadj (Xgraph *G), +#else +static void + dumpcutcadj (), +#endif +#endif + +/* + gomory_hu returns a pointer to the root of a rooted cut tree. The tree is + described by the parent, sibling, and child pointers. + cutval is the weight on the cut (or, edge) between a node and its parent. + ndescendants is the total number of nodes in the subtree rooted at that + node, including itself. This is the size of the cut between that node and + its parent. + special is the special node for this node of the tree. + nlist is a nodeset containing all of the nodes of the graph grouped with the + special node. nlist contains special. + pseudonode and next are work area. + The calling routine should call cuttree_free(root) after it is done with the + cuttree. + + gomory_hu constructs the min-cut tree for the nodes with mark = 1. + pseudonodelist is the head of a linked list of the nodes in the graph +*/ + + +#ifdef CC_PROTOTYPE_ANSI +Xcuttree_node *Xgomory_hu (Xgraph *G) +#else +Xcuttree_node *Xgomory_hu (G) +Xgraph *G; +#endif +{ + Xnodeset special; + Xnodeset nlist; + Xnode *p; + Xcuttree_node *root; + Xnodeptr *pp; + + /* see if there's anything to do */ + p = G->pseudonodelist->next; + while (p && p->mark != 1) + p = p->next; + /* BICO: WAS for (p = pseudonodelist->next; p && p->mark==1; p=p->next);*/ + /* WHATS THIS? IF ALL NODES ARE MARKED WE GIVE UP? */ + if (!p) { + return 0; + } + /* initialize root */ + root = Xcuttree_nodealloc (); + root->parent = (Xcuttree_node *) NULL; + root->sibling = (Xcuttree_node *) NULL; + root->child = (Xcuttree_node *) NULL; + root->cutval = 0.0; + root->pseudonode = (Xnode *) NULL; + root->nlist.head = root->nlist.tail = (Xnodeptr *) NULL; + + /* set up nlist & special */ + special.head = special.tail = (Xnodeptr *) NULL; + nlist.head = nlist.tail = (Xnodeptr *) NULL; + + for (p = G->pseudonodelist->next; p; p = p->next) { + addtonodeset (&nlist, p); + if (p->mark == 1) + addtonodeset (&special, p); + } + + if (!special.head) { + fprintf (stderr, "Big Whoa, calling initial gh_work\n"); + exit (1); + } + gh_work (G, root, &nlist, &special); + + /* restore pseudonodelist */ + G->npseudonodes = 0; + G->pseudonodelist->next = (Xnode *) NULL; + G->pseudonodelist->prev = (Xnode *) NULL; + for (pp = nlist.head; pp; pp = pp->next) { + pp->this->next = G->pseudonodelist->next; + if (G->pseudonodelist->next) + G->pseudonodelist->next->prev = pp->this; + G->pseudonodelist->next = pp->this; + pp->this->prev = G->pseudonodelist; + G->npseudonodes++; + } + + freenodeset (&nlist); + freenodeset (&special); + + countdescendants (root); + + root->cutval = XMAXWEIGHT; + + return root; +} + +#ifdef DEBUG +#ifdef CC_PROTOTYPE_ANSI +static void dumpcutcadj (Xgraph *G) +#else +static void dumpcutcadj (G) +Xgraph *G; +#endif +{ + Xnode *p; + Xedgeptr *ep; + + printf ("CADJ IN GOMORY_HU:\n"); + for (p = G->pseudonodelist->next; p; p = p->next) { + printf ("NODE %d: ", p - G->nodelist); + if (p->mark) + printf ("(S) "); + for (ep = p->cadj.head; ep; ep = ep->next) { + printf ("%d", OTHERCURRENTEND (ep->this, p) - G->nodelist); + printf ("(%f) ", ep->this->x); + } + printf ("\n"); + } +} +#endif /* DEBUG */ + +#ifdef CC_PROTOTYPE_ANSI +static void addtonodeset (Xnodeset *s, Xnode *n) +#else +static void addtonodeset (s, n) +Xnodeset *s; +Xnode *n; +#endif +{ + Xnodeptr *nnew; + + nnew = Xnodeptralloc (); + nnew->this = n; + nnew->next = s->head; + s->head = nnew; + if (!s->tail) + s->tail = nnew; +} + +#ifdef CC_PROTOTYPE_ANSI +static void delfromnodeset (Xnodeset *s, Xnode *n) +#else +static void delfromnodeset (s, n) +Xnodeset *s; +Xnode *n; +#endif +{ + Xnodeptr *oldn, *n1; + + oldn = (Xnodeptr *) NULL; + n1 = s->head; + while (n1 && n1->this != n) { + oldn = n1; + n1 = n1->next; + } + if (!n1) { + fprintf (stderr, "Node vanished from sight\n"); + exit (1); + } + if (!oldn) { /* deleting head */ + s->head = n1->next; + if (!s->head) + s->tail = (Xnodeptr *) NULL; + } else { + oldn->next = n1->next; + if (!oldn->next) + s->tail = oldn; + } + Xnodeptrfree (n1); +} + +#ifdef CC_PROTOTYPE_ANSI +static void delfromedgeset (Xedgeset *s, Xedge *e) +#else +static void delfromedgeset (s, e) +Xedgeset *s; +Xedge *e; +#endif +{ + Xedgeptr *olde, *e1; + + olde = (Xedgeptr *) NULL; + e1 = s->head; + while (e1 && e1->this != e) { + olde = e1; + e1 = e1->next; + } + if (!e1) { + fprintf (stderr, "Edge vanished from sight\n"); + exit (1); + } + if (!olde) { /* deleting head */ + s->head = e1->next; + if (!s->head) + s->tail = (Xedgeptr *) NULL; + } else { + olde->next = e1->next; + if (!olde->next) + s->tail = olde; + } + Xedgeptrfree (e1); +} + +#ifdef CC_PROTOTYPE_ANSI +static void freenodeset (Xnodeset *s) +#else +static void freenodeset (s) +Xnodeset *s; +#endif +{ + Xnodeptr *p, *pnext; + + for (p = s->head; p; p = pnext) { + pnext = p->next; + Xnodeptrfree (p); + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcuttree_free (Xcuttree_node *n) +#else +void Xcuttree_free (n) +Xcuttree_node *n; +#endif +{ + Xcuttree_node *p, *pnext; + + for (p = n->child; p; p = pnext) { + pnext = p->sibling; + Xcuttree_free (p); + } + freenodeset (&n->nlist); + Xcuttree_nodefree (n); +} + +#ifdef CC_PROTOTYPE_ANSI +static int countdescendants (Xcuttree_node *n) +#else +static int countdescendants (n) +Xcuttree_node *n; +#endif +{ + Xcuttree_node *p; + int i; + + i = 1; + for (p = n->child; p; p = p->sibling) + i += countdescendants (p); + n->ndescendants = i; + return i; +} + +/* gh_work(n) expands the Xcuttree_node n. */ + +#ifdef CC_PROTOTYPE_ANSI +static void gh_work (Xgraph *G, Xcuttree_node *n, Xnodeset *nlist, + Xnodeset *special) +#else +static void gh_work (G, n, nlist, special) +Xgraph *G; +Xcuttree_node *n; +Xnodeset *nlist, *special; +#endif +{ + Xnodeset a_nlist, b_nlist; + Xnodeset a_special, b_special; + Xcuttree_node *a_cut, *b_cut; + Xcuttree_node *cp, *nextcp; + Xnodeptr *p; + double fv; + Xedgeset esave; + Xcuttree_node *newcut; + Xnode newnode; + Xnode *anode = (Xnode *) NULL; + Xnode *bnode = (Xnode *) NULL; + int i; + Xnode *v; + + /* termination cases for the recursion */ + if (!special->head) { + fprintf (stderr, "Whoa, gh_work called with a null special list\n"); + exit (1); + } + if (!special->head->next) { + ++(G->magicnum); + if (n->parent) + n->parent->pseudonode->magiclabel = G->magicnum; + for (cp = n->child; cp; cp = cp->sibling) + cp->pseudonode->magiclabel = G->magicnum; + n->special = special->head->this; + n->nlist.head = n->nlist.tail = (Xnodeptr *) NULL; + for (p = nlist->head; p; p = p->next) + if (p->this->magiclabel != G->magicnum) + addtonodeset (&n->nlist, p->this); + return; + } + /* find the split */ + + /* set up G->pseudonodelist so flow is happy */ + G->npseudonodes = 0; + G->pseudonodelist->next = (Xnode *) NULL; + for (p = nlist->head; p; p = p->next) { + p->this->next = G->pseudonodelist->next; + G->pseudonodelist->next = p->this; + G->npseudonodes++; + } + + for (p = special->head, i = 0; p; p = p->next) { + i++; + if (myrandnum (i) == 0) + anode = p->this; + } + + for (p = special->head, i = 0; p; p = p->next) { + if (p->this != anode) { + i++; + if (myrandnum (i) == 0) + bnode = p->this; + } + } + + fv = Xflow (G, anode, bnode, 1.0e10); + + paint (G, bnode, ++(G->magicnum)); + + /* make the two new cuttree_nodes */ + + /* divide them up */ + splitset (nlist, &a_nlist, &b_nlist, G->magicnum); + splitset (special, &a_special, &b_special, G->magicnum); + + if (!a_special.head) { + fprintf (stderr, "Yipes! a_special is null\n"); + if (!b_special.head) + fprintf (stderr, "And so is b_special\n"); + exit (1); + } else if (!b_special.head) { + fprintf (stderr, "Yipes! b_special is null\n"); + printf ("SPECIAL: "); + for (p = a_special.head; p; p = p->next) + printf ("%d ", (int) (p->this - G->nodelist)); + printf ("\n"); + printf ("anode = %d bnode = %d\n", (int) (anode - G->nodelist), + (int) (bnode - G->nodelist)); + printf ("flow value = %f\n", fv); + printf ("npseudonodes = %d\n", G->npseudonodes); + Xdumppseudograph (G); + fv = Xflow (G, anode, bnode, 10.0); + printf ("new flow value = %f\n", fv); + fflush (stdout); + paint (G, bnode, ++(G->magicnum)); + printf ("MIN CUT: "); + fflush (stdout); + for (v = G->pseudonodelist->next; v; v = v->next) + if (v->magiclabel == G->magicnum) { + printf ("%d ", (int) (v - G->nodelist)); + fflush (stdout); + } + printf ("\n"); + Xdumppseudograph_edgelist (G); + exit (1); + } + newcut = Xcuttree_nodealloc (); + newcut->parent = n; + newcut->sibling = (Xcuttree_node *) NULL; + newcut->child = (Xcuttree_node *) NULL; + newcut->cutval = fv; + newcut->nlist.head = newcut->nlist.tail = (Xnodeptr *) NULL; + + if (n->parent && n->parent->pseudonode->magiclabel == G->magicnum) { + a_cut = n; + b_cut = newcut; + } else { + a_cut = newcut; + b_cut = n; + } + + /* divide the children up between the two sides */ + for (cp = n->child, n->child = (Xcuttree_node *) NULL, + newcut->child = (Xcuttree_node *) NULL; cp; cp = nextcp) { + nextcp = cp->sibling; + if (cp->pseudonode->magiclabel == G->magicnum) { + cp->sibling = a_cut->child; + a_cut->child = cp; + } else { + cp->sibling = b_cut->child; + b_cut->child = cp; + } + } + newcut->sibling = n->child; + n->child = newcut; + + newnode.magiclabel = 0; + newnode.stacklabel = 0; + shrinkdown (&a_nlist, &newnode, &esave, G->magicnum); + + a_cut->pseudonode = (Xnode *) NULL; + b_cut->pseudonode = &newnode; + + addtonodeset (&a_nlist, &newnode); + + gh_work (G, a_cut, &a_nlist, &a_special); + + delfromnodeset (&a_nlist, &newnode); + + ++(G->magicnum); + for (p = b_nlist.head; p; p = p->next) + p->this->magiclabel = G->magicnum; + + unshrink (&newnode, &esave, G->magicnum); + + shrinkdown (&b_nlist, &newnode, &esave, G->magicnum); + + a_cut->pseudonode = &newnode; + b_cut->pseudonode = (Xnode *) NULL; + + addtonodeset (&b_nlist, &newnode); + + gh_work (G, b_cut, &b_nlist, &b_special); + + delfromnodeset (&b_nlist, &newnode); + + ++(G->magicnum); + for (p = a_nlist.head; p; p = p->next) + p->this->magiclabel = G->magicnum; + + unshrink (&newnode, &esave, G->magicnum); + + nlist->head = a_nlist.head; + nlist->tail = a_nlist.tail; + mergeset (nlist, &b_nlist); + + special->head = a_special.head; + special->tail = a_special.tail; + mergeset (special, &b_special); + + return; +} + +#ifdef CC_PROTOTYPE_ANSI +static void splitset (Xnodeset *s, Xnodeset *a, Xnodeset *b, int n) +#else +static void splitset (s, a, b, n) +Xnodeset *s, *a, *b; +int n; +#endif +{ + Xnodeptr *p; + Xnodeptr *pnext; + + a->head = a->tail = (Xnodeptr *) NULL; + b->head = b->tail = (Xnodeptr *) NULL; + for (p = s->head; p; p = pnext) { + pnext = p->next; + if (p->this->magiclabel == n) { + p->next = a->head; + a->head = p; + if (!a->tail) + a->tail = p; + } else { + p->next = b->head; + b->head = p; + if (!b->tail) + b->tail = p; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void mergeset (Xnodeset *s, Xnodeset *a) +#else +static void mergeset (s, a) +Xnodeset *s, *a; +#endif +{ + Xnodeptr *p; + Xnodeptr *pnext; + + for (p = a->head; p; p = pnext) { + pnext = p->next; + p->next = s->head; + s->head = p; + if (!s->tail) + s->tail = p; + } +} + +/* shrink everything with G->magicnum != num to pseudo. a is a list of + * everything with G->magicnum == num. */ + +#ifdef CC_PROTOTYPE_ANSI +static void shrinkdown (Xnodeset *a, Xnode *pseudo, Xedgeset *esave, int num) +#else +static void shrinkdown (a, pseudo, esave, num) +Xnodeset *a; +Xnode *pseudo; +Xedgeset *esave; +int num; +#endif +{ + Xedgeset enew; + Xnodeptr *p; + Xedgeptr *e, *enext; + Xnode *x; + double cumx; + + pseudo->cadj.head = pseudo->cadj.tail = (Xedgeptr *) NULL; + esave->head = esave->tail = (Xedgeptr *) NULL; + for (p = a->head; p; p = p->next) { + cumx = 0.0; + enew.head = enew.tail = (Xedgeptr *) NULL; + for (e = p->this->cadj.head; e; e = enext) { + enext = e->next; + x = OTHERCURRENTEND (e->this, p->this); + if (x->magiclabel != num) { + cumx += e->this->x; + e->next = esave->head; + esave->head = e; + if (!esave->tail) + esave->tail = e; + } else { + e->next = enew.head; + enew.head = e; + if (!enew.tail) + enew.tail = e; + } + } + if (cumx > 0.0) { + e = Xedgeptralloc (); + e->this = Xedgealloc (); + e->next = enew.head; + enew.head = e; + if (!enew.tail) + enew.tail = e; + e->this->cends[0] = p->this; + e->this->cends[1] = pseudo; + e->this->x = cumx; + e->this->stay = 1; + e = Xedgeptralloc (); + e->this = enew.head->this; + e->next = pseudo->cadj.head; + pseudo->cadj.head = e; + if (!pseudo->cadj.tail) + pseudo->cadj.tail = e; + } + p->this->cadj.head = enew.head; + p->this->cadj.tail = enew.tail; + } +} + +/* unshrink pseudo. everything inside pseudo has been marked with num */ + +#ifdef CC_PROTOTYPE_ANSI +static void unshrink (Xnode *pseudo, Xedgeset *esave, int num) +#else +static void unshrink (pseudo, esave, num) +Xnode *pseudo; +Xedgeset *esave; +int num; +#endif +{ + Xedgeptr *e, *enext; + Xnode *x; + + /* take out the new edges we added */ + for (e = pseudo->cadj.head; e; e = enext) { + enext = e->next; + x = OTHERCURRENTEND (e->this, pseudo); + delfromedgeset (&x->cadj, e->this); + Xedgefree (e->this); + Xedgeptrfree (e); + } + + /* put back the edges we deleted */ + for (e = esave->head; e; e = enext) { + enext = e->next; + x = e->this->cends[0]; + if (x->magiclabel == num) + x = e->this->cends[1]; + e->next = x->cadj.head; + x->cadj.head = e; + if (!x->cadj.tail) + x->cadj.tail = e; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void paint (Xgraph *G, Xnode *n, int v) +#else +static void paint (G, n, v) +Xgraph *G; +Xnode *n; +int v; +#endif +{ + Xedgeptr *epp; + Xedge *ep; + + n->magiclabel = v; + for (epp = n->cadj.head; epp; epp = epp->next) { + ep = epp->this; + if (ep->cends[0] == n) { + if (ep->x + ep->flow > 0.0 && + ep->cends[1]->magiclabel != G->magicnum) + paint (G, ep->cends[1], v); + } else { + if (ep->x - ep->flow > 0.0 && + ep->cends[0]->magiclabel != G->magicnum) + paint (G, ep->cends[0], v); + } + } +} + +/* +#define RAND_M 1771875 +#define RAND_A 2416 +#define RAND_C 374441 + +#ifdef CC_PROTOTYPE_ANSI +int myrandnum (int n) +#else +int myrandnum (n) +int n; +#endif +{ + static unsigned int seed = 473; + + seed = (seed * RAND_A + RAND_C) % RAND_M; + return (n * seed) / RAND_M; +} +*/ + +#ifdef CC_PROTOTYPE_ANSI +static int myrandnum (int n) +#else +static int myrandnum (n) +int n; +#endif +{ + return (CCutil_lprand () % n); +} + diff --git a/contrib/blossom/concorde97/XSTUFF/Xgraph.c b/contrib/blossom/concorde97/XSTUFF/Xgraph.c new file mode 100644 index 0000000000000000000000000000000000000000..2d5ac7e41d0e4e05546ab794f6e785fa80419b6a --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xgraph.c @@ -0,0 +1,132 @@ +/**************************************************************************/ +/* */ +/* OLD GRAPH STUFF - Routines for building the old style graphs to */ +/* run the separation routines from concorde. */ +/* The separation routines will not be threadsafe. */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void */ +/* Xfreegraph (Xgraph *G) */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI +int Xbuildgraph (Xgraph *G, int ncount, int ecount, int *elist, int *elen) +#else +int Xbuildgraph (G, ncount, ecount, elist, elen) +Xgraph *G; +int ncount; +int ecount; +int *elist; +int *elen; +#endif +{ + Xedge *e; + Xedgeptr *e1; + int i, k, n1, n2; + + G->edgelist = (Xedge *) NULL; + G->nodelist = (Xnode *) NULL; + G->pseudonodelist = (Xnode *) NULL; + G->pseudoedgelist = (Xedge *) NULL; + G->npseudonodes = 0; + G->magicnum = 0; + G->stacknum = 0; + G->magicedgenum = 0; + + G->nnodes = ncount; + G->nedges = ecount; + G->nodelist = CC_SAFE_MALLOC (ncount, Xnode); + if (!G->nodelist) + return 1; + G->edgelist = CC_SAFE_MALLOC (ecount, Xedge); + if (!G->edgelist) { + CC_FREE (G->nodelist, Xnode); + return 1; + } + + for (i = 0; i < ncount; i++) { + G->nodelist[i].adj.head = G->nodelist[i].adj.tail = (Xedgeptr *) NULL; + G->nodelist[i].magiclabel = 0; + G->nodelist[i].stacklabel = 0; + } + for (i = 0, e = G->edgelist, k = 0; i < ecount; i++, e++) { + n1 = elist[k++]; + n2 = elist[k++]; + e->weight = elen[i]; + e->ends[0] = G->nodelist + n1; + e->ends[1] = G->nodelist + n2; + e->elim = 0; + e->weak = 0; + e->fixed = 0; + e->hold = 0; /* use 1 to hold original edges in weak + * remove */ + e->x = 0.0; + e->rc = 0.0; + e->magiclabel = 0; + } + + for (i = ecount, e = G->edgelist; i; i--, e++) { + e1 = Xedgeptralloc (); + e1->next = e->ends[0]->adj.head; + e1->this = e; + e->ends[0]->adj.head = e1; + if (e->ends[0]->adj.tail == (Xedgeptr *) NULL) + e->ends[0]->adj.tail = e1; + e1 = Xedgeptralloc (); + e1->next = e->ends[1]->adj.head; + e1->this = e; + e->ends[1]->adj.head = e1; + if (e->ends[1]->adj.tail == (Xedgeptr *) NULL) + e->ends[1]->adj.tail = e1; + } + Xinit_hash_values (G); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xfreegraph (Xgraph *G) +#else +void Xfreegraph (G) +Xgraph *G; +#endif +{ + int i; + Xnode *n; + Xedgeptr *e, *enext; + + if (G->nodelist) { + for (i = G->nnodes, n = G->nodelist; i; i--, n++) { + for (e = n->adj.head; e; e = enext) { + enext = e->next; + Xedgeptrfree (e); + } + n->adj.head = n->adj.tail = (Xedgeptr *) NULL; + } + CC_FREE (G->nodelist, Xnode); + } + if (G->edgelist) + CC_FREE (G->edgelist, Xedge); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xloadx (Xgraph *G, double *x) +#else +void Xloadx (G, x) +Xgraph *G; +double *x; +#endif +{ + double *dp; + Xedge *pe; + int i; + + for (i = G->nedges, pe = G->edgelist, dp = x; i; i--) + pe++->x = *dp++; + +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xnecklac.c b/contrib/blossom/concorde97/XSTUFF/Xnecklac.c new file mode 100644 index 0000000000000000000000000000000000000000..caa4da5ebccb9007d8e9e194b5535d7c240c9ee4 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xnecklac.c @@ -0,0 +1,1930 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTION: */ +/* int necklaces(Xcplane **, double *) */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" +#include "Xpq.h" +#include "Xnecklac.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + cliquelist_free (Xclique *), + necklace_build_neckedges (double *), + necklace_build_necklaces (PQ_node *), + necklace_build_neckadj (void), + necklace_destroy_neckadj (void), + label_necklaces (PQ_node *), + label_necklaces_work (PQ_node *), + label_necklace (PQ_node *), + label_edges (PQ_node *, PQ_node *, int), + lift_ends (PQ_node *, PQ_node *), + lift_edges (PQ_node *, PQ_node *), + dump_necklaces (void), + dump_necklace_work (PQ_node *), + free_equation (Xeqn *), + compute_toroots (PQ_node *), + free_toroots (PQ_node *), + eqn_addto (Xeqn *, Xeqn *), + dump_intptr_list (Xintptr *), + collect_neck_tooth_leaf (PQ_node *, int, int, Xnodeptr **), + collect_neck_tooth_work (PQ_node *, int, int, Xnodeptr **, PQ_node *), + binsys_init (bin_system *, int), + binsys_elim (bin_system *, Xeqn *), + binsys_random_solution (bin_system *), + binsys_eval_pivot (bin_system *, Xeqn *), + binsys_pop_sparse (bin_system *), + binsys_free_system (bin_system *), + ds_makeset (PQ_node *); + +static int + necklace_cuts (double *, Xcplane **, PQ_node *), + neckedge_compare (const void *, const void *), + count_necklaces (PQ_node *), + find_node_label (PQ_node *), + necklace_crunch_cuts (PQ_node *, Xcplane **), + necklace_add_edge_to_sys (Xneckedge *, bin_system *), + necklace_try_solutions (bin_system *, PQ_node *, Xcplane **, Xintptrptr **), + find_label (Xintptr *, int), + intptr_list_size (Xintptr *), + intptrlist_equal (Xintptr *, Xintptr *), + find_solution (Xintptr *, Xintptrptr *), + necklace_checkout_solution (Xintptr *, PQ_node *, Xcplane **), + count_labeled_children (PQ_node *), + check_realization (PQ_node *, int, PQ_node **, PQ_node **), + collect_necklace_label (PQ_node *), + binsys_add_dense (bin_system *, Xeqn *), + binsys_add_sparse (bin_system *, Xeqn *), + binsys_force_zero (bin_system *, int); + +static PQ_node + *init_elems (PQ_node *elems), + *necklace_build_cuttree (double *), + *necklace_build_spantree (void), + *ds_find (PQ_node *), + *ds_link (PQ_node *, PQ_node *); + +static Xeqn + *necklace_edge_to_eqn (Xneckedge *); + +static Xintptr + *intptr_add (Xintptr *, Xintptr *), + *intptr_add_destruc (Xintptr *, Xintptr *), + *intptr_addto (Xintptr *, Xintptr *), + *intptr_copy (Xintptr *), + *binsys_random_minimal_solution (bin_system *), + *binsys_list_solution (bin_system *); + +static Xnodeptr + *collect_necklace_tooth (PQ_node *, PQ_node *, PQ_node *, PQ_node *), + *collect_necklace_handle (void); + +static int + add_clique_to_PQtree (Xclique *c, PQ_node *elems); +static PQ_node + *clique_to_PQlist (Xclique *c, PQ_node *elems); +static int + find_intptr_list (Xintptr *p, int n); + +#else + +static void + cliquelist_free (), + necklace_build_neckedges (), + necklace_build_necklaces (), + necklace_build_neckadj (), + necklace_destroy_neckadj (), + label_necklaces (), + label_necklaces_work (), + label_necklace (), + label_edges (), + lift_ends (), + lift_edges (), + dump_necklaces (), + dump_necklace_work (), + free_equation (), + compute_toroots (), + free_toroots (), + eqn_addto (), + dump_intptr_list (), + collect_neck_tooth_leaf (), + collect_neck_tooth_work (), + binsys_init (), + binsys_elim (), + binsys_random_solution (), + binsys_eval_pivot (), + binsys_pop_sparse (), + binsys_free_system (), + ds_makeset (); + +static int + necklace_cuts (), + neckedge_compare (), + count_necklaces (), + find_node_label (), + necklace_crunch_cuts (), + necklace_add_edge_to_sys (), + necklace_try_solutions (), + find_label (), + intptr_list_size (), + intptrlist_equal (), + find_solution (), + necklace_checkout_solution (), + count_labeled_children (), + check_realization (), + collect_necklace_label (), + binsys_add_dense (), + binsys_add_sparse (), + binsys_force_zero (); + +static PQ_node + *init_elems (), + *necklace_build_cuttree (), + *necklace_build_spantree (), + *ds_find (), + *ds_link (); + +static Xeqn + *necklace_edge_to_eqn (); + +static Xintptr + *intptr_add (), + *intptr_add_destruc (), + *intptr_addto (), + *intptr_copy (), + *binsys_random_minimal_solution (), + *binsys_list_solution (); + +static Xnodeptr + *collect_necklace_tooth (), + *collect_necklace_handle (); + +static int + add_clique_to_PQtree (); +static PQ_node + *clique_to_PQlist (); +static int + find_intptr_list (); + + +#endif + +#define NECK_ENUM_CUTOFF 5 +#define NECK_ENUM_NTRIES 50 +#define NECK_NEXTTRY(x) (((x)*2)/3) + +static int verbose = 0; +static int nnecklaces; +static PQ_node **necklist; +static Xneckedge *neckedgelist; +static int nneckedges; +static PQ_node *necknodelist; +static int magicneckedgenum = 0; +static Xgraph *G; + +static Xclique *cliquelist = (Xclique *) NULL; +static int ncliques = 0; + +#ifdef CC_PROTOTYPE_ANSI +int Xnecklaces (Xgraph *Gin, Xcplane **list, double *x) +#else +int Xnecklaces (Gin, list, x) +Xgraph *Gin; +Xcplane **list; +double *x; +#endif +{ + double szeit; + PQ_node *pqroot; + int k; + + G = Gin; + + szeit = CCutil_zeit (); + + printf ("CALLED NECKLACE ... (%d, %d)\n", G->nnodes, G->nedges); + fflush (stdout); + + pqroot = necklace_build_cuttree (x); + + if (!pqroot) { + return 0; + } + + k = necklace_cuts (x, list, pqroot); + +/* + for (c = *list; c; c = c->next) + if (c->handles) + printcliquetree (c->handles, c->teeth); + else + printchvatalcomb (c->handle, c->teeth); +*/ + + + XPQ_free_all (pqroot, 1); + CC_FREE (necknodelist, PQ_node); + + printf ("Time in Necklace: %2f\n", CCutil_zeit () - szeit); + fflush (stdout); + + return k; +} + +#ifdef CC_PROTOTYPE_ANSI +static int necklace_cuts (double *x, Xcplane **list, PQ_node *pqroot) +#else +static int necklace_cuts (x, list, pqroot) +double *x; +Xcplane **list; +PQ_node *pqroot; +#endif +{ + PQ_node *spanroot; + int k; + + necklace_build_neckedges (x); + + necklace_build_necklaces (pqroot); + + necklace_build_neckadj (); + + spanroot = necklace_build_spantree (); + + if (!spanroot) { + necklace_destroy_neckadj (); + CC_FREE (necklist, PQ_node *); + CC_FREE (neckedgelist, Xneckedge); + return 0; + } + + spanroot->toroot = (Xintptr *) NULL; + compute_toroots (spanroot); + + k = necklace_crunch_cuts (pqroot, list); + + free_toroots (spanroot); + necklace_destroy_neckadj (); + CC_FREE (necklist, PQ_node *); + CC_FREE (neckedgelist, Xneckedge); + + return k; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *necklace_build_cuttree (double *x) +#else +static PQ_node *necklace_build_cuttree (x) +double *x; +#endif +{ + int i; + Xclique *cnext; + PQ_node *token_elem; + double szeit; + + for (i=0; i<G->nedges; i++) { + G->edgelist[i].x = x[i]; + } + cliquelist = (Xclique *) NULL; + ncliques = 0; + szeit = CCutil_zeit (); + Xall_tightcuts (G, &cliquelist, &ncliques); + printf ("Found %d tight cliques in %.2f seconds\n", ncliques, + CCutil_zeit () - szeit); + + necknodelist = CC_SAFE_MALLOC (G->nnodes, PQ_node); + if (!necknodelist) { + fprintf (stderr, "out of memory in necklace\n"); + exit (1); + } + + token_elem = init_elems (necknodelist); + + while (cliquelist) { + cnext = cliquelist->next; + if (!add_clique_to_PQtree (cliquelist, necknodelist)) { + XPQ_free_all (token_elem, 1); + CC_FREE (necknodelist, PQ_node); + cliquelist_free (cliquelist); + printf ("ZZZ Necklace bailout\n"); + fflush (stdout); + return (PQ_node *) NULL; + } + Xintptr_list_free (cliquelist->nodes); + Xcliquefree (cliquelist); + cliquelist = cnext; + } + return XPQ_find_root (token_elem); +} + +#ifdef CC_PROTOTYPE_ANSI +static void cliquelist_free (Xclique *c) +#else +static void cliquelist_free (c) +Xclique *c; +#endif +{ + Xclique *cnext; + + while (c) { + cnext = c->next; + Xintptr_list_free (c->nodes); + Xcliquefree (c); + c = cnext; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int neckedge_compare (const void *a, const void *b) +#else +static int neckedge_compare (a, b) +const void *a; +const void *b; +#endif +{ + if (((const Xneckedge *) a)->x < ((const Xneckedge *) b)->x) { + return 1; + } else if (((const Xneckedge *) a)->x > ((const Xneckedge *) b)->x) { + return -1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void necklace_build_neckedges (double *x) +#else +static void necklace_build_neckedges (x) +double *x; +#endif +{ + int i; + + for (i=0; i<G->nnodes; i++) { + necknodelist[i].adj = (Xneckedgeptr *) NULL; + necknodelist[i].magiclabel = 0; + } + + neckedgelist = CC_SAFE_MALLOC (G->nedges, Xneckedge); + if (!neckedgelist) { + fprintf (stderr, "out of memory in necklace\n"); + exit (1); + } + for (i=0, nneckedges = 0; i<G->nedges; i++) { + if (x[i] > 0.0) { + neckedgelist[nneckedges].x = x[i]; + neckedgelist[nneckedges].ends[0] = necknodelist + (G->edgelist[i].ends[0] - G->nodelist); + neckedgelist[nneckedges].ends[1] = necknodelist + (G->edgelist[i].ends[1] - G->nodelist); + neckedgelist[nneckedges].magiclabel = 0; + nneckedges++; + } + } + qsort ((char *) neckedgelist, nneckedges, sizeof (Xneckedge), neckedge_compare); +} + +#ifdef CC_PROTOTYPE_ANSI +static void necklace_build_necklaces (PQ_node *pqroot) +#else +static void necklace_build_necklaces (pqroot) +PQ_node *pqroot; +#endif +{ + int neckspace; + + neckspace = count_necklaces (pqroot); + + necklist = CC_SAFE_MALLOC (neckspace, PQ_node *); + if (!necklist) { + fprintf (stderr, "out of memory in necklace\n"); + exit (1); + } + nnecklaces = 0; + + label_necklaces (pqroot); + + if (nnecklaces != neckspace) { + fprintf (stderr, "ZZZ NECKLACE COUNTS WRONG (%d != %d)\n",neckspace, nnecklaces); + } + + printf ("%d necklaces found, ",nnecklaces); + fflush (stdout); + + if (verbose) { + printf ("Necklaces:\n"); + dump_necklaces (); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void necklace_build_neckadj (void) +#else +static void necklace_build_neckadj () +#endif +{ + int i; + + for (i=0; i<nneckedges; i++) { + Xadd_neckedgeptr (&neckedgelist[i].ends[0]->adj, &neckedgelist[i]); + Xadd_neckedgeptr (&neckedgelist[i].ends[1]->adj, &neckedgelist[i]); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void necklace_destroy_neckadj (void) +#else +static void necklace_destroy_neckadj () +#endif +{ + int i; + + for (i=0; i<G->nnodes; i++) { + Xneckedgeptr_list_free (necknodelist[i].adj); + necknodelist[i].adj = (Xneckedgeptr *) NULL; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int count_necklaces (PQ_node *x) +#else +static int count_necklaces (x) +PQ_node *x; +#endif +{ + int cnt = 0; + PQ_node *z, *zprev, *znext; + int childcount = 0; + + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + cnt += count_necklaces (z); + childcount++; + } + if (x->type == Q_NODE || (x->type == P_NODE && childcount == 2)) { + cnt++; + } + return cnt; +} + +#ifdef CC_PROTOTYPE_ANSI +static void label_necklaces (PQ_node *pqroot) +#else +static void label_necklaces (pqroot) +PQ_node *pqroot; +#endif +{ + int i; + + for (i=0; i<nneckedges; i++) { + neckedgelist[i].cends[0] = neckedgelist[i].ends[0]; + neckedgelist[i].cends[1] = neckedgelist[i].ends[1]; + neckedgelist[i].necklabel = -1; + } + + necklace_build_neckadj (); + + label_necklaces_work (pqroot); +/* label_necklaces_work destroys neckadj except for pqroot and magicnode */ + Xneckedgeptr_list_free (pqroot->adj); + pqroot->adj = (Xneckedgeptr *) NULL; + Xneckedgeptr_list_free (necknodelist[MAGICNODE].adj); + necknodelist[MAGICNODE].adj = (Xneckedgeptr *) NULL; + + assert (nnecklaces < G->nnodes); +} + +#ifdef CC_PROTOTYPE_ANSI +static void label_necklaces_work (PQ_node *n) +#else +static void label_necklaces_work (n) +PQ_node *n; +#endif +{ + PQ_node *z; + PQ_node *zprev; + PQ_node *znext; + int cnt; + + cnt = 0; + PQ_set_FOREACH (n->children_set, z, children_elem, zprev, znext) { + cnt++; + label_necklaces_work (z); + } + n->children_set.size = cnt; + + label_necklace (n); +} + +#ifdef CC_PROTOTYPE_ANSI +static void label_necklace (PQ_node *n) +#else +static void label_necklace (n) +PQ_node *n; +#endif +{ + PQ_node *a, *b, *c; + + if (n->type == Q_NODE || (n->type == P_NODE && PQ_set_SIZE (n->children_set) == 2)) { + a = PQ_set_LEFT_ELEM (n->children_set); + assert (a); + b = a->children_elem.ptr1; + if (!b) { + b = a->children_elem.ptr2; + } + assert (b); + + necklist[nnecklaces] = n; + label_edges (a, b, nnecklaces); + nnecklaces++; + } + + if (n->type != LEAF_NODE) { + PQ_set_FOREACH (n->children_set, a, children_elem, b, c) { + lift_ends (a, n); + } + + n->adj = (Xneckedgeptr *) NULL; + PQ_set_FOREACH (n->children_set, a, children_elem, b, c) { + lift_edges (a, n); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void label_edges (PQ_node *a, PQ_node *b, int n) +#else +static void label_edges (a, b, n) +PQ_node *a; +PQ_node *b; +int n; +#endif +{ + Xneckedgeptr *p; + + for (p = a->adj; p; p = p->next) { + assert (p->this->cends[0] == a || p->this->cends[1] == a); + if (p->this->cends[0] == b || p->this->cends[1] == b) { + p->this->necklabel = n; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void lift_ends (PQ_node *a, PQ_node *n) +#else +static void lift_ends (a, n) +PQ_node *a; +PQ_node *n; +#endif +{ + Xneckedgeptr *p; + + for (p = a->adj; p; p = p->next) { + if (p->this->cends[0] == a) { + p->this->cends[0] = n; + } else { + assert (p->this->cends[1] == a); + p->this->cends[1] = n; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void lift_edges (PQ_node *a, PQ_node *n) +#else +static void lift_edges (a, n) +PQ_node *a; +PQ_node *n; +#endif +{ + Xneckedgeptr *p, *pnext; + + for (p = a->adj; p; p = pnext) { + pnext = p->next; + if (p->this->cends[0] != n || p->this->cends[1] != n) { + assert (p->this->cends[0] == n || p->this->cends[1] == n); + p->next = n->adj; + n->adj = p; + } else { + Xneckedgeptrfree (p); + } + } + a->adj = (Xneckedgeptr *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_necklaces (void) +#else +static void dump_necklaces () +#endif +{ + int i; + PQ_node *z, *znext, *zprev; + int j; + + for (i=0; i<nnecklaces; i++) { + printf ("%d:",i); + PQ_set_FOREACH (necklist[i]->children_set, z, children_elem, zprev, znext) { + if (z->type == Q_NODE || (z->type == P_NODE && PQ_set_SIZE (z->children_set) == 2)) { + j = find_node_label (z); + printf (" %d",j); + } else if (z->type == LEAF_NODE) { + printf (" n%d",z->number); + } else { + printf (" ("); + dump_necklace_work (z); + printf (")"); + } + } + printf ("\n"); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_necklace_work (PQ_node *x) +#else +static void dump_necklace_work (x) +PQ_node *x; +#endif +{ + PQ_node *z, *zprev, *znext; + if (x->type == Q_NODE || (x->type == P_NODE && PQ_set_SIZE (x->children_set) == 2)) { + printf ("%d ",find_node_label (x)); + } else if (x->type == LEAF_NODE) { + printf ("n%d ",x->number); + } else { + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + dump_necklace_work (z); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_node_label (PQ_node *z) +#else +static int find_node_label (z) +PQ_node *z; +#endif +{ + int i; + + for (i=0; i<nnecklaces; i++) { + if (necklist[i] == z) { + return i; + } + } + return -1; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *necklace_build_spantree (void) +#else +static PQ_node *necklace_build_spantree () +#endif +{ + int i; + int k; + PQ_node *front, *back, *new; + Xneckedge *e; + Xneckedgeptr *it; + PQ_node *root; + int cnt; + + for (i=0; i<G->nnodes; i++) { + ds_makeset (&necknodelist[i]); + } + for (i=0; i<nneckedges; i++) { + neckedgelist[i].inspanning = 0; + } + + for (i=0, k=G->nnodes-1; k && i < nneckedges; i++) { + if (ds_find (neckedgelist[i].ends[0]) != ds_find (neckedgelist[i].ends[1])) { + ds_link (ds_find (neckedgelist[i].ends[0]), ds_find (neckedgelist[i].ends[1])); + neckedgelist[i].inspanning = 1; + k--; + } + } + if (k) { + return (PQ_node *) NULL; + } + + /* this is a bit clumsy; first we build the spanning tree, then we do + a breadth-first search through it to root it */ + + G->magicnum++; + root = &necknodelist[0]; + cnt = 0; + + front = root; + front->magiclabel = G->magicnum; + cnt++; + front->entered = (Xneckedge *) NULL; + front->next = (PQ_node *) NULL; + back = front; + + while (front) { + for (it = front->adj; it; it = it->next) { + e = it->this; + if (e->inspanning) { + new = (e->ends[0] == front) ? e->ends[1] : e->ends[0]; + if (new->magiclabel != G->magicnum) { + new->magiclabel = G->magicnum; + cnt++; + new->entered = e; + back->next = new; + back = new; + back->next = (PQ_node *) NULL; + } + } + } + front = front->next; + } + if (cnt < G->nnodes) { + printf ("ZZZ !!!!LOST THE SPANNING TREE!!!!\n"); + fflush (stdout); + return (PQ_node *) NULL; + } + return root; +} + +#ifdef CC_PROTOTYPE_ANSI +static int necklace_crunch_cuts (PQ_node *pqroot, Xcplane **list) +#else +static int necklace_crunch_cuts (pqroot, list) +PQ_node *pqroot; +Xcplane **list; +#endif +{ + bin_system necksys; + Xeqn *oneseqn; + int i; + Xintptr *tmp; + int tried; + Xintptrptr *found; + int k; + int trynext; + int v; + + binsys_init (&necksys, nnecklaces); + + for (i=0; i<nneckedges; i++) { + neckedgelist[i].insystem = neckedgelist[i].inspanning; + } + + oneseqn = Xeqnalloc (); + oneseqn->lhs = (Xintptr *) NULL; + for (i = nnecklaces-1; i>=0; i--) { + tmp = Xintptralloc (); + tmp->this = i; + tmp->next = oneseqn->lhs; + oneseqn->lhs = tmp; + } + oneseqn->rhs = 1; + + if (binsys_add_dense (&necksys, oneseqn) != 1) { + fprintf (stderr, "ZZZ ODDNESS CONSTRAINT FAILED\n"); + } + printf ("1"); fflush (stdout); + + found = (Xintptrptr *) NULL; + k = 0; + trynext = NECK_NEXTTRY (nnecklaces); + + tried = 0; + for (i=0; i<nneckedges && necksys.nfreevars > NECK_ENUM_CUTOFF; i++) { + if (!neckedgelist[i].inspanning) { + v = necklace_add_edge_to_sys (&neckedgelist[i], &necksys); + if (v == 1) { + neckedgelist[i].insystem = 1; + printf ("+"); fflush (stdout); + tried = 0; + if (necksys.nfreevars <= trynext) { + printf (" (%.2f:%d)",neckedgelist[i].x,necksys.nfreevars); + fflush (stdout); + k += necklace_try_solutions (&necksys, pqroot, list, &found); + printf ("\n"); fflush (stdout); + tried = 1; + trynext = NECK_NEXTTRY (trynext); + } + } else if (v == 0) { + neckedgelist[i].insystem = 1; + printf ("."); fflush (stdout); + } else { + printf ("-"); fflush (stdout); + } + } + } + if (!tried) { + printf (" (%.2f:%d)",neckedgelist[i-1].x,necksys.nfreevars); + fflush (stdout); + k += necklace_try_solutions (&necksys, pqroot, list, &found); + printf ("\n"); fflush (stdout); + } + + Xintptrptr_list_freeall (found); + binsys_free_system (&necksys); + return k; +} + +#ifdef CC_PROTOTYPE_ANSI +static Xeqn *necklace_edge_to_eqn (Xneckedge *e) +#else +static Xeqn *necklace_edge_to_eqn (e) +Xneckedge *e; +#endif +{ + Xeqn *neweqn; + Xintptr *tmp; + + neweqn = Xeqnalloc (); + neweqn->lhs = intptr_add (e->ends[0]->toroot, e->ends[1]->toroot); + if (e->necklabel != -1) { + tmp = Xintptralloc (); + tmp->this = e->necklabel; + tmp->next = (Xintptr *) NULL; + neweqn->lhs = intptr_add_destruc (neweqn->lhs, tmp); + } + neweqn->rhs = 0; + return neweqn; +} + +#ifdef CC_PROTOTYPE_ANSI +static int necklace_add_edge_to_sys (Xneckedge *e, bin_system *s) +#else +static int necklace_add_edge_to_sys (e, s) +Xneckedge *e; +bin_system *s; +#endif +{ + Xeqn *neweqn; + + neweqn = necklace_edge_to_eqn (e); + return binsys_add_sparse (s, neweqn); +} + +#ifdef CC_PROTOTYPE_ANSI +static int necklace_try_solutions (bin_system *necksys, PQ_node *pqroot, Xcplane **list, Xintptrptr **found) +#else +static int necklace_try_solutions (necksys, pqroot, list, found) +bin_system *necksys; +PQ_node *pqroot; +Xcplane **list; +Xintptrptr **found; +#endif +{ + int i; + int k = 0; + Xintptr *sollst; + Xintptrptr *new; + + for (i=0; i<NECK_ENUM_NTRIES; i++) { + sollst = binsys_random_minimal_solution (necksys); + if (intptr_list_size (sollst) >= 3 && + !find_solution (sollst, *found)) { + new = Xintptrptralloc (); + new->this = sollst; + new->next = *found; + *found = new; + k += necklace_checkout_solution (sollst, pqroot, list); + } else { + Xintptr_list_free (sollst); + } + } + return k; +} + +#ifdef CC_PROTOTYPE_ANSI +static void free_equation (Xeqn *sys) +#else +static void free_equation (sys) +Xeqn *sys; +#endif +{ + Xintptr_list_free (sys->lhs); + Xeqnfree (sys); +} + +#ifdef CC_PROTOTYPE_ANSI +static void compute_toroots (PQ_node *n) +#else +static void compute_toroots (n) +PQ_node *n; +#endif +{ + Xneckedgeptr *ep; + Xneckedge *e; + PQ_node *m; + Xintptr tmp; + + for (ep = n->adj; ep; ep=ep->next) { + if (ep->this->inspanning) { + e = ep->this; + m = (e->ends[0] == n) ? e->ends[1] : e->ends[0]; + if (m->entered == e) { + if (e->necklabel != -1) { + tmp.this = e->necklabel; + tmp.next = (Xintptr *) NULL; + m->toroot = intptr_add (n->toroot, &tmp); + } else { + m->toroot = intptr_copy (n->toroot); + } + compute_toroots (m); + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void free_toroots (PQ_node *n) +#else +static void free_toroots (n) +PQ_node *n; +#endif +{ + Xneckedgeptr *ep; + Xneckedge *e; + PQ_node *m; + + for (ep = n->adj; ep; ep=ep->next) { + if (ep->this->inspanning) { + e = ep->this; + m = (e->ends[0] == n) ? e->ends[1] : e->ends[0]; + if (m->entered == e) { + free_toroots (m); + } + } + } + Xintptr_list_free (n->toroot); + n->toroot = (Xintptr *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static Xintptr *intptr_add (Xintptr *a, Xintptr *b) +#else +static Xintptr *intptr_add (a, b) +Xintptr *a; +Xintptr *b; +#endif +{ + Xintptr *sum; + Xintptr **sumend; + + sum = (Xintptr *) NULL; + sumend = ∑ + + while (a && b) { + if (a->this == b->this) { + a = a->next; + b = b->next; + } else if (a->this < b->this) { + *sumend = Xintptralloc (); + (*sumend)->this = a->this; + sumend = & (*sumend)->next; + a = a->next; + } else { + assert (a->this > b->this); + *sumend = Xintptralloc (); + (*sumend)->this = b->this; + sumend = & (*sumend)->next; + b = b->next; + } + } + if (a) { + *sumend = intptr_copy (a); + } else if (b) { + *sumend = intptr_copy (b); + } else { + *sumend = (Xintptr *) NULL; + } + return sum; +} + +#ifdef CC_PROTOTYPE_ANSI +static Xintptr *intptr_add_destruc (Xintptr *a, Xintptr *b) +#else +static Xintptr *intptr_add_destruc (a, b) +Xintptr *a; +Xintptr *b; +#endif +{ + Xintptr *sum; + Xintptr **sumend; + Xintptr *tnext; + + sum = (Xintptr *) NULL; + sumend = ∑ + + while (a && b) { + if (a->this == b->this) { + tnext = a->next; + Xintptrfree (a); + a = tnext; + tnext = b->next; + Xintptrfree (b); + b = tnext; + } else if (a->this < b->this) { + *sumend = a; + sumend = &a->next; + a = a->next; + } else { + assert (a->this > b->this); + *sumend = b; + sumend = &b->next; + b = b->next; + } + } + if (a) { + *sumend = a; + } else if (b) { + *sumend = b; + } else { + *sumend = (Xintptr *) NULL; + } + return sum; +} + +/* destroys a, but leaves b alone */ +#ifdef CC_PROTOTYPE_ANSI +static Xintptr *intptr_addto (Xintptr *a, Xintptr *b) +#else +static Xintptr *intptr_addto (a, b) +Xintptr *a; +Xintptr *b; +#endif +{ + Xintptr *sum; + Xintptr **sumend; + Xintptr *tnext; + + sum = (Xintptr *) NULL; + sumend = ∑ + + while (a && b) { + if (a->this == b->this) { + tnext = a->next; + Xintptrfree (a); + a = tnext; + b = b->next; + } else if (a->this < b->this) { + *sumend = a; + sumend = &a->next; + a = a->next; + } else { + assert (a->this > b->this); + *sumend = Xintptralloc (); + (*sumend)->this = b->this; + sumend = & (*sumend)->next; + b = b->next; + } + } + if (a) { + *sumend = a; + } else if (b) { + *sumend = intptr_copy (b); + } else { + *sumend = (Xintptr *) NULL; + } + return sum; +} + +#ifdef CC_PROTOTYPE_ANSI +static Xintptr *intptr_copy (Xintptr *a) +#else +static Xintptr *intptr_copy (a) +Xintptr *a; +#endif +{ + Xintptr *sum; + Xintptr **sumend; + + sum = (Xintptr *) NULL; + sumend = ∑ + + while (a) { + *sumend = Xintptralloc (); + (*sumend)->this = a->this; + sumend = & (*sumend)->next; + a = a->next; + } + *sumend = (Xintptr *) NULL; + return sum; +} + +#ifdef CC_PROTOTYPE_ANSI +static void eqn_addto (Xeqn *a, Xeqn *b) +#else +static void eqn_addto (a, b) +Xeqn *a; +Xeqn *b; +#endif +{ + a->lhs = intptr_addto (a->lhs, b->lhs); + a->rhs ^= b->rhs; +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_intptr_list (Xintptr *p) +#else +static void dump_intptr_list (p) +Xintptr *p; +#endif +{ + if (p) { + printf ("%d",p->this); + p = p->next; + } + while (p) { + printf (" %d",p->this); + p = p->next; + } + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_label (Xintptr *e, int label) +#else +static int find_label (e, label) +Xintptr *e; +int label; +#endif +{ + while (e) { + if (e->this == label) return 1; + if (e->this > label) return 0; + e = e->next; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int intptr_list_size (Xintptr *p) +#else +static int intptr_list_size (p) +Xintptr *p; +#endif +{ + int i; + + for (i=0; p; p = p->next) { + i++; + } + return i; +} + +#ifdef CC_PROTOTYPE_ANSI +static int intptrlist_equal (Xintptr *a, Xintptr *b) +#else +static int intptrlist_equal (a, b) +Xintptr *a; +Xintptr *b; +#endif +{ + while (a && b) { + if (a->this != b->this) { + return 0; + } + a = a->next; + b = b->next; + } + return (a == b); +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_solution (Xintptr *sollst, Xintptrptr *found) +#else +static int find_solution (sollst, found) +Xintptr *sollst; +Xintptrptr *found; +#endif +{ + while (found) { + if (intptrlist_equal (sollst, found->this)) { + return 1; + } + found = found->next; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int necklace_checkout_solution (Xintptr *sollst, PQ_node *pqroot, Xcplane **list) +#else +static int necklace_checkout_solution (sollst, pqroot, list) +Xintptr *sollst; +PQ_node *pqroot; +Xcplane **list; +#endif +{ + int cnt; + Xintptr *p; + PQ_node *lefthalf, *righthalf; + Xnodeptrptr *teeth; + Xnodeptrptr *handles; + Xnodeptrptr *npp; + int test; + + if (verbose) { + printf ("New minimal solution: "); + dump_intptr_list (sollst); + printf ("\n"); + fflush (stdout); + } else { + printf ("."); + fflush (stdout); + } + + G->magicnum++; + for (p = sollst, cnt = 0; p; p = p->next) { + cnt++; + necklist[p->this]->magiclabel = G->magicnum; + } + + if (count_labeled_children (pqroot) != cnt) { + fprintf (stderr, "Lost some labels\n"); + exit (1); + } + + for (p = sollst; p; p = p->next) { + if (!check_realization (necklist[p->this], cnt, &lefthalf, &righthalf)) { + if (verbose) { + printf ("Unrealizable!!\n"); + } + return 0; + } + } + if (verbose) { + printf ("Realizable\n"); + } else { + printf ("+"); + fflush (stdout); + } + + magicneckedgenum++; + + teeth = (Xnodeptrptr *) NULL; + for (p = sollst; p; p = p->next) { + if (!check_realization (necklist[p->this], cnt, &lefthalf, &righthalf)) { + fprintf (stderr, "ZZZ Whoops, necklace broke\n"); + exit (1); + } + npp = Xnodeptrptralloc (); + npp->this = collect_necklace_tooth (lefthalf, righthalf, necklist[p->this], pqroot); + npp->next = teeth; + teeth = npp; + } + handles = Xnodeptrptralloc (); + handles->next = (Xnodeptrptr *) NULL; + handles->this = collect_necklace_handle (); + + if (!Xcliquefluff (G, &handles, &teeth)) { + printf ("ZZZ NECKLACE DE FLUFFED TO 0\n"); + fflush (stdout); + return 0; + } + + test = Xloadcplane (list, (Xnodeptr *) NULL, handles, teeth, 0); + if (!test) { + Xfreeteeth (handles); + Xfreeteeth (teeth); + printf ("-"); + fflush (stdout); + } else { + printf ("YES "); + fflush (stdout); + } + + return test; +} + +#ifdef CC_PROTOTYPE_ANSI +static int count_labeled_children (PQ_node *x) +#else +static int count_labeled_children (x) +PQ_node *x; +#endif +{ + int cnt = 0; + PQ_node *z, *zprev, *znext; + + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + cnt += count_labeled_children (z); + } + if (x->magiclabel == G->magicnum) { + cnt++; + } + x->labeled_children_count = cnt; + return cnt; +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_realization (PQ_node *x, int fullcnt, PQ_node **lefthalf, PQ_node **righthalf) +#else +static int check_realization (x, fullcnt, lefthalf, righthalf) +PQ_node *x; +int fullcnt; +PQ_node **lefthalf; +PQ_node **righthalf; +#endif +{ + PQ_node *z, *zprev, *znext; + + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + if (zprev && z->labeled_children_count == 0 && zprev->labeled_children_count == 0) { + *lefthalf = zprev; + *righthalf = z; + return 1; + } + } + if (x->labeled_children_count == fullcnt) { + if (PQ_set_RIGHT_ELEM (x->children_set)->labeled_children_count == 0) { + *lefthalf = PQ_set_RIGHT_ELEM (x->children_set); + *righthalf = (PQ_node *) NULL; + return 1; + } + if (PQ_set_LEFT_ELEM (x->children_set)->labeled_children_count == 0) { + *lefthalf = PQ_set_LEFT_ELEM (x->children_set); + *righthalf = (PQ_node *) NULL; + return 1; + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static Xnodeptr *collect_necklace_tooth (PQ_node *lefthalf, PQ_node *righthalf, PQ_node *x, PQ_node *pqroot) +#else +static Xnodeptr *collect_necklace_tooth (lefthalf, righthalf, x, pqroot) +PQ_node *lefthalf; +PQ_node *righthalf; +PQ_node *x; +PQ_node *pqroot; +#endif +{ + Xnodeptr *tooth; + + tooth = (Xnodeptr *) NULL; + + if (!lefthalf) { + lefthalf = righthalf; + righthalf = (PQ_node *) NULL; + } + G->magicnum++; + collect_neck_tooth_work (lefthalf, 0, G->magicnum, &tooth, (PQ_node *) NULL); + if (righthalf) { + collect_neck_tooth_work (righthalf, 1, G->magicnum, &tooth, (PQ_node *) NULL); + } else { + collect_neck_tooth_work (pqroot, 1, G->magicnum, &tooth, x); + collect_neck_tooth_leaf (&necknodelist[MAGICNODE], 1, G->magicnum, &tooth); + } + return tooth; +} + +#ifdef CC_PROTOTYPE_ANSI +static void collect_neck_tooth_leaf (PQ_node *x, int mode, int label, Xnodeptr **list) +#else +static void collect_neck_tooth_leaf (x, mode, label, list) +PQ_node *x; +int mode; +int label; +Xnodeptr **list; +#endif +{ + Xnodeptr *np; + Xneckedgeptr *ep; + PQ_node *y; + + np = Xnodeptralloc (); + np->this = G->nodelist + x->number; + np->next = *list; + *list = np; + if (mode == 0) { + x->magiclabel = label; + } else { + for (ep = x->adj; ep; ep = ep->next) { + y = ep->this->ends[0]; + if (y == x) y = ep->this->ends[1]; + if (y->magiclabel == label) { + ep->this->magiclabel = magicneckedgenum; + } + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void collect_neck_tooth_work (PQ_node *x, int mode, int label, Xnodeptr **list, PQ_node *avoid) +#else +static void collect_neck_tooth_work (x, mode, label, list, avoid) +PQ_node *x; +int mode; +int label; +Xnodeptr **list; +PQ_node *avoid; +#endif +{ + PQ_node *z, *zprev, *znext; + + if (x == avoid) return; + if (x->type == LEAF_NODE) { + collect_neck_tooth_leaf (x, mode, label, list); + } else { + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + collect_neck_tooth_work (z, mode, label, list, avoid); + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static Xnodeptr *collect_necklace_handle (void) +#else +static Xnodeptr *collect_necklace_handle () +#endif +{ + Xnodeptr *handle; + int cnt; + Xnodeptr *np; + int i; + + G->magicnum++; + cnt = collect_necklace_label (necknodelist); + handle = (Xnodeptr *) NULL; + if (cnt*2 < G->nnodes) { + for (i=0; i<G->nnodes; i++) { + if (necknodelist[i].magiclabel == G->magicnum) { + np = Xnodeptralloc (); + np->this = &(G->nodelist[i]); + np->next = handle; + handle = np; + } + } + } else { + for (i=0; i<G->nnodes; i++) { + if (necknodelist[i].magiclabel != G->magicnum) { + np = Xnodeptralloc (); + np->this = &(G->nodelist[i]); + np->next = handle; + handle = np; + } + } + } + return handle; +} + +#ifdef CC_PROTOTYPE_ANSI +static int collect_necklace_label (PQ_node *x) +#else +static int collect_necklace_label (x) +PQ_node *x; +#endif +{ + int cnt; + Xneckedgeptr *ep; + PQ_node *y; + + x->magiclabel = G->magicnum; + cnt = 1; + + for (ep = x->adj; ep; ep = ep->next) { + if (ep->this->magiclabel != magicneckedgenum && ep->this->insystem) { + y = ep->this->ends[0]; + if (y == x) y = ep->this->ends[1]; + if (y->magiclabel != G->magicnum) { + cnt += collect_necklace_label (y); + } + } + } + return cnt; +} + +#ifdef CC_PROTOTYPE_ANSI +static void binsys_init (bin_system *s, int nvars) +#else +static void binsys_init (s, nvars) +bin_system *s; +int nvars; +#endif +{ + int i; + + s->vars = CC_SAFE_MALLOC (nvars, bin_var); + if (!s->vars) { + fprintf (stderr, "out of memory in necklace\n"); + exit (1); + } + + for (i=0; i<nnecklaces; i++) { + s->vars[i].elim = (Xeqn *) NULL; + s->vars[i].value = VALUE_UNKNOWN; + s->vars[i].fixed = 0; + } + + s->sparselist = (Xeqn *) NULL; + s->denseeqn = (Xeqn *) NULL; + s->nvars = nvars; + s->nfreevars = nvars; +} + +#ifdef CC_PROTOTYPE_ANSI +static int binsys_add_dense (bin_system *s, Xeqn *e) +#else +static int binsys_add_dense (s, e) +bin_system *s; +Xeqn *e; +#endif +{ + assert (s->denseeqn == (Xeqn *) NULL); + binsys_elim (s, e); + if (e->lhs == (Xintptr *) NULL) { + if (e->rhs == 0) { + Xeqnfree (e); + return 0; + } else { + Xeqnfree (e); + return -1; + } + } + s->denseeqn = e; + e->next = (Xeqn *) NULL; + s->nfreevars--; + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static int binsys_add_sparse (bin_system *s, Xeqn *e) +#else +static int binsys_add_sparse (s, e) +bin_system *s; +Xeqn *e; +#endif +{ + binsys_elim (s, e); + + if (!e->lhs) { + if (e->rhs == 0) { + free_equation (e); + return 0; + } else { + free_equation (e); + return -1; + } + } + if (s->denseeqn && intptrlist_equal (e->lhs, s->denseeqn->lhs)) { + if (e->rhs == s->denseeqn->rhs) { + free_equation (e); + return 0; + } else { + free_equation (e); + return -1; + } + } + e->pivot = e->lhs->this; + s->vars[e->pivot].elim = e; + if (s->denseeqn && find_label (s->denseeqn->lhs, e->pivot)) { + eqn_addto (s->denseeqn, e); + assert (s->denseeqn->lhs); + e->hitdense = 1; + } else { + e->hitdense = 0; + } + e->next = s->sparselist; + s->sparselist = e; + s->nfreevars--; + + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static void binsys_elim (bin_system *s, Xeqn *e) +#else +static void binsys_elim (s, e) +bin_system *s; +Xeqn *e; +#endif +{ + Xintptr **p; + Xintptr *q; + Xeqn *f; + + p = &e->lhs; + while ((q = *p) != (Xintptr *) NULL) { + if ((f = s->vars[q->this].elim) != (Xeqn *) NULL) { + if (f->lhs && f->lhs->this == q->this) { + eqn_addto (e, f); + } else { + eqn_addto (e, f); + p = &e->lhs; + } + } else { + p = & (*p)->next; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +static Xintptr *binsys_random_minimal_solution (bin_system *s) +#else +static Xintptr *binsys_random_minimal_solution (s) +bin_system *s; +#endif +{ + Xintptr *sollst; + int nadded; + int i; + + for (i=0; i<s->nvars; i++) { + s->vars[i].fixed = 0; + } + + nadded = 0; + while (s->nfreevars) { + binsys_random_solution (s); + for (i=0; i<s->nvars; i++) { + if (s->vars[i].value == 0 && !s->vars[i].fixed) { + s->vars[i].fixed = 1; + if (binsys_force_zero (s, i) == 1) { + nadded++; + } + } + } + } + binsys_random_solution (s); + sollst = binsys_list_solution (s); + for (i=0; i<nadded; i++) { + binsys_pop_sparse (s); + } + return sollst; +} + +#ifdef CC_PROTOTYPE_ANSI +static void binsys_random_solution (bin_system *s) +#else +static void binsys_random_solution (s) +bin_system *s; +#endif +{ + Xeqn *e; + int i; + + for (i=0; i<s->nvars; i++) { + if (s->vars[i].elim) { + s->vars[i].value = VALUE_UNKNOWN; + } else { + s->vars[i].value = (CCutil_lprand () & 1); + } + } + if (s->denseeqn && s->denseeqn->lhs) { + s->denseeqn->pivot = s->denseeqn->lhs->this; + binsys_eval_pivot (s, s->denseeqn); + } + for (e = s->sparselist; e; e = e->next) { + binsys_eval_pivot (s, e); + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void binsys_eval_pivot (bin_system *s, Xeqn *e) +#else +static void binsys_eval_pivot (s, e) +bin_system *s; +Xeqn *e; +#endif +{ + int val; + Xintptr *p; + + val = e->rhs; + for (p = e->lhs; p; p = p->next) { + if (p->this != e->pivot) { + assert (s->vars[p->this].value != VALUE_UNKNOWN); + val ^= s->vars[p->this].value; + } + } + s->vars[e->pivot].value = val; +} + +#ifdef CC_PROTOTYPE_ANSI +static int binsys_force_zero (bin_system *s, int v) +#else +static int binsys_force_zero (s, v) +bin_system *s; +int v; +#endif +{ + Xeqn *e = Xeqnalloc (); + Xintptr *p; + + e->rhs = 0; + p = Xintptralloc (); + p->this = v; + p->next = (Xintptr *) NULL; + e->lhs = p; + + return binsys_add_sparse (s, e); +} + +#ifdef CC_PROTOTYPE_ANSI +static void binsys_pop_sparse (bin_system *s) +#else +static void binsys_pop_sparse (s) +bin_system *s; +#endif +{ + Xeqn *e; + + e = s->sparselist; + s->sparselist = e->next; + s->vars[e->pivot].elim = (Xeqn *) NULL; + if (e->hitdense && s->denseeqn) { + eqn_addto (s->denseeqn, e); + } + s->nfreevars++; + free_equation (e); +} + +#ifdef CC_PROTOTYPE_ANSI +static Xintptr *binsys_list_solution (bin_system *s) +#else +static Xintptr *binsys_list_solution (s) +bin_system *s; +#endif +{ + Xintptr *lst; + Xintptr **lstend; + Xintptr *new; + int i; + + lst = (Xintptr *) NULL; + lstend = &lst; + for (i=0; i<s->nvars; i++) { + if (s->vars[i].value == 1) { + new = Xintptralloc (); + new->this = i; + *lstend = new; + lstend = &new->next; + } + } + *lstend = (Xintptr *) NULL; + return lst; +} + +#ifdef CC_PROTOTYPE_ANSI +static void binsys_free_system (bin_system *s) +#else +static void binsys_free_system (s) +bin_system *s; +#endif +{ + Xeqn *e, *enext; + + CC_FREE (s->vars, bin_var); + + for (e = s->sparselist; e; e = enext) { + enext = e->next; + free_equation (e); + } + if (s->denseeqn) { + free_equation (s->denseeqn); + } + + s->vars = (bin_var *) NULL; + s->sparselist = (Xeqn *) NULL; + s->denseeqn = (Xeqn *) NULL; + s->nvars = 0; + s->nfreevars = 0; +} + +/* disjoint sets ala Tarjan (from Data Structures and Network Algorithms + by Robert Tarjan) */ + +#ifdef CC_PROTOTYPE_ANSI +static void ds_makeset (PQ_node *v) +#else +static void ds_makeset (v) +PQ_node *v; +#endif +{ + v->setinfo.parent = v; + v->setinfo.rank = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *ds_find (PQ_node *v) +#else +static PQ_node *ds_find (v) +PQ_node *v; +#endif +{ + PQ_node *p = v->setinfo.parent; + + return v == p ? v : (v->setinfo.parent = ds_find (p)); +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *ds_link (PQ_node *x, PQ_node *y) +#else +static PQ_node *ds_link (x, y) +PQ_node *x; +PQ_node *y; +#endif +{ + PQ_node *t; + if (x->setinfo.rank > y->setinfo.rank) { + SWAP (x,y,t); + } else if (x->setinfo.rank == y->setinfo.rank) { + y->setinfo.rank++; + } + x->setinfo.parent = y; + return y; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *init_elems (PQ_node *elems) +#else +static PQ_node *init_elems (elems) +PQ_node *elems; +#endif +{ + int i; + PQ_node *token; + + for (i = 0, token = (PQ_node *) NULL; i < G->nnodes; i++) { + if (i != MAGICNODE) { + elems[i].next = token; + token = &elems[i]; + } + elems[i].number = i; + } + + XPQ_init_tree (token); + return token; +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_clique_to_PQtree (Xclique *c, PQ_node *elems) +#else +static int add_clique_to_PQtree (c, elems) +Xclique *c; +PQ_node *elems; +#endif +{ + PQ_node *cut; + + cut = clique_to_PQlist (c, elems); + return (XPQ_process (cut) != (PQ_node *) NULL); +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *clique_to_PQlist (Xclique *c, PQ_node *elems) +#else +static PQ_node *clique_to_PQlist (c, elems) +Xclique *c; +PQ_node *elems; +#endif +{ + Xintptr *p; + PQ_node *cut; + int n; + + if (find_intptr_list (c->nodes, MAGICNODE)) { + G->magicnum++; + for (p = c->nodes; p; p = p->next) { + G->nodelist[p->this].magiclabel = G->magicnum; + } + for (n = 1, cut = (PQ_node *) NULL; n < G->nnodes; n++) { + if (G->nodelist[n].magiclabel != G->magicnum) { + elems[n].next = cut; + cut = &elems[n]; + } + } + } else { + for (cut = (PQ_node *) NULL, p = c->nodes; p; p = p->next) { + n = p->this; + elems[n].next = cut; + cut = &elems[n]; + } + } + return cut; +} + + + +#ifdef CC_PROTOTYPE_ANSI +static int find_intptr_list (Xintptr *p, int n) +#else +static int find_intptr_list (p, n) +Xintptr *p; +int n; +#endif +{ + while (p) { + if (p->this == n) + return 1; + p = p->next; + } + return 0; +} + + diff --git a/contrib/blossom/concorde97/XSTUFF/Xnecklac.h b/contrib/blossom/concorde97/XSTUFF/Xnecklac.h new file mode 100644 index 0000000000000000000000000000000000000000..e63fd543caab979fc79fe16a435d557e99862479 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xnecklac.h @@ -0,0 +1,65 @@ +#ifndef __XNECKLAC_H +#define __XNECKLAC_H +typedef struct Xneckedge { + struct PQ_node *ends[2]; + struct PQ_node *cends[2]; + double x; + int magiclabel; + int insystem; + int inspanning; + int necklabel; + struct Xneckedge *next; +} Xneckedge; + +typedef struct Xneckedgeptr { + struct Xneckedge *this; + struct Xneckedgeptr *next; +} Xneckedgeptr; + +typedef struct Xeqn { + struct Xintptr *lhs; + int rhs; + struct Xeqn *next; + int pivot; + int hitdense; +} Xeqn; + +typedef struct bin_var { +#define VALUE_UNKNOWN (-1) + int value; + int fixed; + struct Xeqn *elim; +} bin_var; + +typedef struct bin_system { + int nvars; + int nfreevars; + struct bin_var *vars; + struct Xeqn *sparselist; + struct Xeqn *denseeqn; +} bin_system; + +#ifdef CC_PROTOTYPE_ANSI + +/* ouralloc.c */ + +Xeqn *Xeqnalloc (void); +Xneckedgeptr *Xneckedgeptralloc (void); +void Xadd_neckedgeptr (Xneckedgeptr **, Xneckedge *); +void Xeqnfree (Xeqn *); +void Xneckedgeptrfree (Xneckedgeptr *); +void Xneckedgeptr_list_free (Xneckedgeptr *); + +#else + +/* ouralloc.c */ + +Xeqn *Xeqnalloc (); +Xneckedgeptr *Xneckedgeptralloc (); +void Xadd_neckedgeptr (); +void Xeqnfree (); +void Xneckedgeptrfree (); +void Xneckedgeptr_list_free (); + +#endif +#endif /* __XNECKLAC_H */ diff --git a/contrib/blossom/concorde97/XSTUFF/Xnewkids.c b/contrib/blossom/concorde97/XSTUFF/Xnewkids.c new file mode 100644 index 0000000000000000000000000000000000000000..863210ca3ed1d997615f1e43bb9a3809426c172c --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xnewkids.c @@ -0,0 +1,660 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int Xnewkids () */ +/* */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" +#include "Xcutpool.h" +#include "Xpq.h" + +Xgraph *G; + +#ifdef CC_PROTOTYPE_ANSI +int Xsearch_cutpool_for_slack_cliques (Xgraph *H, double maxslack, + int request, int *kcount, Xportableclique **klist, int ecount, + int *elist, double *x); +#else +int Xsearch_cutpool_for_slack_cliques (); +#endif + +#ifdef CC_PROTOTYPE_ANSI + +static void + free_portableclique (Xportableclique *q), + build_weakcliques (double *), + gethist (unsigned int *), + sortcliquelist (void), + mark_clique (Xclique *, int); + +static int + add_clique_to_PQtree (Xclique *c, PQ_node *elems), + add_comblist_to_cutlist (Xclique *[4], Xcplane **), + checkout_cliquelist (Xcplane **), + find_intptr_list (Xintptr *, int), + found_clique_contradiction (Xclique *, Xclique *, Xclique *, Xcplane **), + found_comb_contradiction (Xclique *[4], Xcplane **), + clique_comp (const void *, const void *); + +static PQ_node + *init_elems (PQ_node *elems), + *clique_to_PQlist (Xclique *, PQ_node *); + +static Xclique + *add_cliques_to_PQtree (Xclique *, Xclique *, PQ_node *); + +#else + +static void + free_portableclique (), + build_weakcliques (), + gethist (), + sortcliquelist (), + mark_clique (); + +static int + add_clique_to_PQtree (), + add_comblist_to_cutlist (), + checkout_cliquelist (), + find_intptr_list (), + found_clique_contradiction (), + found_comb_contradiction (), + clique_comp (); + +static PQ_node + *init_elems (), + *clique_to_PQlist (); + +static Xclique + *add_cliques_to_PQtree (); + +#endif + +static int ncliques = 0; +static Xclique *cliquelist = (Xclique *) NULL; + + +#ifdef CC_PROTOTYPE_ANSI +int Xnewkids (Xgraph *Gin, double *x, Xcplane **list) +#else +int Xnewkids (Gin, x, list) +Xgraph *Gin; +double *x; +Xcplane **list; +#endif +{ + int ntight, nweak; + int i, k; + Xclique *c, *cnext; + + G = Gin; + + printf ("CALLED PQ CUTS ... (%d, %d)\n", G->nnodes, G->nedges); + fflush (stdout); + + for (i = 0; i < G->nedges; i++) { + G->edgelist[i].x = x[i]; + } + + cliquelist = (Xclique *) NULL; + ncliques = 0; + + Xall_tightcuts (G, &cliquelist, &ncliques); + ntight = ncliques; + printf ("Found %d tight cliques\n", ntight); + fflush (stdout); + + for (i = 0; i < G->nedges; i++) { + G->edgelist[i].x = x[i]; + } + build_weakcliques (x); + nweak = ncliques - ntight; + printf ("Found %d weak cliques\n", nweak); + fflush (stdout); + + sortcliquelist (); + printf ("Sorted cliques\n"); + + k = checkout_cliquelist (list); + printf ("Checked out cliques\n"); fflush (stdout); + + c = cliquelist; + do { + cnext = c->next; + Xintptr_list_free (c->nodes); + Xcliquefree (c); + c = cnext; + } while (c != cliquelist); + + return k; +} + +#ifdef CC_PROTOTYPE_ANSI +static void build_weakcliques (double *x) +#else +static void build_weakcliques (x) +double *x; +#endif +{ + int ecount; + int *elist = (int *) NULL; + int etemp = G->nedges; + int kcount; + Xportableclique *klist = (Xportableclique *) NULL; + Xclique *c; + Xintptr *ip; + int i, j, k; + + ecount = G->nedges; + elist = CC_SAFE_MALLOC (2 * G->nedges, int); + if (!elist) { + fprintf (stderr, "out of memory in build_weakcliques\n"); + exit (1); + } + for (i = 0, k = 0; i < etemp; i++) { + elist[k++] = G->edgelist[i].ends[0] - G->nodelist; + elist[k++] = G->edgelist[i].ends[1] - G->nodelist; + } + if (Xsearch_cutpool_for_slack_cliques (G, 1.0, 1000000, &kcount, &klist, + ecount, elist, x)) { + fprintf (stderr, "Xsearch_cutpool failed\n"); + exit (1); + } + + for (i = 0; i < kcount; i++) { + ncliques++; + c = Xcliquealloc (); + c->slack = klist[i].cutval; + c->nodes = (Xintptr *) NULL; + for (j = 0; j < klist[i].size; j++) { + ip = Xintptralloc (); + ip->this = klist[i].nodes[j]; + ip->next = c->nodes; + c->nodes = ip; + } + c->next = cliquelist; + cliquelist = c; + free_portableclique (&(klist[i])); + } + if (elist) + CC_FREE (elist, int); + if (klist) + CC_FREE (klist, Xportableclique); +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *init_elems (PQ_node *elems) +#else +static PQ_node *init_elems (elems) +PQ_node *elems; +#endif +{ + int i; + PQ_node *token; + + for (i = 0, token = (PQ_node *) NULL; i < G->nnodes; i++) { + if (i != MAGICNODE) { + elems[i].next = token; + token = &elems[i]; + } + elems[i].number = i; + } + + XPQ_init_tree (token); + return token; +} + +#ifdef CC_PROTOTYPE_ANSI +static int checkout_cliquelist (Xcplane **list) +#else +static int checkout_cliquelist (list) +Xcplane **list; +#endif +{ + PQ_node *elems; + PQ_node *token_elem; + PQ_node *save_root; + Xclique *bot, *top, *botnext, *topnext; + Xclique *save_bot; + Xclique *chk; + int isbot; + int k = 0; + int botcount; + int topcount; + + elems = CC_SAFE_MALLOC (G->nnodes, PQ_node); + if (!elems) { + fprintf (stderr, "out of memory in checkout_cliquelist\n"); + exit (1); + } + + token_elem = init_elems (elems); + + bot = cliquelist; + top = cliquelist; + /* [cliquelist,bot) is base, [top,cliquelist) is tested */ + /* [cliquelist,save_bot) is in save_root */ + + save_root = XPQ_save_tree (token_elem); + save_bot = bot; + botcount = 0; + topcount = 0; + + do { + if (3 * bot->slack + top->prev->slack < 1.0) { + /* putchar ('v'); fflush (stdout); */ + chk = bot; + isbot = 1; + botnext = bot->next; + topnext = top; + } else { + /* putchar ('^'); fflush (stdout); */ + chk = top->prev; + botnext = bot; + topnext = top->prev; + isbot = 0; + if (botcount > 20 && topcount == 0) { + XPQ_save_tree_free (save_root); + save_root = XPQ_save_tree (token_elem); + save_bot = bot; + botcount = 0; + } + } + if (!add_clique_to_PQtree (chk, elems)) { + /* putchar ('!'); fflush (stdout); */ + XPQ_free_all (token_elem, 1); + XPQ_restore_tree (save_root, 1); + topcount = 0; + if (save_bot != bot) { + if (add_cliques_to_PQtree (save_bot, bot, elems)) { + fprintf (stderr, "add_clique error\n"); + exit (1); + } + XPQ_save_tree_free (save_root); + save_root = XPQ_save_tree (token_elem); + save_bot = bot; + botcount = 0; + } + if (!add_clique_to_PQtree (chk, elems)) { + k += found_clique_contradiction (chk, cliquelist, bot, list); + XPQ_free_all (token_elem, 1); + XPQ_restore_tree (save_root, 1); + + if (isbot) { + chk->next->prev = chk->prev; + chk->prev->next = chk->next; + if (save_bot == chk) { + save_bot = bot->next; + } + Xintptr_list_free (chk->nodes); + Xcliquefree (chk); + } + } else { + if (isbot) { + botcount++; + } else { + topcount++; + } + } + } else { + if (isbot) + botcount++; + else + topcount++; + } + top = topnext; + bot = botnext; + } while (bot != top); + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + XPQ_free_all (token_elem, 1); + XPQ_save_tree_free (save_root); + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + CC_FREE (elems, PQ_node); + + return k; +} + +#ifdef CC_PROTOTYPE_ANSI +static int clique_comp (const void *a, const void *b) +#else +static int clique_comp (a, b) +const void *a, *b; +#endif +{ + if ((*(Xclique * const *) a)->slack < + (*(Xclique * const *) b)->slack) { + return -1; + } else if ((*(Xclique * const *) a)->slack > + (*(Xclique * const *) b)->slack) { + return 1; + } else { + return 0; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void sortcliquelist (void) +#else +static void sortcliquelist () +#endif +{ + Xclique **svec; + Xclique *p; + int i; + + svec = CC_SAFE_MALLOC (ncliques, Xclique *); + if (!svec) { + fprintf (stderr, "out of memory in sortcliquelist\n"); + exit (1); + } + for (i = 0, p = cliquelist; p; p = p->next, i++) { + svec[i] = p; + } + if (i != ncliques) { + fprintf (stderr, "Found %d cliques, expected %d\n", i, ncliques); + } + qsort ((char *) svec, ncliques, sizeof (Xclique *), clique_comp); + + for (i = 0; i < ncliques; i++) { + svec[i]->next = svec[i + 1]; + svec[i]->prev = svec[i - 1]; + } + svec[0]->prev = svec[ncliques - 1]; + svec[ncliques - 1]->next = svec[0]; + cliquelist = svec[0]; + + CC_FREE (svec, Xclique *); +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_clique_to_PQtree (Xclique *c, PQ_node *elems) +#else +static int add_clique_to_PQtree (c, elems) +Xclique *c; +PQ_node *elems; +#endif +{ + PQ_node *cut; + + cut = clique_to_PQlist (c, elems); + return (XPQ_process (cut) != (PQ_node *) NULL); +} + +#ifdef CC_PROTOTYPE_ANSI +static Xclique *add_cliques_to_PQtree (Xclique *c, Xclique *cend, PQ_node *elems) +#else +static Xclique *add_cliques_to_PQtree (c, cend, elems) +Xclique *c; +Xclique *cend; +PQ_node *elems; +#endif +{ + while (c != cend) { + if (!add_clique_to_PQtree (c, elems)) { + return c; + } + c = c->next; + } + return (Xclique *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *clique_to_PQlist (Xclique *c, PQ_node *elems) +#else +static PQ_node *clique_to_PQlist (c, elems) +Xclique *c; +PQ_node *elems; +#endif +{ + Xintptr *p; + PQ_node *cut; + int n; + + if (find_intptr_list (c->nodes, MAGICNODE)) { + G->magicnum++; + for (p = c->nodes; p; p = p->next) { + G->nodelist[p->this].magiclabel = G->magicnum; + } + for (n = 1, cut = (PQ_node *) NULL; n < G->nnodes; n++) { + if (G->nodelist[n].magiclabel != G->magicnum) { + elems[n].next = cut; + cut = &elems[n]; + } + } + } else { + for (cut = (PQ_node *) NULL, p = c->nodes; p; p = p->next) { + n = p->this; + elems[n].next = cut; + cut = &elems[n]; + } + } + return cut; +} + +#ifdef CC_PROTOTYPE_ANSI +static int find_intptr_list (Xintptr *p, int n) +#else +static int find_intptr_list (p, n) +Xintptr *p; +int n; +#endif +{ + while (p) { + if (p->this == n) + return 1; + p = p->next; + } + return 0; +} + +/* viol added to [base,bend) results in violation. Convert to comb. */ + +#ifdef CC_PROTOTYPE_ANSI +static int found_clique_contradiction (Xclique *viol, Xclique *base, Xclique *bend, Xcplane **list) +#else +static int found_clique_contradiction (viol, base, bend, list) +Xclique *viol; +Xclique *base; +Xclique *bend; +Xcplane **list; +#endif +{ + Xclique *comblist[4]; + PQ_node *elems; + PQ_node *token_elem; + int i, j; + Xclique *b = (Xclique *) NULL; + + comblist[0] = viol; + elems = CC_SAFE_MALLOC (G->nnodes, PQ_node); + if (!elems) { + fprintf (stderr, "out of memory in found_clique_contradiction\n"); + exit (1); + } + + for (i = 1;; i++) { + token_elem = init_elems (elems); + for (j = 0; j < i; j++) { + if (!add_clique_to_PQtree (comblist[j], elems)) { + if (j != i - 1) { + fprintf (stderr, "Whoa, unexpected violation\n"); + } + XPQ_free_all (token_elem, 1); + CC_FREE (elems, PQ_node); + if (i == 4) { + return found_comb_contradiction (comblist, list); + } else { + return 0; + } + } + } + if (i < 4) { + b = add_cliques_to_PQtree (base, bend, elems); + } + XPQ_free_all (token_elem, 1); + if (i >= 4 || !b) { + CC_FREE (elems, PQ_node); + return 0; + } + comblist[i] = b; + bend = b; + } +} + +#define HANDLE 1 +#define TOOTH1 2 +#define TOOTH2 4 +#define TOOTH3 8 +#define NREGIONS 16 + +int flipseq[NREGIONS] = {0, TOOTH1, TOOTH2, TOOTH3, TOOTH1 | TOOTH2, + TOOTH1 | TOOTH3, TOOTH2 | TOOTH3, TOOTH1 | TOOTH2 | TOOTH3, + HANDLE | TOOTH1, HANDLE | TOOTH2, HANDLE | TOOTH3, + HANDLE | TOOTH1 | TOOTH2, HANDLE | TOOTH1 | TOOTH3, +HANDLE | TOOTH2 | TOOTH3}; + +#ifdef CC_PROTOTYPE_ANSI +static int found_comb_contradiction (Xclique *comblist[4], Xcplane **list) + +#else +static int found_comb_contradiction (comblist, list) +Xclique *comblist[4]; +Xcplane **list; +#endif +{ + int i, i2; + int flip; + int handle; + int hbit; + unsigned int hist[NREGIONS]; + unsigned int hist2[NREGIONS]; + Xclique *tmp; + int test; + + for (i = 0; i < G->nnodes; i++) { + G->nodelist[i].Tmark = 0; + } + for (i = 0; i < 4; i++) { + mark_clique (comblist[i], (1 << i)); + } + gethist (hist); + + for (flip = 0; flip < NREGIONS; flip++) { + for (handle = 0; handle < 4; handle++) { + hbit = (1 << handle); + for (i = 0; i < NREGIONS; i++) { + i2 = i & ~(1 | hbit); + if (i & 1) + i2 |= hbit; + if (i & hbit) + i2 |= 1; + i2 ^= flipseq[flip]; + hist2[i] = hist[i2]; + } + if (Xhistok (hist2)) { + SWAP (comblist[0], comblist[handle], tmp); + test = add_comblist_to_cutlist (comblist, list); + return test; + } + } + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void mark_clique (Xclique *c, int m) +#else +static void mark_clique (c, m) +Xclique *c; +int m; +#endif +{ + Xintptr *p; + + for (p = c->nodes; p; p = p->next) { + G->nodelist[p->this].Tmark |= m; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void gethist (unsigned int *hist) +#else +static void gethist (hist) +unsigned int *hist; +#endif +{ + int i; + + for (i = 0; i < NREGIONS; i++) { + hist[i] = 0; + } + for (i = 0; i < G->nnodes; i++) { + hist[G->nodelist[i].Tmark]++; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int add_comblist_to_cutlist (Xclique *comblist[4], Xcplane **list) +#else +static int add_comblist_to_cutlist (comblist, list) +Xclique *comblist[4]; +Xcplane **list; +#endif +{ + Xintptr *ip; + Xnodeptr *np; + Xnodeptrptr *npp; + Xnodeptrptr *handles, *teeth; + int i; + int test; + + handles = Xnodeptrptralloc (); + handles->next = (Xnodeptrptr *) NULL; + handles->this = (Xnodeptr *) NULL; + for (ip = comblist[0]->nodes; ip; ip = ip->next) { + np = Xnodeptralloc (); + np->this = &G->nodelist[ip->this]; + np->next = handles->this; + handles->this = np; + } + teeth = (Xnodeptrptr *) NULL; + for (i = 1; i < 4; i++) { + npp = Xnodeptrptralloc (); + npp->next = teeth; + teeth = npp; + npp->this = (Xnodeptr *) NULL; + for (ip = comblist[i]->nodes; ip; ip = ip->next) { + np = Xnodeptralloc (); + np->this = &G->nodelist[ip->this]; + np->next = npp->this; + npp->this = np; + } + } + if (!Xcliquefluff (G, &handles, &teeth)) { + printf ("DE FLUFFED TO 0\n"); + fflush (stdout); + return 0; + } + test = Xloadcplane (list, (Xnodeptr *) NULL, handles, teeth, 0); + if (!test) { + Xfreeteeth (handles); + Xfreeteeth (teeth); + } + return test; +} + +#ifdef CC_PROTOTYPE_ANSI +static void free_portableclique (Xportableclique *q) +#else +static void free_portableclique (q) +Xportableclique *q; +#endif +{ + if (q->nodes) + CC_FREE (q->nodes, int); +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xourallo.c b/contrib/blossom/concorde97/XSTUFF/Xourallo.c new file mode 100644 index 0000000000000000000000000000000000000000..6409ff98f3ae07f70f49aef5e75895d58323d4f8 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xourallo.c @@ -0,0 +1,1209 @@ +/**************************************************************************/ +/* */ +/* OLD SUBTOUR STUFF - all functions and types now start with X */ +/* - this stuff is only for testing concorde */ +/* */ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* blockptr *blockptralloc () */ +/* clique *cliquealloc () */ +/* combhash *combhashalloc () */ +/* cplane *cplanealloc () */ +/* cutnodeptr *cutnodeptralloc () */ +/* cuttree_node *cuttree_nodealloc () */ +/* edge *edgealloc () */ +/* edgeptr *edgeptralloc () */ +/* intptr *intptralloc () */ +/* intptrptr *intptrptralloc () */ +/* void add_intptrptr () */ +/* iplane *iplanealloc () */ +/* node *nodealloc () */ +/* nodeptr *nodeptralloc () */ +/* nodeptrptr *nodeptrptralloc () */ +/* void add_edgeptr () */ +/* void add_extralink () */ +/* void add_nodeptr () */ +/* void add_nodeptrptr () */ +/* void blinkfree () */ +/* void blockptrfree () */ +/* void clinkfree () */ +/* void cliquefree () */ +/* void combhashfree () */ +/* void cplane_list_free () */ +/* void cplanefree () */ +/* void cutnodeptrfree () */ +/* void cuttree_nodefree () */ +/* void edgefree () */ +/* void edge_list_free () */ +/* void edgeptr_list_free () */ +/* void edgeptrfree () */ +/* void initialize_ouralloc () */ +/* void intptr_list_free () */ +/* void intptrfree () */ +/* void intptrptr_list_free () */ +/* void intptrptr_list_freeall() */ +/* void intptrptrfree () */ +/* void iplane_list_free () */ +/* void iplanefree () */ +/* void nodefree () */ +/* void nodeptr_list_free () */ +/* void nodeptrfree () */ +/* void nodeptrptr_list_free () */ +/* void nodeptrptrfree () */ +/* void union_nodeptr () */ +/* void ouralloc_reset () */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" +#include "Xnecklac.h" + +#ifdef CC_PROTOTYPE_ANSI + +static Xextralink *Xextralinkalloc (void); +static union size_104 *size_104_alloc (void); +static union size_16 *size_16_alloc (void); +static union size_24 *size_24_alloc (void); +static union size_48 *size_48_alloc (void); +static union size_8 *size_8_alloc (void); +static union size_80 *size_80_alloc (void); +static void Xextralinkfree (Xextralink *); +static void fetch_size_104 (int); +static void fetch_size_16 (int); +static void fetch_size_24 (int); +static void fetch_size_48 (int); +static void fetch_size_8 (int); +static void fetch_size_80 (int); +static void size_104_free (union size_104 *); +static void size_16_free (union size_16 *); +static void size_24_free (union size_24 *); +static void size_48_free (union size_48 *); +static void size_80_free (union size_80 *); +static void size_8_free (union size_8 *); +static void initialize_ouralloc (void); + +#else + +static Xextralink *Xextralinkalloc (); +static union size_104 *size_104_alloc (); +static union size_16 *size_16_alloc (); +static union size_24 *size_24_alloc (); +static union size_48 *size_48_alloc (); +static union size_8 *size_8_alloc (); +static union size_80 *size_80_alloc (); +static void Xextralinkfree (); +static void fetch_size_104 (); +static void fetch_size_16 (); +static void fetch_size_24 (); +static void fetch_size_48 (); +static void fetch_size_8 (); +static void fetch_size_80 (); +static void size_104_free (); +static void size_16_free (); +static void size_24_free (); +static void size_48_free (); +static void size_80_free (); +static void size_8_free (); +static void initialize_ouralloc (); + +#endif + +/* fooALLOCCHUNK * sizeof foo + 16 should be <= a power of 2 */ + +#define CHUNKBASE ((1<<13)-16) + +#define INIT_8_ALLOC (CHUNKBASE / sizeof (union size_8)) +#define SIZE_8_CHUNK (CHUNKBASE / sizeof (union size_8)) + +#define INIT_16_ALLOC (CHUNKBASE / sizeof (union size_16)) +#define SIZE_16_CHUNK (CHUNKBASE / sizeof (union size_16)) + +#define INIT_24_ALLOC (50) +#define SIZE_24_CHUNK (CHUNKBASE / sizeof (union size_24)) + +#define INIT_48_ALLOC (CHUNKBASE / sizeof (union size_48)) +#define SIZE_48_CHUNK (CHUNKBASE / sizeof (union size_48)) + +#define INIT_80_ALLOC (CHUNKBASE / sizeof (union size_80)) +#define SIZE_80_CHUNK (CHUNKBASE / sizeof (union size_80)) + +#define INIT_104_ALLOC (CHUNKBASE / sizeof (union size_104)) +#define SIZE_104_CHUNK (CHUNKBASE / sizeof (union size_104)) + +static int init_ouralloc = 1; + +union size_8 { + Xnodeptr obj_nodeptr; + Xnodeptrptr obj_nodeptrptr; + Xedgeptr obj_edgeptr; + Xneckedgeptr obj_neckedgeptr; + Xclink obj_clink; + Xintptr obj_intptr; + Xintptrptr obj_intptrptr; + Xcutnodeptr obj_cutnodeptr; + Xcombhash obj_combhash; + union size_8 *next; +} *size_8_freelist = (union size_8 *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +static void fetch_size_8 (int n) +#else +static void fetch_size_8 (n) +int n; +#endif +{ + union size_8 *x; + + x = CC_SAFE_MALLOC (n, union size_8); + if (!x) { + fprintf (stderr, "Out of memory in old fetch\n"); + exit (1); + } + x[n - 1].next = size_8_freelist; + size_8_freelist = x; + for (n -= 2; n >= 0; n--, x++) { + x->next = x + 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static union size_8 *size_8_alloc (void) +#else +static union size_8 *size_8_alloc () +#endif +{ + union size_8 *x; + + if (init_ouralloc) { + initialize_ouralloc (); + } + if (!size_8_freelist) { + fetch_size_8 (SIZE_8_CHUNK); + } + x = size_8_freelist; + size_8_freelist = x->next; + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static void size_8_free (union size_8 *x) +#else +static void size_8_free (x) +union size_8 *x; +#endif +{ + x->next = size_8_freelist; + size_8_freelist = x; +} + +#ifdef CC_PROTOTYPE_ANSI +Xnodeptr *Xnodeptralloc (void) +#else +Xnodeptr *Xnodeptralloc () +#endif +{ + return &(size_8_alloc ()->obj_nodeptr); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xnodeptrfree (Xnodeptr *n) +#else +void Xnodeptrfree (n) +Xnodeptr *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xnodeptr_list_free (Xnodeptr *np) +#else +void Xnodeptr_list_free (np) +Xnodeptr *np; +#endif +{ + Xnodeptr *next; + + while (np) { + next = np->next; + Xnodeptrfree (np); + np = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xadd_nodeptr (Xnodeptr **list, Xnode *n) +#else +void Xadd_nodeptr (list, n) +Xnodeptr **list; +Xnode *n; +#endif +{ + Xnodeptr *temp; + + temp = Xnodeptralloc (); + temp->this = n; + temp->next = *list; + *list = temp; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xunion_nodeptr (Xgraph *G, Xnodeptr *a, Xnodeptr *b, Xnodeptr **u) +#else +void Xunion_nodeptr (G, a, b, u) +Xgraph *G; +Xnodeptr *a, *b, **u; +#endif +{ + Xnode *n; + Xnodeptr *np; + + *u = (Xnodeptr *) NULL; + G->magicnum++; + for (np = a; np; np = np->next) { + n = np->this; + if (n->magiclabel != G->magicnum) { + Xadd_nodeptr (u, n); + n->magiclabel = G->magicnum; + } + } + for (np = b; np; np = np->next) { + n = np->this; + if (n->magiclabel != G->magicnum) { + Xadd_nodeptr (u, n); + n->magiclabel = G->magicnum; + } + } +} + +#ifdef CC_PROTOTYPE_ANSI +Xnodeptrptr *Xnodeptrptralloc (void) +#else +Xnodeptrptr *Xnodeptrptralloc () +#endif +{ + return &(size_8_alloc ()->obj_nodeptrptr); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xnodeptrptrfree (Xnodeptrptr *n) +#else +void Xnodeptrptrfree (n) +Xnodeptrptr *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xnodeptrptr_list_free (Xnodeptrptr *np) +#else +void Xnodeptrptr_list_free (np) +Xnodeptrptr *np; +#endif +{ + Xnodeptrptr *next; + + while (np) { + next = np->next; + Xnodeptrptrfree (np); + np = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xadd_nodeptrptr (Xnodeptrptr **list, Xnodeptr *n) +#else +void Xadd_nodeptrptr (list, n) +Xnodeptrptr **list; +Xnodeptr *n; +#endif +{ + Xnodeptrptr *temp; + + temp = Xnodeptrptralloc (); + temp->this = n; + temp->next = *list; + *list = temp; +} + +#ifdef CC_PROTOTYPE_ANSI +Xedgeptr *Xedgeptralloc (void) +#else +Xedgeptr *Xedgeptralloc () +#endif +{ + return &(size_8_alloc ()->obj_edgeptr); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xedgeptrfree (Xedgeptr *n) +#else +void Xedgeptrfree (n) +Xedgeptr *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xedgeptr_list_free (Xedgeptr *ep) +#else +void Xedgeptr_list_free (ep) +Xedgeptr *ep; +#endif +{ + Xedgeptr *next; + + while (ep) { + next = ep->next; + Xedgeptrfree (ep); + ep = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xadd_edgeptr (Xedgeptr **list, Xedge *e) +#else +void Xadd_edgeptr (list, e) +Xedgeptr **list; +Xedge *e; +#endif +{ + Xedgeptr *temp; + + temp = Xedgeptralloc (); + temp->this = e; + temp->next = *list; + *list = temp; +} + +#ifdef CC_PROTOTYPE_ANSI +Xneckedgeptr *Xneckedgeptralloc (void) +#else +Xneckedgeptr *Xneckedgeptralloc () +#endif +{ + return &(size_8_alloc ()->obj_neckedgeptr); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xneckedgeptrfree (Xneckedgeptr *n) +#else +void Xneckedgeptrfree (n) +Xneckedgeptr *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xneckedgeptr_list_free (Xneckedgeptr *ep) +#else +void Xneckedgeptr_list_free (ep) +Xneckedgeptr *ep; +#endif +{ + Xneckedgeptr *next; + + while (ep) { + next = ep->next; + Xneckedgeptrfree (ep); + ep = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xadd_neckedgeptr (Xneckedgeptr **list, Xneckedge *e) +#else +void Xadd_neckedgeptr (list, e) +Xneckedgeptr **list; +Xneckedge *e; +#endif +{ + Xneckedgeptr *temp; + + temp = Xneckedgeptralloc (); + temp->this = e; + temp->next = *list; + *list = temp; +} + +#ifdef CC_PROTOTYPE_ANSI +Xclink *Xclinkalloc (void) +#else +Xclink *Xclinkalloc () +#endif +{ + return &(size_8_alloc ()->obj_clink); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xclinkfree (Xclink *n) +#else +void Xclinkfree (n) +Xclink *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +Xintptr *Xintptralloc (void) +#else +Xintptr *Xintptralloc () +#endif +{ + return &(size_8_alloc ()->obj_intptr); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xintptrfree (Xintptr *n) +#else +void Xintptrfree (n) +Xintptr *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xintptr_list_free (Xintptr *ip) +#else +void Xintptr_list_free (ip) +Xintptr *ip; +#endif +{ + Xintptr *next; + + while (ip) { + next = ip->next; + Xintptrfree (ip); + ip = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +Xintptrptr *Xintptrptralloc (void) +#else +Xintptrptr *Xintptrptralloc () +#endif +{ + return &(size_8_alloc ()->obj_intptrptr); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xintptrptrfree (Xintptrptr *n) +#else +void Xintptrptrfree (n) +Xintptrptr *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xintptrptr_list_free (Xintptrptr *ip) +#else +void Xintptrptr_list_free (ip) +Xintptrptr *ip; +#endif +{ + Xintptrptr *next; + + while (ip) { + next = ip->next; + Xintptrptrfree (ip); + ip = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xintptrptr_list_freeall(Xintptrptr *ip) +#else +void Xintptrptr_list_freeall(ip) +Xintptrptr *ip; +#endif +{ + Xintptrptr *next; + + while (ip) { + next = ip->next; + Xintptr_list_free (ip->this); + Xintptrptrfree (ip); + ip = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xadd_intptrptr (Xintptrptr **list, Xintptr *n) +#else +void Xadd_intptrptr (list, n) +Xintptrptr **list; +Xintptr *n; +#endif +{ + Xintptrptr *temp; + + temp = Xintptrptralloc (); + temp->this = n; + temp->next = *list; + *list = temp; +} + +#ifdef CC_PROTOTYPE_ANSI +Xcutnodeptr *Xcutnodeptralloc (void) +#else +Xcutnodeptr *Xcutnodeptralloc () +#endif +{ + return &(size_8_alloc ()->obj_cutnodeptr); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcutnodeptrfree (Xcutnodeptr *n) +#else +void Xcutnodeptrfree (n) +Xcutnodeptr *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +Xcombhash *Xcombhashalloc (void) +#else +Xcombhash *Xcombhashalloc () +#endif +{ + return &(size_8_alloc ()->obj_combhash); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcombhashfree (Xcombhash *n) +#else +void Xcombhashfree (n) +Xcombhash *n; +#endif +{ + size_8_free ((union size_8 *) n); +} + +union size_16 { + Xblink obj_blink; + Xextralink obj_extralink; + Xblockptr obj_blockptr; + union size_16 *next; +} *size_16_freelist = (union size_16 *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +static void fetch_size_16 (int n) +#else +static void fetch_size_16 (n) +int n; +#endif +{ + union size_16 *x; + + x = CC_SAFE_MALLOC (n, union size_16); + if (!x) { + fprintf (stderr, "Out of memory in old fetch\n"); + exit (1); + } + x[n - 1].next = size_16_freelist; + size_16_freelist = x; + for (n -= 2; n >= 0; n--, x++) { + x->next = x + 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static union size_16 *size_16_alloc (void) +#else +static union size_16 *size_16_alloc () +#endif +{ + union size_16 *x; + + if (init_ouralloc) { + initialize_ouralloc (); + } + if (!size_16_freelist) { + fetch_size_16 (SIZE_16_CHUNK); + } + x = size_16_freelist; + size_16_freelist = x->next; + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static void size_16_free (union size_16 *x) +#else +static void size_16_free (x) +union size_16 *x; +#endif +{ + x->next = size_16_freelist; + size_16_freelist = x; +} + +#ifdef CC_PROTOTYPE_ANSI +static Xextralink *Xextralinkalloc (void) +#else +static Xextralink *Xextralinkalloc () +#endif +{ + return &(size_16_alloc ()->obj_extralink); +} + +#ifdef CC_PROTOTYPE_ANSI +static void Xextralinkfree (Xextralink *n) +#else +static void Xextralinkfree (n) +Xextralink *n; +#endif +{ + size_16_free ((union size_16 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xextralink_list_free (Xextralink *ep) +#else +void Xextralink_list_free (ep) +Xextralink *ep; +#endif +{ + Xextralink *next; + + while (ep) { + next = ep->next; + Xextralinkfree (ep); + ep = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +void Xadd_extralink (Xextralink **list, int end0, int end1, int weight) +#else +void Xadd_extralink (list, end0, end1, weight) +Xextralink **list; +int end0, end1, weight; +#endif +{ + Xextralink *temp; + + temp = Xextralinkalloc (); + temp->ends[0] = end0; + temp->ends[1] = end1; + temp->weight = weight; + temp->next = *list; + *list = temp; +} + +#ifdef CC_PROTOTYPE_ANSI +Xblink *Xblinkalloc (void) +#else +Xblink *Xblinkalloc () +#endif +{ + return &(size_16_alloc ()->obj_blink); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xblinkfree (Xblink *n) +#else +void Xblinkfree (n) +Xblink *n; +#endif +{ + size_16_free ((union size_16 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +Xblockptr *Xblockptralloc (void) +#else +Xblockptr *Xblockptralloc () +#endif +{ + return &(size_16_alloc ()->obj_blockptr); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xblockptrfree (Xblockptr *n) +#else +void Xblockptrfree (n) +Xblockptr *n; +#endif +{ + size_16_free ((union size_16 *) n); +} + +union size_24 { + Xcplane obj_cplane; /* size really 20 */ + Xiplane obj_iplane; + Xclique obj_clique; + Xeqn obj_eqn; + union size_24 *next; +} *size_24_freelist = (union size_24 *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +static void fetch_size_24 (int n) +#else +static void fetch_size_24 (n) +int n; +#endif +{ + union size_24 *x; + + x = CC_SAFE_MALLOC (n, union size_24); + if (!x) { + fprintf (stderr, "Out of memory in old fetch\n"); + exit (1); + } + x[n - 1].next = size_24_freelist; + size_24_freelist = x; + for (n -= 2; n >= 0; n--, x++) { + x->next = x + 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static union size_24 *size_24_alloc (void) +#else +static union size_24 *size_24_alloc () +#endif +{ + union size_24 *x; + + if (init_ouralloc) { + initialize_ouralloc (); + } + if (!size_24_freelist) { + fetch_size_24 (SIZE_24_CHUNK); + } + x = size_24_freelist; + size_24_freelist = x->next; + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static void size_24_free (union size_24 *x) +#else +static void size_24_free (x) +union size_24 *x; +#endif +{ + x->next = size_24_freelist; + size_24_freelist = x; +} + +#ifdef CC_PROTOTYPE_ANSI +Xcplane *Xcplanealloc (void) +#else +Xcplane *Xcplanealloc () +#endif +{ + return &(size_24_alloc ()->obj_cplane); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcplanefree (Xcplane *n) +#else +void Xcplanefree (n) +Xcplane *n; +#endif +{ + size_24_free ((union size_24 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcplane_list_free (Xcplane *ip) +#else +void Xcplane_list_free (ip) +Xcplane *ip; +#endif +{ + Xcplane *next; + + while (ip) { + next = ip->next; + Xcplanefree (ip); + ip = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +Xiplane *Xiplanealloc (void) +#else +Xiplane *Xiplanealloc () +#endif +{ + return &(size_24_alloc ()->obj_iplane); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xiplanefree (Xiplane *n) +#else +void Xiplanefree (n) +Xiplane *n; +#endif +{ + size_24_free ((union size_24 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xiplane_list_free (Xiplane *ip) +#else +void Xiplane_list_free (ip) +Xiplane *ip; +#endif +{ + Xiplane *next; + + while (ip) { + next = ip->next; + Xiplanefree (ip); + ip = next; + } +} + +#ifdef CC_PROTOTYPE_ANSI +Xclique *Xcliquealloc (void) +#else +Xclique *Xcliquealloc () +#endif +{ + return &(size_24_alloc ()->obj_clique); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcliquefree (Xclique *n) +#else +void Xcliquefree (n) +Xclique *n; +#endif +{ + size_24_free ((union size_24 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +Xeqn *Xeqnalloc (void) +#else +Xeqn *Xeqnalloc () +#endif +{ + return &(size_24_alloc ()->obj_eqn); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xeqnfree (Xeqn *n) +#else +void Xeqnfree (n) +Xeqn *n; +#endif +{ + size_24_free ((union size_24 *) n); +} + +union size_48 { + Xcuttree_node obj_cuttree_node; + union size_48 *next; +} *size_48_freelist = (union size_48 *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +static void fetch_size_48 (int n) +#else +static void fetch_size_48 (n) +int n; +#endif +{ + union size_48 *x = (union size_48 *) NULL; + + x = CC_SAFE_MALLOC (n, union size_48); + if (!x) { + fprintf (stderr, "Out of memory in old fetch\n"); + exit (1); + } + x[n - 1].next = size_48_freelist; + size_48_freelist = x; + for (n -= 2; n >= 0; n--, x++) { + x->next = x + 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static union size_48 *size_48_alloc (void) +#else +static union size_48 *size_48_alloc () +#endif +{ + union size_48 *x; + + if (init_ouralloc) { + initialize_ouralloc (); + } + if (!size_48_freelist) { + fetch_size_48 (SIZE_48_CHUNK); + } + x = size_48_freelist; + size_48_freelist = x->next; + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static void size_48_free (union size_48 *x) +#else +static void size_48_free (x) +union size_48 *x; +#endif +{ + x->next = size_48_freelist; + size_48_freelist = x; +} + +#ifdef CC_PROTOTYPE_ANSI +Xcuttree_node *Xcuttree_nodealloc (void) +#else +Xcuttree_node *Xcuttree_nodealloc () +#endif +{ + return &(size_48_alloc ()->obj_cuttree_node); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xcuttree_nodefree (Xcuttree_node *n) +#else +void Xcuttree_nodefree (n) +Xcuttree_node *n; +#endif +{ + size_48_free ((union size_48 *) n); +} + +union size_80 { + Xedge obj_edge; + union size_80 *next; +} *size_80_freelist = (union size_80 *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +static void fetch_size_80 (int n) +#else +static void fetch_size_80 (n) +int n; +#endif +{ + union size_80 *x; + + x = CC_SAFE_MALLOC (n, union size_80); + if (!x) { + fprintf (stderr, "Out of memory in old fetch\n"); + exit (1); + } + x[n - 1].next = size_80_freelist; + size_80_freelist = x; + for (n -= 2; n >= 0; n--, x++) { + x->next = x + 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static union size_80 *size_80_alloc (void) +#else +static union size_80 *size_80_alloc () +#endif +{ + union size_80 *x; + + if (init_ouralloc) { + initialize_ouralloc (); + } + if (!size_80_freelist) { + fetch_size_80 (SIZE_80_CHUNK); + } + x = size_80_freelist; + size_80_freelist = x->next; + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static void size_80_free (union size_80 *x) +#else +static void size_80_free (x) +union size_80 *x; +#endif +{ + x->next = size_80_freelist; + size_80_freelist = x; +} + +#ifdef CC_PROTOTYPE_ANSI +Xedge *Xedgealloc (void) +#else +Xedge *Xedgealloc () +#endif +{ + return &(size_80_alloc ()->obj_edge); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xedgefree (Xedge *n) +#else +void Xedgefree (n) +Xedge *n; +#endif +{ + size_80_free ((union size_80 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xedge_list_free (Xedge *e) +#else +void Xedge_list_free (e) +Xedge *e; +#endif +{ + Xedge *next; + + while (e) { + next = e->next; + Xedgefree (e); + e = next; + } +} + +union size_104 { + Xnode obj_node; + union size_104 *next; +} *size_104_freelist = (union size_104 *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +static void fetch_size_104 (int n) +#else +static void fetch_size_104 (n) +int n; +#endif +{ + union size_104 *x; + + x = CC_SAFE_MALLOC (n, union size_104); + if (!x) { + fprintf (stderr, "Out of memory in old fetch\n"); + exit (1); + } + x[n - 1].next = size_104_freelist; + size_104_freelist = x; + for (n -= 2; n >= 0; n--, x++) { + x->next = x + 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static union size_104 *size_104_alloc (void) +#else +static union size_104 *size_104_alloc () +#endif +{ + union size_104 *x; + + if (init_ouralloc) { + initialize_ouralloc (); + } + if (!size_104_freelist) { + fetch_size_104 (SIZE_104_CHUNK); + } + x = size_104_freelist; + size_104_freelist = x->next; + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static void size_104_free (union size_104 *x) +#else +static void size_104_free (x) +union size_104 *x; +#endif +{ + x->next = size_104_freelist; + size_104_freelist = x; +} + +#ifdef CC_PROTOTYPE_ANSI +Xnode *Xnodealloc (void) +#else +Xnode *Xnodealloc () +#endif +{ + return &(size_104_alloc ()->obj_node); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xnodefree (Xnode *n) +#else +void Xnodefree (n) +Xnode *n; +#endif +{ + size_104_free ((union size_104 *) n); +} + +#ifdef CC_PROTOTYPE_ANSI +static void initialize_ouralloc (void) +#else +static void initialize_ouralloc () +#endif +{ + if (init_ouralloc) { + if (sizeof (union size_8) != 8) { + fprintf (stderr, "Warning, sizeof (union size_8) == %d\n", + (int) sizeof (union size_8)); + } + if (sizeof (union size_16) != 16) { + fprintf (stderr, "Warning, sizeof (union size_16) == %d\n", + (int) sizeof (union size_16)); + } + if (sizeof (union size_24) != 24) { + fprintf (stderr, "Warning, sizeof (union size_24) == %d\n", + (int) sizeof (union size_24)); + } + if (sizeof (union size_48) != 48) { + fprintf (stderr, "Warning, sizeof (union size_48) == %d\n", + (int) sizeof (union size_48)); + } + if (sizeof (union size_80) != 80) { + fprintf (stderr, "Warning, sizeof (union size_80) == %d\n", + (int) sizeof (union size_80)); + } + if (sizeof (union size_104) != 104) { + fprintf (stderr, "Warning, sizeof (union size_104) == %d\n", + (int) sizeof (union size_104)); + } + if (INIT_8_ALLOC) { + fetch_size_8 (INIT_8_ALLOC); + } + if (INIT_16_ALLOC) { + fetch_size_16 (INIT_16_ALLOC); + } + if (INIT_24_ALLOC) { + fetch_size_24 (INIT_24_ALLOC); + } + if (INIT_48_ALLOC) { + fetch_size_48 (INIT_48_ALLOC); + } + if (INIT_80_ALLOC) { + fetch_size_80 (INIT_80_ALLOC); + } + if (INIT_104_ALLOC) { + fetch_size_104 (INIT_104_ALLOC); + } + init_ouralloc = 0; + } +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xpq.h b/contrib/blossom/concorde97/XSTUFF/Xpq.h new file mode 100644 index 0000000000000000000000000000000000000000..d730c467afbe49af3d41be29fde82bcc40d20b15 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xpq.h @@ -0,0 +1,104 @@ +#ifndef __XPQ_H +#define __XPQ_H + +#include "Xpqsets.h" + +#define MAGICNODE 0 + +typedef struct PQ_node { + int number; + struct PQ_node *next; + struct Xedge *base_edge; + int dir_nodenum; + int labeled_children_count; + int magiclabel; + struct Xintptr *toroot; + struct Xneckedgeptr *adj; + struct Xneckedge *entered; + struct { + struct PQ_node *parent; + int rank; + } setinfo; + + PQ_elem queue_elem; + +/* the size of the children_set will not necessarily be correct for Q nodes */ + PQ_set children_set; + PQ_elem children_elem; + + PQ_set full_children_set; + PQ_elem full_children_elem; + + PQ_set partial_children_set; + PQ_elem partial_children_elem; + + PQ_elem blocked_elem; + + PQ_elem leaves_elem; + + struct PQ_node *parent; + + int pertinent_child_count; + int pertinent_leaf_count; + + int mark; +#define IS_UNINITIALIZED(x) ((x)->mark < markbase) +#define UNMARKED (markbase+0) +#define QUEUED (markbase+1) +#define BLOCKED (markbase+2) +#define UNBLOCKED (markbase+3) + + int type; + int parenttype; +#define LEAF_NODE 0 +#define P_NODE 1 +#define Q_NODE 2 +#define DIR_NODE 3 + + int label; +#define IS_EMPTY(x) ((x)->label <= markbase) +#define EMPTY (markbase + 0) +#define PARTIAL (markbase + 1) +#define FULL (markbase + 2) + +} PQ_node; + + +#define BUBBLE_SUCCESS 0 +#define REDUCE_SUCCESS 0 +#define BUBBLE_NO_SOL 1 +#define REDUCE_NO_SOL 2 + +#ifdef CC_PROTOTYPE_ANSI + +/* pq.c */ + +void + XPQ_free_all (PQ_node *, int), + XPQ_save_tree_free (PQ_node *); + +PQ_node + *XPQ_process (PQ_node *), + *XPQ_init_tree (PQ_node *), + *XPQ_find_root (PQ_node *), + *XPQ_save_tree (PQ_node *), + *XPQ_restore_tree (PQ_node *, int); + +#else + +/* pq.c */ + +void + XPQ_free_all (), + XPQ_save_tree_free (); + +PQ_node + *XPQ_process (), + *XPQ_init_tree (), + *XPQ_find_root (), + *XPQ_save_tree (), + *XPQ_restore_tree (); + +#endif + +#endif /* __XPQ_H */ diff --git a/contrib/blossom/concorde97/XSTUFF/Xpqnew.c b/contrib/blossom/concorde97/XSTUFF/Xpqnew.c new file mode 100644 index 0000000000000000000000000000000000000000..1527f9ee7124bcb7fae85bf0c5a77a71dd77b60d --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xpqnew.c @@ -0,0 +1,1743 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* void */ +/* XPQ_free_all (), */ +/* XPQ_save_tree_free (); */ +/* */ +/* PQ_node */ +/* *XPQ_process (), */ +/* *XPQ_init_tree (), */ +/* *XPQ_find_root (), */ +/* *XPQ_save_tree (), */ +/* *XPQ_restore_tree (); */ +/* */ +/**************************************************************************/ + + +#include "machdefs.h" +#include "util.h" +#include "Xsubtour.h" +#include "Xpq.h" + + +#ifdef CC_PROTOTYPE_ANSI + +static void + PQ_tree_grab (PQ_node *, PQ_set *, PQ_node *), + PQ_label_full (PQ_node *), + PQ_label_partial (PQ_node *), + PQ_collect_full_children (PQ_node *, int), + PQ_neighbor_replace (PQ_node *, PQ_set *, PQ_node *, PQ_node *), + PQ_merge_qnode (PQ_node *), + PQ_replace_node (PQ_node *, PQ_node *), + PQ_node_free (PQ_node *), + PQ_tree_free (PQ_node *, int), +#ifndef NDEBUG + dump_solution (PQ_node *), + dump_subtree (PQ_node *), +#endif + print_solution (PQ_node *, PQ_node *); + +static int + PQ_bubble (PQ_node *), + PQ_left_end_is_full (PQ_node *); + +#ifndef NDEBUG +static int + checkout_before (PQ_node *, int), + checkout_after (PQ_node *, int), + check_tree (PQ_node *), + check_node_pert (PQ_node *), + check_node_pert_work (PQ_node *), + check_subtree (PQ_node *), + check_node (PQ_node *); +#endif + +static PQ_node + *PQ_reduce (PQ_node *), + *PQ_template_l1 (PQ_node *), + *PQ_template_p1 (PQ_node *), + *PQ_template_p3_notroot (PQ_node *), + *PQ_template_p5_notroot (PQ_node *), + *PQ_template_q1 (PQ_node *), + *PQ_template_q2 (PQ_node *), + *PQ_template_p2_root (PQ_node *), + *PQ_template_p4_root (PQ_node *), + *PQ_template_p6_root (PQ_node *), + *PQ_template_q3_root (PQ_node *), + *PQ_collect_empty_children (PQ_node *, int), + *PQ_next_nondir (PQ_node *, PQ_node *), + *PQ_node_alloc_work (void), + *PQ_node_alloc (void), + *PQ_save_work (PQ_node *), + *PQ_restore_work (PQ_node *, int); + +#else + +static void + PQ_tree_grab (), + PQ_label_full (), + PQ_label_partial (), + PQ_collect_full_children (), + PQ_neighbor_replace (), + PQ_merge_qnode (), + PQ_replace_node (), + PQ_node_free (), + PQ_tree_free (), +#ifndef NDEBUG + dump_solution (), + dump_subtree (), +#endif + print_solution (); + +static int + PQ_bubble (), + PQ_left_end_is_full (); + +#ifndef NDEBUG +static int + checkout_before (), + checkout_after (), + check_tree (), + check_node_pert (), + check_node_pert_work (), + check_subtree (), + check_node (); +#endif + +static PQ_node + *PQ_reduce (), + *PQ_template_l1 (), + *PQ_template_p1 (), + *PQ_template_p3_notroot (), + *PQ_template_p5_notroot (), + *PQ_template_q1 (), + *PQ_template_q2 (), + *PQ_template_p2_root (), + *PQ_template_p4_root (), + *PQ_template_p6_root (), + *PQ_template_q3_root (), + *PQ_collect_empty_children (), + *PQ_next_nondir (), + *PQ_node_alloc_work (), + *PQ_node_alloc (), + *PQ_save_work (), + *PQ_restore_work (); + +#endif + +/* This is an implementation of the PQ-tree algorithms described in "Testing + * for the Consecutive Ones Property, Interval Graphs, and Graph Planarity + * Using PQ-Tree Algorithms" by Kellogg Booth and George Leuker, Journal of + * Computer and Systems Sciences 13 (1976) pp 335-379. For details, proofs + * of correctness, etc. see the paper */ + +#ifdef CC_PROTOTYPE_ANSI +PQ_node *XPQ_process (PQ_node *S) +#else +PQ_node *XPQ_process (S) +PQ_node *S; +#endif +{ + if (!PQ_bubble (S)) { + return (PQ_node *) NULL; + } + return PQ_reduce (S); +} + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_tree_grab (PQ_node *x, PQ_set *leaves, PQ_node *xprev) +#else +static void PQ_tree_grab (x, leaves, xprev) +PQ_node *x; +PQ_set *leaves; +PQ_node *xprev; +#endif +{ + PQ_node *z, *zprev, *znext; + + if (x->type == LEAF_NODE || x->type == DIR_NODE) { + PQ_set_ADD_RIGHT (x, *leaves, leaves_elem); + if ((x->leaves_elem.ptr1 == (PQ_node *) NULL && + x->children_elem.ptr1 == xprev) || + (x->leaves_elem.ptr2 == (PQ_node *) NULL && + x->children_elem.ptr2 == xprev)) { + /* We want the leaves ptr usage to match the children ptr usage, + * so we can preserve the direction the DIR_NODEs point */ + SWAP (x->leaves_elem.ptr1, x->leaves_elem.ptr2, z); + } + } else { + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + PQ_tree_grab (z, leaves, zprev); + } + } +} + +int markbase = 0; +PQ_set blocked_set; +PQ_node pseudo_root; +int off_the_top; + +#ifdef CC_PROTOTYPE_ANSI +PQ_node *XPQ_init_tree (PQ_node *S) +#else +PQ_node *XPQ_init_tree (S) +PQ_node *S; +#endif +{ + PQ_node *root; + PQ_node *x; + + if (!S->next) { + S->type = LEAF_NODE; + S->parent = (PQ_node *) NULL; + S->parenttype = P_NODE; + PQ_set_INIT (S->children_set); + PQ_set_INIT (S->full_children_set); + PQ_set_INIT (S->partial_children_set); + S->label = 0; + S->mark = 0; + S->pertinent_child_count = 0; + S->pertinent_leaf_count = 0; + return S; + } + root = PQ_node_alloc (); + + PQ_set_INIT (root->children_set); + PQ_set_INIT (root->full_children_set); + PQ_set_INIT (root->partial_children_set); + root->type = P_NODE; + root->parent = (PQ_node *) NULL; + root->parenttype = P_NODE; + + for (x = S; x; x = x->next) { + x->parent = root; + x->parenttype = P_NODE; + PQ_set_ADD (x, root->children_set, children_elem); + x->label = 0; + x->mark = 0; + x->type = LEAF_NODE; + PQ_set_INIT (x->children_set); + PQ_set_INIT (x->full_children_set); + PQ_set_INIT (x->partial_children_set); + x->pertinent_child_count = 0; + x->pertinent_leaf_count = 0; + } + return root; +} + +/* PQ_bubble forms the first half of the PQ-tree implementation. + * + * It takes as input a list of PQ_node(s) linked by (next). + * + * It fills in the parent field of all the nodes in the PQ-tree, notices certain + * unsatisfiable requests, fills in the pertinent_child_counts, ... + * + * It returns either BUBBLE_NO_SOL or BUBBLE_SUCCESS. */ + +#ifdef CC_PROTOTYPE_ANSI +static int PQ_bubble (PQ_node *S) +#else +static int PQ_bubble (S) +PQ_node *S; +#endif +{ + PQ_set q; + int block_count; + PQ_node *x; + PQ_node *zprev, *z, *znext; + PQ_node *leftsib, *rightsib; + int i; + int nbs; + + assert (check_tree (S)); + + markbase += 4; + PQ_set_INIT (q); + block_count = 0; + PQ_set_INIT (blocked_set); + off_the_top = 0; + + for (x = S; x; x = x->next) { + PQ_set_ADD_LEFT (x, q, queue_elem); + } + + while (PQ_set_SIZE (q) + block_count + off_the_top > 1) { + if (PQ_set_ISEMPTY (q)) { + return 0; + } + x = PQ_set_RIGHT_ELEM (q); + PQ_set_DELETE (x, q, queue_elem); + x->mark = BLOCKED; + + x->pertinent_leaf_count = 0; + PQ_set_INIT (x->full_children_set); + PQ_set_INIT (x->partial_children_set); + + nbs = 0; + + leftsib = PQ_next_nondir (x->children_elem.ptr1, x); + rightsib = PQ_next_nondir (x->children_elem.ptr2, x); + + if (leftsib && leftsib->mark == BLOCKED) { + nbs++; + } + if (rightsib && rightsib->mark == BLOCKED) { + nbs++; + } + if (x->parenttype == P_NODE || leftsib == (PQ_node *) NULL + || rightsib == (PQ_node *) NULL) { + x->mark = UNBLOCKED; + } else if (leftsib->mark == UNBLOCKED) { + z = x; + zprev = x->children_elem.ptr2; + PQ_set_FOREACH_FROM (z, children_elem, zprev, znext) { + if (z == leftsib) { + break; + } + z->parent = leftsib->parent; + z->mark = UNBLOCKED; + } + assert (z == leftsib); + } else if (rightsib->mark == UNBLOCKED) { + z = x; + zprev = x->children_elem.ptr1; + PQ_set_FOREACH_FROM (z, children_elem, zprev, znext) { + if (z == rightsib) { + break; + } + z->parent = rightsib->parent; + z->mark = UNBLOCKED; + } + assert (z == rightsib); + } + if (x->mark == UNBLOCKED) { + if (x->parent && IS_UNINITIALIZED (x->parent)) { + x->parent->mark = UNMARKED; + x->parent->pertinent_child_count = 0; + } + PQ_set_FOREACH_ADJ (x, children_elem, z, i) { + zprev = x; + PQ_set_FOREACH_FROM (z, children_elem, zprev, znext) { + if (z->type == DIR_NODE) { + z->parent = x->parent; + } else if (z->mark == BLOCKED) { + z->parent = x->parent; + z->mark = UNBLOCKED; + if (x->parent) { + x->parent->pertinent_child_count++; + } + PQ_set_DELETE (z, blocked_set, blocked_elem); + } else { + break; + } + } + } + + if (x->parent) { + x->parent->pertinent_child_count++; + if (x->parent->mark == UNMARKED) { + PQ_set_ADD_LEFT (x->parent, q, queue_elem); + x->parent->mark = QUEUED; + } + } else { + off_the_top = 1; + } + block_count -= nbs; + } else { + block_count = block_count + 1 - nbs; + PQ_set_ADD (x, blocked_set, blocked_elem); + } + } + if (!PQ_set_ISEMPTY (q)) { + x = PQ_set_LEFT_ELEM (q); + x->pertinent_leaf_count = 0; + if (x->pertinent_child_count == 1) { + x->pertinent_child_count = 0; + } + PQ_set_INIT (x->full_children_set); + PQ_set_INIT (x->partial_children_set); + } + if (block_count) { + pseudo_root.type = Q_NODE; + pseudo_root.parent = (PQ_node *) NULL; + pseudo_root.pertinent_child_count = 0; + PQ_set_FOREACH (blocked_set, x, blocked_elem, zprev, znext) { + x->parent = &pseudo_root; + pseudo_root.pertinent_child_count++; + } + pseudo_root.pertinent_leaf_count = 0; + PQ_set_INIT (pseudo_root.full_children_set); + PQ_set_INIT (pseudo_root.partial_children_set); + pseudo_root.label = 0; + } + assert (check_tree (S)); + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_reduce (PQ_node *S) +#else +static PQ_node *PQ_reduce (S) +PQ_node *S; +#endif +{ + PQ_set q; + PQ_node *x; + int ssize; + PQ_node *y; + + assert (check_tree (S)); + + PQ_set_INIT (q); + + for (x = S, ssize = 0; x; x = x->next, ssize++) { + PQ_set_ADD_LEFT (x, q, queue_elem); + x->pertinent_leaf_count = 1; + } + while (!PQ_set_ISEMPTY (q)) { + x = PQ_set_RIGHT_ELEM (q); + PQ_set_DELETE (x, q, queue_elem); + + assert (check_node_pert (x)); + + if (x->pertinent_leaf_count < ssize) { + /* x is not the root of the pertinent subtree */ + assert (checkout_before (x, 0)); + y = x->parent; + y->pertinent_leaf_count += x->pertinent_leaf_count; + y->pertinent_child_count--; + if (y->pertinent_child_count == 0) { + PQ_set_ADD_LEFT (y, q, queue_elem); + } + /* now, the templates */ + if (!PQ_template_l1 (x) && + !PQ_template_p1 (x) && + !PQ_template_p3_notroot (x) && + !PQ_template_p5_notroot (x) && + !PQ_template_q1 (x) && + !PQ_template_q2 (x)) { + return (PQ_node *) NULL; + } + assert (checkout_after (x, 0)); + } else { + /* x is the root of the pertinent subtree */ + assert (checkout_before (x, 1)); + assert (PQ_set_ISEMPTY (q)); + if ((y = PQ_template_l1 (x)) || + (y = PQ_template_p1 (x)) || + (y = PQ_template_p2_root (x)) || + (y = PQ_template_p4_root (x)) || + (y = PQ_template_p6_root (x)) || + (y = PQ_template_q1 (x)) || + (y = PQ_template_q2 (x)) || + (y = PQ_template_q3_root (x))) { + assert (check_tree (S)); + return y; + } else { + return (PQ_node *) NULL; + } + } + } + return (PQ_node *) NULL; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_l1 (PQ_node *x) +#else +static PQ_node *PQ_template_l1 (x) +PQ_node *x; +#endif +{ + if (x->type != LEAF_NODE) { + return (PQ_node *) NULL; + } + PQ_label_full (x); + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_p1 (PQ_node *x) +#else +static PQ_node *PQ_template_p1 (x) +PQ_node *x; +#endif +{ + if (x->type != P_NODE) { + return (PQ_node *) NULL; + } + if (PQ_set_SIZE (x->full_children_set) != PQ_set_SIZE (x->children_set)) { + return (PQ_node *) NULL; + } + PQ_label_full (x); + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_p3_notroot (PQ_node *x) +#else +static PQ_node *PQ_template_p3_notroot (x) +PQ_node *x; +#endif +{ + if (x->type != P_NODE) { + return (PQ_node *) NULL; + } + if (!PQ_set_ISEMPTY (x->partial_children_set)) { + return (PQ_node *) NULL; + } + assert (!PQ_set_ISEMPTY (x->full_children_set)); + assert (PQ_set_SIZE (x->full_children_set) != PQ_set_SIZE (x->children_set)); + + PQ_collect_full_children (x, Q_NODE); + x = PQ_collect_empty_children (x, Q_NODE); + + PQ_label_partial (x); + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_p5_notroot (PQ_node *x) +#else +static PQ_node *PQ_template_p5_notroot (x) +PQ_node *x; +#endif +{ + PQ_node *partial_child; + PQ_node *full_child; + PQ_node *z; + + if (x->type != P_NODE) { + return (PQ_node *) NULL; + } + if (PQ_set_SIZE (x->partial_children_set) != 1) { + return (PQ_node *) NULL; + } + partial_child = PQ_set_LEFT_ELEM (x->partial_children_set); + PQ_set_DELETE (partial_child, x->children_set, children_elem); + PQ_set_DELETE (partial_child, x->partial_children_set, partial_children_elem); + + PQ_collect_full_children (x, Q_NODE); + if (!PQ_set_ISEMPTY (x->full_children_set)) { + full_child = PQ_set_LEFT_ELEM (x->full_children_set); + PQ_set_DELETE (full_child, x->children_set, children_elem); + PQ_set_DELETE (full_child, x->full_children_set, full_children_elem); + full_child->parent = partial_child; + full_child->parenttype = Q_NODE; + if (PQ_left_end_is_full (partial_child)) { + PQ_set_ADD_LEFT (full_child, partial_child->children_set, children_elem); + PQ_set_ADD_LEFT (full_child, partial_child->full_children_set, full_children_elem); + } else { + PQ_set_ADD_RIGHT (full_child, partial_child->children_set, children_elem); + PQ_set_ADD_RIGHT (full_child, partial_child->full_children_set, full_children_elem); + } + } + PQ_replace_node (x, partial_child); + + if (PQ_set_ISEMPTY (x->children_set)) { + PQ_node_free (x); + } else { + if (PQ_set_SIZE (x->children_set) == 1) { + z = PQ_set_LEFT_ELEM (x->children_set); + PQ_node_free (x); + x = z; + } + x->parent = partial_child; + x->parenttype = Q_NODE; + if (PQ_left_end_is_full (partial_child)) { + PQ_set_ADD_RIGHT (x, partial_child->children_set, children_elem); + } else { + PQ_set_ADD_LEFT (x, partial_child->children_set, children_elem); + } + } + PQ_label_partial (partial_child); + return partial_child; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_q1 (PQ_node *x) +#else +static PQ_node *PQ_template_q1 (x) +PQ_node *x; +#endif +{ + PQ_node *z, *zprev, *znext; + + if (x->type != Q_NODE) { + return (PQ_node *) NULL; + } + if (x == &pseudo_root) { + return (PQ_node *) NULL; + } + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + if (z->label != FULL && z->type != DIR_NODE) { + return (PQ_node *) NULL; + } + } + PQ_label_full (x); + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_q2 (PQ_node *x) +#else +static PQ_node *PQ_template_q2 (x) +PQ_node *x; +#endif +{ + PQ_node *partial_child; + int full_count; + PQ_node *z, *zprev, *znext; + PQ_node *full_end, *empty_end; + + if (x->type != Q_NODE) { + return (PQ_node *) NULL; + } + if (x == &pseudo_root) { + return (PQ_node *) NULL; + } + if (PQ_set_SIZE (x->partial_children_set) > 1) { + return (PQ_node *) NULL; + } + if (PQ_left_end_is_full (x)) { + full_end = PQ_set_LEFT_ELEM (x->children_set); + empty_end = PQ_set_RIGHT_ELEM (x->children_set); + } else { + full_end = PQ_set_RIGHT_ELEM (x->children_set); + empty_end = PQ_set_LEFT_ELEM (x->children_set); + } + + full_count = 0; + z = full_end; + zprev = (PQ_node *) NULL; + + PQ_set_FOREACH_FROM (z, children_elem, zprev, znext) { + if (z->label == FULL) { + full_count++; + } else if (z->type != DIR_NODE) { + break; + } + } + + if (full_count != PQ_set_SIZE (x->full_children_set)) { + return (PQ_node *) NULL; + } + if (!PQ_set_ISEMPTY (x->partial_children_set) && + z != PQ_set_LEFT_ELEM (x->partial_children_set)) { + return (PQ_node *) NULL; + } + assert (!PQ_set_ISEMPTY (x->full_children_set) || !PQ_set_ISEMPTY (x->partial_children_set)); + + if (!PQ_set_ISEMPTY (x->partial_children_set)) { + partial_child = PQ_set_LEFT_ELEM (x->partial_children_set); + PQ_set_DELETE (partial_child, x->partial_children_set, partial_children_elem); + PQ_merge_qnode (partial_child); + } + PQ_label_partial (x); + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_p2_root (PQ_node *x) +#else +static PQ_node *PQ_template_p2_root (x) +PQ_node *x; +#endif +{ + if (x->type != P_NODE) { + return (PQ_node *) NULL; + } + if (!PQ_set_ISEMPTY (x->partial_children_set)) { + return (PQ_node *) NULL; + } + assert (!PQ_set_ISEMPTY (x->full_children_set)); + assert (PQ_set_SIZE (x->full_children_set) != PQ_set_SIZE (x->children_set)); + + PQ_collect_full_children (x, P_NODE); + + return PQ_set_LEFT_ELEM (x->full_children_set); +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_p4_root (PQ_node *x) +#else +static PQ_node *PQ_template_p4_root (x) +PQ_node *x; +#endif +{ + PQ_node *partial_child; + PQ_node *full_child; + + if (x->type != P_NODE) { + return (PQ_node *) NULL; + } + if (PQ_set_SIZE (x->partial_children_set) != 1) { + return (PQ_node *) NULL; + } + partial_child = PQ_set_LEFT_ELEM (x->partial_children_set); + + PQ_collect_full_children (x, Q_NODE); + + if (!PQ_set_ISEMPTY (x->full_children_set)) { + full_child = PQ_set_LEFT_ELEM (x->full_children_set); + PQ_set_DELETE (full_child, x->children_set, children_elem); + PQ_set_DELETE (full_child, x->full_children_set, full_children_elem); + full_child->parent = partial_child; + full_child->parenttype = Q_NODE; + if (PQ_left_end_is_full (partial_child)) { + PQ_set_ADD_LEFT (full_child, partial_child->children_set, children_elem); + PQ_set_ADD_LEFT (full_child, partial_child->full_children_set, full_children_elem); + } else { + PQ_set_ADD_RIGHT (full_child, partial_child->children_set, children_elem); + PQ_set_ADD_RIGHT (full_child, partial_child->full_children_set, full_children_elem); + } + } + if (PQ_set_SIZE (x->children_set) == 1) { + full_child = PQ_set_LEFT_ELEM (x->children_set); + PQ_replace_node (x, full_child); + PQ_node_free (x); + } + return partial_child; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_p6_root (PQ_node *x) +#else +static PQ_node *PQ_template_p6_root (x) +PQ_node *x; +#endif +{ + PQ_node *partial_child1, *partial_child2; + PQ_node *full_end1, *empty_end1, *full_end2, *empty_end2; + PQ_node *z, *zprev, *znext; + PQ_node *full_child; + + if (x->type != P_NODE) { + return (PQ_node *) NULL; + } + if (PQ_set_SIZE (x->partial_children_set) > 2) { + return (PQ_node *) NULL; + } + assert (PQ_set_SIZE (x->partial_children_set) == 2); + + partial_child1 = PQ_set_LEFT_ELEM (x->partial_children_set); + partial_child2 = PQ_set_RIGHT_ELEM (x->partial_children_set); + + PQ_collect_full_children (x, Q_NODE); + + if (!PQ_set_ISEMPTY (x->full_children_set)) { + full_child = PQ_set_LEFT_ELEM (x->full_children_set); + PQ_set_DELETE (full_child, x->children_set, children_elem); + PQ_set_DELETE (full_child, x->full_children_set, full_children_elem); + + full_child->parent = partial_child1; + full_child->parenttype = Q_NODE; + if (PQ_left_end_is_full (partial_child1)) { + PQ_set_ADD_LEFT (full_child, partial_child1->children_set, children_elem); + PQ_set_ADD_LEFT (full_child, partial_child1->full_children_set, full_children_elem); + } else { + PQ_set_ADD_RIGHT (full_child, partial_child1->children_set, children_elem); + PQ_set_ADD_RIGHT (full_child, partial_child1->full_children_set, full_children_elem); + } + } + if (PQ_left_end_is_full (partial_child1)) { + full_end1 = PQ_set_LEFT_ELEM (partial_child1->children_set); + empty_end1 = PQ_set_RIGHT_ELEM (partial_child1->children_set); + } else { + full_end1 = PQ_set_RIGHT_ELEM (partial_child1->children_set); + empty_end1 = PQ_set_LEFT_ELEM (partial_child1->children_set); + } + if (PQ_left_end_is_full (partial_child2)) { + full_end2 = PQ_set_LEFT_ELEM (partial_child2->children_set); + empty_end2 = PQ_set_RIGHT_ELEM (partial_child2->children_set); + } else { + full_end2 = PQ_set_RIGHT_ELEM (partial_child2->children_set); + empty_end2 = PQ_set_LEFT_ELEM (partial_child2->children_set); + } + + PQ_set_PTR_REPLACE (full_end1->children_elem, 0, full_end2); + PQ_set_PTR_REPLACE (full_end2->children_elem, 0, full_end1); + + if (partial_child1->children_set.left == full_end1) { + partial_child1->children_set.left = empty_end2; + } else { + partial_child1->children_set.right = empty_end2; + } + partial_child1->children_set.size += partial_child2->children_set.size; + empty_end2->parent = partial_child1; + + PQ_set_FOREACH_DEL (partial_child2->full_children_set, z, full_children_elem, zprev, znext) { + PQ_set_DELETE (z, partial_child2->full_children_set, full_children_elem); + PQ_set_ADD (z, partial_child1->full_children_set, full_children_elem); + z->parent = partial_child1; + } + + PQ_set_DELETE (partial_child2, x->children_set, children_elem); + PQ_set_DELETE (partial_child2, x->partial_children_set, partial_children_elem); + + PQ_node_free (partial_child2); + + if (PQ_set_SIZE (x->children_set) == 1) { + full_child = PQ_set_LEFT_ELEM (x->children_set); + PQ_replace_node (x, full_child); + PQ_node_free (x); + } + return partial_child1; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_template_q3_root (PQ_node *x) +#else +static PQ_node *PQ_template_q3_root (x) +PQ_node *x; +#endif +{ + int full_count; + PQ_node *z, *zprev, *znext, *zstart; + + /* note that we cannot talk about x->children_set, since x might be the + * pseudo_root */ + + if (x->type != Q_NODE) { + return (PQ_node *) NULL; + } + if (PQ_set_ISEMPTY (x->partial_children_set)) { + zstart = PQ_set_LEFT_ELEM (x->full_children_set); + assert (zstart->label == FULL); + full_count = 1; + zprev = zstart; + z = zstart->children_elem.ptr1; + + PQ_set_FOREACH_FROM (z, children_elem, zprev, znext) { + if (z->label == FULL) { + full_count++; + } else if (z->type != DIR_NODE) { + break; + } + } + + zprev = zstart; + z = zstart->children_elem.ptr2; + + PQ_set_FOREACH_FROM (z, children_elem, zprev, znext) { + if (z->label == FULL) { + full_count++; + } else if (z->type != DIR_NODE) { + break; + } + } + if (full_count != PQ_set_SIZE (x->full_children_set)) { + return (PQ_node *) NULL; + } + } else { + zstart = PQ_set_LEFT_ELEM (x->partial_children_set); + z = PQ_next_nondir (zstart->children_elem.ptr1, zstart); + + if (z && !IS_EMPTY (z)) { + z = zstart->children_elem.ptr1; + } else { + z = zstart->children_elem.ptr2; + } + + zprev = zstart; + full_count = 0; + PQ_set_FOREACH_FROM (z, children_elem, zprev, znext) { + if (z->label == FULL) { + full_count++; + } else if (z->type != DIR_NODE) { + break; + } + } + if (full_count != PQ_set_SIZE (x->full_children_set)) { + return (PQ_node *) NULL; + } + if (z && z->label == PARTIAL && PQ_set_SIZE (x->partial_children_set) != 2) { + return (PQ_node *) NULL; + } + if (z && z->label != PARTIAL && PQ_set_SIZE (x->partial_children_set) != 1) { + return (PQ_node *) NULL; + } + } + + PQ_set_FOREACH_DEL (x->partial_children_set, z, partial_children_elem, zprev, znext) { + PQ_set_DELETE (z, x->partial_children_set, partial_children_elem); + PQ_merge_qnode (z); + } + + return x; +} + +/* PQ_label_full marks a node as full, and if it has a parent, adds it to the + * parents list of full children */ + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_label_full (PQ_node *x) +#else +static void PQ_label_full (x) +PQ_node *x; +#endif +{ + x->label = FULL; + if (x->parent) { + PQ_set_ADD (x, x->parent->full_children_set, full_children_elem); + } +} /* PQ_LABEL_FULL */ + +/* PQ_label_partial marks a node as partial, and if it has a parent, adds it + * to the parents list of partial children */ + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_label_partial (PQ_node *x) +#else +static void PQ_label_partial (x) +PQ_node *x; +#endif +{ + x->label = PARTIAL; + if (x->parent) { + PQ_set_ADD (x, x->parent->partial_children_set, partial_children_elem); + } +} + +/* PQ_collect_full_children collects all the full children of x, and places + * them under a new P-node below x. It sets the parenttype of the new node + * to t */ + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_collect_full_children (PQ_node *x, int t) +#else +static void PQ_collect_full_children (x, t) +PQ_node *x; +int t; +#endif +{ + PQ_node *new_node; + PQ_node *z, *zprev, *znext; + + assert (x->type == P_NODE); + if (PQ_set_SIZE (x->full_children_set) > 1) { + new_node = PQ_node_alloc (); + PQ_set_INIT (new_node->children_set); + PQ_set_INIT (new_node->full_children_set); + PQ_set_INIT (new_node->partial_children_set); + new_node->label = FULL; + new_node->type = P_NODE; + PQ_set_FOREACH_DEL (x->full_children_set, z, full_children_elem, zprev, znext) { + PQ_set_DELETE (z, x->children_set, children_elem); + PQ_set_DELETE (z, x->full_children_set, full_children_elem); + z->parent = new_node; + z->parenttype = P_NODE; + PQ_set_ADD (z, new_node->children_set, children_elem); + PQ_set_ADD (z, new_node->full_children_set, full_children_elem); + } + assert (PQ_set_ISEMPTY (x->full_children_set)); + new_node->parent = x; + new_node->parenttype = t; + PQ_set_ADD (new_node, x->children_set, children_elem); + PQ_set_ADD (new_node, x->full_children_set, full_children_elem); + } else if (PQ_set_SIZE (x->full_children_set) == 1) { + z = PQ_set_LEFT_ELEM (x->full_children_set); + z->parenttype = t; + } +} /* PQ_COLLECT_FULL_CHILDREN */ + +/* PQ_collect_empty_children collects all the emtpy children of x, and places + * them under a new P-node below x. It sets the parenttype of the new node + * to t. If there is more than 1 empty child, it actually does this by + * creating a new node to replace x, and moves all the full children of x to + * the new node, and moves x down. It returns a pointer to the node that is + * where x used to be. */ + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_collect_empty_children (PQ_node *x, int t) +#else +static PQ_node *PQ_collect_empty_children (x, t) +PQ_node *x; +int t; +#endif +{ + PQ_node *y; + PQ_node *z, *zprev, *znext; + PQ_node *new_node; + + assert (x->type == P_NODE); + assert (PQ_set_ISEMPTY (x->partial_children_set)); + assert (PQ_set_SIZE (x->children_set) > PQ_set_SIZE (x->full_children_set)); + + if (PQ_set_SIZE (x->children_set) - PQ_set_SIZE (x->full_children_set) > 1) { + new_node = PQ_node_alloc (); + PQ_set_INIT (new_node->children_set); + PQ_set_INIT (new_node->full_children_set); + PQ_set_INIT (new_node->partial_children_set); + new_node->label = x->label; + new_node->type = t; + + PQ_set_FOREACH_DEL (x->full_children_set, z, full_children_elem, zprev, znext) { + PQ_set_DELETE (z, x->children_set, children_elem); + PQ_set_DELETE (z, x->full_children_set, full_children_elem); + z->parent = new_node; + z->parenttype = t; + PQ_set_ADD (z, new_node->children_set, children_elem); + PQ_set_ADD (z, new_node->full_children_set, full_children_elem); + } + + y = x->parent; + new_node->parent = y; + new_node->parenttype = x->parenttype; + new_node->children_elem.ptr1 = x->children_elem.ptr1; + new_node->children_elem.ptr2 = x->children_elem.ptr2; + if (y) { + PQ_neighbor_replace (new_node->children_elem.ptr1, &y->children_set, x, new_node); + PQ_neighbor_replace (new_node->children_elem.ptr2, &y->children_set, x, new_node); + } + x->parent = new_node; + x->parenttype = t; + + x->label = EMPTY; + PQ_set_ADD (x, new_node->children_set, children_elem); + + x = new_node; + } else if (PQ_set_SIZE (x->children_set) - PQ_set_SIZE (x->full_children_set) == 1) { + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + if (IS_EMPTY (z)) { + z->parenttype = t; + break; + } + } + x->type = t; + } + return x; +} + +/* PQ_neighbor_replace replaces the pointer to q in the children list with a + * pointer to r */ + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_neighbor_replace (PQ_node *x, PQ_set *s, PQ_node *q, + PQ_node *r) +#else +static void PQ_neighbor_replace (x, s, q, r) +PQ_node *x; +PQ_set *s; +PQ_node *q; +PQ_node *r; +#endif +{ + if (x) { + PQ_set_PTR_REPLACE (x->children_elem, q, r); + } else { + if (s->left == q) { + s->left = r; + } else { + assert (s->right == q); + s->right = r; + } + } +} + +/* PQ_merge_qnode merges x into its parent */ + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_merge_qnode (PQ_node *x) +#else +static void PQ_merge_qnode (x) +PQ_node *x; +#endif +{ + PQ_node *parent = x->parent; + PQ_node *full_end, *empty_end; + PQ_node *z, *zprev, *znext; + PQ_node *empty_neighbor, *full_neighbor; + PQ_node *empty_neighbor2, *full_neighbor2; + + assert (x->type == Q_NODE); + if (PQ_left_end_is_full (x)) { + full_end = PQ_set_LEFT_ELEM (x->children_set); + empty_end = PQ_set_RIGHT_ELEM (x->children_set); + } else { + full_end = PQ_set_RIGHT_ELEM (x->children_set); + empty_end = PQ_set_LEFT_ELEM (x->children_set); + } + + PQ_set_FOREACH_DEL (x->full_children_set, z, full_children_elem, zprev, znext) { + PQ_set_DELETE (z, x->full_children_set, full_children_elem); + PQ_set_ADD (z, parent->full_children_set, full_children_elem); + z->parent = parent; + } + + full_end->parent = parent; + empty_end->parent = parent; + empty_neighbor = x->children_elem.ptr1; + full_neighbor = x->children_elem.ptr2; + empty_neighbor2 = PQ_next_nondir (empty_neighbor, x); + full_neighbor2 = PQ_next_nondir (full_neighbor, x); + if ((empty_neighbor2 && !IS_EMPTY (empty_neighbor2)) || + (full_neighbor2 && IS_EMPTY (full_neighbor2))) { + SWAP (empty_neighbor, full_neighbor, z); + SWAP (empty_neighbor2, full_neighbor2, z); + } + assert (full_end != empty_end); + assert (empty_neighbor2 == 0 || IS_EMPTY (empty_neighbor2)); + assert (full_neighbor2 == 0 || full_neighbor2->label == FULL || full_neighbor2->label == PARTIAL); + assert (empty_neighbor2 || full_neighbor2); + + PQ_set_PTR_REPLACE (full_end->children_elem, 0, full_neighbor); + PQ_set_PTR_REPLACE (empty_end->children_elem, 0, empty_neighbor); + PQ_neighbor_replace (full_neighbor, &parent->children_set, x, full_end); + PQ_neighbor_replace (empty_neighbor, &parent->children_set, x, empty_end); + + parent->children_set.size += x->children_set.size - 1; + + PQ_node_free (x); +} + +/* PQ_replace_node replaces old with new */ + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_replace_node (PQ_node *old, PQ_node *new) +#else +static void PQ_replace_node (old, new) +PQ_node *old; +PQ_node *new; +#endif +{ + new->parent = old->parent; + new->parenttype = old->parenttype; + + new->children_elem.ptr1 = old->children_elem.ptr1; + new->children_elem.ptr2 = old->children_elem.ptr2; + + if (new->parent) { + PQ_neighbor_replace (new->children_elem.ptr1, &new->parent->children_set, old, new); + PQ_neighbor_replace (new->children_elem.ptr2, &new->parent->children_set, old, new); + } else { + if (new->children_elem.ptr1) { + PQ_set_PTR_REPLACE (new->children_elem.ptr1->children_elem, old, new); + } + if (new->children_elem.ptr2) { + PQ_set_PTR_REPLACE (new->children_elem.ptr2->children_elem, old, new); + } + } +} + +/* PQ_left_end_is_full is a boolean which indicates whether the left end of a + * partial Q_NODE is full or not */ + +#ifdef CC_PROTOTYPE_ANSI +static int PQ_left_end_is_full (PQ_node *x) +#else +static int PQ_left_end_is_full (x) +PQ_node *x; +#endif +{ + PQ_node *left_end; + PQ_node *right_end; + + assert (x->type == Q_NODE); + + left_end = PQ_next_nondir (PQ_set_LEFT_ELEM (x->children_set), (PQ_node *) NULL); + right_end = PQ_next_nondir (PQ_set_RIGHT_ELEM (x->children_set), (PQ_node *) NULL); + return IS_EMPTY (right_end) || left_end->label == FULL; +} + +/* PQ_next_nondir finds the next neighbor which is not of type DIR_NODE, + * heading from z away from zprev */ + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_next_nondir (PQ_node *z, PQ_node *zprev) +#else +static PQ_node *PQ_next_nondir (z, zprev) +PQ_node *z; +PQ_node *zprev; +#endif +{ + PQ_node *znext; + + PQ_set_FOREACH_FROM (z, children_elem, zprev, znext) { + if (z->type != DIR_NODE) + return z; + } + return (PQ_node *) NULL; +} + +static int node_counter = -1; +static PQ_node *PQ_node_freelist = (PQ_node *) NULL; + +#define PQ_alloc_chunk (((1<<17)-16)/sizeof (PQ_node)) + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_node_alloc_work (void) +#else +static PQ_node *PQ_node_alloc_work () +#endif +{ + PQ_node *x; + int i; + + if (!PQ_node_freelist) { + PQ_node_freelist = CC_SAFE_MALLOC (PQ_alloc_chunk, PQ_node); + if (!PQ_node_freelist) { + fprintf (stderr, "out of memory in PQ_node_alloc_work\n"); + exit (1); + } + printf ("MALLOC %d PQ NODES\n", (int) PQ_alloc_chunk); + fflush (stdout); + if (!PQ_node_freelist) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } + for (i = 0; i < (int) PQ_alloc_chunk - 1; i++) { + PQ_node_freelist[i].next = &PQ_node_freelist[i + 1]; + } + PQ_node_freelist[PQ_alloc_chunk - 1].next = (PQ_node *) NULL; + } + x = PQ_node_freelist; + PQ_node_freelist = PQ_node_freelist->next; + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_node_alloc (void) +#else +static PQ_node *PQ_node_alloc () +#endif +{ + PQ_node *x; + + x = PQ_node_alloc_work (); + x->next = (PQ_node *) NULL; + x->number = node_counter; + node_counter--; + x->base_edge = (struct Xedge *) NULL; + x->queue_elem.ptr1 = (PQ_node *) NULL; + x->queue_elem.ptr2 = (PQ_node *) NULL; + PQ_set_INIT (x->children_set); + PQ_set_INIT (x->partial_children_set); + PQ_set_INIT (x->full_children_set); + x->children_elem.ptr1 = (PQ_node *) NULL; + x->children_elem.ptr2 = (PQ_node *) NULL; + x->partial_children_elem.ptr1 = (PQ_node *) NULL; + x->partial_children_elem.ptr2 = (PQ_node *) NULL; + x->full_children_elem.ptr1 = (PQ_node *) NULL; + x->full_children_elem.ptr2 = (PQ_node *) NULL; + x->blocked_elem.ptr1 = (PQ_node *) NULL; + x->blocked_elem.ptr2 = (PQ_node *) NULL; + x->leaves_elem.ptr1 = (PQ_node *) NULL; + x->leaves_elem.ptr2 = (PQ_node *) NULL; + x->parent = (PQ_node *) NULL; + x->pertinent_child_count = 0; + x->pertinent_leaf_count = 0; + x->mark = 0; + x->type = 0; + x->parenttype = 0; + x->label = 0; + x->magiclabel = 0; + + return x; +} + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_node_free (PQ_node *x) +#else +static void PQ_node_free (x) +PQ_node *x; +#endif +{ + x->next = PQ_node_freelist; + PQ_node_freelist = x; +} + +/* PQ_tree_free recursively frees the tree rooted at x */ + +#ifdef CC_PROTOTYPE_ANSI +static void PQ_tree_free (PQ_node *x, int saveleaves) +#else +static void PQ_tree_free (x, saveleaves) +PQ_node *x; +int saveleaves; +#endif +{ + PQ_node *z, *zprev, *znext; + + PQ_set_FOREACH_DEL (x->children_set, z, children_elem, zprev, znext) { + PQ_set_DELETE (z, x->children_set, children_elem); + PQ_tree_free (z, saveleaves); + } + if (!(saveleaves && (x->type == DIR_NODE || x->type == LEAF_NODE))) { + PQ_node_free (x); + } +} + +/* PQ_free_all frees storage for a tree */ + +#ifdef CC_PROTOTYPE_ANSI +void XPQ_free_all (PQ_node *x, int saveleaves) +#else +void XPQ_free_all (x, saveleaves) +PQ_node *x; +int saveleaves; +#endif +{ + PQ_tree_free (XPQ_find_root (x), saveleaves); +} + +/* PQ_find_root is only used by the dump and check routines, and PQ_free_all */ + +#ifdef CC_PROTOTYPE_ANSI +PQ_node *XPQ_find_root (PQ_node *x) +#else +PQ_node *XPQ_find_root (x) +PQ_node *x; +#endif +{ + PQ_node *zprev, *znext; + + for (;;) { + if (x->parenttype == P_NODE) { + if (x->parent) + x = x->parent; + else + return x; + } else { + zprev = x->children_elem.ptr1; + PQ_set_FOREACH_FROM (x, children_elem, zprev, znext); + if (zprev->parent) + x = zprev->parent; + else + return zprev; + } + } +} + +#ifndef NDEBUG + +#ifdef CC_PROTOTYPE_ANSI +static void dump_solution (PQ_node *x) +#else +static void dump_solution (x) +PQ_node *x; +#endif +{ + dump_subtree (XPQ_find_root (x)); +} + +#ifdef CC_PROTOTYPE_ANSI +static void dump_subtree (PQ_node *x) +#else +static void dump_subtree (x) +PQ_node *x; +#endif +{ + print_solution (x, (PQ_node *) NULL); + printf ("\n"); +} + +#endif + +#ifdef CC_PROTOTYPE_ANSI +static void print_solution (PQ_node *x, PQ_node *xprev) +#else +static void print_solution (x, xprev) +PQ_node *x; +PQ_node *xprev; +#endif +{ + PQ_node *z, *zprev, *znext; + + if (x->type == LEAF_NODE) { + printf ("%d ", x->number); + } else if (x->type == DIR_NODE) { + if (x->children_elem.ptr1 == xprev) { + printf ("<<%d<< ", x->number); + } else { + printf (">>%d>> ", x->number); + } + } else if (x->type == P_NODE) { + printf ("("); + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + print_solution (z, zprev); + } + printf (")<%d> ", x->number); + } else { + printf ("["); + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + print_solution (z, zprev); + } + printf ("]<%d> ", x->number); + } +} + +/* the various check routines are for debugging use only, to verify that the + * state of the PQ_tree is valid. */ + +#ifndef NDEBUG + +#ifdef CC_PROTOTYPE_ANSI +static int checkout_before (PQ_node *x, int isroot) +#else +static int checkout_before (x, isroot) +PQ_node *x; +int isroot; +#endif +{ + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static int checkout_after (PQ_node *x, int isroot) +#else +static int checkout_after (x, isroot) +PQ_node *x; +int isroot; +#endif +{ + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_tree (PQ_node *x) +#else +static int check_tree (x) +PQ_node *x; +#endif +{ + if (!check_subtree (XPQ_find_root (x))) { + dump_solution (x); + return 0; + } else { + return 1; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_subtree (PQ_node *x) +#else +static int check_subtree (x) +PQ_node *x; +#endif +{ + PQ_node *z, *zprev, *znext; + + if (!check_node (x)) { + return 0; + } + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + if (!check_subtree (z)) { + return 0; + } + } + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_node (PQ_node *x) +#else +static int check_node (x) +PQ_node *x; +#endif +{ + PQ_node *z, *zprev, *znext; + int cnt; + + cnt = 0; + + if (x == &pseudo_root) { + return 1; + } + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + cnt++; + if (z->parenttype != x->type) { + printf ("Node %x has parenttype %d, parent %x has type %d\n", + (unsigned int) z, z->parenttype, (unsigned int) x, + x->type); + return 0; + } + if (x->type == P_NODE && z->parent != x) { + printf ("Node %x has parent %x, should be P-node %x\n", + (unsigned int) z, (unsigned int) z->parent, + (unsigned int) x); + return 0; + } + if (!((z->children_elem.ptr1 == zprev && z->children_elem.ptr2 != zprev) || + (z->children_elem.ptr2 == zprev && z->children_elem.ptr1 != zprev))) { + printf ("Node %x has children ptr1 %x ptr2 %x, should be =, != %x\n", + (unsigned int) z, (unsigned int) z->children_elem.ptr1, + (unsigned int) z->children_elem.ptr2, + (unsigned int) zprev); + return 0; + } + } + if (x->type == P_NODE && cnt != PQ_set_SIZE (x->children_set)) { + printf ("P-node %x has %d children, set size %d\n", (unsigned int) x, + cnt, PQ_set_SIZE (x->children_set)); + return 0; + } + if (x->type == Q_NODE && PQ_set_LEFT_ELEM (x->children_set)->parent != x) { + printf ("Q_node %x left child %x has parent %x\n", (unsigned int) x, + (unsigned int) PQ_set_LEFT_ELEM (x->children_set), + (unsigned int) PQ_set_LEFT_ELEM (x->children_set)->parent); + return 0; + } + if (x->type == Q_NODE && PQ_set_RIGHT_ELEM (x->children_set)->parent != x) { + printf ("Q_node %x right child %x has parent %x\n", (unsigned int) x, + (unsigned int) PQ_set_RIGHT_ELEM (x->children_set), + (unsigned int) PQ_set_RIGHT_ELEM (x->children_set)->parent); + return 0; + } + if (x->type != LEAF_NODE && x->type != DIR_NODE && PQ_set_ISEMPTY (x->children_set)) { + printf ("node %x is type %d, but has no children\n", (unsigned int) x, + x->type); + return 0; + } + if (x->type == LEAF_NODE && !PQ_set_ISEMPTY (x->children_set)) { + printf ("leaf node %x has children\n", (unsigned int) x); + return 0; + } + if (x->type == DIR_NODE && !PQ_set_ISEMPTY (x->children_set)) { + printf ("dir node %x has children\n", (unsigned int) x); + return 0; + } + if (x->type == DIR_NODE && (x->children_elem.ptr1 == (PQ_node *) NULL || + x->children_elem.ptr2 == (PQ_node *) NULL)) { + printf ("dir node doesn't have 2 neighbors\n"); + return 0; + } + if (x->type == P_NODE && cnt < 2) { + printf ("P-node %d only has %d children\n", x->number, cnt); + return 0; + } + if (x->type == Q_NODE && cnt < ((x->label == PARTIAL) ? 2 : 3)) { + printf ("Q-node %d only has %d children\n", x->number, cnt); + return 0; + } + return 1; +} + +#ifdef CC_PROTOTYPE_ANSI +static int check_node_pert (PQ_node *x) +#else +static int check_node_pert (x) +PQ_node *x; +#endif +{ + if (!check_node_pert_work (x)) { + dump_solution (x); + return 0; + } else { + return 1; + } +} + + +#ifdef CC_PROTOTYPE_ANSI +static int check_node_pert_work (PQ_node *x) +#else +static int check_node_pert_work (x) +PQ_node *x; +#endif +{ + PQ_node *z, *zprev, *znext; + int cnt, full_cnt, partial_cnt, empty_cnt; + + if (!check_node (x)) { + return 0; + } + if (x != &pseudo_root) { + empty_cnt = 0; + full_cnt = 0; + partial_cnt = 0; + PQ_set_FOREACH (x->children_set, z, children_elem, zprev, znext) { + if (IS_EMPTY (z)) + empty_cnt++; + else if (z->label == PARTIAL) + partial_cnt++; + else if (z->label == FULL) + full_cnt++; + else { + printf ("Node %x has label %d\n", (unsigned int) z, z->label); + return 0; + } + if (!IS_EMPTY (z) && x != &pseudo_root && z->parent != x) { + printf ("Node %x has parent %x, should be %x\n", + (unsigned int) z, (unsigned int) z->parent, + (unsigned int) x); + return 0; + } + } + + if (full_cnt != PQ_set_SIZE (x->full_children_set)) { + printf ("node %x has full children size %d, but has %d children full\n", + (unsigned int) x, PQ_set_SIZE (x->full_children_set), + full_cnt); + return 0; + } + if (partial_cnt != PQ_set_SIZE (x->partial_children_set)) { + printf ("node %x has partial children size %d, but has %d children partial\n", + (unsigned int) x, PQ_set_SIZE (x->partial_children_set), + partial_cnt); + return 0; + } + } + cnt = 0; + PQ_set_FOREACH (x->full_children_set, z, full_children_elem, zprev, znext) { + cnt++; + if (!((z->full_children_elem.ptr1 == zprev && z->full_children_elem.ptr2 != zprev) || + (z->full_children_elem.ptr2 == zprev && z->full_children_elem.ptr1 != zprev) || + (z->full_children_elem.ptr1 == zprev && + z->full_children_elem.ptr2 == zprev && zprev == (PQ_node *) NULL))) { + printf ("Node %x has full_children ptr1 %x ptr2 %x, should be =, != %x\n", + (unsigned int) z, + (unsigned int) z->full_children_elem.ptr1, + (unsigned int) z->full_children_elem.ptr2, + (unsigned int) zprev); + return 0; + } + if (z->label != FULL) { + printf ("Node %x has label %d, but is in full set\n", + (unsigned int) z, z->label); + return 0; + } + } + if (cnt != PQ_set_SIZE (x->full_children_set)) { + printf ("node %x has %d full children, set size %d\n", + (unsigned int) x, cnt, PQ_set_SIZE (x->full_children_set)); + return 0; + } + cnt = 0; + PQ_set_FOREACH (x->partial_children_set, z, partial_children_elem, zprev, znext) { + cnt++; + if (!((z->partial_children_elem.ptr1 == zprev && z->partial_children_elem.ptr2 != zprev) || + (z->partial_children_elem.ptr2 == zprev && z->partial_children_elem.ptr1 != zprev) || + (z->partial_children_elem.ptr1 == zprev && + z->partial_children_elem.ptr2 == zprev && zprev == (PQ_node *) NULL))) { + printf ("Node %x has partial_children ptr1 %x ptr2 %x, should be =, != %x\n", + (unsigned int) z, + (unsigned int) z->partial_children_elem.ptr1, + (unsigned int) z->partial_children_elem.ptr2, + (unsigned int) zprev); + return 0; + } + if (z->label != PARTIAL) { + printf ("Node %x has label %d, but is in partial set\n", + (unsigned int) z, (unsigned int) z->label); + return 0; + } + } + if (cnt != PQ_set_SIZE (x->partial_children_set)) { + printf ("node %x has %d partial children, set size %d\n", + (unsigned int) x, cnt, PQ_set_SIZE (x->partial_children_set)); + return 0; + } + return 1; +} + +#endif /* NDEBUG */ + +#ifdef CC_PROTOTYPE_ANSI +PQ_node *XPQ_save_tree (PQ_node *x) +#else +PQ_node *XPQ_save_tree (x) +PQ_node *x; +#endif +{ + PQ_node *rootcopy = PQ_save_work (XPQ_find_root (x)); + + rootcopy->parent = (PQ_node *) NULL; + rootcopy->parenttype = P_NODE; + + return rootcopy; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_save_work (PQ_node *x) +#else +static PQ_node *PQ_save_work (x) +PQ_node *x; +#endif +{ + PQ_node *xcopy = PQ_node_alloc_work (); + PQ_node *y, *yprev, *ynext; + PQ_node *ycopy; + + xcopy->type = x->type; + xcopy->number = x->number; + xcopy->next = x; + PQ_set_INIT (xcopy->children_set); + + PQ_set_FOREACH (x->children_set, y, children_elem, yprev, ynext) { + ycopy = PQ_save_work (y); + ycopy->parent = xcopy; + ycopy->parenttype = xcopy->type; + PQ_set_ADD_LEFT (ycopy, xcopy->children_set, children_elem); + } + return xcopy; +} + +#ifdef CC_PROTOTYPE_ANSI +PQ_node *XPQ_restore_tree (PQ_node *x, int saveleaves) +#else +PQ_node *XPQ_restore_tree (x, saveleaves) +PQ_node *x; +int saveleaves; +#endif +{ + PQ_node *rootcopy = PQ_restore_work (x, saveleaves); + + rootcopy->parent = (PQ_node *) NULL; + rootcopy->parenttype = P_NODE; + + return rootcopy; +} + +#ifdef CC_PROTOTYPE_ANSI +static PQ_node *PQ_restore_work (PQ_node *x, int saveleaves) +#else +static PQ_node *PQ_restore_work (x, saveleaves) +PQ_node *x; +int saveleaves; +#endif +{ + PQ_node *xcopy; + PQ_node *y, *yprev, *ynext; + PQ_node *ycopy; + + if (saveleaves && (x->type == DIR_NODE || x->type == LEAF_NODE)) { + xcopy = x->next; + } else { + xcopy = PQ_node_alloc_work (); + } + + xcopy->type = x->type; + xcopy->number = x->number; + PQ_set_INIT (xcopy->full_children_set); + PQ_set_INIT (xcopy->partial_children_set); + xcopy->label = 0; + xcopy->mark = 0; + xcopy->pertinent_child_count = 0; + xcopy->pertinent_leaf_count = 0; + + PQ_set_INIT (xcopy->children_set); + + PQ_set_FOREACH (x->children_set, y, children_elem, yprev, ynext) { + ycopy = PQ_restore_work (y, saveleaves); + ycopy->parent = xcopy; + ycopy->parenttype = xcopy->type; + PQ_set_ADD_LEFT (ycopy, xcopy->children_set, children_elem); + } + return xcopy; +} + +#ifdef CC_PROTOTYPE_ANSI +void XPQ_save_tree_free (PQ_node *x) +#else +void XPQ_save_tree_free (x) +PQ_node *x; +#endif +{ + PQ_tree_free (x, 0); +} + diff --git a/contrib/blossom/concorde97/XSTUFF/Xpqsets.h b/contrib/blossom/concorde97/XSTUFF/Xpqsets.h new file mode 100644 index 0000000000000000000000000000000000000000..e2874d22990ef82c273c4e690ddc5ce4316dbe96 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xpqsets.h @@ -0,0 +1,278 @@ +#ifndef __XPQSETS_H +#define __XPQSETS_H + +typedef struct PQ_set { + int size; + struct PQ_node *left; + struct PQ_node *right; +} PQ_set; + +typedef struct PQ_elem { + struct PQ_node *ptr1; + struct PQ_node *ptr2; +} PQ_elem; + +/* Summary of the macros: + PQ_set_INIT(PQ_set s) initializes s to the empty set + + PQ_set_ISEMPTY(PQ_set s) is an expression which tests if s is empty + + PQ_set_SIZE(PQ_set s) is the size of s + + PQ_set_PTR_TO(PQ_elem e, PQ_node *q) is the field of e which points to q + + PQ_set_PTR_REPLACE(PQ_elem e, PQ_node *q, PQ_node *r) replaces q with r + in e + + PQ_set_PTR_AWAY(PQ_elem e, PQ_node *q) is the field of e which doesn't + point to q + + PQ_set_ADD_WORK(PQ_node *x, PQ_set s, ELEM_FIELD efield, DIRECTION dir) + adds x to s at the dir end, using the efield field to link things + together. It is intended to be an internal macro used by PQ_set_ADD_LEFT + and PQ_set_ADD_RIGHT. + + PQ_set_ADD_LEFT(PQ_node *x, PQ_set s, ELEM_FIELD efield) adds x to s at + the left end. + + PQ_set_ADD_RIGHT(PQ_node *x, PQ_set s, ELEM_FIELD efield) adds x to s at + the right end. + + PQ_set_ADD(PQ_node *x, PQ_set s, ELEM_FIELD efield) adds x to s + + PQ_set_DELETE(PQ_node *x, PQ_set s, ELEM_FIELD efield) deletes x from s + + PQ_set_DELETE2(PQ_node *x, SET_FIELD sfield, ELEM_FIELD efield) deletes + x from the sfield set of its parent. If x is an endmost child in this + set, then DELETE2 uses the parent pointer to find the set field. + Otherwise, the parent pointer is not used. + + PQ_set_LEFT_ELEM(PQ_set s) is the left element of s, or NULL if s is + empty + + PQ_set_RIGHT_ELEM(PQ_set s) is the right element of s, or NULL if s is + empty + + PQ_set_FOREACH(PQ_set s, PQ_node *x, ELEM_FIELD efield, PQ_node *xprev, + PQ_node *xnext) iterates x over elements of s using + temporary variables xprev and xnext. + + PQ_set_FOREACH_FROM(PQ_node *x, ELEM_FIELD efield, PQ_node *xprev, + PQ_node *xnext) iterates x over elements of s starting + at x and going away from xprev. xnext is a temporary variable used in + the loop, which also changes xprev and x + + PQ_set_FOREACH_DEL(PQ_set s, PQ_node *x, ELEM_FIELD efield, + PQ_node *xprev, PQ_node *xnext) iterates x over + elements of s using temporary variables xprev and xnext. x may be deleted + from the set in the body of the loop (but delete any other element from s + at your own risk). + + PQ_set_FOREACH_ADJ(PQ_node *x, ELEM_FIELD efield, PQ_node *z, int itemp) + iterates z over the immediate neighbors of x using itemp as a temporary + variable. It is just used to save code replication when you want to do + something for each of the two neighbors. + +*/ + + +/* PQ_set_INIT(PQ_set s) initializes s to the empty set */ + +#define PQ_set_INIT(s) { \ + (s).size = 0; \ + (s).left = (PQ_node *) NULL; \ + (s).right = (PQ_node *) NULL; \ +} + +/* In the comments below, something of type ELEM_FIELD is the name of a field + in a PQ_node of type PQ_elem, and something of type DIRECTION is either + left or right. */ + +/* PQ_set_ISEMPTY(PQ_set s) is an expression which tests if s is empty */ + +#define PQ_set_ISEMPTY(s) ((s).left == (PQ_node *) NULL) + +/* PQ_set_SIZE(PQ_set s) is the size of s */ + +#define PQ_set_SIZE(s) ((s).size) + +/* PQ_set_PTR_TO(PQ_elem e, PQ_node *q) is the field of e which points to q */ + +#define PQ_set_PTR_TO(e,q) (((e).ptr1 == (q)) ? ((e).ptr1) : ((e).ptr2)) + +/* PQ_set_PTR_REPLACE(PQ_elem e, PQ_node *q, PQ_node *r) replaces q with r + in e */ + +#define PQ_set_PTR_REPLACE(e,q,r) { \ + if ((e).ptr1 == (q)) { \ + (e).ptr1 = (r); \ + } else { \ + (e).ptr2 = (r); \ + } \ +} + +/* PQ_set_PTR_AWAY(pq_elem e, PQ_node *q) is the field of e which doesn't + point to q */ + +#define PQ_set_PTR_AWAY(e,q) (((e).ptr1 == (q)) ? ((e).ptr2) : ((e).ptr1)) + +/* PQ_set_ADD_WORK(PQ_node *x, PQ_set s, ELEM_FIELD efield, DIRECTION dir) + adds x to s at the dir end, using the efield field to link things + together. It is intended to be an internal macro used by PQ_set_ADD_LEFT + and PQ_set_ADD_RIGHT. */ + +#define PQ_set_ADD_WORK(x,s,efield,dir) { \ + (x)->efield.ptr1 = (s).dir; \ + (x)->efield.ptr2 = (PQ_node *) NULL; \ + if ((s).dir) { \ + PQ_set_PTR_REPLACE((s).dir->efield,(PQ_node *) NULL, (x)); \ + (s).dir = (x); \ + } else { \ + (s).left = (s).right = (x); \ + } \ + (s).size++; \ +} + +/* PQ_set_ADD_LEFT(PQ_node *x, PQ_set s, ELEM_FIELD efield) adds x to s at + the left end. */ + +#define PQ_set_ADD_LEFT(x,s,efield) PQ_set_ADD_WORK(x,s,efield,left) + +/* PQ_set_ADD_RIGHT(PQ_node *x, PQ_set s, ELEM_FIELD efield) adds x to s at + the right end. */ + +#define PQ_set_ADD_RIGHT(x,s,efield) PQ_set_ADD_WORK(x,s,efield,right) + +/* PQ_set_ADD(PQ_node *x, PQ_set s, ELEM_FIELD efield) adds x to s */ + +#define PQ_set_ADD(x,s,efield) PQ_set_ADD_LEFT(x,s,efield) + +/* PQ_set_DELETE(PQ_node *x, PQ_set s, ELEM_FIELD efield) deletes x from s */ + +#define PQ_set_DELETE(x,s,efield) { \ + if (PQ_set_ISEMPTY(s)) { \ + fprintf (stderr, "Error - attempt to delete from empty set\n"); \ + } \ + if ((x)->efield.ptr1) { \ + PQ_set_PTR_REPLACE((x)->efield.ptr1->efield,(x),(x)->efield.ptr2); \ + } else { \ + if ((s).left == (x)) { \ + (s).left = (x)->efield.ptr2; \ + } else { \ + (s).right = (x)->efield.ptr2; \ + } \ + } \ + if ((x)->efield.ptr2) { \ + PQ_set_PTR_REPLACE((x)->efield.ptr2->efield,(x),(x)->efield.ptr1);\ + } else { \ + if ((s).right == (x)) { \ + (s).right = (x)->efield.ptr1; \ + } else { \ + (s).left = (x)->efield.ptr1; \ + } \ + } \ + (s).size--; \ +} + +/* PQ_set_DELETE2(PQ_node *x, SET_FIELD sfield, ELEM_FIELD efield) deletes + x from the sfield set of its parent. If x is an endmost child in this + set, then DELETE2 uses the parent pointer to find the set field. + Otherwise, the parent pointer is not used. If the parent pointer is + NULL, then the parent update is ignored. */ + +#define PQ_set_DELETE2(x,sfield,efield) { \ + if ((x)->efield.ptr1) { \ + PQ_set_PTR_REPLACE((x)->efield.ptr1->efield,(x),(x)->efield.ptr2); \ + } else if ((x)->parent) { \ + if ((x)->parent->sfield.left == (x)) { \ + (x)->parent->sfield.left = (x)->efield.ptr2; \ + } else { \ + (x)->parent->sfield.right = (x)->efield.ptr2; \ + } \ + } \ + if ((x)->efield.ptr2) { \ + PQ_set_PTR_REPLACE((x)->efield.ptr2->efield,(x),(x)->efield.ptr1);\ + } else if ((x)->parent) { \ + if ((x)->parent->sfield.right == (x)) { \ + (x)->parent->sfield.right = (x)->efield.ptr1; \ + } else { \ + (x)->parent->sfield.left = (x)->efield.ptr1; \ + } \ + } \ + if ((x)->parent) { \ + (x)->parent->sfield.size--; \ + } \ +} + +/* PQ_set_LEFT_ELEM(PQ_set s) is the left element of s, or NULL if s is + empty */ + +#define PQ_set_LEFT_ELEM(s) ((s).left) + +/* PQ_set_RIGHT_ELEM(PQ_set s) is the right element of s, or NULL if s is + empty */ + +#define PQ_set_RIGHT_ELEM(s) ((s).right) + +/* PQ_set_FOREACH(PQ_set s, PQ_node *x, ELEM_FIELD efield, PQ_node *xprev, + PQ_node *xnext) iterates x over elements of s using + temporary variables xprev and xnext. */ + +#define PQ_set_FOREACH(s,x,efield,xprev,xnext) \ + for ((xprev) = (PQ_node *) NULL, \ + (x) = (s).left; \ + (x); \ + (xnext) = PQ_set_PTR_AWAY((x)->efield,xprev), \ + (xprev) = (x), \ + (x) = (xnext) \ +) + +/* PQ_set_FOREACH_FROM(PQ_node *x, ELEM_FIELD efield, PQ_node *xprev, + PQ_node *xnext) iterates x over elements of s starting + at x and going away from xprev. xnext is a temporary variable used in + the loop, which also changes xprev and x */ + +#define PQ_set_FOREACH_FROM(x,efield,xprev,xnext) \ + for (; \ + (x); \ + (xnext) = PQ_set_PTR_AWAY((x)->efield,xprev), \ + (xprev) = (x), \ + (x) = (xnext) \ +) + +/* PQ_set_FOREACH_DEL(PQ_set s, PQ_node *x, ELEM_FIELD efield, + PQ_node *xprev, PQ_node *xnext) iterates x over + elements of s using temporary variables xprev and xnext. x may be deleted + from the set in the body of the loop (but delete any other element from s + at your own risk). */ + +#define PQ_set_FOREACH_DEL(s,x,efield,xprev,xnext) \ + for ((xprev) = (PQ_node *) NULL, \ + (x) = (s).left, \ + (xnext) = ((x) ? PQ_set_PTR_AWAY((x)->efield,(PQ_node *) NULL) \ + : (PQ_node *) NULL); \ + (x); \ + (xprev) = (((xprev) ? (((xprev)->efield.ptr1 == (x)) \ + || ((xprev)->efield.ptr2 == (x))) \ + : ((s).left == (x))) \ + ? (x) : (xprev)), \ + (x) = (xnext), \ + (xnext) = ((x) ? PQ_set_PTR_AWAY((x)->efield, xprev) \ + : (PQ_node *) NULL) \ +) + +/* PQ_set_FOREACH_ADJ(PQ_node *x, ELEM_FIELD efield, PQ_node *z, int itemp) + iterates z over the immediate neighbors of x using itemp as a temporary + variable. It is just used to save code replication when you want to do + something for each of the two neighbors. */ + +#define PQ_set_FOREACH_ADJ(x,efield,z,itemp) \ + for (z = x->efield.ptr1, itemp = 0; \ + itemp < 2; \ + z = x->efield.ptr2, itemp++) + +#ifndef SWAP +#define SWAP(x, y, t) (((t) = (x)),((x) = (y)),((y) = (t))) +#endif + +#endif /* __XPQSETS_H */ diff --git a/contrib/blossom/concorde97/XSTUFF/Xshrink.c b/contrib/blossom/concorde97/XSTUFF/Xshrink.c new file mode 100644 index 0000000000000000000000000000000000000000..7af67b61ea4929221c84ab64f9b0423715b11ce3 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xshrink.c @@ -0,0 +1,482 @@ +/**************************************************************************/ +/* */ +/* EXPORTED FUNCTIONS: */ +/* */ +/* int shrinkprocess (); */ +/* void buildpseudonodelist (); */ +/* void buildpseudonodenumbers (); */ +/* void destroypseudonodelist (); */ +/* void dumppseudograph (); */ +/* void dumppseudograph_edgelist () */ +/* void simpleshrink (); */ +/* void rebuildcadj (); */ +/* */ +/**************************************************************************/ + +#include "machdefs.h" +#include "Xsubtour.h" + +#ifdef CC_PROTOTYPE_ANSI + +static void + markedge (Xgraph *G, Xedge *e), + marknode (Xnode *n, int v), + deletepseudonode (Xgraph *G, Xnode *), + destroynode (Xnode *), + mergebase (Xnode *, Xnode *), + rebuildnodecadj (Xnode *); + +static int + mergeadj (Xgraph *G, Xcplane **, Xnode *, Xnode *, Xnode **, int); + +#else + +static void + markedge (), + marknode (), + deletepseudonode (), + destroynode (), + mergebase (), + rebuildnodecadj (); + +static int + mergeadj (); + +#endif + +#ifdef CC_PROTOTYPE_ANSI +void Xbuildpseudonodelist (Xgraph *G, int all) +#else +void Xbuildpseudonodelist (G, all) +Xgraph *G; +int all; +#endif +{ + int i; + Xnode *n; + Xedge *e; + Xedgeptr *e1; + static Xnode pseudodummy; + + G->pseudonodelist = &pseudodummy; + pseudodummy.prev = (Xnode *) NULL; + pseudodummy.next = G->nodelist; + for (i = 0, n = G->nodelist; i < G->nnodes; i++, n++) { + n->base.head = Xnodeptralloc (); + n->base.tail = n->base.head; + n->base.head->next = (Xnodeptr *) NULL; + n->base.head->this = n; + n->cadj.head = n->cadj.tail = (Xedgeptr *) NULL; + n->prev = n - 1; + n->next = n + 1; + } + G->nodelist->prev = G->pseudonodelist; + G->nodelist[G->nnodes - 1].next = (Xnode *) NULL; + + for (i = G->nedges, e = G->edgelist; i; i--, e++) + if (all || e->x > 0.00001) { /* 0.0 */ + e->stay = 1; + e->cends[0] = e->ends[0]; + e->cends[1] = e->ends[1]; + e1 = Xedgeptralloc (); + e1->next = (e->cends[0])->cadj.head; + e1->this = e; + (e->cends[0])->cadj.head = e1; + if ((e->cends[0])->cadj.tail == (Xedgeptr *) NULL) + (e->cends[0])->cadj.tail = e1; + e1 = Xedgeptralloc (); + e1->next = (e->cends[1])->cadj.head; + e1->this = e; + (e->cends[1])->cadj.head = e1; + if ((e->cends[1])->cadj.tail == (Xedgeptr *) NULL) + (e->cends[1])->cadj.tail = e1; + } else + e->stay = 0; + G->npseudonodes = G->nnodes; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xbuildpseudonodenumbers (Xgraph *G) +#else +void Xbuildpseudonodenumbers (G) +Xgraph *G; +#endif +{ + int i = 0; + Xnode *n; + + for (n = G->pseudonodelist->next; n; n = n->next, i++) + n->pseudonumber = i; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xdumppseudograph (Xgraph *G) +#else +void Xdumppseudograph (G) +Xgraph *G; +#endif +{ + Xnode *n; + Xedge *e; + Xedgeptr *ep; + int i; + + printf ("PSEUDOGRAPH:\n"); + printf ("nnodes = %d nodes: ", G->npseudonodes); + for (i = 0, n = G->pseudonodelist->next; n; n = n->next, i++) { + printf (" %d", (int) (n - G->nodelist)); + if (i % 10 == 9) + printf ("\n"); + } + if (i % 10) + printf ("\n"); + for (n = G->pseudonodelist->next; n; n = n->next) { + printf ("node %d: ", (int) (n - G->nodelist)); + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->stay) + printf (" (%d, %d, %.2f)", + (int) (e->cends[0] - G->nodelist), + (int) (e->cends[1] - G->nodelist), + e->x); + } +/* + printf (" base: "); + for (np = n->base.head; np; np = np->next) + printf ("%d ", (int) (np->this - G->nodelist)); +*/ + printf ("\n"); + } + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xdumppseudograph_edgelist (Xgraph *G) +#else +void Xdumppseudograph_edgelist (G) +Xgraph *G; +#endif +{ + Xnode *n; + Xedge *e; + Xedgeptr *ep; + int count; + + printf ("PSEUDOGRAPH EDGELIST:\n"); + Xbuildpseudonodenumbers (G); + for (count = 0, n = G->pseudonodelist->next; n; n = n->next) + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->stay) + count++; + } + printf ("%d %d\n", G->npseudonodes, count / 2); + G->magicedgenum++; + for (n = G->pseudonodelist->next; n; n = n->next) + for (ep = n->cadj.head; ep; ep = ep->next) { + e = ep->this; + if (e->stay && e->magiclabel != G->magicedgenum) { + e->magiclabel = G->magicedgenum; + printf ("%d %d %f\n", + e->cends[0]->pseudonumber, + e->cends[1]->pseudonumber, + e->x); + } + } + + fflush (stdout); +} + +#ifdef CC_PROTOTYPE_ANSI +void Xdestroypseudonodelist (Xgraph *G) +#else +void Xdestroypseudonodelist (G) +Xgraph *G; +#endif +{ + Xnode *n; + + for (n = G->pseudonodelist->next; n; n = n->next) { + destroynode (n); + } + G->npseudonodes = 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void destroynode (Xnode *n) +#else +static void destroynode (n) +Xnode *n; +#endif +{ + Xedgeptr *e, *enext; + Xnodeptr *np, *npnext; + + + for (e = n->cadj.head; e; e = enext) { + enext = e->next; + Xedgeptrfree (e); + } + for (np = n->base.head; np; np = npnext) { + npnext = np->next; + Xnodeptrfree (np); + } +} + +#ifdef CC_PROTOTYPE_ANSI +int Xshrinkprocess (Xgraph *G, Xcplane **list) +#else +int Xshrinkprocess (G, list) +Xgraph *G; +Xcplane **list; +#endif +{ + Xnode *stack, headstack, *n1, *n2; + int i, returnval = 0; + Xedge *e; + + stack = &headstack; + stack->snext = (Xnode *) NULL; + + for (i = G->nedges, e = G->edgelist; i; e++, i--) { + if (G->npseudonodes <= 3) + return returnval; + if (!e->stay) + continue; + if (e->x < 1.0 - XEPSILON) + continue; + if (e->x > 1.0 + XEPSILON) { + markedge (G, e); + returnval += Xloadcplane_cut (G, list, G->magicnum); + } + n1 = e->cends[0]; + e->cends[1]->snext = stack; + stack = e->cends[1]; + n1->stacklabel = ++(G->stacknum); + do { + if (G->npseudonodes <= 3) + return returnval; + n2 = stack; + stack = stack->snext; + + mergebase (n1, n2); + returnval += mergeadj (G, list, n1, n2, &stack, 1); + deletepseudonode (G, n2); + } while (stack != &headstack); + } + return returnval; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xsimpleshrink (Xgraph *G, Xnode *n1, Xnode *n2) +#else +void Xsimpleshrink (G, n1, n2) +Xgraph *G; +Xnode *n1, *n2; +#endif +{ + Xnode dummystack, *stack, *n3; + Xedgeptr *e; + + stack = &dummystack; + mergebase (n1, n2); + mergeadj (G, (Xcplane **) NULL, n1, n2, &stack, 0); + /* since repeat = 0, dont load */ + deletepseudonode (G, n2); + for (e = n1->cadj.head; e; e = e->next) + if (e->this->stay) { + n3 = OTHERCURRENTEND (e->this, n1); + rebuildnodecadj (n3); + } + rebuildnodecadj (n1); +} + +#ifdef CC_PROTOTYPE_ANSI +static void markedge (Xgraph *G, Xedge *e) +#else +static void markedge (G, e) +Xgraph *G; +Xedge *e; +#endif +{ + G->magicnum++; + marknode (e->cends[0], G->magicnum); + marknode (e->cends[1], G->magicnum); +} + +#ifdef CC_PROTOTYPE_ANSI +static void marknode (Xnode *n, int v) +#else +static void marknode (n, v) +Xnode *n; +int v; +#endif +{ + Xnodeptr *np; + + n->magiclabel = v; + for (np = n->base.head; np; np = np->next) { + np->this->magiclabel = v; + } +} + +#ifdef CC_PROTOTYPE_ANSI +static void mergebase (Xnode *n1, Xnode *n2) +#else +static void mergebase (n1, n2) +Xnode *n1, *n2; +#endif +{ + n1->base.tail->next = n2->base.head; + n1->base.tail = n2->base.tail; +} + +#ifdef CC_PROTOTYPE_ANSI +static int mergeadj (Xgraph *G, Xcplane **list, Xnode *n1, Xnode *n2, + Xnode **pstack, int repeat) +#else +static int mergeadj (G, list, n1, n2, pstack, repeat) +Xgraph *G; +Xcplane **list; +Xnode *n1, *n2, **pstack; +int repeat; +#endif +{ + Xedgeptr *e, *memo; + Xnode *stack, *n3; + int returnval = 0; + + stack = *pstack; + + for (e = n2->cadj.head; e != (Xedgeptr *) NULL; e = e->next) { + if (!e->this->stay) + continue; + if (OTHERCURRENTEND (e->this, n2) == n1) + e->this->stay = 0; + else + (OTHERCURRENTEND (e->this, n2))->pe = (Xedge *) NULL; + } + + for (e = n1->cadj.head; e != (Xedgeptr *) NULL; e = e->next) + if (e->this->stay) + (OTHERCURRENTEND (e->this, n1))->pe = e->this; + + for (e = n2->cadj.head; e != (Xedgeptr *) NULL;) { + if (!e->this->stay) { + memo = e; + e = e->next; + Xedgeptrfree (memo); + } else if ((n3 = (OTHERCURRENTEND (e->this, n2)))->pe + != (Xedge *) NULL) { + n3->pe->x += e->this->x; + n3->pe->rc += e->this->rc; + e->this->stay = 0; + memo = e; + e = e->next; + Xedgeptrfree (memo); + if (n3->pe->x > 1.0 + XEPSILON && repeat) { + markedge (G, n3->pe); + returnval += Xloadcplane_cut (G, list, G->magicnum); + if (n3->stacklabel != G->stacknum) { + n3->snext = stack; + stack = n3; + n3->stacklabel = G->stacknum; + } + } + if (n3->pe->x > 1.0 - XEPSILON && + n3->stacklabel != G->stacknum && repeat) { + n3->snext = stack; + stack = n3; + } + } else { + n1->cadj.tail->next = e; + n1->cadj.tail = e; + if (e->this->cends[0] == n2) + e->this->cends[0] = n1; + else + e->this->cends[1] = n1; + e = e->next; + } + } + n1->cadj.tail->next = (Xedgeptr *) NULL; + return returnval; +} + +#ifdef CC_PROTOTYPE_ANSI +static void deletepseudonode (Xgraph *G, Xnode *n2) +#else +static void deletepseudonode (G, n2) +Xgraph *G; +Xnode *n2; +#endif +{ + n2->prev->next = n2->next; + if (n2->next != (Xnode *) NULL) + n2->next->prev = n2->prev; + G->npseudonodes--; +} + +#ifdef CC_PROTOTYPE_ANSI +void Xrebuildcadj (Xgraph *G) +#else +void Xrebuildcadj (G) +Xgraph *G; +#endif +{ + Xnode *n; + + for (n = G->pseudonodelist->next; n; n = n->next) + rebuildnodecadj (n); +} + +#ifdef CC_PROTOTYPE_ANSI +static void rebuildnodecadj (Xnode *n) +#else +static void rebuildnodecadj (n) +Xnode *n; +#endif +{ + Xedgeptr *e, *olde, *memo; + + olde = n->cadj.head; + while (olde && !olde->this->stay) { + memo = olde; + olde = olde->next; + Xedgeptrfree (memo); + } + n->cadj.head = olde; + if (!olde) + return; + + e = olde->next; + while (e) { + if (!e->this->stay) { + olde->next = e->next; + memo = e; + e = e->next; + Xedgeptrfree (memo); + } else { + olde = e; + e = e->next; + } + } + n->cadj.tail = olde; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xheavy_edge_cuts (Xgraph *G, Xcplane **list, double *x) +#else +int Xheavy_edge_cuts (G, list, x) +Xgraph *G; +Xcplane **list; +double *x; +#endif +{ + int cnt; + + Xloadx (G, x); + Xbuildpseudonodelist (G, 0); + cnt = Xshrinkprocess (G, list); + Xdestroypseudonodelist (G); + return cnt; +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xstuff.c b/contrib/blossom/concorde97/XSTUFF/Xstuff.c new file mode 100644 index 0000000000000000000000000000000000000000..8a1924ffe7c22ae827f06e9588c1231aece088f7 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xstuff.c @@ -0,0 +1,892 @@ +/***************************************************************************/ +/* */ +/* Interface to a subset of the old subtour routines */ +/* */ +/* */ +/* WARNING: These routines are messy ports of old cut, they use many */ +/* static variables, may not clean up their memory, and are known to */ +/* have bugs. These routines will not be included in future versions */ +/* of concorde. */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: Novemeber 6, 1995 */ +/* */ +/* Exported Functions: */ +/* */ +/* int */ +/* Xfastcuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, */ +/* int ecount, int *elist, double *x), */ +/* Xslowcuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, */ +/* int ecount, int *elist, double *x), */ +/* Xfastsubtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, */ +/* int ecount, int *elist, double *x), */ +/* Xexactsubtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, */ +/* int ecount, int *elist, double *x), */ +/* Xcliquetrees (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, */ +/* int ecount, int *elist, double *x), */ +/* Xconsecutiveones (CCtsp_lpcut_in **cuts, int *cutcount, */ +/* int ncount, int ecount, int *elist, double *x, */ +/* CCtsp_lpcuts *pool) */ +/* Xnecklacecuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, */ +/* int ecount, int *elist, double *x, CCtsp_lpcuts *pool)*/ +/* -cuts should point to a NULL terminated cutlist. The new cuts */ +/* will be added to the front of this list. */ +/* -cutcount will return the number of new cuts found. */ +/* */ +/* Link with: */ +/* SEE conmake.grs */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" +#include "Xsubtour.h" +#include "Xstuff.h" + +#ifdef CC_PROTOTYPE_ANSI + +static int + munch_the_list (CCtsp_lpcut_in **cuts, int *cutcount, Xgraph *G, + Xcplane *list), + send_the_cut (CCtsp_lpcut_in **cuts, Xgraph *G, Xcplane *c), + cplane_to_lpcut_in (Xgraph *G, Xcplane *c, CCtsp_lpcut_in *lc), + nodeptr_to_lpclique (Xgraph *G, Xnodeptr *npclique, CCtsp_lpclique *cliq); + +#else + +static int + munch_the_list (), + send_the_cut (), + cplane_to_lpcut_in (), + nodeptr_to_lpclique (); + +#endif + +static CCtsp_lpcuts *xpool = (CCtsp_lpcuts *) NULL; + +#ifdef CC_PROTOTYPE_ANSI +int Xfastcuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x) +#else +int Xfastcuts (cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount; +int ecount; +int *elist; +double *x; +#endif +{ + double szeit = CCutil_zeit (); + double tzeit; + Xcplane *list = (Xcplane *) NULL; + int i, cnt; + int *elen = (int *) NULL; + Xgraph G; + int rval = 0; + + *cutcount = 0; + + G.nodelist = (Xnode *) NULL; + G.edgelist = (Xedge *) NULL; + + elen = CC_SAFE_MALLOC (ecount, int); + if (!elen) { + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < ecount; i++) + elen[i] = 0; + + if (Xbuildgraph (&G, ncount, ecount, elist, elen)) { + fprintf (stderr, "Xbuildgraph failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Xfastcuts:\n"); fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xrunconnectcuts (&G, &list, x); + printf (" %d connect cuts in %.2f seconds\n", cnt, + CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xheavy_edge_cuts (&G, &list, x); + printf (" %d heavy-edge cuts in %.2f seconds\n", cnt, + CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xblobcuts (&G, &list, x); + printf (" %d blob cuts in %.2f seconds\n", cnt, CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xblockcombs (&G, &list, x); + printf (" %d block combs in %.2f seconds\n", cnt, CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xlocalcombs (&G, &list, x); + printf (" %d local combs in %.2f seconds\n", cnt, CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xglobalcombs (&G, &list, x); + printf (" %d global combs in %.2f seconds\n", cnt, + CCutil_zeit () - tzeit); + fflush (stdout); + + { + Xcplane *c, *cnext; + int ksub = 0, kcomb = 0, kctree = 0, k = 0; + + for (c = list; c; c = c->next) { + k++; + if (c->handle) { + if (!c->teeth) + ksub++; + else + kcomb++; + } else { + if (!c->teeth) + ksub++; + else { + if (!c->handles->next) + kcomb++; + else + kctree++; + } + } + } + + printf ("\n%d CUTS (%d subtours, %d combs, %d cliquetrees)\n", + k, ksub, kcomb, kctree); + for (c = list; c; c = cnext) { + cnext = c->next; + if (send_the_cut (cuts, &G, c)) { + fprintf (stderr, "send_the_cut failed\n"); + rval = 1; + goto CLEANUP; + } + Xfreecplanestruct (c); + (*cutcount)++; + } + } + + + printf ("Total Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + Xfreegraph (&G); + CC_IFFREE (elen, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xslowcuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x) +#else +int Xslowcuts (cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount; +int ecount; +int *elist; +double *x; +#endif +{ + double szeit = CCutil_zeit (); + double tzeit; + Xcplane *list = (Xcplane *) NULL; + int i, cnt; + int *elen = (int *) NULL; + Xgraph G; + int rval = 0; + + *cutcount = 0; + + G.nodelist = (Xnode *) NULL; + G.edgelist = (Xedge *) NULL; + + elen = CC_SAFE_MALLOC (ecount, int); + if (!elen) { + rval = 1; + goto CLEANUP; + } + + for (i = 0; i < ecount; i++) + elen[i] = 0; + + if (Xbuildgraph (&G, ncount, ecount, elist, elen)) { + fprintf (stderr, "Xbuildgraph failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Xslowcuts:\n"); fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xexactblossoms_run (&G, &list, x); + printf (" %d exact blossoms in %.2f seconds\n", cnt, + CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xolaf_combs (&G, &list, x); + printf (" %d olaf combs in %.2f seconds\n", cnt, CCutil_zeit () - tzeit); + fflush (stdout); + + { + Xcplane *c, *cnext; + int ksub = 0, kcomb = 0, kctree = 0, k = 0; + + for (c = list; c; c = c->next) { + k++; + if (c->handle) { + if (!c->teeth) + ksub++; + else + kcomb++; + } else { + if (!c->teeth) + ksub++; + else { + if (!c->handles->next) + kcomb++; + else + kctree++; + } + } + } + + printf ("\n%d CUTS (%d subtours, %d combs, %d cliquetrees)\n", + k, ksub, kcomb, kctree); + for (c = list; c; c = cnext) { + cnext = c->next; + if (send_the_cut (cuts, &G, c)) { + fprintf (stderr, "send_the_cut failed\n"); + rval = 1; + goto CLEANUP; + } + Xfreecplanestruct (c); + (*cutcount)++; + } + } + + printf ("Total Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + Xfreegraph (&G); + CC_IFFREE (elen, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xfastsubtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x) +#else +int Xfastsubtours (cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount; +int ecount; +int *elist; +double *x; +#endif +{ + double tzeit; + Xcplane *list = (Xcplane *) NULL; + int i, cnt, rval = 0; + int *elen = (int *) NULL; + Xgraph G; + + *cutcount = 0; + + G.nodelist = (Xnode *) NULL; + G.edgelist = (Xedge *) NULL; + + elen = CC_SAFE_MALLOC (ecount, int); + if (!elen) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ecount; i++) + elen[i] = 0; + + if (Xbuildgraph (&G, ncount, ecount, elist, elen)) { + fprintf (stderr, "Xbuildgraph failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Xfastsubtours:\n"); fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xrunconnectcuts (&G, &list, x); + printf (" %d connect cuts in %.2f seconds\n", cnt, + CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xheavy_edge_cuts (&G, &list, x); + printf (" %d heavy-edge cuts in %.2f seconds\n", cnt, + CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + cnt = Xblobcuts (&G, &list, x); + printf (" %d blob cuts in %.2f seconds\n", cnt, + CCutil_zeit () - tzeit); + fflush (stdout); + + + if (munch_the_list (cuts, cutcount, &G, list)) { + fprintf (stderr, "munch_the_list failed\n"); + return 1; + } + +CLEANUP: + + Xfreegraph (&G); + CC_IFFREE (elen, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xexactsubtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x) +#else +int Xexactsubtours (cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount; +int ecount; +int *elist; +double *x; +#endif +{ + double tzeit; + Xcplane *list = (Xcplane *) NULL; + int i, rval = 0; + int *elen = (int *) NULL; + Xgraph G; + + *cutcount = 0; + + G.nodelist = (Xnode *) NULL; + G.edgelist = (Xedge *) NULL; + + elen = CC_SAFE_MALLOC (ecount, int); + if (!elen) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ecount; i++) + elen[i] = 0; + + if (Xbuildgraph (&G, ncount, ecount, elist, elen)) { + fprintf (stderr, "Xbuildgraph failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Xexactcutcheck:\n"); fflush (stdout); + tzeit = CCutil_zeit (); + i = Xexactcutcheck (&G, &list, x); + printf (" %d exact cuts in %.2f seconds\n", i, CCutil_zeit () - tzeit); + fflush (stdout); + + if (munch_the_list (cuts, cutcount, &G, list)) { + fprintf (stderr, "munch_the_list failed\n"); + return 1; + } + +CLEANUP: + + Xfreegraph (&G); + CC_IFFREE (elen, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xconsecutiveones (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x, CCtsp_lpcuts *pool) +#else +int Xconsecutiveones (cuts, cutcount, ncount, ecount, elist, x, pool) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount; +int ecount; +int *elist; +double *x; +CCtsp_lpcuts *pool; +#endif +{ + double tzeit; + Xcplane *list = (Xcplane *) NULL; + int i, rval = 0; + int *elen = (int *) NULL; + Xgraph G; + + xpool = pool; + + *cutcount = 0; + + G.nodelist = (Xnode *) NULL; + G.edgelist = (Xedge *) NULL; + + elen = CC_SAFE_MALLOC (ecount, int); + if (!elen) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ecount; i++) + elen[i] = 0; + + if (Xbuildgraph (&G, ncount, ecount, elist, elen)) { + fprintf (stderr, "Xbuildgraph failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Xconsecutiveones:\n"); fflush (stdout); + tzeit = CCutil_zeit (); + i = Xnewkids (&G, x, &list); + printf (" %d consecutive ones cuts in %.2f seconds\n", i, + CCutil_zeit () - tzeit); + fflush (stdout); + + if (munch_the_list (cuts, cutcount, &G, list)) { + fprintf (stderr, "munch_the_list failed\n"); + return 1; + } + +CLEANUP: + + Xfreegraph (&G); + CC_IFFREE (elen, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xnecklacecuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x, CCtsp_lpcuts *pool) +#else +int Xnecklacecuts (cuts, cutcount, ncount, ecount, elist, x, pool) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount; +int ecount; +int *elist; +double *x; +CCtsp_lpcuts *pool; +#endif +{ + double tzeit; + Xcplane *list = (Xcplane *) NULL; + int i, rval = 0; + int *elen = (int *) NULL; + Xgraph G; + + xpool = pool; + + *cutcount = 0; + + G.nodelist = (Xnode *) NULL; + G.edgelist = (Xedge *) NULL; + + elen = CC_SAFE_MALLOC (ecount, int); + if (!elen) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ecount; i++) + elen[i] = 0; + + if (Xbuildgraph (&G, ncount, ecount, elist, elen)) { + fprintf (stderr, "Xbuildgraph failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Xnecklaces:\n"); fflush (stdout); + tzeit = CCutil_zeit (); + i = Xnecklaces (&G, &list, x); + printf (" %d necklace cuts in %.2f seconds\n", i, CCutil_zeit () - tzeit); + fflush (stdout); + + if (munch_the_list (cuts, cutcount, &G, list)) { + fprintf (stderr, "munch_the_list failed\n"); + return 1; + } + +CLEANUP: + + Xfreegraph (&G); + CC_IFFREE (elen, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xcliquetrees (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x) +#else +int Xcliquetrees (cuts, cutcount, ncount, ecount, elist, x) +CCtsp_lpcut_in **cuts; +int *cutcount; +int ncount; +int ecount; +int *elist; +double *x; +#endif +{ + double tzeit, szeit = CCutil_zeit (); + Xcplane *list = (Xcplane *) NULL; + int i, rval = 0; + int *elen = (int *) NULL; + Xgraph G; + + *cutcount = 0; + + G.nodelist = (Xnode *) NULL; + G.edgelist = (Xedge *) NULL; + + elen = CC_SAFE_MALLOC (ecount, int); + if (!elen) { + rval = 1; + goto CLEANUP; + } + for (i = 0; i < ecount; i++) + elen[i] = 0; + + if (Xbuildgraph (&G, ncount, ecount, elist, elen)) { + fprintf (stderr, "Xbuildgraph failed\n"); + rval = 1; + goto CLEANUP; + } + + printf ("Xcliquetrees:\n"); fflush (stdout); + tzeit = CCutil_zeit (); + i = Xcliquetree (&G, &list, x); + printf (" %d cliquetrees in %.2f seconds\n", i, CCutil_zeit () - tzeit); + fflush (stdout); + + tzeit = CCutil_zeit (); + i = Xbasiccliques (&G, &list, x); + printf (" %d basic cliquetrees in %.2f seconds\n", i, + CCutil_zeit () - tzeit); + fflush (stdout); + + if (munch_the_list (cuts, cutcount, &G, list)) { + fprintf (stderr, "munch_the_list failed\n"); + return 1; + } + + printf ("Total Running Time: %.2f (seconds)\n", CCutil_zeit () - szeit); + fflush (stdout); + +CLEANUP: + + Xfreegraph (&G); + CC_IFFREE (elen, int); + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int munch_the_list (CCtsp_lpcut_in **cuts, int *cutcount, Xgraph *G, + Xcplane *list) +#else +static int munch_the_list (cuts, cutcount, G, list) +CCtsp_lpcut_in **cuts; +int *cutcount; +Xgraph *G; +Xcplane *list; +#endif +{ + Xcplane *c, *cnext; + + for (c = list; c; c = cnext) { + cnext = c->next; + if (send_the_cut (cuts, G, c)) { + fprintf (stderr, "send_the_cut failed\n"); + return 1; + } + Xfreecplanestruct (c); + (*cutcount)++; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int send_the_cut (CCtsp_lpcut_in **cuts, Xgraph *G, Xcplane *c) +#else +static int send_the_cut (cuts, G, c) +CCtsp_lpcut_in **cuts; +Xgraph *G; +Xcplane *c; +#endif +{ + CCtsp_lpcut_in *lc; + + lc = CC_SAFE_MALLOC (1, CCtsp_lpcut_in); + if (!lc) { + fprintf (stderr, "out of memory in send_the_cut\n"); + return 1; + } + + if (cplane_to_lpcut_in (G, c, lc)) { + fprintf (stderr, "cplane_to_lpcut_in failed\n"); + CC_FREE (lc, CCtsp_lpcut_in); + return 1; + } + + lc->next = *cuts; + *cuts = lc; + +#ifdef XSTUFF_DEBUG + CCtsp_print_lpcut_in (lc); +#endif + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int cplane_to_lpcut_in (Xgraph *G, Xcplane *c, CCtsp_lpcut_in *lc) +#else +static int cplane_to_lpcut_in (G, c, lc) +Xgraph *G; +Xcplane *c; +CCtsp_lpcut_in *lc; +#endif +{ + Xnodeptrptr *npp; + int hcnt = 0, ccnt = 0; + + lc->handlecount = 0; + lc->cliquecount = 0; + lc->cliques = (CCtsp_lpclique *) NULL; + + if (c->handle) { + ccnt++; + if (c->teeth) + hcnt++; + } else { + for (npp = c->handles; npp; npp = npp->next) { + hcnt++; + ccnt++; + } + } + for (npp = c->teeth; npp; npp = npp->next) + ccnt++; + + lc->cliques = CC_SAFE_MALLOC (ccnt, CCtsp_lpclique); + if (!lc->cliques) { + fprintf (stderr, "out of memory in cplane_to_lpcut_in\n"); + return 1; + } + + ccnt = 0; + if (c->handle) { + if (nodeptr_to_lpclique (G, c->handle, &(lc->cliques[ccnt++]))) { + fprintf (stderr, "nodeptr_to_lpclique failed\n"); + CC_FREE (lc->cliques, CCtsp_lpclique); + return 1; + } + } else { + for (npp = c->handles; npp; npp = npp->next) { + if (nodeptr_to_lpclique (G, npp->this, &(lc->cliques[ccnt++]))) { + fprintf (stderr, "nodeptr_to_lpclique failed\n"); + CC_FREE (lc->cliques, CCtsp_lpclique); + return 1; + } + } + } + for (npp = c->teeth; npp; npp = npp->next) { + if (nodeptr_to_lpclique (G, npp->this, &(lc->cliques[ccnt++]))) { + fprintf (stderr, "nodeptr_to_lpclique failed\n"); + CC_FREE (lc->cliques, CCtsp_lpclique); + return 1; + } + } + lc->handlecount = hcnt; + lc->cliquecount = ccnt; + lc->rhs = CCtsp_CUTRHS(lc); + lc->sense = 'G'; + lc->branch = 0; + + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static int nodeptr_to_lpclique (Xgraph *G, Xnodeptr *npcliq, + CCtsp_lpclique *cliq) +#else +static int nodeptr_to_lpclique (G, npcliq, cliq) +Xgraph *G; +Xnodeptr *npcliq; +CCtsp_lpclique *cliq; +#endif +{ + int i, k = 0; + Xnodeptr *np; + int *ac = (int *) NULL; + int nseg; + + cliq->segcount = 0; + cliq->nodes = (CCtsp_segment *) NULL; + + for (np = npcliq; np; np = np->next) + k++; + + if (!k) { + fprintf (stderr, "empty clique in nodeptr_to_lpclique\n"); + return 1; + } + + ac = CC_SAFE_MALLOC (k, int); + if (!ac) { + fprintf (stderr, "out of memory in nodeptr_to_lpclique\n"); + return 1; + } + + for (i = 0, np = npcliq; np; np = np->next, i++) { + ac[i] = np->this - G->nodelist; + } + + CCutil_int_array_quicksort (ac, k); + + nseg = 0; + i = 0; + while (i < k) { + while (i < (k - 1) && ac[i + 1] == (ac[i] + 1)) + i++; + i++; + nseg++; + } + + cliq->nodes = CC_SAFE_MALLOC (nseg, CCtsp_segment); + if (!cliq->nodes) { + fprintf (stderr, "out of memory in in nodeptr_to_lpclique\n"); + CC_FREE (ac, int); + return 1; + } + cliq->segcount = nseg; + + nseg = 0; + i = 0; + while (i < k) { + cliq->nodes[nseg].lo = ac[i]; + while (i < (k - 1) && ac[i + 1] == (ac[i] + 1)) + i++; + cliq->nodes[nseg].hi = ac[i++]; + nseg++; + } + + CC_FREE (ac, int); + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +int Xsearch_cutpool_for_slack_cliques (Xgraph *G, double maxslack, + int request, int *kcount, Xportableclique **klist, int ecount, + int *elist, double *x) +#else +int Xsearch_cutpool_for_slack_cliques (G, maxslack, request, kcount, klist, + ecount, elist, x) +Xgraph *G; +double maxslack; +int request; +int *kcount; +Xportableclique **klist; +int ecount; +int *elist; +double *x; +#endif +{ + int i, j, isize, k, p; + CCtsp_lpclique *c; + CCtsp_lpclique *cliquelist = (CCtsp_lpclique *) NULL; + double *cliquevals = (double *) NULL; + int cliquecount = 0; + double maxdelta = maxslack * 2.0 + 2.0; + int maxcliques = request; + int rval = 0; + + *kcount = 0; + *klist = (Xportableclique *) NULL; + + printf ("Checking Xpoolcliques...\n"); fflush (stdout); + + rval = CCtsp_search_cutpool_cliques (xpool, &cliquelist, &cliquecount, + G->nnodes, ecount, elist, x, maxdelta, maxcliques, + &cliquevals); + + printf ("Back from CCtsp_search_cutpool_cliques\n"); fflush (stdout); + if (rval) { + fprintf (stderr, "CCtsp_search_cutpool_cliques failed\n"); + goto CLEANUP; + } + + if (!cliquecount) { + printf ("Found no nearly tight cliques\n"); fflush (stdout); + goto CLEANUP; + } + + *klist = CC_SAFE_MALLOC (cliquecount, Xportableclique); + if (!(*klist)) { + fprintf (stderr, "out of memory in Xsearch_cutpool\n"); + rval = 1; goto CLEANUP; + } + + for (i = 0; i < cliquecount; i++) { + c = &(cliquelist[i]); + isize = 0; + for (k = 0; k < c->segcount; k++) { + isize += (c->nodes[k].hi - c->nodes[k].lo + 1); + } + (*klist)[i].size = isize; + (*klist)[i].nodes = CC_SAFE_MALLOC (isize, int); + if (!(*klist)[i].nodes) { + fprintf (stderr, "out of memory in Xsearch_cutpool A\n"); + CC_FREE (*klist, Xportableclique); + rval = 1; goto CLEANUP; + } + p = 0; + for (k = 0; k < c->segcount; k++) { + for (j = c->nodes[k].lo; j <= c->nodes[k].hi; j++) { + (*klist)[i].nodes[p++] = j; + } + } + (*klist)[i].cutval = ((2.0 *((double) isize)) - cliquevals[i])/2.0; + (*klist)[i].cutval = (double) isize - 1.0 - (*klist)[i].cutval; + } + *kcount = cliquecount; + +CLEANUP: + + for (i = 0; i < cliquecount; i++) { + CC_IFFREE (cliquelist[i].nodes, CCtsp_segment); + } + CC_IFFREE (cliquelist, CCtsp_lpclique); + CC_IFFREE (cliquevals, double); + return rval; +} diff --git a/contrib/blossom/concorde97/XSTUFF/Xsubtour.h b/contrib/blossom/concorde97/XSTUFF/Xsubtour.h new file mode 100644 index 0000000000000000000000000000000000000000..ae5679e9ba0666fc29759addb9ec45bb9c6a04b0 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xsubtour.h @@ -0,0 +1,718 @@ +#ifndef __XSUBTOUR_H +#define __XSUBTOUR_H + +#include "Xcutpool.h" + +#define XFALSE 0 +#define XEPSILON .0001 +#define XCUTTOLERANCE .01 +#define XBLOTOLERANCE .01 +#define XCUTTWO (2.0-XCUTTOLERANCE) +#define XCUTNUM 150 +#define XMAXWEIGHT 1e30 +#define XBIGNEG -10000000000.0 +#define SWAP(x,y,temp) (temp = x, x = y, y = temp) +#define OTHEREND(e,n) (e->ends[0] == n ? e->ends[1] : e->ends[0]) +#define OTHERCURRENTEND(e,n) ((e)->cends[0] == (n) ? (e)->cends[1] : (e)->cends[0]) + +typedef struct Xedge { + struct Xnode *ends[2]; + struct Xnode *cends[2]; + struct Xnode *splitter; + int weight; + double x; + double rc; + double flow; + int stay; + int elim; + int weak; + int hold; + int fixed; + int magiclabel; + struct Xedge *next; +} Xedge; + +typedef struct Xextraedge { + int ends[2]; + int weight; + int elim; +} Xextraedge; + +typedef struct Xextralink { + int ends[2]; + int weight; + struct Xextralink *next; +} Xextralink; + +typedef struct Xedgeptr { + struct Xedge *this; + struct Xedgeptr *next; +} Xedgeptr; + +typedef struct Xedgeset { + struct Xedgeptr *head; + struct Xedgeptr *tail; +} Xedgeset; + +typedef struct Xnodeset { + struct Xnodeptr *head; + struct Xnodeptr *tail; +} Xnodeset; + +typedef struct Xnode { + Xedgeset adj; + Xedgeset cadj; + Xnodeset base; + int degree; + int magiclabel; + int stacklabel; + int pseudonumber; + double excess; + int flowlabel; + Xedgeptr *current; + int active; + struct Xnode *next, *prev; + struct Xnode *snext; + struct Xnode *tnext; /* Only use locally */ + Xedge *pe; + struct Xclink *cuts; + struct Xblink *blossoms; + int mark; + int Tmark; + int rand1; + int rand2; +} Xnode; + +typedef struct Xnodeptr { + struct Xnode *this; + struct Xnodeptr *next; +} Xnodeptr; + +typedef struct Xnodeptrptr { + struct Xnodeptr *this; + struct Xnodeptrptr *next; +} Xnodeptrptr; + +typedef struct Xclink { + int cut; + struct Xclink *next; +} Xclink; + +typedef struct Xblink { + int cut; + char handle; + int tooth; + struct Xblink *next; +} Xblink; + +typedef struct Xconstraint { + int sort; + struct Xnodeptr *teeth; + int rhs; +} Xconstraint; + +typedef struct Xcplane { + unsigned long val; + struct Xnodeptr *handle; + struct Xnodeptrptr *handles; + struct Xnodeptrptr *teeth; + struct Xcplane *next; +} Xcplane; + +typedef struct Xiplane { + struct Xintptr *handle; + struct Xintptrptr *handles; + struct Xintptrptr *teeth; + struct Xiplane *next; +} Xiplane; + +typedef struct Xcuttree_node { + struct Xcuttree_node *parent; + struct Xcuttree_node *sibling; + struct Xcuttree_node *child; + double cutval; + int ndescendants; + Xnode *special; + Xnodeset nlist; + Xnode *pseudonode; + struct Xcuttree_node *next; +} Xcuttree_node; + +typedef struct Xintptr { + int this; + struct Xintptr *next; +} Xintptr; + +typedef struct Xintptrptr { + Xintptr *this; + struct Xintptrptr *next; +} Xintptrptr; + +typedef struct Xblock { + Xnodeptr *members; + struct Xcutnodeptr *cutnodes; + struct Xblockptr *neighbors; + Xedgeptr *one; + double weight; + double x; + int mark; +} Xblock; + +typedef struct Xblockptr { + struct Xblockptr *next; + struct Xblock *this; + double hood_weight; +} Xblockptr; + +typedef struct Xcutnode { + Xnode *name; + Xblockptr *blocks; + int mark; +} Xcutnode; + +typedef struct Xcutnodeptr { + struct Xcutnode *this; + struct Xcutnodeptr *next; +} Xcutnodeptr; + +typedef struct Xcombhash { + unsigned long val; + struct Xcombhash *next; +} Xcombhash; + +typedef struct Xclique { + double slack; + Xintptr *nodes; + struct Xclique *next; + struct Xclique *prev; +} Xclique; + +typedef struct Xgraph { + int nnodes; + Xnode *nodelist; + int nedges; + Xedge *edgelist; + Xnode *pseudonodelist; + Xedge *pseudoedgelist; + int npseudonodes; + int magicnum; + int stacknum; + int magicedgenum; +} Xgraph; + +#ifdef CC_PROTOTYPE_ANSI + +/* adjacency.c */ + +void + Xbuildpanadjlist (void), + Xbuildmatadjlist (void); + +/* allcuts.c */ + +void + Xall_tightcuts (Xgraph *Gin, Xclique **cliquelistin, int *ncliquesin); + +/* Xblock.c */ + +void + Xlocalshrink_a (Xgraph *G, int component), + Xlocalshrink_b (Xgraph *G, int component), + Xlocalshrink_c (Xgraph *G, int component), + Xadd_tooth (Xnode *t, Xnodeptr **list); + +int + Xblockcombs (Xgraph *G, Xcplane **cplanelist, double *x), + Xlocalcombs (Xgraph *G, Xcplane **cplanelist, double *x), + Xglobalcombs (Xgraph *G, Xcplane **cplanelist, double *x), + XTmark_components (Xgraph *G), + Xbasiccliques (Xgraph *G, Xcplane **list, double *x), + Xsearchbasiccliques (Xgraph *G, Xcplane **list, int pseudo, double *x), + Xbasicclique (Xgraph *G, Xcplane **list, double *x, Xblock *bigtooth), + Xmarktooth (Xedge *e, Xnodeptr **list), + Xmarktoothend (Xnode *n, Xnodeptr **list), + Xrepeat_1_shrink (Xgraph *G, Xnode *n, Xedge *e); + +Xedge + *Xcurrentedge (Xnode *n1, Xnode *n2); + + +/* Xblocheck.c */ + +int + Xexactblossoms_run (Xgraph *G, Xcplane **list, double *x), + Xexactblossomcheck (Xgraph *G, Xcplane **list, int pseudo, double *x), + Xolaf (Xgraph *G, int choice); + + +/* Xclique.c */ + +int + Xcliquetree (Xgraph *G, Xcplane **list, double *x), + Xcliquetree_work (Xgraph *G, Xcplane **list, int pseudo, double *x, + int type_of_grow); + + +/* Xcuthash.c */ + +void + Xinit_hash_values (Xgraph *G); + +unsigned long + Xcut_hash_value (Xnodeptr *h), + Xcomb_hash_value (Xnodeptr *h, Xnodeptrptr *t), + Xclique_hash_value (Xnodeptrptr *h, Xnodeptrptr *t); + + +/* Xblobs.c */ + +void + Xpancakex (Xgraph *G, double *x), + Xfreepancake (void), + Xshrinksmallblobs (Xgraph *G, int rnum, int biggest), + Xtightblobs (Xgraph *G); + +int + Xblobsviolated (Xgraph *G, Xcplane **list ); + + +/* Xcclean.c */ + +void + Xcleancomb (Xgraph *G, Xnodeptr **handle, Xnodeptrptr **teeth, + int *nteeth, double *x); +int + Xcheckcomb (Xgraph *G, Xnodeptr *handle, Xnodeptrptr *teeth), + Xcliquefluff (Xgraph *G, Xnodeptrptr **handles, Xnodeptrptr **teeth), + Xtemp_combfluff (Xgraph *G, Xnodeptr **handle, Xnodeptrptr **teeth), + Xcombfluff (Xgraph *G, Xnodeptrptr **handles, Xnodeptrptr **teeth, + int cliquetest), + Xhistok (unsigned int *hist), + Xtemp_combcheck (Xgraph *G, Xnodeptr *handle, Xnodeptrptr *teeth), + Xcheckclique (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth); + +/* Xcutload.c */ + +void + Xcliquetree_slack_rhs_flow (Xgraph *G, Xnodeptrptr *handles, + Xnodeptrptr *teeth, double *x, double *slack, double *rhs), + Xfreecplanelist (Xcplane **list); + +int + Xcutchecksout (Xgraph *G, int x), + Xtemp_doblossom (Xgraph *G, Xcplane **cplanelist, Xnodeptr *handle, + Xedgeptr *teeth), + Xviolated_clique_flow (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth, + double *x), + Xloadcplane (Xcplane **list, Xnodeptr *h, Xnodeptrptr *H, + Xnodeptrptr *t, int countcheck), + Xloadcplane_cut (Xgraph *G, Xcplane **list, int num); + + +/* Xcuts.c */ + +int + Xolaf_combs (Xgraph *G, Xcplane **list, double *x), + Xblobcuts (Xgraph *G, Xcplane **list, double *x); + +int + Xreallyfaststuff (Xcplane **, double *, double *), + Xfaststuff (Xcplane **, double *, double *), + Xmediumstuff (Xcplane **, double *, double *), + Xslowstuff (Xcplane **, double *, double *), + Xreallyslowstuff (Xcplane **, double *, double *), + Xall_run_olaf (Xcplane **, double *), + Xheuristiccutcheck (Xcplane **, double *); + +/* Xcututil.c */ + +void + Xfreecplanestruct (Xcplane *c), + Xfreeiplanestruct (Xiplane *c), + Xcplane_to_iplane (Xgraph *G, Xcplane *c, Xiplane **ipl), + Xiplane_to_cplane (Xgraph *G, Xiplane *c, Xcplane **cpl), + Xportablecut_to_cplane (Xgraph *G, Xportablecut *p, Xcplane **cpl), + Xportablecut_to_handles_and_teeth (Xgraph *G, Xportablecut *p, + Xnodeptrptr **handles, Xnodeptrptr **teeth), + Xportablecut_to_iplane (Xportablecut *p, Xiplane **ipl), + Xiplane_to_portablecut (Xiplane *c, Xportablecut *p), + Xfreeteeth (Xnodeptrptr *teeth), + Xprintchvatalcomb (Xgraph *G, Xnodeptr *h, Xnodeptrptr *t), + Xprintcliquetree (Xgraph *G, Xnodeptrptr *h, Xnodeptrptr *t), + Xdumpchvatalcomb (FILE *out, Xintptr *h, Xintptrptr *t), + Xdumpcliquetree (FILE *out, Xintptrptr *h, Xintptrptr *t); + +int + Xslackclique (Xgraph *G, Xnodeptrptr *handles, Xnodeptrptr *teeth, + double *slack), + Xinduced_edges_flow (Xgraph *G, Xnodeptr *set); + + +/* Xflow.c */ + +double + Xflow (Xgraph *G, Xnode *, Xnode *, double); + +int + Xmincut (Xgraph *G, Xnode *, Xnode *, double, double *, int *), + Xexactcutcheck (Xgraph *G, Xcplane **list, double *x), + Xrunconnectcuts (Xgraph *G, Xcplane **, double *); + + +/* Xgomhu.c */ + +Xcuttree_node + *Xgomory_hu (Xgraph *G); + +void + Xcuttree_free (Xcuttree_node *n); + +/* necklace.c */ + +int + Xnecklaces (Xgraph *Gin, Xcplane **, double *); + +/* newkids.c */ + +int + Xnewkids (Xgraph *Gin, double *x, Xcplane **list); + +/* Xourallo.c */ + +Xblink *Xblinkalloc (void); +Xblockptr *Xblockptralloc (void); +Xclink *Xclinkalloc (void); +Xclique *Xcliquealloc (void); +Xcombhash *Xcombhashalloc (void); +Xcplane *Xcplanealloc (void); +Xcutnodeptr *Xcutnodeptralloc (void); +Xcuttree_node *Xcuttree_nodealloc (void); +Xedge *Xedgealloc (void); +Xedgeptr *Xedgeptralloc (void); +Xintptr *Xintptralloc (void); +Xintptrptr *Xintptrptralloc (void); +void Xadd_intptrptr (Xintptrptr **, Xintptr *); +Xiplane *Xiplanealloc (void); +Xnode *Xnodealloc (void); +Xnodeptr *Xnodeptralloc (void); +Xnodeptrptr *Xnodeptrptralloc (void); +void Xadd_edgeptr (Xedgeptr **, Xedge *); +void Xadd_extralink (Xextralink **, int, int, int); +void Xadd_nodeptr (Xnodeptr **, Xnode *); +void Xadd_nodeptrptr (Xnodeptrptr **, Xnodeptr *); +void Xblinkfree (Xblink *); +void Xblockptrfree (Xblockptr *); +void Xclinkfree (Xclink *); +void Xcliquefree (Xclique *); +void Xcombhashfree (Xcombhash *); +void Xcplane_list_free (Xcplane *); +void Xcplanefree (Xcplane *); +void Xcutnodeptrfree (Xcutnodeptr *); +void Xcuttree_nodefree (Xcuttree_node *); +void Xedgefree (Xedge *); +void Xedge_list_free (Xedge *); +void Xedgeptr_list_free (Xedgeptr *); +void Xedgeptrfree (Xedgeptr *); +void Xextralink_list_free (Xextralink *); +void Xinitialize_ouralloc (void); +void Xintptr_list_free (Xintptr *); +void Xintptrfree (Xintptr *); +void Xintptrptr_list_free (Xintptrptr *); +void Xintptrptr_list_freeall(Xintptrptr *); +void Xintptrptrfree (Xintptrptr *); +void Xiplane_list_free (Xiplane *); +void Xiplanefree (Xiplane *); +void Xnodefree (Xnode *); +void Xnodeptr_list_free (Xnodeptr *); +void Xnodeptrfree (Xnodeptr *); +void Xnodeptrptr_list_free (Xnodeptrptr *); +void Xnodeptrptrfree (Xnodeptrptr *); +void Xunion_nodeptr (Xgraph *G, Xnodeptr *, Xnodeptr *, Xnodeptr **); + + +/* Xshrink.c */ + +void + Xbuildpseudonodelist (Xgraph *G, int all), + Xbuildpseudonodenumbers (Xgraph *G), + Xdestroypseudonodelist (Xgraph *G), + Xdumppseudograph (Xgraph *G), + Xdumppseudograph_edgelist (Xgraph *G), + Xsimpleshrink (Xgraph *G, Xnode *, Xnode *), + Xrebuildcadj (Xgraph *G); + +int + Xshrinkprocess (Xgraph *G, Xcplane **), + Xheavy_edge_cuts (Xgraph *G, Xcplane **list, double *x); + + +/* Xgraph.c */ + +void + Xfreegraph (Xgraph *G), + Xloadx (Xgraph *G, double *x); + +int + Xbuildgraph (Xgraph *G, int ncount, int ecount, int *elist, int *elen); + +/* Xstuff.c */ + +int + Xsearch_cutpool_for_slack_cliques (Xgraph *G, double maxslack, + int request, int *kcount, Xportableclique **klist, int ecount, + int *elist, double *x); + +#else + +/* adjacency.c */ + +void + Xbuildpanadjlist (), + Xbuildmatadjlist (); + +/* allcuts.c */ + +void + Xall_tightcuts (); + +/* Xblock.c */ + +void + Xlocalshrink_a (), + Xlocalshrink_b (), + Xlocalshrink_c (), + Xadd_tooth (); + +int + Xblockcombs (), + Xlocalcombs (), + Xglobalcombs (), + XTmark_components (), + Xbasiccliques (), + Xsearchbasiccliques (), + Xbasicclique (), + Xmarktooth (), + Xmarktoothend (), + Xrepeat_1_shrink (); + +Xedge + *Xcurrentedge (); + + +/* Xblocheck.c */ + +int + Xexactblossoms_run (), + Xexactblossomcheck (), + Xolaf (); + + +/* Xclique.c */ + +int + Xcliquetree (), + Xcliquetree_work (); + + +/* Xcuthash.c */ + +void + Xinit_hash_values (); + +unsigned long + Xcut_hash_value (), + Xcomb_hash_value (), + Xclique_hash_value (); + + +/* Xblobs.c */ + +void + Xpancakex (), + Xfreepancake (), + Xshrinksmallblobs (), + Xtightblobs (); + +int + Xblobsviolated (); + + +/* Xcclean.c */ + +void + Xcleancomb (); +int + Xcheckcomb (), + Xcliquefluff (), + Xtemp_combfluff (), + Xcombfluff (), + Xhistok (), + Xtemp_combcheck (), + Xcheckclique (); + +/* Xcutload.c */ + +void + Xcliquetree_slack_rhs_flow (), + Xfreecplanelist (); + +int + Xcutchecksout (), + Xtemp_doblossom (), + Xviolated_clique_flow (), + Xloadcplane (), + Xloadcplane_cut (); + + +/* Xcuts.c */ + +int + Xolaf_combs (), + Xblobcuts (); + +int + Xreallyfaststuff (), + Xfaststuff (), + Xmediumstuff (), + Xslowstuff (), + Xreallyslowstuff (), + Xall_run_olaf (), + Xheuristiccutcheck (); + +/* Xcututil.c */ + +void + Xfreecplanestruct (), + Xfreeiplanestruct (), + Xcplane_to_iplane (), + Xiplane_to_cplane (), + Xportablecut_to_cplane (), + Xportablecut_to_handles_and_teeth (), + Xportablecut_to_iplane (), + Xiplane_to_portablecut (), + Xfreeteeth (), + Xprintchvatalcomb (), + Xprintcliquetree (), + Xdumpchvatalcomb (), + Xdumpcliquetree (); + +int + Xslackclique (), + Xinduced_edges_flow (); + + +/* Xflow.c */ + +double + Xflow (); + +int + Xmincut (), + Xexactcutcheck (), + Xrunconnectcuts (); + + +/* Xgomhu.c */ + +Xcuttree_node + *Xgomory_hu (); + +void + Xcuttree_free (); + +/* necklace.c */ + +int + Xnecklaces (); + +/* newkids.c */ + +int + Xnewkids (); + +/* Xourallo.c */ + +Xblink *Xblinkalloc (); +Xblockptr *Xblockptralloc (); +Xclink *Xclinkalloc (); +Xclique *Xcliquealloc (); +Xcombhash *Xcombhashalloc (); +Xcplane *Xcplanealloc (); +Xcutnodeptr *Xcutnodeptralloc (); +Xcuttree_node *Xcuttree_nodealloc (); +Xedge *Xedgealloc (); +Xedgeptr *Xedgeptralloc (); +Xintptr *Xintptralloc (); +Xintptrptr *Xintptrptralloc (); +void Xadd_intptrptr (); +Xiplane *Xiplanealloc (); +Xnode *Xnodealloc (); +Xnodeptr *Xnodeptralloc (); +Xnodeptrptr *Xnodeptrptralloc (); +void Xadd_edgeptr (); +void Xadd_extralink (); +void Xadd_nodeptr (); +void Xadd_nodeptrptr (); +void Xblinkfree (); +void Xblockptrfree (); +void Xclinkfree (); +void Xcliquefree (); +void Xcombhashfree (); +void Xcplane_list_free (); +void Xcplanefree (); +void Xcutnodeptrfree (); +void Xcuttree_nodefree (); +void Xedgefree (); +void Xedge_list_free (); +void Xedgeptr_list_free (); +void Xedgeptrfree (); +void Xextralink_list_free (); +void Xinitialize_ouralloc (); +void Xintptr_list_free (); +void Xintptrfree (); +void Xintptrptr_list_free (); +void Xintptrptr_list_freeall(); +void Xintptrptrfree (); +void Xiplane_list_free (); +void Xiplanefree (); +void Xnodefree (); +void Xnodeptr_list_free (); +void Xnodeptrfree (); +void Xnodeptrptr_list_free (); +void Xnodeptrptrfree (); +void Xunion_nodeptr (); + + +/* Xshrink.c */ + +void + Xbuildpseudonodelist (), + Xbuildpseudonodenumbers (), + Xdestroypseudonodelist (), + Xdumppseudograph (), + Xdumppseudograph_edgelist (), + Xsimpleshrink (), + Xrebuildcadj (); + +int + Xshrinkprocess (), + Xheavy_edge_cuts (); + + +/* Xgraph.c */ + +void + Xfreegraph (), + Xloadx (); + +int + Xbuildgraph (); + +/* Xstuff.c */ + +int + Xsearch_cutpool_for_slack_cliques (); + +#endif +#endif /* __XSUBTOUR_H */ + diff --git a/contrib/blossom/concorde97/XSTUFF/Xtest.c b/contrib/blossom/concorde97/XSTUFF/Xtest.c new file mode 100644 index 0000000000000000000000000000000000000000..27d8155e0e7d719ea18692f3ba011490a27a4b15 --- /dev/null +++ b/contrib/blossom/concorde97/XSTUFF/Xtest.c @@ -0,0 +1,229 @@ +/***************************************************************************/ +/* */ +/* THE MAIN PROGRAM FOR CONCORDE */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: September 25, 1995 */ +/* */ +/* SEE short decsribtion in usage (). */ +/* */ +/* Link with: */ +/* SEE conmake.grs */ +/* */ +/***************************************************************************/ + +#include "machdefs.h" +#include "util.h" +#include "tsp.h" +#include "Xstuff.h" + +static int seed = 0; +static char *xfilename = (char *) NULL; + + +#ifdef CC_PROTOTYPE_ANSI + +int + main (int ac, char **av); + +static void + usage (char *f); + +static int + parseargs (int ac, char **av), + getxvector (char *f, int *ncount, int *ecount, int **elist, double **x); + +#else /* CC_PROTOTYPE_ANSI */ + +int + main (); + +static void + usage (); + +static int + parseargs (), + getxvector (); + +#endif /* CC_PROTOTYPE_ANSI */ + + +#ifdef CC_PROTOTYPE_ANSI +int main (int ac, char **av) +#else +int main (ac, av) +int ac; +char **av; +#endif +{ + int ncount, ecount; + int *elist = (int *) NULL; + double *x = (double *) NULL; + int cnt; + CCtsp_lpcut_in *cuts = (CCtsp_lpcut_in *) NULL; + int rval = 0; + + seed = (int) CCutil_real_zeit (); + if (parseargs (ac, av)) + return 0; + CCutil_sprand (seed); + + if (xfilename == (char *) NULL) { + usage (av[0]); + return 0; + } + + if (getxvector (xfilename, &ncount, &ecount, &elist, &x)) { + fprintf (stderr, "getxvector failed\n"); + rval = 1; + goto CLEANUP; + } + + if (Xfastcuts (&cuts, &cnt, ncount, ecount, elist, x)) { + fprintf (stderr, "Xfastcuts failed\n"); + rval = 1; + goto CLEANUP; + } + + if (Xexactsubtours (&cuts, &cnt, ncount, ecount, elist, x)) { + fprintf (stderr, "Xfastcuts failed\n"); + rval = 1; + goto CLEANUP; + } + +CLEANUP: + + CC_IFFREE (elist, int); + CC_IFFREE (x, double); + + if (CCutil_bigchunk_free_world ()) { + fprintf (stderr, "ERROR: bigchunk_free_world failed\n"); + return 1; + } + + return rval; +} + +#ifdef CC_PROTOTYPE_ANSI +static int parseargs (int ac, char **av) +#else +static int parseargs (ac, av) +int ac; +char **av; +#endif +{ + int c; + + while ((c = CCutil_bix_getopt (ac, av, "s:x:")) != EOF) + switch (c) { + case 's': + seed = atoi (CCutil_bix_optarg); + break; + case 'x': + xfilename = CCutil_bix_optarg; + break; + case CC_BIX_GETOPT_UNKNOWN: + case '?': + default: + usage (av[0]); + return 1; + } + if (CCutil_bix_optind != ac) { + usage (av[0]); + return 1; + } + return 0; +} + +#ifdef CC_PROTOTYPE_ANSI +static void usage (char *f) +#else +static void usage (f) +char *f; +#endif +{ + fprintf (stderr, "Usage: %s [-see below-]\n", f); + fprintf (stderr, " -s # random seed\n"); + fprintf (stderr, " -x f x-vector file\n"); +} + +#ifdef CC_PROTOTYPE_ANSI +static int getxvector (char *f, int *ncount, int *ecount, int **elist, + double **x) +#else +static int getxvector (f, ncount, ecount, elist, x) +char *f; +int *ncount, *ecount; +int **elist; +double **x; +#endif +{ + FILE *in = fopen (f, "r"); + int i; + + *ncount = 0; + *ecount = 0; + *elist = (int *) NULL; + *x = (double *) NULL; + + if (in == (FILE *) NULL) { + perror (f); + fprintf (stderr, "Unable to open %s for input\n", f); + return 1; + } + + fscanf (in, "%d %d\n", ncount, ecount); + printf ("nnodes = %d, nedges = %d\n", *ncount, *ecount); + fflush (stdout); + + *elist = CC_SAFE_MALLOC ((*ecount) * 2, int); + if (!(*elist)) { + fprintf (stderr, "Out of memory\n"); + fclose (in); + return 1; + } + *x = CC_SAFE_MALLOC (*ecount, double); + if (!(*x)) { + fprintf (stderr, "Out of memory\n"); + CC_FREE (*elist, int); + fclose (in); + return 1; + } + + for (i = 0; i < *ecount; i++) { + fscanf (in, "%d %d %lf", &((*elist)[2 * i]), &((*elist)[(2 * i) + 1]), + &((*x)[i])); + } + + fclose (in); + return 0; +} + +/* Dummies for now */ + +/* +#ifdef CC_PROTOTYPE_ANSI +int Xloadcplane_cut (Xgraph *G, Xcplane **list, int k) +#else +int Xloadcplane_cut (G, list, k) +Xgraph *G; +Xcplane **list; +int k; +#endif +{ + int i; + + printf ("Subtour: "); + for (i = 0; i < G->nnodes; i++) { + if (G->nodelist[i].magiclabel == k) + printf ("%d ", i); + } + printf ("\n"); + fflush (stdout); + + return 1; +} +*/ diff --git a/contrib/blossom/concorde97/concorde.h b/contrib/blossom/concorde97/concorde.h new file mode 100644 index 0000000000000000000000000000000000000000..20ec25de96aac14403f70c3c2c045a904255d686 --- /dev/null +++ b/contrib/blossom/concorde97/concorde.h @@ -0,0 +1,2735 @@ +#ifndef __PREFIX_H +#define __PREFIX_H + +#define CC_PROTOTYPE_ANSI + +#include <stdio.h> +#include <stdlib.h> + +#endif /* __PREFIX_H */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* PROTOTYPES FOR FILES IN UTIL */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + + +#ifndef __UTIL_H +#define __UTIL_H + + + +/***************************************************************************/ +/* */ +/* allocrus.c */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* */ +/* MEMORY ALLOCATION MACROS */ +/* */ +/* TSP CODE */ +/* */ +/* */ +/* Written by: Applegate, Bixby, Chvatal, and Cook */ +/* Date: February 24, 1995 (cofeb24) */ +/* */ +/* */ +/* EXPORTED MACROS: */ +/* CC_SAFE_MALLOC (nnum,type) */ +/* int nnum (the number of objects to be malloced) */ +/* data type (the sort of objects to be malloced) */ +/* RETURNS a pointer to the allocated space. If out of memory, */ +/* it prints an error message and returns NULL. */ +/* */ +/* CC_FREE (object,type) */ +/* type *object (pointer to previously allocated space) */ +/* data type (the sort of object) */ +/* ACTION: frees the memory and sets the object to NULL. */ +/* */ +/* CC_IFFREE (object,type) */ +/* type *object (pointer to previously allocated space) */ +/* data type (the sort of object) */ +/* ACTION: if *object is not NULL, frees the memory and sets */ +/* the object to NULL. */ +/* */ +/* CC_PTR_ALLOC_ROUTINE (type, functionname, chunklist, freelist) */ +/* data type (the sort of objects) */ +/* string functionname (the generated function) */ +/* CCbigchunkptr *chunklist (used to accumulate bigchunks) */ +/* type *freelist (used for the linked list of objects) */ +/* ACTION: Generates a function ("functionname") that returns */ +/* (type *) objects, keeping the free ones on freelist */ +/* and getting its space from calls to bigchunkalloc. */ +/* */ +/* CC_PTR_FREE_ROUTINE (type, functionname, freelist) */ +/* Parameters as above. */ +/* ACTION: Generates a function that adds an object to the */ +/* freelist. */ +/* */ +/* CC_PTR_FREE_LIST_ROUTINE (type, functionname, freefunction) */ +/* Parameters defined as above, with freefunction the function */ +/* generated by PTR_FREE_ROUTINE. */ +/* ACTION: Generates a function to free a linked list of */ +/* objects using calls to freefunction. */ +/* */ +/* CC_PTR_FREE_WORLD_ROUTINE( type, functionname, chunklist, freelist) */ +/* Parameters defined as above. */ +/* ACTION: Generates a function that returns all of the */ +/* memory used in the PTR_ALLOC_ROUTINE allocations */ +/* back to the global supply of CCbigchunkptrs. */ +/* */ +/* CC_PTR_LEAKS_ROUTINE (type, name, chunklist, freelist, field, */ +/* fieldtype) */ +/* As above, with "field" the name of a "fieldtype" field in the */ +/* object type that can be set to 0 or to 1. */ +/* ACTION: Generates a function that checks to see that we have */ +/* not leaked any of the objects. */ +/* */ +/* CC_PTR_STATUS_ROUTINE (type, name, chunklist, freelist) */ +/* ACTION: Like LEAKS, but does not check for duplicates (and so */ +/* does not corrupt the objects). */ +/* */ +/* NOTES: */ +/* These routines use the functions in allocrus.c. The PTR macros */ +/* The PTR macros generate the functions for allocating objects for */ +/* linked lists. They get their raw memory from the bigchunk supply, so */ +/* so foo_free_world (geneated by PTR_FREE_WORLD_ROUTINE) should be */ +/* called for each type of linked object "foo" when closing down the */ +/* local memory. */ +/* To use these functions, put the macros near the top of the file */ +/* before any calls to the functions (since the macros also write the */ +/* function prototypes). If you use PTR_FREE_LIST_ROUTINE for foo, you */ +/* must also use PTR_FREE_ROUTINE, and PTR_FREE_LIST_ROUTINE must be */ +/* listed after CC_PTR_FREE_ROUTINE (to get the prototype). */ +/* */ +/***************************************************************************/ + + +#define CC_SAFE_MALLOC(nnum,type) \ + (type *) CCutil_allocrus (((unsigned int) (nnum)) * sizeof (type)) + +#define CC_FREE(object,type) { \ + CCutil_freerus ((void *) (object)); \ + object = (type *) NULL; \ +} + +#define CC_IFFREE(object,type) { \ + if ((object)) CC_FREE ((object),type); \ +} + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_ALLOC_ROUTINE(type, functionname) \ +static type * functionname (void); \ +static type * functionname (void) +#else +#define CC_HEADER_PTR_ALLOC_ROUTINE(type, functionname) \ +static type * functionname (); \ +static type * functionname () +#endif + +#define CC_PTR_ALLOC_ROUTINE(type, functionname, chunklist, freelist) \ +static type * freelist = ( type * ) NULL; \ +static CCbigchunkptr * chunklist = ( CCbigchunkptr * ) NULL; \ + CC_HEADER_PTR_ALLOC_ROUTINE (type, functionname) \ +{ \ + type *p; \ + \ + if (! freelist ) { \ + int count = CC_BIGCHUNK / sizeof ( type ); \ + CCbigchunkptr *bp; \ + \ + bp = CCutil_bigchunkalloc (); \ + if (!bp) { \ + fprintf (stderr, "ptr alloc failed\n"); \ + return ( type * ) NULL; \ + } \ + freelist = ( type * ) bp->this; \ + bp->next = chunklist ; \ + chunklist = bp; \ + \ + for (p = freelist + count - 2; p >= freelist ; p--) \ + p->next = p + 1; \ + freelist [count - 1].next = ( type * ) NULL; \ + } \ + p = freelist ; \ + freelist = p->next; \ + \ + return p; \ +} + + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_FREE_ROUTINE(type, functionname) \ +static void functionname ( type *p ); \ +static void functionname ( type *p ) +#else +#define CC_HEADER_PTR_FREE_ROUTINE(type, functionname) \ +static void functionname (); \ +static void functionname ( p ) \ +type *p; +#endif + +#define CC_PTR_FREE_ROUTINE(type, functionname, freelist) \ + CC_HEADER_PTR_FREE_ROUTINE(type, functionname) \ +{ \ + p->next = freelist ; \ + freelist = p; \ +} + + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_FREE_LIST_ROUTINE(type, functionname) \ +static void functionname ( type *p ); \ +static void functionname ( type *p ) +#else +#define CC_HEADER_PTR_FREE_LIST_ROUTINE(type, functionname) \ +static void functionname (); \ +static void functionname ( p ) \ +type *p; +#endif + +#define CC_PTR_FREE_LIST_ROUTINE(type, functionname, freefunction) \ + CC_HEADER_PTR_FREE_LIST_ROUTINE (type, functionname) \ +{ \ + type *next; \ + \ + while (p) { \ + next = p->next; \ + freefunction (p); \ + p = next; \ + } \ +} + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_FREE_WORLD_ROUTINE(functionname) \ +static void functionname (void); \ +static void functionname (void) +#else +#define CC_HEADER_PTR_FREE_WORLD_ROUTINE(functionname) \ +static void functionname (); \ +static void functionname () +#endif + +#define CC_PTR_FREE_WORLD_ROUTINE(type, functionname, chunklist, freelist) \ + CC_HEADER_PTR_FREE_WORLD_ROUTINE(functionname) \ +{ \ + CCbigchunkptr *bp, *bpnext; \ + \ + for (bp = chunklist ; bp; bp = bpnext) { \ + bpnext = bp->next; \ + CCutil_bigchunkfree (bp); \ + } \ + chunklist = (CCbigchunkptr *) NULL; \ + freelist = (type *) NULL; \ +} + + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_LEAKS_ROUTINE(functionname) \ +static int functionname (int *total, int *onlist); \ +static int functionname (int *total, int *onlist) +#else +#define CC_HEADER_PTR_LEAKS_ROUTINE(functionname) \ +static int functionname (); \ +static int functionname (total, onlist) \ +int *total, *onlist; +#endif + +#define CC_PTR_LEAKS_ROUTINE(type,name,chunklist,freelist,field,fieldtype) \ + CC_HEADER_PTR_LEAKS_ROUTINE(name) \ +{ \ + int count = CC_BIGCHUNK / sizeof ( type ); \ + int duplicates = 0; \ + type * p; \ + CCbigchunkptr *bp; \ + \ + *total = 0; \ + *onlist = 0; \ + \ + for (bp = chunklist ; bp; bp = bp->next) \ + (*total) += count; \ + \ + for (p = freelist ; p; p = p->next) { \ + (*onlist)++; \ + p-> field = ( fieldtype ) 0; \ + } \ + for (p = freelist ; p; p = p->next) { \ + if (p-> field == ( fieldtype ) 1) \ + duplicates++; \ + else \ + p-> field = ( fieldtype ) 1; \ + } \ + if (duplicates) { \ + fprintf (stderr, "WARNING: %d duplicates on ptr free list \n", \ + duplicates); \ + } \ + return *total - *onlist; \ +} + +#ifdef CC_PROTOTYPE_ANSI +#define CC_HEADER_PTR_STATUS_ROUTINE(functionname) \ +static int functionname (int *total, int *onlist); \ +static int functionname (int *total, int *onlist) +#else +#define CC_HEADER_PTR_STATUS_ROUTINE(functionname) \ +static int functionname (); \ +static int functionname (total, onlist) \ +int *total, *onlist; +#endif + +#define CC_PTR_STATUS_ROUTINE(type, name, chunklist, freelist) \ + CC_HEADER_PTR_STATUS_ROUTINE(name) \ +{ \ + int count = CC_BIGCHUNK / sizeof ( type ); \ + type * p; \ + CCbigchunkptr *bp; \ + \ + *total = 0; \ + *onlist = 0; \ + \ + for (bp = chunklist ; bp; bp = bp->next) \ + (*total) += count; \ + \ + for (p = freelist ; p; p = p->next) \ + (*onlist)++; \ + return *total - *onlist; \ +} + + +#define CC_BIGCHUNK ((int) ((1<<16)-16)) + +typedef struct CCbigchunkptr { + void *this; + struct CCbigchunkptr *next; +} CCbigchunkptr; + + +#ifdef CC_PROTOTYPE_ANSI + +void + *CCutil_allocrus (unsigned int size), + *CCutil_reallocrus (void *ptr, unsigned int size), + CCutil_freerus (void *p), + CCutil_bigchunkquery (int *total, int *reserve), + CCutil_bigchunkfree (CCbigchunkptr *bp); + +int + CCutil_reallocrus_scale (void **pptr, int *pnnum, int count, double scale, + unsigned int size), + CCutil_reallocrus_count (void **pptr, int count, unsigned int size), + CCutil_bigchunk_free_world (void); + +CCbigchunkptr + *CCutil_bigchunkalloc (void); + +#else + +void + *CCutil_allocrus (), + *CCutil_reallocrus (), + CCutil_freerus (), + CCutil_bigchunkquery (), + CCutil_bigchunkfree (); + +int + CCutil_reallocrus_scale (), + CCutil_reallocrus_count (), + CCutil_bigchunk_free_world (); + +CCbigchunkptr + *CCutil_bigchunkalloc (); + +#endif + + +/***************************************************************************/ +/* */ +/* bgetopt.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_bix_getopt (int, char **, char *); + +#else + +int + CCutil_bix_getopt (); + +#endif + +#define CC_BIX_GETOPT_UNKNOWN -3038 + +extern int CCutil_bix_optind; +extern char *CCutil_bix_optarg; + + + +/***************************************************************************/ +/* */ +/* dheaps_i.c */ +/* */ +/***************************************************************************/ + +typedef struct CCdheap { + double *key; + int *entry; + int *loc; + int total_space; + int size; +} CCdheap; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCutil_dheap_free (CCdheap *h), + CCutil_dheap_insert (CCdheap *h, int i), + CCutil_dheap_delete (CCdheap *h, int i), + CCutil_dheap_changekey (CCdheap *h, int i, double newkey); +int + CCutil_dheap_init (CCdheap *h, int k), + CCutil_dheap_resize (CCdheap *h, int newsize), + CCutil_dheap_findmin (CCdheap *h), + CCutil_dheap_deletemin (CCdheap *h); + +#else + +void + CCutil_dheap_free (), + CCutil_dheap_insert (), + CCutil_dheap_delete (), + CCutil_dheap_changekey (); +int + CCutil_dheap_init (), + CCutil_dheap_resize (), + CCutil_dheap_findmin (), + CCutil_dheap_deletemin (); + +#endif + + +/***************************************************************************/ +/* */ +/* edg2cyc.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_edge_to_cycle (int ncount, int *elist, int *cyc); + +#else + +int + CCutil_edge_to_cycle (); + +#endif + + + +/***************************************************************************/ +/* */ +/* edgelen.c */ +/* */ +/***************************************************************************/ + +typedef struct CCdatagroup { + double *x; + double *y; + double *z; + int **adj; + int norm; +} CCdatagroup; + + +#ifdef CC_PROTOTYPE_ANSI + +extern int + (*CCutil_dat_edgelen) (int i, int j, CCdatagroup *dat); +int + CCutil_init_dat_edgelen (CCdatagroup *dat), + CCutil_max_edgelen (int i, int j, CCdatagroup *dat), + CCutil_euclid_edgelen (int i, int j, CCdatagroup *dat), + CCutil_ibm_edgelen (int i, int j, CCdatagroup *dat), + CCutil_euclid_ceiling_edgelen (int i, int j, CCdatagroup *dat), + CCutil_euclid3d_edgelen (int i, int j, CCdatagroup *dat), + CCutil_geographic_edgelen (int i, int j, CCdatagroup *dat), + CCutil_att_edgelen (int i, int j, CCdatagroup *dat), + CCutil_dsjrand_edgelen (int i, int j, CCdatagroup *dat), + CCutil_crystal_edgelen (int i, int j, CCdatagroup *dat), + CCutil_matrix_edgelen (int i, int j, CCdatagroup *dat); +void + CCutil_dsjrand_init (int maxdist, int seed), + CCutil_freedatagroup (int ncount, CCdatagroup *dat); + +#else + +extern int + (*CCutil_dat_edgelen) (); +int + CCutil_init_dat_edgelen (), + CCutil_max_edgelen (), + CCutil_euclid_edgelen (), + CCutil_ibm_edgelen (), + CCutil_euclid_ceiling_edgelen (), + CCutil_euclid3d_edgelen (), + CCutil_geographic_edgelen (), + CCutil_att_edgelen (), + CCutil_dsjrand_edgelen (), + CCutil_crystal_edgelen (), + CCutil_matrix_edgelen (); +void + CCutil_dsjrand_init (), + CCutil_freedatagroup (); + +#endif + + +#define CC_KD_NORM_TYPE 128 /* Kdtrees work */ +#define CC_X_NORM_TYPE 256 /* Old nearest works */ +#define CC_JUNK_NORM_TYPE 512 /* Nothing works */ + +#define CC_D2_NORM_SIZE 1024 /* x,y coordinates */ +#define CC_D3_NORM_SIZE 2048 /* x,y,z coordinates */ +#define CC_MATRIX_NORM_SIZE 4096 /* adj matrix */ + +#define CC_NORM_BITS (CC_KD_NORM_TYPE | CC_X_NORM_TYPE | CC_JUNK_NORM_TYPE) +#define CC_NORM_SIZE_BITS (CC_D2_NORM_SIZE | CC_D3_NORM_SIZE | CC_MATRIX_NORM_SIZE) + +#define CC_MAXNORM (0 | CC_KD_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_EUCLIDEAN_CEIL (1 | CC_KD_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_EUCLIDEAN (2 | CC_KD_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_EUCLIDEAN_3D (3 | CC_X_NORM_TYPE | CC_D3_NORM_SIZE) +#define CC_IBM (4 | CC_JUNK_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_ATT (5 | CC_X_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_GEOGRAPHIC (6 | CC_X_NORM_TYPE | CC_D2_NORM_SIZE) +#define CC_MATRIXNORM (7 | CC_JUNK_NORM_TYPE | CC_MATRIX_NORM_SIZE) +#define CC_DSJRANDNORM (8 | CC_JUNK_NORM_TYPE) +#define CC_CRYSTAL (9 | CC_X_NORM_TYPE | CC_D3_NORM_SIZE) + +#define CC_GEOGRAPHIC_SCALE (6378.388 * 3.14 / 180.0) /* see edgelen.c */ +#define CC_ATT_SCALE (.31622) /* sqrt(1/10) */ + +/* For X-NORMS, scales are such that |x[i] - x[j]| * scale <= edgelen(i,j). */ +/* Ggeographic is slightly off, since the fractional part of x[i] is really */ +/* really minutes, not fractional degrees. */ + + + +/***************************************************************************/ +/* */ +/* fastread.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_readint (FILE *); + +#else + +int + CCutil_readint (); + +#endif + + + +/***************************************************************************/ +/* */ +/* genhash.c */ +/* */ +/***************************************************************************/ + +typedef struct CCgenhash { + int nelem; + int maxelem; + int size; +#ifdef CC_PROTOTYPE_ANSI + int (*hcmp) (void *key1, void *key2, void *u_data); + unsigned int (*hfunc) (void *key, void *u_data); +#else + int (*hcmp) (); + unsigned int (*hfunc) (); +#endif + void *u_data; + double maxdensity; + double lowdensity; + struct CCgenhash_elem **table; +} CCgenhash; + +typedef struct CCgenhash_iter { + int i; + struct CCgenhash_elem *next; +} CCgenhash_iter; + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_genhash_init (CCgenhash *h, int size, + int (*hcmp) (void *key1, void *key2, void *u_data), + unsigned int (*hfunc) (void *key, void *u_data), + void *u_data, double maxdensity, double lowdensity), + CCutil_genhash_insert (CCgenhash *h, void *key, void *data), + CCutil_genhash_insert_h (CCgenhash *h, unsigned int hashval, void *key, + void *data), + CCutil_genhash_replace (CCgenhash *h, void *key, void *data), + CCutil_genhash_replace_h (CCgenhash *h, unsigned int hashval, void *key, + void *data), + CCutil_genhash_delete (CCgenhash *h, void *key), + CCutil_genhash_delete_h (CCgenhash *h, unsigned int hashval, void *key); + +unsigned int + CCutil_genhash_hash (CCgenhash *h, void *key); + +void + *CCutil_genhash_lookup (CCgenhash *h, void *key), + *CCutil_genhash_lookup_h (CCgenhash *h, unsigned int hashval, void *key), + *CCutil_genhash_next (CCgenhash *h, CCgenhash_iter *iter, void **key, + int *keysize); + +void + CCutil_genhash_u_data (CCgenhash *h, void *u_data), + CCutil_genhash_free (CCgenhash *h, void (*freefunc)(void *key, void *data, + void *u_data)), + CCutil_genhash_start (CCgenhash *h, CCgenhash_iter *iter); + +#else + +int + CCutil_genhash_init (), + CCutil_genhash_insert (), + CCutil_genhash_insert_h (), + CCutil_genhash_replace (), + CCutil_genhash_replace_h (), + CCutil_genhash_delete (), + CCutil_genhash_delete_h (); + +unsigned int + CCutil_genhash_hash (); + +void + *CCutil_genhash_lookup (), + *CCutil_genhash_lookup_h (), + *CCutil_genhash_next (); + +void + CCutil_genhash_u_data (), + CCutil_genhash_free (), + CCutil_genhash_start (); + +#endif + + + +/***************************************************************************/ +/* */ +/* getdata.c */ +/* */ +/***************************************************************************/ + +#define CC_MASTER_NO_DAT 100 +#define CC_MASTER_DAT 101 + +#ifdef CC_PROTOTYPE_ANSI + +int + CCutil_getdata (char *datname, int binary_in, int innorm, int *ncount, + CCdatagroup *dat), + CCutil_writemaster (char *mastername, int ncount, CCdatagroup *dat, + int *perm), + CCutil_getmaster (char *mastername, int *ncount, CCdatagroup *dat, + int **perm), + CCutil_getnodeweights (char *weightname, int ncount, int weight_limit, + double **wcoord), + CCutil_gettsplib (char *datname, int *ncount, CCdatagroup *dat), + CCutil_datagroup_perm (int ncount, CCdatagroup *dat, int *perm), + CCutil_getedgelist (int ncount, char *fname, int *ecount, int **elist, + int **elen), + CCutil_getedgelist_n (int *ncount, char *fname, int *ecount, int **elist, + int **elen), + CCutil_getcycle_edgelist (int ncount, char *cyclename, int *outcycle), + CCutil_getcycle (int ncount, char *cyclename, int *outcycle), + CCutil_getedges_double (int *ncount, char *fname, int *ecount, int **elist, + double **elen, int binary_in), + CCutil_writeedges (int ncount, char *outedgename, int ecount, int *elist, + CCdatagroup *dat), + CCutil_writecycle_edgelist (int ncount, char *outedgename, int *cycle, + CCdatagroup *dat), + CCutil_writecycle (int ncount, char *outcyclename, int *cycle), + CCutil_writeedges_double (int ncount, char *outedgename, int ecount, + int *elist, double *elen, int binary_out); + +#else + +int + CCutil_getdata (), + CCutil_writemaster (), + CCutil_getmaster (), + CCutil_getnodeweights (), + CCutil_gettsplib (), + CCutil_datagroup_perm (), + CCutil_getedgelist (), + CCutil_getedgelist_n (), + CCutil_getcycle_edgelist (), + CCutil_getcycle (), + CCutil_getedges_double (), + CCutil_writeedges (), + CCutil_writecycle_edgelist (), + CCutil_writecycle (), + CCutil_writeedges_double (); + +#endif + + + +/***************************************************************************/ +/* */ +/* priority.c */ +/* */ +/***************************************************************************/ + +typedef struct CCpriority { + CCdheap heap; + union pri_data { + void *data; + int next; + } *pri_info; + int space; + int freelist; +} CCpriority; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCutil_priority_free (CCpriority *pri), + CCutil_priority_delete (CCpriority *pri, int handle), + CCutil_priority_changekey (CCpriority *pri, int handle, double newkey), + *CCutil_priority_findmin (CCpriority *pri, double *keyval), + *CCutil_priority_deletemin (CCpriority *pri, double *keyval); + +int + CCutil_priority_init (CCpriority *pri, int k), + CCutil_priority_insert (CCpriority *pri, void *data, double keyval); + +#else + +void + CCutil_priority_free (), + CCutil_priority_delete (), + CCutil_priority_changekey (), + *CCutil_priority_findmin (), + *CCutil_priority_deletemin (); + +int + CCutil_priority_init (), + CCutil_priority_insert (); + +#endif + + +/***************************************************************************/ +/* */ +/* safe_io.c */ +/* */ +/***************************************************************************/ + +#define CC_SBUFFER_SIZE (4000) +#define CC_SFNAME_SIZE (32) + +typedef struct CC_SFILE { + int status; + int desc; + int chars_in_buffer; + int current_buffer_char; /* only used for reading */ + int bits_in_last_char; /* writing: number of empty bits in + * buffer[chars_in_buffer]; + * reading: number of full bits in + * buffer[?] */ + int pos; + char fname[CC_SFNAME_SIZE]; + unsigned char buffer[CC_SBUFFER_SIZE]; +} CC_SFILE; + +#ifdef CC_PROTOTYPE_ANSI + +CC_SFILE + *CCutil_sopen (char *f, char *s), + *CCutil_sdopen (int d, char *s); + +int + CCutil_swrite (CC_SFILE *f, unsigned char *buf, int size), + CCutil_swrite_bits (CC_SFILE *f, unsigned int x, int xbits), + CCutil_swrite_char (CC_SFILE *f, unsigned char x), + CCutil_swrite_string (CC_SFILE *f, unsigned char *x), + CCutil_swrite_short (CC_SFILE *f, unsigned short x), + CCutil_swrite_int (CC_SFILE *f, unsigned int x), + CCutil_swrite_double (CC_SFILE *f, double x), + CCutil_sread (CC_SFILE *f, unsigned char *buf, int size), + CCutil_sread_bits (CC_SFILE *f, unsigned int *x, int xbits), + CCutil_sread_char (CC_SFILE *f, unsigned char *x), + CCutil_sread_string (CC_SFILE *f, unsigned char *x, int maxlen), + CCutil_sread_short (CC_SFILE *f, unsigned short *x), + CCutil_sread_short_r (CC_SFILE *f, unsigned short *x), + CCutil_sread_int (CC_SFILE *f, unsigned int *x), + CCutil_sread_int_r (CC_SFILE *f, unsigned int *x), + CCutil_sread_double (CC_SFILE *f, double *x), + CCutil_sread_double_r (CC_SFILE *f, double *x), + CCutil_sflush (CC_SFILE *f), + CCutil_stell (CC_SFILE *f), + CCutil_sseek (CC_SFILE *f, int offset), + CCutil_srewind (CC_SFILE *f), + CCutil_sclose (CC_SFILE *f), + CCutil_sbits (unsigned int x), + CCutil_sdelete_file (char *fname), + CCutil_sdelete_file_backup (char *fname); + +#else + +CC_SFILE + *CCutil_sopen (), + *CCutil_sdopen (); + +int + CCutil_swrite (), + CCutil_swrite_bits (), + CCutil_swrite_char (), + CCutil_swrite_string (), + CCutil_swrite_short (), + CCutil_swrite_int (), + CCutil_swrite_double (), + CCutil_sread (), + CCutil_sread_bits (), + CCutil_sread_char (), + CCutil_sread_string (), + CCutil_sread_short (), + CCutil_sread_short_r (), + CCutil_sread_int (), + CCutil_sread_int_r (), + CCutil_sread_double (), + CCutil_sread_double_r (), + CCutil_sflush (), + CCutil_stell (), + CCutil_sseek (), + CCutil_srewind (), + CCutil_sclose (), + CCutil_sbits (), + CCutil_sdelete_file (), + CCutil_sdelete_file_backup (); + +#endif + + + +/***************************************************************************/ +/* */ +/* sortrus.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +void + CCutil_int_array_quicksort (int *len, int n), + CCutil_int_perm_quicksort (int *perm, int *len, int n), + CCutil_double_perm_quicksort (int *perm, double *len, int n), + CCutil_rselect (int *arr, int l, int r, int m, double *coord); + +char + *CCutil_linked_radixsort (char *data, char *datanext, char *dataval, + int valsize); + +#else + +void + CCutil_int_array_quicksort (), + CCutil_int_perm_quicksort (), + CCutil_double_perm_quicksort (), + CCutil_rselect (); + +char + *CCutil_linked_radixsort (); + +#endif + + + +/***************************************************************************/ +/* */ +/* urandom.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +void + CCutil_sprand (int); +int + CCutil_lprand (void); + +#else + +void + CCutil_sprand (); +int + CCutil_lprand (); + +#endif + + + +/***************************************************************************/ +/* */ +/* util.c */ +/* */ +/***************************************************************************/ + + +#ifdef CC_PROTOTYPE_ANSI + +char + *CCutil_strrchr (char *s, int c); + +unsigned int + CCutil_nextprime (unsigned int x); + +int + CCutil_our_gcd (int a, int b); + +#else + +char + *CCutil_strrchr (); + +unsigned int + CCutil_nextprime (); + +int + CCutil_our_gcd (); + +#endif + + + +/***************************************************************************/ +/* */ +/* zeit.c */ +/* */ +/***************************************************************************/ + + +#ifdef CC_PROTOTYPE_ANSI + +double + CCutil_zeit (void), + CCutil_real_zeit (void); + +#else + +double + CCutil_zeit (), + CCutil_real_zeit (); + +#endif + + +#endif /* __UTIL_H */ +#ifndef __BIGGUY_H +#define __BIGGUY_H + + +#ifdef CC_BIGGUY_LONGLONG + +typedef long long CCbigguy; + +#define CCbigguy_FRACBITS 32 +#define CCbigguy_DUALSCALE (((CCbigguy) 1) << CCbigguy_FRACBITS) +#define CCbigguy_FRACPART(x) ((x) & (CCbigguy_DUALSCALE-1)) +#define CCbigguy_MAXBIGGUY (((((CCbigguy) 1) << 62) - 1) + \ + (((CCbigguy) 1) << 62)) +#define CCbigguy_MINBIGGUY (-CCbigguy_MAXBIGGUY) +#define CCbigguy_bigguytod(x) (((double) (x)) / ((double) CCbigguy_DUALSCALE)) +#define CCbigguy_itobigguy(d) ((CCbigguy) ((d) * (double) CCbigguy_DUALSCALE)) +#define CCbigguy_ceil(x) (CCbigguy_FRACPART(x) ? \ + ((x) + (CCbigguy_DUALSCALE - CCbigguy_FRACPART(x))) : (x)) +#define CCbigguy_cmp(x,y) (((x) < (y)) ? -1 : ((x) > (y)) ? 1 : 0) +#define CCbigguy_ZERO ((CCbigguy) 0) +#define CCbigguy_ONE ((CCbigguy) CCbigguy_DUALSCALE) +#define CCbigguy_addmult(x,y,m) ((*x) += (y)*(m)) +#define CCbigguy_dtobigguy(d) ((CCbigguy) ((d) * (double) CCbigguy_DUALSCALE)) + +#else /* CC_BIGGUY_LONGLONG */ + +typedef struct CCbigguy { + unsigned short ihi; + unsigned short ilo; + unsigned short fhi; + unsigned short flo; +} CCbigguy; + +extern const CCbigguy CCbigguy_MINBIGGUY; +extern const CCbigguy CCbigguy_MAXBIGGUY; +extern const CCbigguy CCbigguy_ZERO; +extern const CCbigguy CCbigguy_ONE; + +#ifdef CC_PROTOTYPE_ANSI + + void + CCbigguy_addmult (CCbigguy *x, CCbigguy y, short m); + + int + CCbigguy_cmp (CCbigguy x, CCbigguy y); + + double + CCbigguy_bigguytod (CCbigguy x); + + CCbigguy + CCbigguy_itobigguy (int d), + CCbigguy_dtobigguy (double d), + CCbigguy_ceil (CCbigguy x); + +#else + + void + CCbigguy_addmult (); + + int + CCbigguy_cmp (); + + double + CCbigguy_bigguytod (); + + CCbigguy + CCbigguy_itobigguy (), + CCbigguy_dtobigguy (), + CCbigguy_ceil (); + +#endif + +#endif /* CC_BIGGUY_LONGLONG */ + +#define CCbigguy_add(x,y) (CCbigguy_addmult(x,y,1)) +#define CCbigguy_sub(x,y) (CCbigguy_addmult(x,y,-1)) + +#ifdef CC_PROTOTYPE_ANSI + +int + CCbigguy_swrite (CC_SFILE *f, CCbigguy x), + CCbigguy_sread (CC_SFILE *f, CCbigguy *x); + +#else + +int + CCbigguy_swrite (), + CCbigguy_sread (); + +#endif + +#endif /* __BIGGUY_H */ +#ifndef __LP_H +#define __LP_H + +#define CClp_METHOD_DUAL 1 +#define CClp_METHOD_BARRIER 2 + +#define CClp_SUCCESS 0 +#define CClp_FAILURE 1 +#define CClp_UNBOUNDED 2 +#define CClp_INFEASIBLE 3 +#define CClp_UNKNOWN 4 + +typedef struct CClp { + struct cpxenv *cplex_env; + struct cpxlp *cplex_lp; + int lp_allocated; +} CClp; + +typedef struct CClpbasis { + int *rstat; + int *cstat; + double *dnorm; +} CClpbasis; + +#ifdef CC_PROTOTYPE_ANSI + +int + CClp_init (CClp *lp), + CClp_loadlp (CClp *lp, char *name, int ncols, int nrows, int objsense, + double *obj, double *rhs, char *sense, int *matbeg, int *matcnt, + int *matind, double *matval, double *lb, double *ub), + CClp_opt (CClp *lp, int method), + CClp_dualopt (CClp *lp), + CClp_limited_dualopt (CClp *lp, int lim, int *status, double *upperbound), + CClp_primalopt (CClp *lp), + CClp_addrows (CClp *lp, int newrows, int newnz, double *rhs, char *sense, + int *rmatbeg, int *rmatind, double *rmatval), + CClp_addcols (CClp *lp, int newcols, int newnz, double *obj, + int *cmatbeg, int *cmatind, double *cmatval, double *lb, + double *ub), + CClp_delete_row (CClp *lp, int i), + CClp_delete_set_of_rows (CClp *lp, int *delstat), + CClp_delete_column (CClp *lp, int i), + CClp_delete_set_of_columns (CClp *lp, int *delstat), + CClp_setbnd (CClp *lp, int col, char lower_or_upper, double bnd), + CClp_get_basis_and_norms (CClp *lp, CClpbasis *b), + CClp_load_basis_and_norms (CClp *lp, CClpbasis *b), + CClp_basis (CClp *lp, int *cstat, int *rstat), + CClp_loadbasis (CClp *lp, int *cstat, int *rstat), + CClp_getbasis_and_norms (CClp *lp, int *cstat, int *rstat, + double *dnorm), + CClp_loadbasis_and_norms (CClp *lp, int *cstat, int *rstat, + double *dnorm), + CClp_x (CClp *lp, double *x), + CClp_rc (CClp *lp, double *rc), + CClp_pi_range (CClp *lp, double *pi, int from, int to), + CClp_objval (CClp *lp, double *obj), + CClp_nonzeros (CClp *lp), + CClp_status (CClp *lp, int *status), + CClp_getweight (CClp *lp, int nrows, int *rmatbeg, int *rmatind, + double *rmatval, double *weight), + CClp_dump_lp (CClp *lp, char *fname), + CClp_getgoodlist (CClp *lp, int *goodlist, int *goodlen_p, + double *downpen, double *uppen), + CClp_strongbranch (CClp *lp, int *candidatelist, int ncand, + double *downpen, double *uppen, int iterations, + double *upperbound), + CClp_getfarkasmultipliers (CClp *lp, double *y); + +void + CClp_init_struct (CClp *lp), + CClp_free (CClp *lp), + CClp_init_basis (CClpbasis *b), + CClp_free_basis (CClpbasis *b), + CClp_pivotin (CClp *lp, int i); + +#else + +int + CClp_init (), + CClp_loadlp (), + CClp_opt (), + CClp_dualopt (), + CClp_limited_dualopt (), + CClp_primalopt (), + CClp_addrows (), + CClp_addcols (), + CClp_delete_row (), + CClp_delete_set_of_rows (), + CClp_delete_column (), + CClp_delete_set_of_columns (), + CClp_setbnd (), + CClp_get_basis_and_norms (), + CClp_load_basis_and_norms (), + CClp_basis (), + CClp_loadbasis (), + CClp_getbasis_and_norms (), + CClp_loadbasis_and_norms (), + CClp_x (), + CClp_rc (), + CClp_pi_range (), + CClp_objval (), + CClp_nonzeros (), + CClp_status (), + CClp_getweight (), + CClp_dump_lp (), + CClp_getgoodlist (), + CClp_strongbranch (), + CClp_getfarkasmultipliers (); + +void + CClp_init_struct (), + CClp_free (), + CClp_init_basis (), + CClp_free_basis (), + CClp_pivotin (); + +#endif + + +#endif /* __LP_H */ +#ifndef __KDTREE_H +#define __KDTREE_H + + +typedef struct CCkdnode { + double cutval; + struct CCkdnode *loson; + struct CCkdnode *hison; + struct CCkdnode *father; + struct CCkdnode *next; + struct CCkdbnds *bnds; + int lopt; + int hipt; + char bucket; + char empty; + char cutdim; +} CCkdnode; + +typedef struct CCkdtree { + CCkdnode *root; + CCkdnode **bucketptr; + int *perm; +} CCkdtree; + +typedef struct CCkdbnds { + double x[2]; + double y[2]; + struct CCkdbnds *next; +} CCkdbnds; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCkdtree_free (CCkdtree *kt), + CCkdtree_delete (CCkdtree *kt, int k), + CCkdtree_delete_all (CCkdtree *kt, int ncount), + CCkdtree_undelete (CCkdtree *kt, int k), + CCkdtree_undelete_all (CCkdtree *kt, int ncount); +int + CCkdtree_build (CCkdtree *kt, int ncount, CCdatagroup *dat, double *wcoord), + CCkdtree_k_nearest (CCkdtree *kt, int ncount, int k, CCdatagroup *dat, + double *wcoord, int wantlist, int *ocount, int **olist), + CCkdtree_quadrant_k_nearest (CCkdtree *kt, int ncount, int k, + CCdatagroup *dat, double *wcoord, int wantlist, int *ocount, + int **olist), + CCkdtree_node_k_nearest (CCkdtree *kt, int ncount, int n, int k, + CCdatagroup *dat, double *wcoord, int *list), + CCkdtree_node_quadrant_k_nearest (CCkdtree *kt, int ncount, int n, int k, + CCdatagroup *dat, double *wcoord, int *list), + CCkdtree_node_nearest (CCkdtree *kt, int n, CCdatagroup *dat, + double *wcoord), + CCkdtree_fixed_radius_nearest (CCkdtree *kt, CCdatagroup *dat, + double *wcoord, int n, double rad, + int (*doit_fn) (int, int, void *), void *pass_param), + CCkdtree_nearest_neighbor_tour (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val), + CCkdtree_nearest_neighbor_2match (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outmatch, double *val), + CCkdtree_prim_spanningtree (CCkdtree *kt, int ncount, CCdatagroup *dat, + double *wcoord, int *outtree, double *val), + CCkdtree_greedy_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val), + CCkdtree_far_add_tour (CCkdtree *kt, int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val), + CCkdtree_qboruvka_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val), + CCkdtree_boruvka_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *outcycle, double *val), + CCkdtree_twoopt_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *incycle, int *outcycle, double *val, + int in_run_two_and_a_half_opt, int run_silently), + CCkdtree_3opt_tour (CCkdtree *kt, int ncount, CCdatagroup *dat, + int *incycle, int *outcycle, double *val, int run_silently); + +#else + +void + CCkdtree_free (), + CCkdtree_delete (), + CCkdtree_delete_all (), + CCkdtree_undelete (), + CCkdtree_undelete_all (); +int + CCkdtree_build (), + CCkdtree_k_nearest (), + CCkdtree_quadrant_k_nearest (), + CCkdtree_node_k_nearest (), + CCkdtree_node_quadrant_k_nearest (), + CCkdtree_node_nearest (), + CCkdtree_fixed_radius_nearest (), + CCkdtree_nearest_neighbor_tour (), + CCkdtree_nearest_neighbor_2match (), + CCkdtree_prim_spanningtree (), + CCkdtree_greedy_tour (), + CCkdtree_far_add_tour (), + CCkdtree_qboruvka_tour (), + CCkdtree_boruvka_tour (), + CCkdtree_twoopt_tour (), + CCkdtree_3opt_tour (); +#endif + +#endif /* __KDTREE_H */ + +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* PROTOTYPES FOR FILES IN CUT */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + + +#ifndef __CUT_H +#define __CUT_H + + +#define CC_MINCUT_BIGDOUBLE (100000000000.0) +#define CC_MINCUT_ONE_EPSILON (0.000001) + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCcut_mincut (int ncount, int ecount, int *elist, double *dlen, + double *valval, int **cut, int *cutcount), + CCcut_violated_cuts (int ncount, int ecount, int *elist, double *dlen, + double cutoff, int (*doit_fn) (double, int, int *, void *), + void *pass_param), + CCcut_mincut_st (int ncount, int ecount, int *elist, double *ecap, + int s, int t, double *value, int **cut, int *cutcount), + CCcut_linsub (int ncount, int ecount, int *elist, double *x, double cutoff, + int (*doit_fn) (double, int, int, void *), void *pass_param), + CCcut_connect_components (int ncount, int ecount, int *elist, double *x, + int *ncomp, int **compscount, int **comps); + +#else + +int + CCcut_mincut (), + CCcut_violated_cuts (), + CCcut_mincut_st (), + CCcut_linsub (), + CCcut_connect_components (); + +#endif + + + +/***************************************************************************/ +/* */ +/* shrink.c */ +/* */ +/***************************************************************************/ + +typedef struct CC_SRKnode { + struct CC_SRKedge *adj; + struct CC_SRKnode *next; + struct CC_SRKnode *prev; + struct CC_SRKnode *members; + struct CC_SRKnode *parent; + struct CC_SRKnode *qnext; + double prweight; + double weight; + int num; + int newnum; + int onecnt; + int onqueue; +} CC_SRKnode; + +typedef struct CC_SRKedge { + struct CC_SRKnode *end; + struct CC_SRKedge *other; + struct CC_SRKedge *next; + struct CC_SRKedge *prev; + double weight; +} CC_SRKedge; + +typedef struct CC_SRKgraph { + struct CC_SRKnode *nodespace; + struct CC_SRKedge *edgespace; + struct CC_SRKnode *head; + struct CC_SRKedge **hit; + int original_ncount; + int original_ecount; +} CC_SRKgraph; + +typedef struct CC_SRKexpinfo { + int *members; + int *memindex; +} CC_SRKexpinfo; + +typedef struct CC_SRKcallback { + double cutoff; + void *pass_param; +#ifdef CC_PROTOTYPE_ANSI + int (*doit_fn) (double, int, int *, void *); +#else + int (*doit_fn) (); +#endif +} CC_SRKcallback; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCcut_SRK_identify_paths (CC_SRKgraph *G, int *newcount, int onecnt_okay), + CCcut_SRK_identify_paths_to_edges (CC_SRKgraph *G, int *newcount, + int onecnt_okay), + CCcut_SRK_identify_ones (CC_SRKgraph *G, int *count, double epsilon), + CCcut_SRK_identify_one_triangles (CC_SRKgraph *G, int *count, + CC_SRKnode *qstart, double epsilon), + CCcut_SRK_identify_nodes (CC_SRKgraph *G, CC_SRKnode *n, CC_SRKnode *m), + CCcut_SRK_init_graph (CC_SRKgraph *G), + CCcut_SRK_free_graph (CC_SRKgraph *G), + CCcut_SRK_init_expinfo (CC_SRKexpinfo *expand), + CCcut_SRK_free_expinfo (CC_SRKexpinfo *expand), + CCcut_SRK_init_callback (CC_SRKcallback *cb); + +int + CCcut_SRK_buildgraph (CC_SRKgraph *G, int ncount, int ecount, int *elist, + double *dlen), + CCcut_SRK_subtour_shrink (CC_SRKgraph *G, double *minval, double epsilon, + CC_SRKcallback *cb, int **cut, int *cutcount), + CCcut_SRK_identify_pr_edges (CC_SRKgraph *G, double *minval, int *count, + CC_SRKnode *qstart, double epsilon, CC_SRKcallback *cb, int **cut, + int *cutcount), + CCcut_SRK_defluff (CC_SRKgraph *G), + CCcut_SRK_grab_edges (CC_SRKgraph *G, int *oncount, int *oecount, + int **olist, double **olen, CC_SRKexpinfo *expand), + CCcut_SRK_grab_nodes (CC_SRKgraph *G, CC_SRKexpinfo *expand), + CCcut_SRK_trivial (int ncount, CC_SRKexpinfo *expand), + CCcut_SRK_expand (CC_SRKexpinfo *expand, int *arr, int size, int **pnewarr, + int *pnewsize); + +#else + +void + CCcut_SRK_identify_paths (), + CCcut_SRK_identify_paths_to_edges (), + CCcut_SRK_identify_ones (), + CCcut_SRK_identify_one_triangles (), + CCcut_SRK_identify_nodes (), + CCcut_SRK_init_graph (), + CCcut_SRK_free_graph (), + CCcut_SRK_init_expinfo (), + CCcut_SRK_free_expinfo (), + CCcut_SRK_init_callback (); + +int + CCcut_SRK_buildgraph (), + CCcut_SRK_subtour_shrink (), + CCcut_SRK_identify_pr_edges (), + CCcut_SRK_defluff (), + CCcut_SRK_grab_edges (), + CCcut_SRK_grab_nodes (), + CCcut_SRK_trivial (), + CCcut_SRK_expand (); + +#endif + +#endif /* __CUT_H */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* PROTOTYPES FOR FILES IN EDGEGEN */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + +#ifndef __EDGEGEN_H +#define __EDGEGEN_H + + + +/***************************************************************************/ +/* */ +/* edgegen.c */ +/* */ +/***************************************************************************/ + +typedef struct CCedgegengroup { + struct { + int count; + int quadnearest; + int nearest; + int nearest_start; + int greedy_start; + int random_start; + int nkicks; + } linkern; + + struct { + int twoopt_count; + int twoopt5_count; + int threeopt_count; + int greedy; + int nearest_count; + int random_count; + } tour; + + struct { + int wantit; + int basic; + int priced; + } f2match; + + struct { + int number; + int basic; + int priced; + } f2match_nearest; + + int nearest; + int quadnearest; + int want_tree; + int nearest_twomatch_count; + int delaunay; + int mlinkern; +} CCedgegengroup; + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCedgegen_read (char *egname, CCedgegengroup *plan), + CCedgegen_edges (CCedgegengroup *plan, int ncount, CCdatagroup *dat, + double *wcoord, int *ecount, int **elist); +void + CCedgegen_init_edgegengroup (CCedgegengroup *plan); + +#else + +int + CCedgegen_read (), + CCedgegen_edges (); +void + CCedgegen_init_edgegengroup (); + +#endif + + + +/***************************************************************************/ +/* */ +/* xnear.c */ +/* */ +/***************************************************************************/ + +typedef struct CCxnear { + struct CCdatagroup dat; + double *w; + int *nodenames; + int *invnames; +} CCxnear; + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCedgegen_x_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist), + CCedgegen_x_quadrant_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist), + CCedgegen_x_node_k_nearest (CCxnear *xn, int n, int nearnum, int ncount, + int *list), + CCedgegen_x_node_quadrant_k_nearest (CCxnear *xn, int n, int nearnum, + int ncount, int *list), + CCedgegen_x_node_nearest (CCxnear *xn, int ncount, int ni, char *marks), + CCedgegen_x_nearest_neighbor_tour (int ncount, int start, CCdatagroup *dat, + int *outcycle, double *val), + CCedgegen_junk_k_nearest (int ncount, int num, CCdatagroup *dat, + double *wcoord, int wantlist, int *ecount, int **elist), + CCedgegen_junk_node_k_nearest (CCdatagroup *dat, double *wcoord, int n, + int nearnum, int ncount, int *list), + CCedgegen_junk_node_nearest (CCdatagroup *dat, double *wcoord, int ncount, + int n, char *marks), + CCedgegen_junk_nearest_neighbor_tour (int ncount, int start, + CCdatagroup *dat, int *outcycle, double *val), + CCedgegen_xnear_build (int ncount, CCdatagroup *dat, double *wcoord, + CCxnear *xn); + +void + CCedgegen_xnear_free (int ncount, CCxnear *xn); + +#else + +int + CCedgegen_x_k_nearest (), + CCedgegen_x_quadrant_k_nearest (), + CCedgegen_x_node_k_nearest (), + CCedgegen_x_node_quadrant_k_nearest (), + CCedgegen_x_node_nearest (), + CCedgegen_x_nearest_neighbor_tour (), + CCedgegen_junk_k_nearest (), + CCedgegen_junk_node_k_nearest (), + CCedgegen_junk_node_nearest (), + CCedgegen_junk_nearest_neighbor_tour (), + CCedgegen_xnear_build (); +void + CCedgegen_xnear_free (); + +#endif + +#endif /* __EDGEGEN_H */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* PROTOTYPES FOR FILES IN CUT */ +/* */ +/***************************************************************************/ +/***************************************************************************/ + + +#ifndef __TSP_H +#define __TSP_H + + +/*************** Tolerances for the LP and Cutting routines ***************/ + +#define CCtsp_MIN_VIOL (0.00001) /* min violation for cut to be added to lp */ +#define CCtsp_CUTS_NEXT_TOL (0.0001) /* to try next level */ +#define CCtsp_CUTS_NEXT_ROUND (0.00000001) /* if improve is less, stop round */ +#define CCtsp_PRICE_RCTHRESH (-0.00001) /* to add a bad edge */ +#define CCtsp_PRICE_MAXPENALTY (0.49) /* penalty permitted in addbad */ +#define CCtsp_PHASE1_RCTHRESH (-0.000000001) +#define CCtsp_PHASE1_MAXPENALTY (0.00000001) +#define CCtsp_EDGE_LIFE (1000000) /* 200 */ /* Large for subtour runs */ +#define CCtsp_CUT_LIFE (50) +#define CCtsp_CUT_BATCH (250) /* number of new cuts before lp optimize */ +#define CCtsp_STORE_BATCH (50) /* number of new cuts before lp addrows */ +#define CCtsp_INTTOL (0.0001) /* used to check if lp soln is integral */ + +/************************** Branching Strategies ************************/ + +#define CCtsp_BRANCH_MIDDLE 1 +#define CCtsp_BRANCH_STRONG 2 + +/*************************************************************************/ + +#define CCtsp_LP_MAXDOUBLE 1e30 + +#define CCtsp_CUTRHS(c) (3*(c)->cliquecount - (c)->handlecount - 1) + +typedef struct CCtsp_lpnode { + int deg; + int mark; + struct CCtsp_lpadj *adj; +} CCtsp_lpnode; + +typedef struct CCtsp_lpedge { + int ends[2]; /* ends[0] should always be < ends[1] */ + int fixed; + int branch; /* < 0 means set to 0 and > 0 means set to 1 */ + int len; + int age; + int coef; /* should be maintained at zero */ + int coefnext; /* should be maintained at -2 */ +} CCtsp_lpedge; + +typedef struct CCtsp_lpadj { + int to; + int edge; +} CCtsp_lpadj; + +typedef struct CCtsp_lpgraph { + int ncount; + int espace; + int ecount; + int nodemarker; + CCtsp_lpnode *nodes; + CCtsp_lpedge *edges; + CCtsp_lpadj *adjspace; + int adjstart; + int adjend; +} CCtsp_lpgraph; + +typedef struct CCtsp_predge { + int ends[2]; + int len; + double rc; +} CCtsp_predge; + +typedef struct CCtsp_pricegroup { + int ncount; + int espace; + int ecount; + CCtsp_lpnode *nodes; + CCtsp_predge *edges; + int cliquecount; + struct CCtsp_lpclique *cliques; /* just a copy of the pointer */ + CCtsp_lpgraph *graph; /* pointer to the copy in a CCtsp_lp */ + CCtsp_lpadj *adjspace; + double *node_pi; + double *clique_pi; + double penalty; +} CCtsp_pricegroup; + +typedef struct CCtsp_extraedge { + int ends[2]; +} CCtsp_extraedge; + +typedef struct CCtsp_sparser { + unsigned int node : 24; + unsigned int mult : 8; +} CCtsp_sparser; + +typedef struct CCtsp_segment { + int lo; + int hi; +} CCtsp_segment; + +typedef struct CCtsp_lpclique { + int segcount; + struct CCtsp_segment *nodes; + int hashnext; + int refcount; +} CCtsp_lpclique; + +#define CC_FOREACH_NODE_IN_CLIQUE(i,c,tmp) \ + for(tmp=0;tmp<(c).segcount;tmp++) \ + for(i=(c).nodes[tmp].lo;i<=(c).nodes[tmp].hi;i++) + +#define CCtsp_NEWCUT_AGE (-1) + +typedef struct CCtsp_lpcut { + int handlecount; + int cliquecount; + int modcount; + int age; + int rhs; + char sense; + char branch; + int *cliques; + struct CCtsp_sparser *mods; +} CCtsp_lpcut; + +typedef struct CCtsp_lpcut_in { + int handlecount; + int cliquecount; + int rhs; + char sense; + char branch; + CCtsp_lpclique *cliques; + struct CCtsp_lpcut_in *next; + struct CCtsp_lpcut_in *prev; +} CCtsp_lpcut_in; + +typedef struct CCtsp_lp_result { + double ub; + double lb; + int ecount; + int *elist; + double *x; + double *rc; +} CCtsp_lp_result; + +typedef struct CCtsp_lpcuts { + int cutcount; + int cliqueend; + int cutspace; + int cliquespace; + int cliquehashsize; + int cliquefree; + int *cliquehash; + CCtsp_lpcut *cuts; + CCtsp_lpclique *cliques; + CCgenhash *cuthash; + char *tempcuthash; + int tempcuthashsize; +} CCtsp_lpcuts; + +typedef struct CCtsp_bigdual { + int cutcount; + CCbigguy *node_pi; + CCbigguy *cut_pi; +} CCtsp_bigdual; + +typedef struct CCtsp_tighten_info { + int ncall; + int nfail; + int nadd; + int nadd_tied; + int ndel; + int ndel_tied; + double add_delta; + double del_delta; + double time; +} CCtsp_tighten_info; + +typedef struct CCtsp_branchobj { + int depth; + int rhs; + int ends[2]; + char sense; + CCtsp_lpclique *clique; +} CCtsp_branchobj; + +typedef struct CCtsp_cutselect { + int cutpool; + int connect; + int segments; + int exactsubtour; + int tighten_lp; + int decker_lp; + int teething_lp; + int tighten_pool; + int decker_pool; + int teething_pool; + int maxchunksize; + int Xfastcuts; + int Xexactsubtours; + int Xslowcuts; + int consecutiveones; + int necklace; + int usetighten; /* set to 1 to tighten before cuts are added */ + int extra_connect; /* set to 1 to force a connected solution */ + double nexttol; + double roundtol; +} CCtsp_cutselect; + +/* nodes are reordered to match compression tour */ + +typedef struct CCtsp_genadj { + int deg; + struct CCtsp_genadjobj *list; +} CCtsp_genadj; + +typedef struct CCtsp_genadjobj { + int end; + int len; +} CCtsp_genadjobj; + +typedef struct CCtsp_edgegenerator { + double *node_piest; + struct CCdatagroup *dg; + int *supply; + CCkdtree *kdtree; + CCxnear *xnear; + struct CCtsp_xnorm_pricer *xprice; + CCtsp_genadjobj *adjobjspace; + CCtsp_genadj *adj; + int ncount; + int nneighbors; + int start; + int current; + int supplyhead; + int supplycount; +} CCtsp_edgegenerator; + +typedef struct CCtsp_xnorm_pricer_val { + double val; + struct CCtsp_xnorm_pricer_val *next; + struct CCtsp_xnorm_pricer_val *prev; + int index; +} CCtsp_xnorm_pricer_val; + +typedef struct CCtsp_xnorm_pricer { + CCdatagroup *dat; + double *pi; + int *order; + CCtsp_xnorm_pricer_val *xminuspi_space; + CCtsp_xnorm_pricer_val *xminuspi; + int *invxminuspi; + int ncount; +} CCtsp_xnorm_pricer; + +typedef struct CCtsp_lp { + CCtsp_lpgraph graph; + CCtsp_lpcuts cuts; + CCtsp_lpcuts *pool; + CClp lp; + int *perm; + CCdatagroup *dat; + int fullcount; + struct CCtsp_genadj *fulladj; + struct CCtsp_genadjobj *fulladjspace; + int nfixededges; + int *fixededges; + struct CCtsp_qsparsegroup *sparsifier; + int edge_life; + int cut_life; + char *name; + int id; + int parent_id; + int root; + double upperbound; + double lowerbound; + CCbigguy exact_lowerbound; + CCtsp_bigdual *exact_dual; + int infeasible; + int full_edges_valid; + CClpbasis *basis; + CCtsp_lpcut_in cutqueue; /* dummy entry for doubly-linked + list */ + CCtsp_lp_result result; + CCtsp_tighten_info tighten_stats; + int branchdepth; + CCtsp_branchobj *branchhistory; +} CCtsp_lp; + +typedef struct CCtsp_lprow { + int rowcnt; + int nzcnt; + char *sense; + double *rhs; + int *begin; /* offset into the array for start of row */ + int indexspace; + int *indices; /* the column indices of the row entries */ + int entryspace; + double *entries; /* the matrix entries */ +} CCtsp_lprow; + + + +/***************************************************************************/ +/* */ +/* tsp_lp.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCtsp_cutting_loop (CCtsp_lp *lp, CCtsp_cutselect *sel, int savelp), + CCtsp_subtour_loop (CCtsp_lp *lp), + CCtsp_pricing_loop (CCtsp_lp *lp, double *bnd), + CCtsp_init_cutselect (CCtsp_lp *lp, CCtsp_cutselect *s), + CCtsp_call_x_heuristic (CCtsp_lp *lp, double *val, int *outcyc), + CCtsp_bb_cutting (char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double *upbound, CCtsp_lpcuts *pool, + CCtsp_cutselect *sel, double *val, int *prune, int *foundtour, + int *besttour), + CCtsp_init_lp (CCtsp_lp **lp, char *probname, int probnum, + char *probfilename, int ncount, CCdatagroup *dat, int ecount, + int *elist, int *elen, int excount, int *exlist, int *exlen, + int exvalid, int *ptour, double initial_ub, CCtsp_lpcuts *pool), + CCtsp_bb_init_lp (CCtsp_lp **lp, char *probname, int probnum, + int ncount, CCdatagroup *dat, int *ptour, double initial_ub, + CCtsp_lpcuts *pool), + CCtsp_get_lp_result (CCtsp_lp *lp, double *lb, double *ub, int *ecount, + int **elist, double **x, double **rc, double **node_pi, + double **cut_pi), + CCtsp_process_cuts (CCtsp_lp *lp, int *pnadded, int tighten), + CCtsp_add_cut_to_cutlist (CCtsp_lpcuts *cuts, CCtsp_lpcut *c), + CCtsp_add_cut (CCtsp_lp *lp, CCtsp_lpcut_in *d, CCtsp_lprow *cr), + CCtsp_lpcut_in_nzlist (CCtsp_lpgraph *g, CCtsp_lpcut_in *c), + CCtsp_add_nzlist_to_lp (CCtsp_lp *lp, int nzlist, int rhs, char sense, + CCtsp_lprow *cr), + CCtsp_add_vars_to_lp (CCtsp_lp *lp, CCtsp_predge *prlist, int n), + CCtsp_update_result (CCtsp_lp *lp), + CCtsp_infeas_recover (CCtsp_lp *lp), + CCtsp_test_cut_branch (CCtsp_lp *lp, CCtsp_lpclique *c, double *down, + double *up), + CCtsp_register_cliques (CCtsp_lpcuts *cuts, CCtsp_lpcut_in *c, + CCtsp_lpcut *new), + CCtsp_addbad_variables (CCtsp_lp *lp, struct CCtsp_edgegenerator *eg, + double *ppenalty, int *pnadded, double rcthresh, + double maxpenalty, int phase1, int *feasible), + CCtsp_eliminate_variables (CCtsp_lp *lp), + CCtsp_build_lpgraph (CCtsp_lpgraph *g, int ncount, int ecount, + int *elist, int *elen), + CCtsp_build_lpadj (CCtsp_lpgraph *g, int estart, int eend), + CCtsp_add_multiple_rows (CCtsp_lp *lp, CCtsp_lprow *cr), + CCtsp_delete_cut (CCtsp_lp *lp, int i), + CCtsp_find_edge (CCtsp_lpgraph *g, int from, int to), + CCtsp_find_branch (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_branchobj **bobj, double *val, int **cyc, int usecliques), + CCtsp_bb_find_branch (char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double *upperbound, + CCtsp_lpcuts *pool, CCtsp_branchobj **b, int usecliques, + int *foundtour, int *besttour), + CCtsp_check_integral (CCtsp_lp *lp, double *val, int **cyc, int *yesno), + CCtsp_find_branch_edge (CCtsp_lp *lp, int *n0, int *n1, double *val, + int **cyc, int branchtype), + CCtsp_find_branch_cliques (CCtsp_lp *lp, int nwant, int *ngot, + CCtsp_lpclique **bcliques, double **bval), + CCtsp_execute_branch (CCtsp_lp *lp, CCtsp_branchobj *b), + CCtsp_execute_unbranch (CCtsp_lp *lp, CClpbasis *basis), + CCtsp_splitprob (CCtsp_lp *lp, CCtsp_branchobj *b, int child0, int child1), + CCtsp_bb_splitprob (char *probname, int probnum, int ncount, + CCdatagroup *dat, int *ptour, double initial_ub, CCtsp_lpcuts *pool, + CCtsp_branchobj *b, int child0, int child1, double *val0, + double *val1, int *prune0, int *prune1), + CCtsp_dumptour (int ncount, CCdatagroup *dat, int *perm, char *probname, + int *tour), + CCtsp_add_branchhistory_to_lp (CCtsp_lp *lp), + CCtsp_easy_dfs_brancher (CCtsp_lp *lp, CCtsp_cutselect *sel, int depth, + double *upbound, int *bbcount, int usecliques, int *besttour), + CCtsp_bfs_brancher (char *probname, int id, double lowerbound, + CCtsp_cutselect *sel, double *upbound, int *bbcount, int usecliques, + CCdatagroup *mydat, int *ptour, CCtsp_lpcuts *pool, int ncount, + int *besttour), + CCtsp_do_interactive_branch (CCtsp_lp *lp), + CCtsp_inspect_full_edges (CCtsp_lp *lp), + CCtsp_read_probfile (CCtsp_lp *lp, char *fname, int ncount), + CCtsp_read_probfile_id (CCtsp_lp *lp, char *fname, int id, int ncount), + CCtsp_write_probfile_sav (CCtsp_lp *lp), + CCtsp_write_probfile_id (CCtsp_lp *lp), + CCtsp_dump_x (CCtsp_lp *lp, char *fname), + CCtsp_exact_price (CCtsp_lp *lp, CCbigguy *bound, int phase1), + CCtsp_edge_elimination (CCtsp_lp *lp), + CCtsp_exact_dual (CCtsp_lp *lp), + CCtsp_verify_infeasible_lp (CCtsp_lp *lp, int *yesno), + CCtsp_verify_lp_prune (CCtsp_lp *lp, int *yesno), + CCtsp_tighten_lpcut_in (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, + double *x, CCtsp_lpcut_in *d, CCtsp_tighten_info *stats, + double *pimprove), + CCtsp_tighten_lpcut (CCtsp_lpgraph *g, CCtsp_lpclique *cliques, + CCtsp_lpcut *c, double *x, CCtsp_lpcut_in *d, + CCtsp_tighten_info *stats, double *pimprove), + CCtsp_test_pure_comb (int ncount, CCtsp_lpcut_in *c, int *yes_no, + int *handle), + CCtsp_test_pseudocomb (int ncount, CCtsp_lpcut_in *c, int handle, + int *yes_no), + CCtsp_test_teeth_disjoint (int ncount, CCtsp_lpcut_in *c, int handle, + int *yes_no), + CCtsp_find_pure_handle (int ncount, CCtsp_lpcut_in *c, int *handle), + CCtsp_comb_to_double_decker (CCtsp_lpgraph *g, double *x, + CCtsp_lpcut_in *c, CCtsp_lpcut_in **d), + CCtsp_teething (CCtsp_lpgraph *g, double *x, CCtsp_lpcut_in *cut, + CCtsp_lpcut_in **newcut), + CCtsp_init_cutpool (int ncount, char *poolfilename, CCtsp_lpcuts **pool), + CCtsp_write_cutpool (int ncount, char *poolfilename, CCtsp_lpcuts *pool), + CCtsp_search_cutpool (CCtsp_lpcuts *pool, CCtsp_lpcut_in **cuts, + int *cutcount, int ncount, int ecount, int *elist, double *x), + CCtsp_search_cutpool_cliques (CCtsp_lpcuts *pool, CCtsp_lpclique **cliques, + int *cliquecount, int ncount, int ecount, int *elist, double *x, + double maxdelta, int maxcliques, double **cliquevals), + CCtsp_branch_cutpool_cliques (CCtsp_lpcuts *pool, CCtsp_lpclique **cliques, + int *cliquecount, int ncount, int ecount, int *elist, double *x, + int nwant, double **cliquevals), + CCtsp_add_to_cutpool (CCtsp_lpcuts *pool, CCtsp_lpcuts *cuts, + CCtsp_lpcut *c), + CCtsp_add_to_cutpool_lpcut_in (CCtsp_lpcuts *pool, CCtsp_lpcut_in *cut), + CCtsp_display_cutpool (CCtsp_lpcuts *pool), + CCtsp_price_cuts (CCtsp_lpcuts *pool, int ncount, int ecount, int *elist, + double *x, double *cutval), + CCtsp_clique_to_array (CCtsp_lpclique *c, int **ar, int *count), + CCtsp_clique_delta (CCtsp_lpgraph *g, double *x, CCtsp_lpclique *c, + double *delta), + CCtsp_x_greedy_tour (CCdatagroup *dat, int ncount, int ecount, int *elist, + double *x, int *cyc, double *val), + CCtsp_x_greedy_tour_lk (CCdatagroup *dat, int ncount, int ecount, + int *elist, double *x, int *cyc, double *val); + +void + CCtsp_init_tsp_lp_struct (CCtsp_lp *lp), + CCtsp_free_tsp_lp_struct (CCtsp_lp **lp), + CCtsp_add_cuts_to_queue (CCtsp_lp *lp, CCtsp_lpcut_in **c), + CCtsp_delete_cut_from_cutlist (CCtsp_lpcuts *cuts, int ind), + CCtsp_init_lprow (CCtsp_lprow *cr), + CCtsp_free_lprow (CCtsp_lprow *cr), + CCtsp_unregister_cliques (CCtsp_lpcuts *cuts, CCtsp_lpcut *c), + CCtsp_free_cutpool (CCtsp_lpcuts **pool), + CCtsp_init_lpgraph_struct (CCtsp_lpgraph *g), + CCtsp_free_lpgraph (CCtsp_lpgraph *g), + CCtsp_free_lpcut_in (CCtsp_lpcut_in *c), + CCtsp_free_lpclique (CCtsp_lpclique *c), + CCtsp_free_bigdual (CCtsp_bigdual **d), + CCtsp_init_branchobj (CCtsp_branchobj *b), + CCtsp_free_branchobj (CCtsp_branchobj *b), + CCtsp_print_branchhistory (CCtsp_lp *lp), + CCtsp_init_tighten_info (CCtsp_tighten_info *stats), + CCtsp_print_tighten_info (CCtsp_tighten_info *stats), + CCtsp_mark_clique (CCtsp_lpclique *c, int *marks, int marker), + CCtsp_mark_clique_and_neighbors (CCtsp_lpgraph *g, CCtsp_lpclique *c, + int *marks, int marker), + CCtsp_mark_cut (CCtsp_lpcut_in *c, int *marks, int marker), + CCtsp_mark_cut_and_neighbors (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, + int *marks, int marker), + CCtsp_mark_clique_and_neighbors_double (CCtsp_lpgraph *g, CCtsp_lpclique *c, + double *marks, double marker), + CCtsp_is_clique_marked (CCtsp_lpclique *c, int *marks, int marker, + int *yes_no), + CCtsp_clique_count (CCtsp_lpclique *c, int *count); + + +double + CCtsp_cutprice (CCtsp_lpgraph *g, CCtsp_lpcut_in *c, double *x); + +#else + +int + CCtsp_cutting_loop (), + CCtsp_subtour_loop (), + CCtsp_pricing_loop (), + CCtsp_init_cutselect (), + CCtsp_call_x_heuristic (), + CCtsp_bb_cutting (), + CCtsp_init_lp (), + CCtsp_bb_init_lp (), + CCtsp_get_lp_result (), + CCtsp_process_cuts (), + CCtsp_add_cut_to_cutlist (), + CCtsp_add_cut (), + CCtsp_lpcut_in_nzlist (), + CCtsp_add_nzlist_to_lp (), + CCtsp_add_vars_to_lp (), + CCtsp_update_result (), + CCtsp_infeas_recover (), + CCtsp_test_cut_branch (), + CCtsp_register_cliques (), + CCtsp_addbad_variables (), + CCtsp_eliminate_variables (), + CCtsp_build_lpgraph (), + CCtsp_build_lpadj (), + CCtsp_add_multiple_rows (), + CCtsp_delete_cut (), + CCtsp_find_edge (), + CCtsp_find_branch (), + CCtsp_bb_find_branch (), + CCtsp_check_integral (), + CCtsp_find_branch_edge (), + CCtsp_find_branch_cliques (), + CCtsp_execute_branch (), + CCtsp_execute_unbranch (), + CCtsp_splitprob (), + CCtsp_bb_splitprob (), + CCtsp_dumptour (), + CCtsp_add_branchhistory_to_lp (), + CCtsp_easy_dfs_brancher (), + CCtsp_bfs_brancher (), + CCtsp_do_interactive_branch (), + CCtsp_inspect_full_edges (), + CCtsp_read_probfile (), + CCtsp_read_probfile_id (), + CCtsp_write_probfile_sav (), + CCtsp_write_probfile_id (), + CCtsp_dump_x (), + CCtsp_exact_price (), + CCtsp_edge_elimination (), + CCtsp_exact_dual (), + CCtsp_verify_infeasible_lp (), + CCtsp_verify_lp_prune (), + CCtsp_tighten_lpcut_in (), + CCtsp_tighten_lpcut (), + CCtsp_test_pure_comb (), + CCtsp_test_pseudocomb (), + CCtsp_test_teeth_disjoint (), + CCtsp_find_pure_handle (), + CCtsp_comb_to_double_decker (), + CCtsp_teething (), + CCtsp_init_cutpool (), + CCtsp_write_cutpool (), + CCtsp_search_cutpool (), + CCtsp_search_cutpool_cliques (), + CCtsp_branch_cutpool_cliques (), + CCtsp_add_to_cutpool (), + CCtsp_add_to_cutpool_lpcut_in (), + CCtsp_display_cutpool (), + CCtsp_price_cuts (), + CCtsp_clique_to_array (), + CCtsp_clique_delta (), + CCtsp_x_greedy_tour (), + CCtsp_x_greedy_tour_lk (); + +void + CCtsp_init_tsp_lp_struct (), + CCtsp_free_tsp_lp_struct (), + CCtsp_add_cuts_to_queue (), + CCtsp_delete_cut_from_cutlist (), + CCtsp_init_lprow (), + CCtsp_free_lprow (), + CCtsp_unregister_cliques (), + CCtsp_free_cutpool (), + CCtsp_init_lpgraph_struct (), + CCtsp_free_lpgraph (), + CCtsp_free_lpcut_in (), + CCtsp_free_lpclique (), + CCtsp_free_bigdual (), + CCtsp_init_branchobj (), + CCtsp_free_branchobj (), + CCtsp_print_branchhistory (), + CCtsp_init_tighten_info (), + CCtsp_print_tighten_info (), + CCtsp_mark_clique (), + CCtsp_mark_clique_and_neighbors (), + CCtsp_mark_cut (), + CCtsp_mark_cut_and_neighbors (), + CCtsp_mark_clique_and_neighbors_double (), + CCtsp_is_clique_marked (), + CCtsp_clique_count (); + + +double + CCtsp_cutprice (); + +#endif + +/***************************************************************************/ +/* */ +/* cliqhash.c */ +/* */ +/***************************************************************************/ + +#ifdef CC_PROTOTYPE_ANSI + +int + CCtsp_init_cliquehash (CCtsp_lpcuts *cuts, int size), + CCtsp_register_clique (CCtsp_lpcuts *cuts, CCtsp_lpclique *c); + +void + CCtsp_free_cliquehash (CCtsp_lpcuts *cuts), + CCtsp_unregister_clique (CCtsp_lpcuts *cuts, int c); + +#else + +int + CCtsp_init_cliquehash (), + CCtsp_register_clique (); + +void + CCtsp_free_cliquehash (), + CCtsp_unregister_clique (); + +#endif + + + +/***************************************************************************/ +/* */ +/* cutcall.c */ +/* */ +/***************************************************************************/ + +typedef struct cutinfo { + CC_SRKexpinfo expand; + CCtsp_lpcut_in **clist; + CCtsp_lpcut_in *current; + int *cutcount; +} cutinfo; + +#ifdef CC_PROTOTYPE_ANSI + +int + CCtsp_connect_cuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x), + CCtsp_segment_cuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x), + CCtsp_exact_subtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, + int ecount, int *elist, double *x), + CCtsp_tighten_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts), + CCtsp_double_decker_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts), + CCtsp_teething_lp (CCtsp_lpcuts *cuts, CCtsp_tighten_info *stats, + CCtsp_lpcut_in **cutsout, int *cutcount, int ncount, int ecount, + int *elist, double *x, double testtol, int maxcuts), + CCtsp_copy_lpcut_in (CCtsp_lpcut_in *c, CCtsp_lpcut_in *new), + CCtsp_segment_to_subtour (CCtsp_lpcut_in **cut, int a, int b), + CCtsp_array_to_subtour (CCtsp_lpcut_in **cut, int *ar, int acount), + CCtsp_array_to_lpclique (int *ar, int acount, CCtsp_lpclique *cliq), + CCtsp_seglist_to_lpclique (int nseg, int *list, CCtsp_lpclique *cliq), + CCtsp_add_node_to_lpclique (CCtsp_lpclique *cin, CCtsp_lpclique *cout, + int n), + CCtsp_delete_node_from_lpclique (CCtsp_lpclique *cin, + CCtsp_lpclique *cout, int n), + CCtsp_lpcut_to_lpcut_in (CCtsp_lpcuts *cuts, CCtsp_lpcut *c, + CCtsp_lpcut_in *new), + CCtsp_copy_lpclique (CCtsp_lpclique *c, CCtsp_lpclique *new), + CCtsp_file_cuts (char *cutfile, CCtsp_lpcut_in **cuts, int *cutcount, + int ncount, int *tour), + CCtsp_file_cuts_write (char *cutfile, CCtsp_lpcuts *cuts, int *tour), + CCtsp_buildcut_begin (cutinfo *cuts, int init_cliquecount), + CCtsp_buildcut_addclique (cutinfo *cuts, int *arr, int size, int handle); + +void + CCtsp_init_lpcut_in (CCtsp_lpcut_in *c), + CCtsp_init_lpclique (CCtsp_lpclique *c), + CCtsp_print_lpcut_in (CCtsp_lpcut_in *c), + CCtsp_print_lpclique (CCtsp_lpclique *c), + CCtsp_lpclique_compare (CCtsp_lpclique *a, CCtsp_lpclique *b, int *diff), + CCtsp_buildcut_abort (cutinfo *cuts), + CCtsp_buildcut_finish (cutinfo *cuts, int rhs); + +#else + +int + CCtsp_connect_cuts (), + CCtsp_segment_cuts (), + CCtsp_exact_subtours (), + CCtsp_tighten_lp (), + CCtsp_double_decker_lp (), + CCtsp_teething_lp (), + CCtsp_copy_lpcut_in (), + CCtsp_segment_to_subtour (), + CCtsp_array_to_subtour (), + CCtsp_array_to_lpclique (), + CCtsp_seglist_to_lpclique (), + CCtsp_add_node_to_lpclique (), + CCtsp_delete_node_from_lpclique (), + CCtsp_lpcut_to_lpcut_in (), + CCtsp_copy_lpclique (), + CCtsp_file_cuts (), + CCtsp_file_cuts_write (), + CCtsp_buildcut_begin (), + CCtsp_buildcut_addclique (); + +void + CCtsp_init_lpcut_in (), + CCtsp_init_lpclique (), + CCtsp_print_lpcut_in (), + CCtsp_print_lpclique (), + CCtsp_lpclique_compare (), + CCtsp_buildcut_abort (), + CCtsp_buildcut_finish (); + +#endif + + + +/***************************************************************************/ +/* */ +/* edgemap.c */ +/* */ +/***************************************************************************/ + +typedef struct CCtsp_edgeinf { + int ends[2]; + int val; + struct CCtsp_edgeinf *next; +} CCtsp_edgeinf; + +typedef struct CCtsp_edgehash { + struct CCtsp_edgeinf **table; + unsigned int size; + unsigned int mult; +} CCtsp_edgehash; + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCtsp_edgehash_init (CCtsp_edgehash *h, int size), + CCtsp_edgehash_add (CCtsp_edgehash *h, int end1, int end2, int val), + CCtsp_edgehash_del (CCtsp_edgehash *h, int end1, int end2), + CCtsp_edgehash_find (CCtsp_edgehash *h, int end1, int end2); + +void + CCtsp_edgehash_delall (CCtsp_edgehash *h), + CCtsp_edgehash_free (CCtsp_edgehash *h); + +#else + +int + CCtsp_edgehash_init (), + CCtsp_edgehash_add (), + CCtsp_edgehash_del (), + CCtsp_edgehash_find (); + +void + CCtsp_edgehash_delall (), + CCtsp_edgehash_free (); + +#endif + + +/***************************************************************************/ +/* */ +/* generate.c */ +/* */ +/***************************************************************************/ + +#define CCtsp_PRICE_COMPLETE_GRAPH -1 +#define CCtsp_GEN_PRICE_EPSILON 0.0001 /* 0.0000001 */ +#define CCtsp_GEN_USE_ADJ 50 /* Cutoff for using explicit adj list */ + +#ifdef CC_PROTOTYPE_ANSI + +void + CCtsp_free_edgegenerator (CCtsp_edgegenerator *eg); + +int + CCtsp_init_edgegenerator (CCtsp_edgegenerator *eg, int ncount, + CCdatagroup *dg, CCtsp_genadj *adj, int nneighbors), + CCtsp_reset_edgegenerator (CCtsp_edgegenerator *eg, double *node_piest), + CCtsp_generate_edges (CCtsp_edgegenerator *eg, int nwant, int *pngot, + int *elist, int *elen, int *finished), + CCtsp_edgelist_to_genadj (int ncount, int ecount, int *elist, int *elen, + CCtsp_genadj **adj, CCtsp_genadjobj **adjobjspace); + +#else + +void + CCtsp_free_edgegenerator (); + +int + CCtsp_init_edgegenerator (), + CCtsp_reset_edgegenerator (), + CCtsp_generate_edges (), + CCtsp_edgelist_to_genadj (); + +#endif + + + +/***************************************************************************/ +/* */ +/* prob_io.c */ +/* */ +/***************************************************************************/ + +#define CCtsp_PROB_IO_VERSION 1 +#define CCtsp_PROB_FILE_NAME_LEN 128 + +#define CCtsp_PROB_IO_CUTS_VERSION_BASE -1000 +#define CCtsp_PROB_IO_CUTS_VERSION -1001 /* Should be <= BASE (-1000) */ + +typedef struct CCtsp_PROB_FILE { + CC_SFILE *f; + char name[CCtsp_PROB_FILE_NAME_LEN]; + int id; + int parent; + double ub; + double lb; + CCbigguy exactlb; + int nnodes; + int child0; + int child1; + int real; /* Set to 1 when we know this is a real child */ + int processed; + int infeasible; + struct { + int dat; + int edge; + int fulladj; + int cut; + int tour; + int basis; + int norms; + int fix; + int exactdual; + int history; + } offsets; +} CCtsp_PROB_FILE; + + +#ifdef CC_PROTOTYPE_ANSI + +CCtsp_PROB_FILE + *CCtsp_prob_read (char *f, int n), + *CCtsp_prob_read_name (char *f), + *CCtsp_prob_write (char *f, int n), + *CCtsp_prob_write_name (char *fname, char *pname); + +int + CCtsp_prob_file_delete (char *f, int n), + CCtsp_prob_getname (CCtsp_PROB_FILE *p, char *name), + CCtsp_prob_getid (CCtsp_PROB_FILE *p, int *id), + CCtsp_prob_getparent (CCtsp_PROB_FILE *p, int *parent), + CCtsp_prob_getub (CCtsp_PROB_FILE *p, double *ub), + CCtsp_prob_getlb (CCtsp_PROB_FILE *p, double *lb), + CCtsp_prob_getexactlb (CCtsp_PROB_FILE *p, CCbigguy *lb), + CCtsp_prob_getnnodes (CCtsp_PROB_FILE *p, int *nnodes), + CCtsp_prob_getchildren (CCtsp_PROB_FILE *p, int *child0, int *child1), + CCtsp_prob_getreal (CCtsp_PROB_FILE *p, int *real), + CCtsp_prob_getprocessed (CCtsp_PROB_FILE *p, int *processed), + CCtsp_prob_getinfeasible (CCtsp_PROB_FILE *p, int *infeasible), + CCtsp_prob_gettour (CCtsp_PROB_FILE *p, int **tour), + CCtsp_prob_getedges (CCtsp_PROB_FILE *p, int *nedges, int **elist, + int **elen), + CCtsp_prob_getcuts (CCtsp_PROB_FILE *p, CC_SFILE *s, CCtsp_lpcuts *cuts), + CCtsp_prob_getbasis (CCtsp_PROB_FILE *p, int *ccount, int *rcount, + int **cstat, int **rstat), + CCtsp_prob_getnorms (CCtsp_PROB_FILE *p, int *rcount, double **dnorm), + CCtsp_prob_getfulladj (CCtsp_PROB_FILE *p, int ncount, int *fullcount, + CCtsp_genadj **adj, CCtsp_genadjobj **adjspace), + CCtsp_prob_getfixed (CCtsp_PROB_FILE *p, int *ecount, int **elist), + CCtsp_prob_getexactdual (CCtsp_PROB_FILE *p, int ncount, + CCtsp_bigdual **d), + CCtsp_prob_gethistory (CCtsp_PROB_FILE *p, int *depth, + CCtsp_branchobj **history), + CCtsp_prob_rclose (CCtsp_PROB_FILE *p), + + CCtsp_prob_putname (CCtsp_PROB_FILE *p, char *name), + CCtsp_prob_putid (CCtsp_PROB_FILE *p, int id), + CCtsp_prob_putparent (CCtsp_PROB_FILE *p, int parent), + CCtsp_prob_putub (CCtsp_PROB_FILE *p, double ub), + CCtsp_prob_putlb (CCtsp_PROB_FILE *p, double lb), + CCtsp_prob_putexactlb (CCtsp_PROB_FILE *p, CCbigguy lb), + CCtsp_prob_putnnodes (CCtsp_PROB_FILE *p, int nnodes), + CCtsp_prob_putchildren (CCtsp_PROB_FILE *p, int child0, int child1), + CCtsp_prob_putreal (CCtsp_PROB_FILE *p, int real), + CCtsp_prob_putprocessed (CCtsp_PROB_FILE *p, int processed), + CCtsp_prob_putinfeasible (CCtsp_PROB_FILE *p, int infeasible), + CCtsp_prob_puttour (CCtsp_PROB_FILE *p, int *tour), + CCtsp_prob_putedges (CCtsp_PROB_FILE *p, int nedges, int *elist, int *elen), + CCtsp_prob_putcuts (CCtsp_PROB_FILE *p, CC_SFILE *s, CCtsp_lpcuts *cuts), + CCtsp_prob_putbasis (CCtsp_PROB_FILE *p, int ccount, int rcount, int *cstat, + int *rstat), + CCtsp_prob_putnorms (CCtsp_PROB_FILE *p, int rcount, double *dnorm), + CCtsp_prob_putfulladj (CCtsp_PROB_FILE *p, int ncount, int fullcount, + CCtsp_genadj *adj), + CCtsp_prob_putfixed (CCtsp_PROB_FILE *p, int ecount, int *elist), + CCtsp_prob_putexactdual (CCtsp_PROB_FILE *p, CCtsp_bigdual *d, int ncount), + CCtsp_prob_puthistory (CCtsp_PROB_FILE *p, int depth, + CCtsp_branchobj *history), + CCtsp_prob_wclose (CCtsp_PROB_FILE *p); + +#else + +CCtsp_PROB_FILE + *CCtsp_prob_read (), + *CCtsp_prob_read_name (), + *CCtsp_prob_write (), + *CCtsp_prob_write_name (); + +int + CCtsp_prob_file_delete (), + CCtsp_prob_getname (), + CCtsp_prob_getid (), + CCtsp_prob_getparent (), + CCtsp_prob_getub (), + CCtsp_prob_getlb (), + CCtsp_prob_getexactlb (), + CCtsp_prob_getnnodes (), + CCtsp_prob_getchildren (), + CCtsp_prob_getreal (), + CCtsp_prob_getprocessed (), + CCtsp_prob_getinfeasible (), + CCtsp_prob_gettour (), + CCtsp_prob_getedges (), + CCtsp_prob_getcuts (), + CCtsp_prob_getbasis (), + CCtsp_prob_getnorms (), + CCtsp_prob_getfulladj (), + CCtsp_prob_getfixed (), + CCtsp_prob_getexactdual (), + CCtsp_prob_gethistory (), + CCtsp_prob_rclose (), + + CCtsp_prob_putname (), + CCtsp_prob_putid (), + CCtsp_prob_putparent (), + CCtsp_prob_putub (), + CCtsp_prob_putlb (), + CCtsp_prob_putexactlb (), + CCtsp_prob_putnnodes (), + CCtsp_prob_putchildren (), + CCtsp_prob_putreal (), + CCtsp_prob_putprocessed (), + CCtsp_prob_putinfeasible (), + CCtsp_prob_puttour (), + CCtsp_prob_putedges (), + CCtsp_prob_putcuts (), + CCtsp_prob_putbasis (), + CCtsp_prob_putnorms (), + CCtsp_prob_putfulladj (), + CCtsp_prob_putfixed (), + CCtsp_prob_putexactdual (), + CCtsp_prob_puthistory (), + CCtsp_prob_wclose (); + +#endif + + + +/***************************************************************************/ +/* */ +/* qsparse.c */ +/* */ +/***************************************************************************/ + +typedef struct CCtsp_qsparsegroup { + CCdheap *add_queue; /* An empty heap will be maintained */ + CCdheap *sub_queue; /* An empty heap will be maintained */ + int *count_m1; /* The array will be maintained at 0 */ + int *count_non0; /* The array will be maintained at 0 */ + int *count_1; /* The array will be maintained at 0 */ + int *on_add_queue; /* The array will be maintained at 0 */ + int *on_sub_queue; /* The array will be maintained at 0 */ + int *mults; /* The array will be maintained at 0 */ +} CCtsp_qsparsegroup; + +#ifdef CC_PROTOTYPE_ANSI + +void + CCtsp_free_qsparsify (CCtsp_qsparsegroup **pqs); +int + CCtsp_qsparsify (CCtsp_qsparsegroup **pqs, struct CCtsp_lpgraph *g, + int *pnzlist, int *scount, struct CCtsp_sparser **slist, + int *savedcount); +#else + +void + CCtsp_free_qsparsify (); +int + CCtsp_qsparsify (); + +#endif + +#endif /* __TSP_H */ +#ifndef __XSTUFF_H +#define __XSTUFF_H + +#ifdef CC_PROTOTYPE_ANSI + +int + Xfastcuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xslowcuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xfastsubtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xexactsubtours (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xcliquetrees (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x), + Xconsecutiveones (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x, CCtsp_lpcuts *pool), + Xnecklacecuts (CCtsp_lpcut_in **cuts, int *cutcount, int ncount, int ecount, + int *elist, double *x, CCtsp_lpcuts *pool); + +#else + +int + Xfastcuts (), + Xslowcuts (), + Xfastsubtours (), + Xexactsubtours (), + Xcliquetrees (), + Xconsecutiveones (), + Xnecklacecuts (); + +#endif + +#endif /* __XSTUFF_H */ +#ifndef __FMATCH_H +#define __FMATCH_H + + +#ifdef CC_PROTOTYPE_ANSI + +int + CCfmatch_fractional_2match (int ncount, int ecount, int *elist, int *elen, + CCdatagroup *dat, double *val, int *thematching, int *thedual, + int *thebasis, int wantbasic); + +#else + +int + CCfmatch_fractional_2match (); + +#endif + +#endif /* __FMATCH_H */ +#ifndef __LINKERN_H +#define __LINKERN_H + + +#ifdef CC_PROTOTYPE_ANSI + +int + CClinkern_tour (int ncount, CCdatagroup *dat, int ecount, + int *elist, int stallcount, int repeatcount, int *incycle, + int *outcycle, double *val, int run_silently, double time_bound, + double length_bound, char *saveit_name); + +#else + +int + CClinkern_tour (); + +#endif + + + +/***************************************************************************/ +/* */ +/* Must define exactly one of: */ +/* */ +/* CC_LINKED_LIST_FLIPPER (flip_llX) */ +/* CC_ARRAY_FLIPPER (flip_ary) */ +/* CC_TWO_LEVEL_FLIPPER (flip_two) */ +/* CC_SEGMENTS_FLIPPER (flip_sg1) */ +/* CC_NO_UNDO_SEGMENTS_FLIPPER (flip_sg2) */ +/* CC_FULL_SEGMENTS_FLIPPER (flip_sg3) */ +/* CC_SPLAY_FLIPPER (flip_sp2) */ +/* CC_BTREE_FLIPPER (flip_btr) */ +/* */ +/* NOTE: If MARK_NEIGHBORS is not defined in linkern.c, then */ +/* NO_UNDO_SEGMENTS may follow a different improving sequence then */ +/* the other flippers, since the next and prevs in turn () will be */ +/* with respect to an out-of-date-tour. */ +/* */ +/***************************************************************************/ + + +#define CC_TWO_LEVEL_FLIPPER +/* #define BTREE_FLIPPER */ + +#ifdef CC_LINKED_LIST_FLIPPER +#define CC_EXTRA_INFO_FLIP +#endif + +#ifdef CC_ARRAY_FLIPPER +#define CC_USE_FLIP_CLEANING +#endif + +#ifdef CC_TWO_LEVEL_FLIPPER +#define CC_USE_FLIP_CLEANING +#endif + +#ifdef CC_NO_UNDO_SEGMENTS_FLIPPER +#define CC_USE_FLIP_CLEANING +#define CC_USE_QUICK_FLIPS +#endif + +#ifdef CC_FULL_SEGMENTS_FLIPPER +#define CC_USE_FLIP_CLEANING +#endif + +#ifdef CC_SPLAY_FLIPPER +#define CC_USE_FLIP_CLEANING +#define CC_EXTRA_INFO_FLIP +#endif + +#ifdef CC_BTREE_FLIPPER +#define CC_USE_FLIP_CLEANING +#define CC_EXTRA_INFO_FLIP +#endif + +#ifdef CC_PROTOTYPE_ANSI + +int + CClinkern_flipper_init (int ncount, int *cyc), + CClinkern_flipper_reset_perm (int ncount), + CClinkern_flipper_reset_temp (int ncount), + CClinkern_flipper_next (int x), + CClinkern_flipper_prev (int x), + CClinkern_flipper_cycle (int *x), + CClinkern_flipper_sequence_burst (int x, int y, int z), + CClinkern_flipper_sequence (int x, int y, int z); + +void +#ifdef CC_EXTRA_INFO_FLIP + CClinkern_flipper_flip (int xprev, int x, int y, int ynext), +#else + CClinkern_flipper_flip (int x, int y), +#endif + CClinkern_flipper_flip_quick (int x, int y), + CClinkern_flipper_flip_perm (int x, int y), + CClinkern_flipper_sequence_burst_init (int x, int z), + CClinkern_flipper_finish (void), + CClinkern_flipper_free_world (void); + +#else + +int + CClinkern_flipper_init (), + CClinkern_flipper_reset_perm (), + CClinkern_flipper_reset_temp (), + CClinkern_flipper_next (), + CClinkern_flipper_prev (), + CClinkern_flipper_cycle (), + CClinkern_flipper_sequence_burst (), + CClinkern_flipper_sequence (); + +void + CClinkern_flipper_flip (), + CClinkern_flipper_flip_quick (), + CClinkern_flipper_flip_perm (), + CClinkern_flipper_sequence_burst_init (), + CClinkern_flipper_finish (), + CClinkern_flipper_free_world (); + +#endif + +#endif /* __LINKERN_H */ +#ifndef __MACRORUS_H +#define __MACRORUS_H + +#define CC_SWAP(a,b,t) (((t)=(a)),((a)=(b)),((b)=(t))) + +#define CC_OURABS(a) (((a) >= 0) ? (a) : -(a)) + +#endif /* __MACRORUS_H */ diff --git a/demos/homology.geo b/demos/homology.geo index d8ba7da69b631c9a6a731495b1cfc535c70339eb..aacb943e18e296c2e7d86f1caa62c063ee3d4752 100644 --- a/demos/homology.geo +++ b/demos/homology.geo @@ -1,7 +1,7 @@ /********************************************************************* * * Gmsh tutorial 10 - * + * * Homology computation * *********************************************************************/ @@ -133,6 +133,7 @@ Physical Surface(74) = {46, 18, 20, 52, 22, 50, 24, 48, 66, 63, 60, 58, 56, 54}; // Complement of the domain surface respect to the four terminals Physical Surface(75) = {46, 63, 66, 52, 50, 48, 54, 60, 58, 56}; +/* // Create a mesh of the model Mesh 3; @@ -156,3 +157,4 @@ HomCut("t10_hom.msh") = {{69}, {70, 71, 72, 73}}; // HomGen("t10_hom.msh") = {{}, {}}; // HomGen("t10_hom.msh") = {{69}, {74}}; // HomGen("t10_hom.msh") = {{}, {74}}; +*/ diff --git a/doc/CREDITS.txt b/doc/CREDITS.txt index bc8673ed450445276c7ed58f7548353802e5d807..fae780bdc8902bcb7e3719fb09a008ae9a10f21b 100644 --- a/doc/CREDITS.txt +++ b/doc/CREDITS.txt @@ -105,6 +105,27 @@ This version of Gmsh may contain code (in the contrib/Tetgen subdirectory) copyright (C) 2002-2007 Hang Si: check the configuration options. +This version of Gmsh may contain code (in the contrib/Salome +subdirectory) copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, +CEA/DEN, CEDRAT, EDF R& D, LEG, PRINCIPIA R& D, BUREAU VERITAS: check +the configuration options. + +This version of Gmsh may contain code (in the contrib/bamg +subdirectory) from Freefem++ copyright (C) Frederic Hecht: check the +configuration options. + +This version of Gmsh may contain code (in the contrib/lbfgs +subdirectory) (C) Sergey Bochkanov (ALGLIB project): check the +configuration options. + +This version of Gmsh may contain code (in the contrib/mmg3d +subdirectory) from MMG3D Version 4.0 (C) 2004-2011 Cecile Dobrzynski +and Pascal Frey (IPB - UPMC - INRIA): check the configuration options. + +This version of Gmsh may contain code (in the contrib/Blossom +subdirectory) copyright (C) 1995-1997 Bill Cook et al.: check the +configuration options. + Special thanks to Bill Spitzak, Michael Sweet, Matthias Melcher, Greg Ercolano and others for the Fast Light Tool Kit on which Gmsh's GUI is based. See http://www.fltk.org for more info on this excellent