Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid copies if it is possible to undo a move #50

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

adolenc
Copy link

@adolenc adolenc commented May 3, 2024

For states with complex objects, copies can take a significant bulk of the time spent by the algorithm. This pull requests add optional support for defining def undo_move(self) method on the class, which the user can implement to undo the last move, almost avoiding the copying in the body of the annealing.

For demonstration purposes consider the following (admittedly convoluted) example:

import random
from simanneal import Annealer

class Queen:
    def __init__(self, row):
        self.row = row
        self.dummy1 = set(range(12))
        self.dummy2 = {i:i for i in range(15)}
        self.dummy3 = {i:i for i in range(20)}


class NQueensProblem(Annealer):
    def move(self):
        """Move a queen on a random column to some different row."""
        column = random.randrange(len(self.state))
        new_row = random.randrange(len(self.state))

        self.last_move = (column, self.state[column].row)
        self.state[column].row = new_row

    def undo_move(self):
        self.state[self.last_move[0]].row = self.last_move[1]

    def energy(self):
        """Calculates the number of attacks among the queens."""
        e = 0
        for i in range(len(self.state)):
            for j in range(i + 1, len(self.state)):
                e += self.state[i].row == self.state[j].row
                e += abs(i - j) == abs(self.state[i].row - self.state[j].row)
        return e


if __name__ == '__main__':
    nqueens = NQueensProblem([Queen(row) for row in range(20)])
    nqueens.Tmax = 100
    nqueens.Tmin = 0.1
    nqueens.steps = 500000
    state, e = nqueens.anneal()

    print()
    print(f"number of attacks: {e}")
    print([s.row for s in state])

On my pc, this code runs approximately 20x slower when I comment out undo_move (3 minutes vs 10 seconds).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant