summaryrefslogtreecommitdiffstats
path: root/all_pairs/source/anagram/anagram.c
diff options
context:
space:
mode:
authorJoshua Bakita <bakitajoshua@gmail.com>2019-10-07 19:13:39 -0400
committerJoshua Bakita <bakitajoshua@gmail.com>2019-10-07 19:13:39 -0400
commit386b7d3366f1359a265da207a9cafa3edf553b64 (patch)
treec76120c2c138faed822e4ae386be6ef22a738a78 /all_pairs/source/anagram/anagram.c
parent54a3f7091a2146b29c73a6fdc4b62a5c4ad7a3d8 (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.c670
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
190typedef unsigned int anagram_Quad; /* for building our bit mask */
191
192/* A Word remembers the information about a candidate word. */
193typedef struct {
194 char *pchWord; /* the word itself */
195 anagram_Quad aqMask[ anagram_MAX_QUADS ]; /* the word's mask */