Solving CryptoQuotes with PVM:

Description of the Algorithm


Return to Contents Return to Project Reports

A Word About PVM

PVM creates a "virtual machine"; that is, an abstract representation of a large problem divided into many smaller "tasks". There can be any number of actual hosts present, all connected over a network of some kind. PVM is implemented here as C or C++ libraries, and these libraries contain commands allowing the user to "spawn" tasks to a specific host or allow PVM to divide up the tasks. Typically, the former is not done unless the user wants to address issues of load balancing, especially if s/he knows that a physical host on the network is significantly faster or slower than the other architechtures present.

A control console for PVM can be accessed via a unix command, and there the user can add or delete hosts from the current configuration. Values may be assigned to the relative processing speeds of the hosts, and this information can be retrieved from within the C code for the process. This is useful, again, for load balancing.



The Algorithm

Each task in this problem is given a word to work on. The task eliminates words if possible and determines through elimination which letters each scrambled letter cannot be. When a task reaches the end of its assigned dictionary (appropriate to the length of the word it is assigned), it performs a global update, giving the other slaves its newfound information about which letters can be eliminated from their lists Meanwhile, the other slaves were doing the same thing, and every so often (in a variable set by the user), the task checks its message buffer to see if the is an update waiting. If so, it gets the update and improves its local version of the letter matching list.

The letters are represented by a matrix, and a 1 in the matrix indicates that a given letter in the scrambled quote cannot be a certain letter in the solved quote. At a certain point during the execution, a slave may discover that there is only one word left in its dictionary, and determines that it must be the solution. It imparts this finding to the master, who in turn performs a global update to all the slaves still dutifully racing towards a solution. When all the words are solved, the master halts and prints the solution to standard output.

During the course of a normal execution, some slaves may become halted, unable to proceed further with its word because there are too many possibilities for each letter to effectively narrow down the dictionary to one word. The key to this algorithm is that updates are mutually beneficial, and all the tasks must halt in order for the program to admit defeat. Sometimes, of course, the puzzle is, unfortunately, unsolvable. This may be due to one or more of the following:

  • A slave is able to eliminate all words from its dictionary; this means that word is in fact not in the dictionary.
  • A slave runs into some unpleasant memory fault... unavoidable if too many slaves are spawned to one host
  • All the slaves are halted, waiting for updates, and there are no updates in their buffers to be gotten
  • If the puzzle is unsolvable, the program will exit and print out all that it has discovered about the cryptoquote, including a list of what letters have not been eliminated and the different possibilities for the various words yet unsolved in the quote. This is typical of very short quotes or quotes containing only very short words. It should be noted that humans cannot solve such quotes either...

    Here is pseudocode for the cryptoquote solving program, the MASTER part:

      CRYPTO (cryptoquote filename) (dictionary name)
        read in cryptoquote
        for (n words in cryptoquote)
          spawn task "crypto_slave"
          pass message with a word to task
        while not(problem solved) and not(problem halted)
          wait for message in buffer
          case (messagetype)
            "word solved": 
    	  update all slaves with new info
    	  reduce list of words left to solve
    	  print to screen the solution of the word
    	"task halted": note the fact in an array of n booleans
          if (wordsleft unsolved) = 0
            problem solved
          if all positions in (is a given slave halted)and 
    	(no messages in any slave's buffer)
            problem halted
        if (problem solved)
          print solution
        else
          print knowledge so far
      end CRYPTO
    

    Here is psudocode for the SLAVE part:

    		
     CRYPTO_SLAVE (cryptoquote filename) (dictionary name)
        read in the dictionary
        while not(word solved) 
          while not(wordsleft less than 2) and not(time to check buffer)
    	if (first pass)
    	  if (pattern of word = pattern of dictionary word)
    	    if (word possible considering letters eliminated)
                  accept word
              else 
                reject word
            else 
    	  if (word possible considering letters eliminated)
                  accept word
              else 
                reject word
            if (word accepted)
              add appropriate letters to "canbe" array
          if not(end of list)
            check buffer
            if (message present)
    	  get message
              update local version of letter list
          else 
    	from list of "canbe" letters, calculate "cannotbe" 
            if (current "cannotbe" better than from start of pass)
    	  send global update
            else 
              indicate process halted to master
              wait for update
    

  • Go back to Strategy
  • Go on to Timing Data


  • Written by:

    Ko-Ming Chang
    Computer Science 397
    Parallel Computing
    Dr. Thomas Whaley
    Washington and Lee University
    Lexington, VA 24450

    Questions? Mail me at kchang@liberty.uc.wlu.edu