{"id":18521777,"url":"https://github.com/simphotonics/simulated_annealing","last_synced_at":"2025-05-14T18:09:18.999Z","repository":{"id":56839436,"uuid":"313135134","full_name":"simphotonics/simulated_annealing","owner":"simphotonics","description":"Simulated annealing framework for Dart. ","archived":false,"fork":false,"pushed_at":"2024-05-30T17:27:13.000Z","size":7142,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-17T05:25:18.789Z","etag":null,"topics":["algorithm","continuous-variable","discrete-variable","optimization","probabilistic","random-number","simulated-annealing","temperature"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/simulated_annealing","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simphotonics.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-15T22:24:23.000Z","updated_at":"2024-05-30T17:27:16.000Z","dependencies_parsed_at":"2024-05-30T20:14:29.766Z","dependency_job_id":"aeb2deae-04ee-4320-9beb-ee02921e8d27","html_url":"https://github.com/simphotonics/simulated_annealing","commit_stats":{"total_commits":366,"total_committers":1,"mean_commits":366.0,"dds":0.0,"last_synced_commit":"3be769b618a45912399a239bb8512ceb3e355255"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simphotonics%2Fsimulated_annealing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simphotonics%2Fsimulated_annealing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simphotonics%2Fsimulated_annealing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simphotonics%2Fsimulated_annealing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simphotonics","download_url":"https://codeload.github.com/simphotonics/simulated_annealing/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254198510,"owners_count":22030966,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithm","continuous-variable","discrete-variable","optimization","probabilistic","random-number","simulated-annealing","temperature"],"created_at":"2024-11-06T17:27:35.066Z","updated_at":"2025-05-14T18:09:13.990Z","avatar_url":"https://github.com/simphotonics.png","language":"Dart","readme":"# Simulated Annealing For Dart\n[![Dart](https://github.com/simphotonics/simulated_annealing/actions/workflows/dart.yml/badge.svg)](https://github.com/simphotonics/simulated_annealing/actions/workflows/dart.yml)\n\n\n## Introduction\n[Simulated annealing][SA-Wiki] (SA) is an algorithm aimed at finding the *global* minimum\nof a function E(x\u003csub\u003e0\u003c/sub\u003e,\u0026nbsp;x\u003csub\u003e1\u003c/sub\u003e,\u0026nbsp;...,\u0026nbsp;x\u003csub\u003en\u003c/sub\u003e)\nfor a given region \u0026omega;(x\u003csub\u003e0\u003c/sub\u003e,\u0026nbsp;x\u003csub\u003e1\u003c/sub\u003e,\u0026nbsp;...,\u0026nbsp;x\u003csub\u003en\u003c/sub\u003e).\nThe function to be minimized can be interpreted as the\n**system energy**. In that case, the global minimum represents\nthe **ground state** of the system.\n\nSimulated annealing works by randomly\nselecting a new point (y\u003csub\u003e0\u003c/sub\u003e,\u0026nbsp;y\u003csub\u003e1\u003c/sub\u003e,\u0026nbsp;\n...,\u0026nbsp;y\u003csub\u003en\u003c/sub\u003e)  in the neighbourhood of the\ncurrent solution, evaluating the energy function E(y\u003csub\u003e0\u003c/sub\u003e,\u0026nbsp;\ny\u003csub\u003e1\u003c/sub\u003e,\u0026nbsp;...,\u0026nbsp;y\u003csub\u003en\u003c/sub\u003e),\nand deciding if the new solution is accepted or rejected:\n* If \u0026Delta;E = E - E\u003csub\u003emin\u003c/sub\u003e \u003c 0 ,where E\u003csub\u003emin\u003c/sub\u003e is a previously\nfound energy minimum, the new solution is accepted with probability: 1.0.\n* If \u0026Delta;E \u003e 0, the new solution is accepted with probability:\nP(\u0026Delta;E \u003e 0, T) = e\u003csup\u003e-\u0026Delta;E/(k\u003csub\u003eB\u003c/sub\u003e\u0026middot;T)\u003c/sup\u003e.\nThe [Boltzmann constant][Boltzmann] k\u003csub\u003eB\u003c/sub\u003e  relates the system\ntemperature with the kinetic energy of particles in a gas.\nIn the context of SA, it is customary to set k\u003csub\u003eB\u003c/sub\u003e\u0026nbsp;\u0026equiv;\u0026nbsp;1.\n\nAccepting up-hill moves provides a method of escaping from local energy minima.\nThe acceptance probability for solution satisfying \u0026Delta;E \u003e 0\ndecreases with decreasing temperature. As such, the temperature is a parameter\nthat controls the probability of up-hill moves.\n\n\u003cdetails\u003e\u003csummary\u003e The algorithm name was coined by ... click to show details.\n\u003c/summary\u003e\nKirkpatrick et al. and was\nderived from the process of annealing a metal alloy or glass.\nThe first step of the annealing process consists of heating a\nsolid material above a critical temperature. This allows its atoms to gain\nsufficient kinetic energy to be able to rearrange themselves.\nThen the temperature is decreased sufficiently slowly\nin order to minimize atomic lattice defects as the material solidifies.\n\n\n\nThe expression above ensures\nthat the acceptance probability decreases with decreasing temperature (for \u0026Delta;E \u003e 0).\nAs such, the temperature is a parameter that controls the probability of up-hill moves.\n\u003c/details\u003e\n\n![Energy Simulated Annealing](https://github.com/simphotonics/simulated_annealing/raw/main/images/energy_composite.gif)\n\nThe process is demonstrated in the animation above. The left figure shows a\nspherical 3D search space while the energy value is represented by colour.\nThe figure on the right shows a projection of the energy function onto the\nx-y plane. Initially, random points are chosen\nfrom a large region encompasing the entire spherical search space.\n In the simulation shown above, intermediate solutions\nnear the local minimum are followed by up-hill moves.\nAs the temperature drops the search neighourhood\nis contracted and the solution converges to the\nglobal minimum.\n\n## Usage\nTo use this package include [`simulated_annealing`][simulated_annealing]\nas a `dependency` in your `pubspec.yaml` file.\n\nThe following steps are required to set up the SA algorithm.\n1. Specify the [search space][search space] \u0026omega;.\n   Common 2d and 3d search spaces\n   (circle, sphere, rectangle, box, disk, cone, triangle)\n   are predefined as static functions of the\n   class [`SearchSpace`][SearchSpace].\n\n   \u003cdetails\u003e\u003csummary\u003e Click to show the source code.\u003c/summary\u003e\n\n    ```Dart\n    // Defining a spherical space in terms of Cartesian Coordinates\n    // using parametric intervals.\n    import 'dart:math';\n\n    import 'package:list_operators/list_operators.dart';\n    import 'package:simulated_annealing/simulated_annealing.dart';\n\n    final radius = 2;\n    final x = FixedInterval(-radius, radius, name: 'x');\n\n    num yLimit() =\u003e sqrt(pow(radius, 2) - pow(x.next(), 2));\n    final y = ParametricInterval(() =\u003e -yLimit(), yLimit, name: 'y');\n\n    num zLimit() =\u003e sqrt(pow(radius, 2) - pow(y.next(), 2) - pow(x.next(), 2));\n    final z = ParametricInterval(() =\u003e -zLimit(), zLimit, name: 'z');\n\n    final deltaPositionMin = \u003cnum\u003e[1e-6, 1e-6, 1e-6];\n    final space = SearchSpace.parametric([x, y, z]);\n    ```\n    \u003c/details\u003e\n\n\n2. Define the system [`EnergyField`][EnergyField], an object encapsulating\n   the energy function (cost function) and its domain: the search space.\n\n   \u003cdetails\u003e\u003csummary\u003e Click to show the source code.\u003c/summary\u003e\n\n    ```Dart\n    // Defining an energy function.\n    final globalMin = [0.5, 0.7, 0.8];\n    final localMin = [-1.0, -1.0, -0.5];\n    num energy(List\u003cnum\u003e position) {\n      return 4.0 -\n          4.0 * exp(-4 * globalMin.distance(position)) -\n          0.3 * exp(-6 * localMin.distance(position));\n    }\n\n    final field = EnergyField(\n      energy,\n      space,\n    );\n\n    ```\n    \u003c/details\u003e\n3. Create an instance of [`LoggingSimulator`][LoggingSimulator] or\n   alternatively extend the abstract class [`Simulator`][SimulatorClass].\n    \u003cdetails\u003e\u003csummary\u003e Click to show source code.\u003c/summary\u003e\n\n    ```Dart\n    import 'dart:io';\n    import 'package:list_operators/list_operators.dart';\n    import 'package:simulated_annealing/simulated_annealing.dart';\n    import '../../test/src/energy_field_instance.dart';\n\n      // Construct a simulator instance.\n      final simulator = LoggingSimulator(\n        field, // Defined in file `energy_field_example.dart'\n        gammaStart: 0.8,\n        gammaEnd: 0.05,\n        outerIterations: 100,\n        innerIterationsStart: 2,\n        innerIterationsEnd: 10,\n      );\n\n      // The perturbation magnitude at the end of the annealing cycle.\n      simulator.deltaPositionEnd = [1e-7, 1e-7, 1e-7];\n    ```\n    \u003c/details\u003e\n\n4. Start the [simulated annealing][simulator] process.\n    \u003cdetails\u003e\u003csummary\u003e Click to show the source code.\u003c/summary\u003e\n\n    ```Dart\n\n    /// To run this program navigate to the root folder in your local\n    /// copy of the package `simulated_annealing` and use the command:\n    /// $ dart example/bin/simulated_annealing_example.dart\n    void main() async {\n      print(await simulator.info);\n\n      print('Start annealing process ...');\n      final xSol = await simulator.anneal(\n        isRecursive: true,\n        isVerbose: true,\n      );\n      print('Annealing ended.');\n      print('Writing log to file: example/data/log.dat');\n      await File('example/data/log.dat').writeAsString(simulator.export());\n      print('Finished writing. ');\n\n      print('Solution: $xSol');\n      print('xSol - globalMin: ${xSol - globalMin}.');\n    }\n    ```\n    \u003c/details\u003e\n\n\n## Algorithm Tuning\n\nIt can be shown that by selecting a sufficiently high initial\ntemperature the algorithm converges to the global minimum if the temperature\ndecreases on a logarithmic scale (slow cooling schedule) and\nthe number of inner iterations (Markov chain length)\nis sufficiently high [\\[1\\]][nikolaev2010].\n\nPractical implementations of the SA algorithm aim to generate\nan acceptable solution with *minimal* computational effort.\nFor such *fast cooling* schedules, algorithm convergence to the\nglobal minimum is not\nstrictly guaranteed. In that sense, SA is a heuristic approach and some\ndegree of trial and error is required to determine which annealing schedule\nworks best for a given problem.\n\n\nThe behaviour of the annealing simulator can be tuned using the following **optional** parameters of the [`Simulator`][SimulatorClass] constructor:\n* `gammaStart`: Initial acceptance probability with default value 0.7. Useful values for \u0026gamma;\u003csub\u003estart\u003c/sub\u003e\nare in the range of \\[0.7,\u0026nbsp;0.9\\]. If \u0026gamma;\u003csub\u003estart\u003c/sub\u003e is too low, up-hill moves are unlikely (potentially) preventing the SA algorithm from\nescaping a local miniumum. If \u0026gamma;\u003csub\u003estart\u003c/sub\u003e is set close to 1.0 the algorithm will accept\ntoo many up-hill moves at high temperatures wasting computational time and delaying convergence.\n* `gammaEnd`: Final acceptance probability. Towards the end of the annealing process one assumes\n   that the solution has converged towards the global minimum and up-hill moves should be restricted. For this reason \u0026gamma;\u003csub\u003eend\u003c/sub\u003e has default value 0.05.\n* `outerIterations`: Determines the number of temperature steps in the annealing schedule.\n   It is recommended to start with a higher number of\n   outer iterations (number of entries in the sequence of temperatures) and log\n   quantities like the current system energy, temperature, and the intermediate solutions.\n* `innerIterationsStart`: The number of inner iterations (at constant temperature)\n   at the start of the annealing process.\n* `innerIterationsEnd`: The number of inner iterations (at constant temperature)\n   at the end of the annealing process.\n* `sampleSize`: The size of the sample used to determine the initial and final\n   annealing temperature.\n\n\nAdditionally, it is possible to set the class variable `temperatureSequence`\nto function of type [`TemperatureSequence`][TemperatureSequence]\nthat is used to determine the temperature at each outer iteration step.\n\n\nThe figure below shows a typical SA log where the x-coordinate of the solution (green dots)\nconverges asymptotically to 0.5.\nThe graph is discussed in more detail [here].\n\n![Convergence Graph](https://github.com/simphotonics/simulated_annealing/raw/main/images/convergence.gif)\n\nThe number of inner iterations (performed while the temperature is kept constant)\nis also referred to as Markov chain length and is determined by a\nfunction with typedef [`MarkovChainLength`][MarkovChainLength]. It can be adjusted by setting the\nsimulator arguments `innerIterationsStart` and `innerIterationsEnd`. In general,\nit is advisable to increase the number of inner Iterations towards the end of\nthe annealing process in order to increase the algorithm precision.\n\n\n## Annealing Schedule\n\nIn general, the following information is required to define an annealing schedule:\n* T\u003csub\u003estart\u003c/sub\u003e, the initial temperature,\n* T\u003csub\u003eend\u003c/sub\u003e, the final temperature,\n* the number of outer iterations (temperature steps),\n* a function of type [`TemperatureSequence`][TemperatureSequence]\n  that is used to determine the temperature at each (outer) iteration step.\n\nThe class [`EnergyField`][EnergyField] provides the methods `tStart` and `tEnd`.\nThese use an algorithm introduced by Ben-Ameur to calculate the\ninitial and final annealing temperature [\\[2\\]][ben-ameur2004].\n\n\n## Examples\n\nFurther information can be found in the folder [example]. The following topics are covered:\n- [search space],\n- [annealing schedule],\n- system energy and logging [simulator].\n\n\n\n## Features and bugs\n\nPlease file feature requests and bugs at the [issue tracker][tracker].\n\n[tracker]: https://github.com/simphotonics/simulated_annealing/issues\n\n[example]: https://github.com/simphotonics/simulated_annealing/tree/main/example\n\n[anneal]: https://pub.dev/documentation/simulated_annealing/latest/simulated_annealing/Simulator/anneal.html\n\n[annealing schedule]: https://github.com/simphotonics/simulated_annealing/tree/main/example/ANNEALING_SCHEDULE.md\n\n[Boltzmann]: https://en.wikipedia.org/wiki/Boltzmann_constant\n\n[EnergyField]: https://pub.dev/documentation/simulated_annealing/latest/simulated_annealing/EnergyField-class.html\n\n[here]: https://github.com/simphotonics/simulated_annealing/tree/main/example/SIMULATOR.md\n\n[kirkpatrick1983]: https://doi.org/10.1126%2Fscience.220.4598.671\n\n[ledesma2008]: https://cdn.intechopen.com/pdfs/4631/InTech-Practical_considerations_for_simulated_annealing_implementation.pdf\n\n[LoggingSimulator]: https://pub.dev/documentation/simulated_annealing/latest/simulated_annealing/LoggingSimulator-class.html\n\n[MarkovChainLength]: https://pub.dev/documentation/simulated_annealing/latest/simulated_annealing/MarkovChainLength.html\n\n[nikolaev2010]: https://doi.org/10.1007/978-1-4419-1665-5_1\n\n[simulated_annealing]: https://pub.dev/packages/simulated_annealing\n\n[SimulatorClass]: https://pub.dev/documentation/simulated_annealing/latest/simulated_annealing/Simulator-class.html\n\n[SA-Wiki]: https://en.wikipedia.org/wiki/Simulated_annealing\n\n[search space]: https://github.com/simphotonics/simulated_annealing/tree/main/example/SEARCH_SPACE.md\n\n[SearchSpace]: https://pub.dev/documentation/simulated_annealing/latest/simulated_annealing/SearchSpace-class.html\n\n[simulator]: https://github.com/simphotonics/simulated_annealing/tree/main/example/SIMULATOR.md\n\n[TemperatureSequence]: https://pub.dev/documentation/simulated_annealing/latest/simulated_annealing/TemperatureSequence.html\n\n[ben-ameur2004]: https://www.researchgate.net/publication/227061666_Computing_the_Initial_Temperature_of_Simulated_Annealing","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimphotonics%2Fsimulated_annealing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimphotonics%2Fsimulated_annealing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimphotonics%2Fsimulated_annealing/lists"}