anneal method Null safety

Future<List<num>> anneal(
  1. MarkovChainLength markov,
  2. {bool isRecursive = false,
  3. num ratio = 0.5,
  4. bool isVerbose = false}
)

Starts the simulated annealing process and returns the best solution found.

  • isRecursive: Flag used to call the method recursively if the algorithm converges towards a local minimum. (The algorithm keeps track of the lowest energy values previously visited.)
  • ratio: Factor reducing the length of the initial temperature sequence during recursive calls. The parameter is used to model repeated annealing cycles with decreasing initial temperature.
  • Note: 0.0 < ratio < 1.0.

Implementation

Future<List<num>> anneal(
  MarkovChainLength markov, {
  bool isRecursive = false,
  num ratio = 0.5,
  bool isVerbose = false,
}) async {
  /// Initialize parameters:
  final temperatures = await this.temperatures;
  final perturbationMagnitudes = await this.perturbationMagnitudes;
  final grid = await this.grid;
  num dE = 0;

  if (_recursionCounter == 0) {
    _t = temperatures.first;
    _deltaPosition = perturbationMagnitudes.first;
    _currentGrid = grid.first;
    prepareLog();
    recordLog();
  }

  // During the first iteration _ratio = 1.0 and i = 0.
  final _ratio = pow(ratio.abs(), _recursionCounter);
  var i = (temperatures.length * (1.0 - _ratio)).toInt();

  if (_recursionCounter > 0 && isVerbose) {
    print('Restarted annealing at:');
    print('  temperature: ${temperatures[i]},');
    print('  position: $_currentMinPosition, ');
    print('  energy: $_currentMinEnergy');
  }
  ++_recursionCounter;

  // Outer iteration loop.
  for (i; i < temperatures.length; i++) {
    _t = temperatures[i];
    _deltaPosition = perturbationMagnitudes[i];
    _currentGrid = grid[i];

    // Inner iteration loop.
    for (var j = 0; j < markov(_t, _currentGrid); j++) {
      // Choose next random point and calculate energy difference.
      dE = _field.perturb(
            _currentMinPosition,
            _deltaPosition,
            grid: _currentGrid,
          ) -
          _currentMinEnergy;

      if (dE < 0) {
        _currentMinEnergy = _field.value;
        _currentMinPosition = _field.position;
        _acceptanceProbability = 1.0;
      } else {
        _acceptanceProbability = exp(-dE / _t);
        if (_acceptanceProbability > Interval.random.nextDouble()) {
          _currentMinEnergy = _field.value;
          _currentMinPosition = _field.position;
        }
      }
      recordLog();
    }

  }
  if (globalMinEnergy < _currentMinEnergy) {
    if (isVerbose) {
      print('------------------------------------------------');
      print('E_min_global($globalMinPosition) = $globalMinEnergy ');
      print('E_min($_currentMinPosition) = $_currentMinEnergy!');
      print('Returning global minimum solution!');
      print('');
    }
    _currentMinPosition = globalMinPosition;
    _currentMinEnergy = globalMinEnergy;
    if (isRecursive) {
      _currentMinPosition = await anneal(
        markov,
        isRecursive: isRecursive,
        ratio: ratio,
      );
    }
  }
  return _currentMinPosition;
}