perfhlib.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /*
  2. *$Log: perfhlib.c,v $
  3. * Revision 1.5 93/09/29 14:45:02 emmerik
  4. * Oops, didn't do the casts last check in
  5. *
  6. * Revision 1.4 93/09/29 14:41:45 emmerik
  7. * Added casts to mod instructions to keep the SVR4 compiler happy
  8. *
  9. *
  10. * Perfect hashing function library. Contains functions to generate perfect
  11. * hashing functions
  12. */
  13. #include "perfhlib.h"
  14. #include "PatternCollector.h"
  15. #include <stdio.h>
  16. #include <cassert>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. /* Private data structures */
  20. //static int NumEntry; /* Number of entries in the hash table (# keys) */
  21. //static int EntryLen; /* Size (bytes) of each entry (size of keys) */
  22. //static int SetSize; /* Size of the char set */
  23. //static char SetMin; /* First char in the set */
  24. //static int NumVert; /* c times NumEntry */
  25. //static uint16_t *T1base, *T2base; /* Pointers to start of T1, T2 */
  26. static uint16_t *T1, *T2; /* Pointers to T1[i], T2[i] */
  27. static int *graphNode; /* The array of edges */
  28. static int *graphNext; /* Linked list of edges */
  29. static int *graphFirst;/* First edge at a vertex */
  30. static int numEdges; /* An edge counter */
  31. static bool *visited; /* Array of bools: whether visited */
  32. static bool *deleted; /* Array of bools: whether deleted */
  33. /* Private prototypes */
  34. static void initGraph(void);
  35. static void addToGraph(int e, int v1, int v2);
  36. static bool isCycle(void);
  37. static void duplicateKeys(int v1, int v2);
  38. void PerfectHash::setHashParams(int _NumEntry, int _EntryLen, int _SetSize, char _SetMin,
  39. int _NumVert)
  40. {
  41. /* These parameters are stored in statics so as to obviate the need for
  42. passing all these (or defererencing pointers) for every call to hash()
  43. */
  44. NumEntry = _NumEntry;
  45. EntryLen = _EntryLen;
  46. SetSize = _SetSize;
  47. SetMin = _SetMin;
  48. NumVert = _NumVert;
  49. /* Allocate the variable sized tables etc */
  50. if ((T1base = (uint16_t *)malloc(EntryLen * SetSize * sizeof(uint16_t))) == 0)
  51. {
  52. goto BadAlloc;
  53. }
  54. if ((T2base = (uint16_t *)malloc(EntryLen * SetSize * sizeof(uint16_t))) == 0)
  55. {
  56. goto BadAlloc;
  57. }
  58. if ((graphNode = (int *)malloc((NumEntry*2 + 1) * sizeof(int))) == 0)
  59. {
  60. goto BadAlloc;
  61. }
  62. if ((graphNext = (int *)malloc((NumEntry*2 + 1) * sizeof(int))) == 0)
  63. {
  64. goto BadAlloc;
  65. }
  66. if ((graphFirst = (int *)malloc((NumVert + 1) * sizeof(int))) == 0)
  67. {
  68. goto BadAlloc;
  69. }
  70. if ((g = (short *)malloc((NumVert+1) * sizeof(short))) == 0)
  71. {
  72. goto BadAlloc;
  73. }
  74. if ((visited = (bool *)malloc((NumVert+1) * sizeof(bool))) == 0)
  75. {
  76. goto BadAlloc;
  77. }
  78. if ((deleted = (bool *)malloc((NumEntry+1) * sizeof(bool))) == 0)
  79. {
  80. goto BadAlloc;
  81. }
  82. return;
  83. BadAlloc:
  84. printf("Could not allocate memory\n");
  85. hashCleanup();
  86. exit(1);
  87. }
  88. void PerfectHash::hashCleanup(void)
  89. {
  90. /* Free the storage for variable sized tables etc */
  91. if (T1base) free(T1base);
  92. if (T2base) free(T2base);
  93. if (graphNode) free(graphNode);
  94. if (graphNext) free(graphNext);
  95. if (graphFirst) free(graphFirst);
  96. if (g) free(g);
  97. if (visited) free(visited);
  98. if (deleted) free(deleted);
  99. }
  100. void PerfectHash::map(PatternCollector *collector)
  101. {
  102. m_collector = collector;
  103. assert(nullptr!=collector);
  104. int i, j, c;
  105. uint16_t f1, f2;
  106. bool cycle;
  107. uint8_t *keys;
  108. c = 0;
  109. do
  110. {
  111. initGraph();
  112. cycle = false;
  113. /* Randomly generate T1 and T2 */
  114. for (i=0; i < SetSize*EntryLen; i++)
  115. {
  116. T1base[i] = rand() % NumVert;
  117. T2base[i] = rand() % NumVert;
  118. }
  119. for (i=0; i < NumEntry; i++)
  120. {
  121. f1 = 0; f2 = 0;
  122. keys = m_collector->getKey(i);
  123. for (j=0; j < EntryLen; j++)
  124. {
  125. T1 = T1base + j * SetSize;
  126. T2 = T2base + j * SetSize;
  127. f1 += T1[keys[j] - SetMin];
  128. f2 += T2[keys[j] - SetMin];
  129. }
  130. f1 %= (uint16_t)NumVert;
  131. f2 %= (uint16_t)NumVert;
  132. if (f1 == f2)
  133. {
  134. /* A self loop. Reject! */
  135. printf("Self loop on vertex %d!\n", f1);
  136. cycle = true;
  137. break;
  138. }
  139. addToGraph(numEdges++, f1, f2);
  140. }
  141. if (cycle || (cycle = isCycle())) /* OK - is there a cycle? */
  142. {
  143. printf("Iteration %d\n", ++c);
  144. }
  145. else
  146. {
  147. break;
  148. }
  149. }
  150. while (/* there is a cycle */ 1);
  151. }
  152. /* Initialise the graph */
  153. void PerfectHash::initGraph()
  154. {
  155. int i;
  156. for (i=1; i <= NumVert; i++)
  157. {
  158. graphFirst[i] = 0;
  159. }
  160. for (i= -NumEntry; i <= NumEntry; i++)
  161. {
  162. /* No need to init graphNode[] as they will all be filled by successive
  163. calls to addToGraph() */
  164. graphNext[NumEntry+i] = 0;
  165. }
  166. numEdges = 0;
  167. }
  168. /* Add an edge e between vertices v1 and v2 */
  169. /* e, v1, v2 are 0 based */
  170. void PerfectHash::addToGraph(int e, int v1, int v2)
  171. {
  172. e++; v1++; v2++; /* So much more convenient */
  173. graphNode[NumEntry+e] = v2; /* Insert the edge information */
  174. graphNode[NumEntry-e] = v1;
  175. graphNext[NumEntry+e] = graphFirst[v1]; /* Insert v1 to list of alphas */
  176. graphFirst[v1]= e;
  177. graphNext[NumEntry-e] = graphFirst[v2]; /* Insert v2 to list of omegas */
  178. graphFirst[v2]= -e;
  179. }
  180. bool PerfectHash::DFS(int parentE, int v)
  181. {
  182. int e, w;
  183. /* Depth first search of the graph, starting at vertex v, looking for
  184. cycles. parent and v are origin 1. Note parent is an EDGE,
  185. not a vertex */
  186. visited[v] = true;
  187. /* For each e incident with v .. */
  188. for (e = graphFirst[v]; e; e = graphNext[NumEntry+e])
  189. {
  190. uint8_t *key1;
  191. if (deleted[abs(e)])
  192. {
  193. /* A deleted key. Just ignore it */
  194. continue;
  195. }
  196. key1 = m_collector->getKey(abs(e)-1);
  197. w = graphNode[NumEntry+e];
  198. if (visited[w])
  199. {
  200. /* Did we just come through this edge? If so, ignore it. */
  201. if (abs(e) != abs(parentE))
  202. {
  203. /* There is a cycle in the graph. There is some subtle code here
  204. to work around the distinct possibility that there may be
  205. duplicate keys. Duplicate keys will always cause unit
  206. cycles, since f1 and f2 (used to select v and w) will be the
  207. same for both. The edges (representing an index into the
  208. array of keys) are distinct, but the key values are not.
  209. The logic is as follows: for the candidate edge e, check to
  210. see if it terminates in the parent vertex. If so, we test
  211. the keys associated with e and the parent, and if they are
  212. the same, we can safely ignore e for the purposes of cycle
  213. detection, since edge e adds nothing to the cycle. Cycles
  214. involving v, w, and e0 will still be found. The parent
  215. edge was not similarly eliminated because at the time when
  216. it was a candidate, v was not yet visited.
  217. We still have to remove the key from further consideration,
  218. since each edge is visited twice, but with a different
  219. parent edge each time.
  220. */
  221. /* We save some stack space by calculating the parent vertex
  222. for these relatively few cases where it is needed */
  223. int parentV = graphNode[NumEntry-parentE];
  224. if (w == parentV)
  225. {
  226. uint8_t *key2;
  227. key2=m_collector->getKey(abs(parentE)-1);
  228. if (memcmp(key1, key2, EntryLen) == 0)
  229. {
  230. printf("Duplicate keys with edges %d and %d (",
  231. e, parentE);
  232. m_collector->dispKey(abs(e)-1);
  233. printf(" & ");
  234. m_collector->dispKey(abs(parentE)-1);
  235. printf(")\n");
  236. deleted[abs(e)] = true; /* Wipe the key */
  237. }
  238. else
  239. {
  240. /* A genuine (unit) cycle. */
  241. printf("There is a unit cycle involving vertex %d and edge %d\n", v, e);
  242. return true;
  243. }
  244. }
  245. else
  246. {
  247. /* We have reached a previously visited vertex not the
  248. parent. Therefore, we have uncovered a genuine cycle */
  249. printf("There is a cycle involving vertex %d and edge %d\n", v, e);
  250. return true;
  251. }
  252. }
  253. }
  254. else /* Not yet seen. Traverse it */
  255. {
  256. if (DFS(e, w))
  257. {
  258. /* Cycle found deeper down. Exit */
  259. return true;
  260. }
  261. }
  262. }
  263. return false;
  264. }
  265. bool PerfectHash::isCycle(void)
  266. {
  267. int v, e;
  268. for (v=1; v <= NumVert; v++)
  269. {
  270. visited[v] = false;
  271. }
  272. for (e=1; e <= NumEntry; e++)
  273. {
  274. deleted[e] = false;
  275. }
  276. for (v=1; v <= NumVert; v++)
  277. {
  278. if (!visited[v])
  279. {
  280. if (DFS(-32767, v))
  281. {
  282. return true;
  283. }
  284. }
  285. }
  286. return false;
  287. }
  288. void PerfectHash::traverse(int u)
  289. {
  290. int w, e;
  291. visited[u] = true;
  292. /* Find w, the neighbours of u, by searching the edges e associated with u */
  293. e = graphFirst[1+u];
  294. while (e)
  295. {
  296. w = graphNode[NumEntry+e]-1;
  297. if (!visited[w])
  298. {
  299. g[w] = (abs(e)-1 - g[u]) % NumEntry;
  300. if (g[w] < 0) g[w] += NumEntry; /* Keep these positive */
  301. traverse(w);
  302. }
  303. e = graphNext[NumEntry+e];
  304. }
  305. }
  306. void PerfectHash::assign(void)
  307. {
  308. int v;
  309. for (v=0; v < NumVert; v++)
  310. {
  311. g[v] = 0; /* g is sparse; leave the gaps 0 */
  312. visited[v] = false;
  313. }
  314. for (v=0; v < NumVert; v++)
  315. {
  316. if (!visited[v])
  317. {
  318. g[v] = 0;
  319. traverse(v);
  320. }
  321. }
  322. }
  323. int PerfectHash::hash(uint8_t *string)
  324. {
  325. uint16_t u, v;
  326. int j;
  327. u = 0;
  328. for (j=0; j < EntryLen; j++)
  329. {
  330. T1 = T1base + j * SetSize;
  331. u += T1[string[j] - SetMin];
  332. }
  333. u %= NumVert;
  334. v = 0;
  335. for (j=0; j < EntryLen; j++)
  336. {
  337. T2 = T2base + j * SetSize;
  338. v += T2[string[j] - SetMin];
  339. }
  340. v %= NumVert;
  341. return (g[u] + g[v]) % NumEntry;
  342. }
  343. #if 0
  344. void dispRecord(int i);
  345. void
  346. duplicateKeys(int v1, int v2)
  347. {
  348. int i, j;
  349. uint8_t *keys;
  350. int u, v;
  351. v1--; v2--; /* These guys are origin 1 */
  352. printf("Duplicate keys:\n");
  353. for (i=0; i < NumEntry; i++)
  354. {
  355. getKey(i, &keys);
  356. u = 0;
  357. for (j=0; j < EntryLen; j++)
  358. {
  359. T1 = T1base + j * SetSize;
  360. u += T1[keys[j] - SetMin];
  361. }
  362. u %= NumVert;
  363. if ((u != v1) && (u != v2)) continue;
  364. v = 0;
  365. for (j=0; j < EntryLen; j++)
  366. {
  367. T2 = T2base + j * SetSize;
  368. v += T2[keys[j] - SetMin];
  369. }
  370. v %= NumVert;
  371. if ((v == v2) || (v == v1))
  372. {
  373. printf("Entry #%d key: ", i+1);
  374. for (j=0; j < EntryLen; j++) printf("%02X ", keys[j]);
  375. printf("\n");
  376. dispRecord(i+1);
  377. }
  378. }
  379. exit(1);
  380. }
  381. #endif