diff options
| author | Joshua Bakita <bakitajoshua@gmail.com> | 2019-10-07 19:13:39 -0400 |
|---|---|---|
| committer | Joshua Bakita <bakitajoshua@gmail.com> | 2019-10-07 19:13:39 -0400 |
| commit | 386b7d3366f1359a265da207a9cafa3edf553b64 (patch) | |
| tree | c76120c2c138faed822e4ae386be6ef22a738a78 /all_pairs/source/anagram/anagram.c | |
| parent | 54a3f7091a2146b29c73a6fdc4b62a5c4ad7a3d8 (diff) | |
Reorganize and commit all the modified TACLeBench code and run scripts
Diffstat (limited to 'all_pairs/source/anagram/anagram.c')
| -rw-r--r-- | all_pairs/source/anagram/anagram.c | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/all_pairs/source/anagram/anagram.c b/all_pairs/source/anagram/anagram.c new file mode 100644 index 0000000..8f140a3 --- /dev/null +++ b/all_pairs/source/anagram/anagram.c | |||
| @@ -0,0 +1,670 @@ | |||
| 1 | /* | ||
| 2 | |||
| 3 | This program is part of the TACLeBench benchmark suite. | ||
| 4 | Version 2.0 | ||
| 5 | |||
| 6 | Name: anagram | ||
| 7 | |||
| 8 | Author: Raymond Chen | ||
| 9 | |||
| 10 | Function: A program that computes anagrams. | ||
| 11 | |||
| 12 | Source: See below. | ||
| 13 | |||
| 14 | Original name: anagram | ||
| 15 | |||
| 16 | Changes: See ChangeLog.txt | ||
| 17 | |||
| 18 | License: See below. | ||
| 19 | |||
| 20 | */ | ||
| 21 | |||
| 22 | /* | ||
| 23 | Anagram program by Raymond Chen, | ||
| 24 | inspired by a similar program by Brian Scearce | ||
| 25 | |||
| 26 | This program is Copyright 1991 by Raymond Chen. | ||
| 27 | (rjc@math.princeton.edu) | ||
| 28 | |||
| 29 | This program may be freely distributed provided all alterations | ||
| 30 | to the original are clearly indicated as such. | ||
| 31 | */ | ||
| 32 | |||
| 33 | /* There are two tricks. First is the Basic Idea: | ||
| 34 | |||
| 35 | When the user types in a phrase, the phrase is first preprocessed to | ||
| 36 | determine how many of each letter appears. A bit field is then constructed | ||
| 37 | dynamically, such that each field is large enough to hold the next power | ||
| 38 | of two larger than the number of times the character appears. For example, | ||
| 39 | if the phrase is hello, world, the bit field would be | ||
| 40 | |||
| 41 | 00 00 00 000 000 00 00 | ||
| 42 | d e h l o r w | ||
| 43 | |||
| 44 | The phrase hello, world, itself would be encoded as | ||
| 45 | |||
| 46 | 01 01 01 011 010 01 01 | ||
| 47 | d e h l o r w | ||
| 48 | |||
| 49 | and the word hollow would be encoded as | ||
| 50 | |||
| 51 | 00 00 01 010 010 00 01 | ||
| 52 | d e h l o r w | ||
| 53 | |||
| 54 | The top bit of each field is set in a special value called the sign. | ||
| 55 | Here, the sign would be | ||
| 56 | |||
| 57 | 10 10 10 100 100 10 10 | ||
| 58 | d e h l o r w | ||
| 59 | |||
| 60 | |||
| 61 | The reason for packing the values into a bit field is that the operation | ||
| 62 | of subtracting out the letters of a word from the current phrase can be | ||
| 63 | carried out in parallel. for example, subtracting the word hello from | ||
| 64 | the phrase hello, world, is merely | ||
| 65 | |||
| 66 | d e h l o r w | ||
| 67 | 01 01 01 011 010 01 01 (dehllloorw) | ||
| 68 | - 00 00 01 010 010 00 01 (hlloow) | ||
| 69 | ======================== | ||
| 70 | 01 01 00 001 000 01 00 (delr) | ||
| 71 | |||
| 72 | Since none of the sign bits is set, the word fits, and we can continue. | ||
| 73 | Suppose the next word we tried was hood. | ||
| 74 | |||
| 75 | d e h l o r w | ||
| 76 | 01 01 00 001 000 01 00 (delr) | ||
| 77 | - 01 00 01 000 010 00 00 (hood) | ||
| 78 | ======================== | ||
| 79 | 00 00 11 000 110 01 00 | ||
| 80 | ^ ^ | ||
| 81 | A sign bit is set. (Two, actually.) This means that hood does not | ||
| 82 | fit in delr, so we skip it and try another word. (Observe that | ||
| 83 | when a sign bit becomes set, it screws up the values for the letters to | ||
| 84 | the left of that bit, but that's not important.) | ||
| 85 | |||
| 86 | The inner loop of an anagram program is testing to see if a | ||
| 87 | word fits in the collection of untried letters. Traditional methods | ||
| 88 | keep an array of 26 integers, which are then compared in turn. This | ||
| 89 | means that there are 26 comparisons per word. | ||
| 90 | |||
| 91 | This method reduces the number of comparisons to MAX_QUAD, typically 2. | ||
| 92 | Instead of looping through an array, we merely perform the indicated | ||
| 93 | subtraction and test if any of the sign bits is set. | ||
| 94 | */ | ||
| 95 | |||
| 96 | /* The nuts and bolts: | ||
| 97 | |||
| 98 | The dictionary is loaded and preprocessed. The preprocessed dictionary | ||
| 99 | is a concatenation of copies of the structure: | ||
| 100 | |||
| 101 | struct dictword { | ||
| 102 | char bStructureSize; -- size of this structure | ||
| 103 | char cLetters; -- number of letters in the word | ||
| 104 | char achWord[]; -- the word itself (0-terminated) | ||
| 105 | } | ||
| 106 | |||
| 107 | Since this is a variable-sized structure, we keep its size in the structure | ||
| 108 | itself for rapid stepping through the table. | ||
| 109 | |||
| 110 | When a phrase is typed in, it is first preprocessed as described in the | ||
| 111 | Basic Idea. We then go through the dictionary, testing each word. If | ||
| 112 | the word fits in our phrase, we build the bit field for its frequency | ||
| 113 | table and add it to the list of candidates. | ||
| 114 | */ | ||
| 115 | |||
| 116 | /* | ||
| 117 | The Second Trick: | ||
| 118 | |||
| 119 | Before diving into our anagram search, we then tabulate how many times | ||
| 120 | each letter appears in our list of candidates, and sort the table, with | ||
| 121 | the rarest letter first. | ||
| 122 | |||
| 123 | We then do our anagram search. | ||
| 124 | |||
| 125 | Like most anagram programs, this program does a depth-first search. | ||
| 126 | Although most anagram programs do some sort of heuristics to decide what | ||
| 127 | order to place words in the list_of_candidates, the search itself proceeds | ||
| 128 | according to a greedy algorithm. That is, once you find a word that fits, | ||
| 129 | subtract it and recurse. | ||
| 130 | |||
| 131 | This anagram program exercises some restraint and does not march down | ||
| 132 | every branch that shows itself. Instead, it only goes down branches | ||
| 133 | that use the rarest unused letter. This helps to find dead ends faster. | ||
| 134 | |||
| 135 | FindAnagram(unused_letters, list_of_candidates) { | ||
| 136 | l = the rarest letter as yet unused | ||
| 137 | For word in list_of_candidates { | ||
| 138 | if word does not fit in unused_letters, go on to the next word. | ||
| 139 | if word does not contain l, defer. | ||
| 140 | FindAnagram(unused_letters - word, list_of_candidates[word,...]) | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | |||
| 145 | The heuristic of the Second Trick can probably be improved. I invite | ||
| 146 | anyone willing to improve it to do so. | ||
| 147 | */ | ||
| 148 | |||
| 149 | /* Before compiling, make sure Quad and MASK_BITS are set properly. For best | ||
| 150 | results, make Quad the largest integer size supported on your machine. | ||
| 151 | So if your machine has long longs, make Quad an unsigned long long. | ||
| 152 | (I called it Quad because on most machines, the largest integer size | ||
| 153 | supported is a four-byte unsigned long.) | ||
| 154 | |||
| 155 | If you need to be able to anagram larger phrases, increase MAX_QUADS. | ||
| 156 | If you increase it beyond 4, you'll have to add a few more loop unrolling | ||
| 157 | steps to FindAnagram. | ||
| 158 | */ | ||
| 159 | |||
| 160 | #include "../extra.h" | ||
| 161 | #include "anagram_ctype.h" | ||
| 162 | #include "anagram_stdlib.h" | ||
| 163 | #include "anagram_strings.h" | ||
| 164 | |||
| 165 | #include "anagram_compare.h" | ||
| 166 | |||
| 167 | |||
| 168 | /* | ||
| 169 | Defines | ||
| 170 | */ | ||
| 171 | |||
| 172 | #define anagram_DICTWORDS 2279 | ||
| 173 | #define anagram_MASK_BITS 32 /* number of bits in a Quad */ | ||
| 174 | #define anagram_MAX_QUADS 2 /* controls largest phrase */ | ||
| 175 | #define anagram_MAXCAND 100 /* candidates */ | ||
| 176 | #define anagram_MAXSOL 51 /* words in the solution */ | ||
| 177 | #define anagram_ALPHABET 26 /* letters in the alphabet */ | ||
| 178 | |||
| 179 | #define anagram_OneStep( i ) \ | ||
| 180 | if ( ( aqNext[ i ] = pqMask[ i ] - pw->aqMask[ i ] ) & anagram_aqMainSign[ i ] ) { \ | ||
| 181 | ppwStart ++; \ | ||
| 182 | continue; \ | ||
| 183 | } | ||
| 184 | |||
| 185 | |||
| 186 | /* | ||
| 187 | Type definitions | ||
| 188 | */ | ||
| 189 | |||
| 190 | typedef unsigned int anagram_Quad; /* for building our bit mask */ | ||
| 191 | |||
| 192 | /* A Word remembers the information about a candidate word. */ | ||
| 193 | typedef struct { | ||
| 194 | char *pchWord; /* the word itself */ | ||
| 195 | anagram_Quad aqMask[ anagram_MAX_QUADS ]; /* the word's mask */ | ||
