SCIP

Solving Constraint Integer Programs

Heur2opt.cpp
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2016 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License. */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file Heur2opt.cpp
17  * @brief 2-Optimum - combinatorial improvement heuristic for TSP
18  * @author Timo Berthold
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <cassert>
24 #include <iostream>
25 
26 #include "objscip/objscip.h"
27 #include "GomoryHuTree.h"
28 #include "Heur2opt.h"
29 #include "ProbDataTSP.h"
30 
31 using namespace tsp;
32 using namespace std;
33 
34 
35 /** method finding the edge going from the node with id index1 to the node with id index2 */
36 static
38  GRAPHNODE* nodes, /**< all nodes of the graph */
39  GRAPHNODE* node1, /**< id of the node where the searched edge starts */
40  GRAPHNODE* node2 /**< id of the node where the searched edge ends */
41  )
42 {
43  GRAPHEDGE* edge = node1->first_edge;
44 
45  // regard every outgoing edge of node index1 and stop if adjacent to node index2
46  while( edge != NULL )
47  {
48  if( edge->adjac == node2 )
49  break;
50  edge = edge->next;
51  }
52  return edge;
53 } /*lint !e715*/
54 
55 
56 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
57 SCIP_DECL_HEURFREE(Heur2opt::scip_free)
58 {
59  return SCIP_OKAY;
60 } /*lint !e715*/
61 
62 
63 /** initialization method of primal heuristic (called after problem was transformed) */
64 SCIP_DECL_HEURINIT(Heur2opt::scip_init)
65 {
66  return SCIP_OKAY;
67 } /*lint !e715*/
68 
69 
70 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
71 SCIP_DECL_HEUREXIT(Heur2opt::scip_exit)
72 {
73  return SCIP_OKAY;
74 } /*lint !e715*/
75 
76 
77 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin)
78  *
79  * This method is called when the presolving was finished and the branch and bound process is about to begin.
80  * The primal heuristic may use this call to initialize its branch and bound specific data.
81  *
82  */
83 SCIP_DECL_HEURINITSOL(Heur2opt::scip_initsol)
84 {
85  ProbDataTSP* probdata = dynamic_cast<ProbDataTSP*>(SCIPgetObjProbData(scip));
86  graph_ = probdata->getGraph(); /*lint !e613*/
87  capture_graph(graph_);
88 
89  ncalls_ = 0;
90  sol_ = NULL;
91  SCIP_CALL( SCIPallocMemoryArray(scip, &tour_, graph_->nnodes) );
92 
93  return SCIP_OKAY;
94 } /*lint !e715*/
95 
96 
97 /** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed)
98  *
99  * This method is called before the branch and bound process is freed.
100  * The primal heuristic should use this call to clean up its branch and bound data.
101  */
102 SCIP_DECL_HEUREXITSOL(Heur2opt::scip_exitsol)
103 {
104  release_graph(&graph_);
105  SCIPfreeMemoryArray(scip, &tour_);
106 
107  return SCIP_OKAY;
108 } /*lint !e715*/
109 
110 
111 /** execution method of primal heuristic 2-Opt */
112 SCIP_DECL_HEUREXEC(Heur2opt::scip_exec)
113 {
114  assert( heur != NULL );
115  SCIP_SOL* sol = SCIPgetBestSol( scip );
116  bool newsol;
117 
118  // check whether a new solution was found meanwhile
119  if( sol != sol_ )
120  {
121  sol_ = sol;
122  ncalls_ = 0;
123  newsol = true;
124  }
125  else
126  newsol = false;
127 
128  ncalls_++;
129 
130  int nnodes = graph_->nnodes; /*lint !e613*/
131 
132  // some cases need not to be handled
133  if( nnodes < 4 || sol == NULL || ncalls_ >= nnodes )
134  {
135  *result = SCIP_DIDNOTRUN;
136  return SCIP_OKAY;
137  }
138 
139  *result= SCIP_DIDNOTFIND;
140 
141  GRAPHNODE* nodes = graph_->nodes; /*lint !e613*/
142 
143  // get tour from sol and sort edges by length, if new solution was found
144  if( newsol )
145  {
146  GRAPHEDGE* edge;
147  GRAPHEDGE* lastedge = NULL;
148  GRAPHNODE* node = &nodes[0];
149  int i = 0;
150 
151  do
152  {
153  edge = node->first_edge;
154  while( edge != NULL )
155  {
156  // find the next edge of the tour
157  if( edge->back != lastedge && SCIPgetSolVal(scip, sol, edge->var) > 0.5 )
158  {
159  node = edge->adjac;
160  lastedge = edge;
161 
162  int j;
163  // shift edge through the (sorted) array
164  for(j = i; j > 0 && tour_[j-1]->length < edge->length; j-- ) /*lint !e613*/
165  tour_[j] = tour_[j-1]; /*lint !e613*/
166 
167  // and insert the edge at the right position
168  tour_[j] = edge; /*lint !e613*/
169 
170  i++;
171  break;
172  }
173  edge = edge->next;
174 
175  }
176  }while ( node != &nodes[0] );
177  assert( i == nnodes );
178 
179  }
180 
181  GRAPHEDGE** edges2test = NULL;
182  SCIP_CALL( SCIPallocBufferArray(scip, &edges2test, 4) );
183 
184  // test current edge with all 'longer' edges for improvement
185  // if swapping with crossing edges (though do 2Opt for one edge)
186  for( int i = 0; i < ncalls_ && *result != SCIP_FOUNDSOL; i++ )
187  {
188  edges2test[0] = tour_[ncalls_]; /*lint !e613*/
189  edges2test[1] = tour_[i]; /*lint !e613*/
190  edges2test[2] = findEdge( nodes, edges2test[0]->back->adjac, edges2test[1]->back->adjac );
191  edges2test[3] = findEdge( nodes, edges2test[0]->adjac, edges2test[1]->adjac );
192  assert( edges2test[2] != NULL );
193  assert( edges2test[3] != NULL );
194 
195  // if the new solution is better and variables are not fixed, update and end
196  if( edges2test[0]->length + edges2test[1]->length > edges2test[2]->length + edges2test[3]->length
197  && SCIPvarGetLbGlobal(edges2test[0]->var) == 0.0
198  && SCIPvarGetLbGlobal(edges2test[1]->var) == 0.0
199  && SCIPvarGetUbGlobal(edges2test[2]->var) == 1.0
200  && SCIPvarGetUbGlobal(edges2test[3]->var) == 1.0 )
201  {
202 
203  SCIP_Bool success;
204  SCIP_SOL* swapsol; // copy of sol with 4 edges swapped
205 
206  SCIP_CALL( SCIPcreateSol(scip, &swapsol, heur) );
207 
208  // copy the old solution
209  for( int j = 0; j < nnodes; j++)
210  {
211  SCIP_CALL( SCIPsetSolVal(scip, swapsol, tour_[j]->var, 1.0) ); /*lint !e613*/
212  }
213 
214  // and replace two edges
215  SCIP_CALL( SCIPsetSolVal(scip, swapsol, edges2test[0]->var, 0.0) );
216  SCIP_CALL( SCIPsetSolVal(scip, swapsol, edges2test[1]->var, 0.0) );
217  SCIP_CALL( SCIPsetSolVal(scip, swapsol, edges2test[2]->var, 1.0) );
218  SCIP_CALL( SCIPsetSolVal(scip, swapsol, edges2test[3]->var, 1.0) );
219  SCIP_CALL( SCIPaddSolFree(scip, &swapsol, &success) );
220 
221  assert(success);
222  *result = SCIP_FOUNDSOL;
223  ncalls_ = 0;
224 
225  }
226  }
227  SCIPfreeBufferArray(scip, &edges2test);
228 
229  return SCIP_OKAY;
230 } /*lint !e715*/
231 
232 /** clone method which will be used to copy a objective plugin */
233 SCIP_DECL_HEURCLONE(scip::ObjCloneable* Heur2opt::clone) /*lint !e665*/
234 {
235  return new Heur2opt(scip);
236 }
struct GraphEdge * next
Definition: GomoryHuTree.h:59
double length
Definition: GomoryHuTree.h:57
2-Optimum - combinatorial improvement heuristic for TSP
SCIP_DECL_HEUREXITSOL(Heur2opt::scip_exitsol)
Definition: Heur2opt.cpp:102
SCIP_DECL_HEURINIT(Heur2opt::scip_init)
Definition: Heur2opt.cpp:64
generator for global cuts in undirected graphs
SCIP_DECL_HEURFREE(Heur2opt::scip_free)
Definition: Heur2opt.cpp:57
SCIP_VAR * var
Definition: GomoryHuTree.h:64
SCIP_DECL_HEUREXEC(Heur2opt::scip_exec)
Definition: Heur2opt.cpp:112
GRAPHNODE * adjac
Definition: GomoryHuTree.h:62
struct GraphEdge * back
Definition: GomoryHuTree.h:60
struct GraphEdge * first_edge
Definition: GomoryHuTree.h:43
SCIP_DECL_HEUREXIT(Heur2opt::scip_exit)
Definition: Heur2opt.cpp:71
static GRAPHEDGE * findEdge(GRAPHNODE *nodes, GRAPHNODE *node1, GRAPHNODE *node2)
Definition: Heur2opt.cpp:37
GRAPH * getGraph()
Definition: ProbDataTSP.h:111
C++ problem data for TSP.
SCIP_DECL_HEURINITSOL(Heur2opt::scip_initsol)
Definition: Heur2opt.cpp:83
SCIP_DECL_HEURCLONE(scip::ObjCloneable *Heur2opt::clone)
Definition: Heur2opt.cpp:233
void capture_graph(GRAPH *gr)
void release_graph(GRAPH **gr)