############################################ # Copyright (c) Microsoft Corporation. All Rights Reserved. # # Check if the given graph has a Hamiltonian cycle. # # Author: Ganesh Gopalakrishnan ganesh@cs.utah.edu ############################################ from z3 import * def gencon(gr): """ Input a graph as an adjacency list, e.g. {0:[1,2], 1:[2], 2:[1,0]}. Produces solver to check if the given graph has a Hamiltonian cycle. Query the solver using s.check() and if sat, then s.model() spells out the cycle. Two example graphs from http://en.wikipedia.org/wiki/Hamiltonian_path are tested. ======================================================= Explanation: Generate a list of Int vars. Constrain the first Int var ("Node 0") to be 0. Pick a node i, and attempt to number all nodes reachable from i to have a number one higher (mod L) than assigned to node i (use an Or constraint). ======================================================= """ L = len(gr) cv = [Int('cv%s'%i) for i in range(L)] s = Solver() s.add(cv[0]==0) for i in range(L): s.add(Or([cv[j]==(cv[i]+1)%L for j in gr[i]])) return s def examples(): # Example Graphs: The Dodecahedral graph from http://en.wikipedia.org/wiki/Hamiltonian_path grdodec = { 0: [1, 4, 5], 1: [0, 7, 2], 2: [1, 9, 3], 3: [2, 11, 4], 4: [3, 13, 0], 5: [0, 14, 6], 6: [5, 16, 7], 7: [6, 8, 1], 8: [7, 17, 9], 9: [8, 10, 2], 10: [9, 18, 11], 11: [10, 3, 12], 12: [11, 19, 13], 13: [12, 14, 4], 14: [13, 15, 5], 15: [14, 16, 19], 16: [6, 17, 15], 17: [16, 8, 18], 18: [10, 19, 17], 19: [18, 12, 15] } import pprint pp = pprint.PrettyPrinter(indent=4) pp.pprint(grdodec) sdodec=gencon(grdodec) print(sdodec.check()) print(sdodec.model()) # ======================================================= # See http://en.wikipedia.org/wiki/Hamiltonian_path for the Herschel graph # being the smallest possible polyhedral graph that does not have a Hamiltonian # cycle. # grherschel = { 0: [1, 9, 10, 7], 1: [0, 8, 2], 2: [1, 9, 3], 3: [2, 8, 4], 4: [3, 9, 10, 5], 5: [4, 8, 6], 6: [5, 10, 7], 7: [6, 8, 0], 8: [1, 3, 5, 7], 9: [2, 0, 4], 10: [6, 4, 0] } pp.pprint(grherschel) sherschel=gencon(grherschel) print(sherschel.check()) # ======================================================= if __name__ == "__main__": examples()