summaryrefslogtreecommitdiff
path: root/casa/annealing/Anneal.C
blob: b77e344f33154bf4a6c8beb23cbed2ef309461d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2008, 2009 Brady J. Garvin

// This file is part of Covering Arrays by Simulated Annealing (CASA).

// CASA is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// CASA is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with CASA.  If not, see <http://www.gnu.org/licenses/>.


#include "io/Usage.H"

#include "annealing/Anneal.H"
#include "annealing/Bounds.H"
#include "annealing/AnnealingSuccess.H"
#include "annealing/AnnealingPartitioner.H"

#include "search/Search.H"
#include "search/StateGuide.H"

#include "covering/space/SingleChangeSpace.H"
#include "covering/space/GraftSpace.H"
#include "covering/heuristic/CoveringArrayHeuristic.H"
#include "covering/goal/CoverageGoal.H"
#include "covering/filter/CoveringArrayAnnealingFilter.H"
#include "covering/report/IterationReport.H"

#include "algorithms/BinarySearch.H"

CoveringArray anneal
  (const SpecificationFile&specification,
   const ConstraintFile&constraints,
   unsigned iterations,
   double startingTemperature,
   double decrement) {
  std::cout << "Setting up annealing framework" << std::endl;
  // Build and connect all of the pieces of the search.
  // For simulated annealing:
  SearchConfiguration configuration(false,true,1U,0U);
#ifdef WITHOUT_INNER
  SingleChangeSpace space
#else
  GraftSpace space
#endif
    (specification.getStrength(), specification.getOptions());
  // Add the constraints.
  {
    SATSolver&solver = space.getSolver();
    const Array<InputClause>&clauses = constraints.getClauses();
    for (unsigned i = clauses.getSize(); i--;) {
      solver.addClause(const_cast<InputClause&>(clauses[i]));
    }
  }
  CoveringArrayHeuristic heuristic;
  StateGuide<CoveringArray, CoverageCost>guide;
  CoverageGoal goal(space.computeTargetCoverage());
  CoveringArrayAnnealingFilter filter(startingTemperature,decrement);
  IterationReport iterationReport;
  Search<CoveringArray, CoverageCost>search
    (configuration, &space, &heuristic, &guide, &goal, &filter, true);
  AnnealingPartitioner partitioner;
  // Add the listeners.
  {
    // For cooling:
    ((EventSource<SearchIteration>&)search).addListener(filter);
    typedef EventSource<SearchFinish<CoveringArray, CoverageCost> >
      FinishEventSourceT;
    // Structure start states:
    ((FinishEventSourceT&)search).addListener(space);
    // Use search feedback to guide the outer search:
    ((FinishEventSourceT&)search).addListener(partitioner);
    // Give reports on iterations taken:
    ((FinishEventSourceT&)search).addListener(iterationReport);
  }
  CoveringArray initialSolution
    (0,
     specification.getStrength(),
     specification.getOptions(),
     space.getSolver());

  // Here we go...
  std::cout << "Annealing"
#ifdef WITHOUT_INNER
       << " (without t-set replacement)"
#endif
#ifdef WITHOUT_OUTER
       << " (without extra outer search)"
#endif
       << std::endl;
  unsigned lower =
    computeLowerBound(specification.getStrength(), specification.getOptions());
  unsigned upper =
    computeUpperBound(specification.getStrength(), specification.getOptions());
  AnnealingSuccess annealingSuccess(search, iterations, initialSolution);

  std::cout << "Suspect that the optimum number of rows is in [" << lower <<
    ".." << upper << ']' << std::endl;
  std::cout << "Starting binary search" << std::endl;
  BinarySearch binarySearch(annealingSuccess, partitioner);
  unsigned result = binarySearch(lower, upper + 1 - lower);
  while (result > upper) {
    upper <<= 1;
    std::cout << "Trying more conservative upper bound " << upper << std::endl;
    result = binarySearch(lower, upper + 1 - lower);
  }
#ifndef WITHOUT_OUTER
  do {
    if (result == lower) {
      if (lower > 5) {
	lower -= 5;
      } else {
	--lower;
	if (!lower) {
	  break;
	}
      }
      std::cout << "Trying less conservative lower bound " << lower <<
	std::endl;
    }
    unsigned lastResult = result;
    unsigned upped = 0;
    do {
      if (lastResult == result) {
	iterations *= 2;
	annealingSuccess.setIterations(iterations);
	std::cout << "Upping iterations to " << iterations << std::endl;
	++upped;
      } else {
	upped = 0;
      }
      lastResult = result;
      std::cout << "Restarting binary search with best result at " <<
	lastResult << " rows" << std::endl;
      filter.setTemperature(startingTemperature);
      result = binarySearch(lower, lastResult - lower);
    } while ((result < lastResult || upped < retries) && result > lower);
  } while (result == lower);
#endif
  std::cout << "Giving up with best result at " << result << " rows" <<
    std::endl;
  std::cout << "Total cost of computation: " << iterationReport.getTotal() <<
    " iteration(s)" << std::endl;
  return annealingSuccess.getSolution();
}