Node.java 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. package com.pact;
  2. import java.util.*;
  3. public class Node {
  4. static int ID = 0;
  5. Node parent;
  6. private String venn;
  7. private List<Node> children;
  8. List<Node> linkNodes;
  9. private Node linkNode;
  10. private final int id = ++ID; // Unique Identifier for all created nodes
  11. private int hash;
  12. public Node(Node p, String s) {
  13. this.linkNode = null;
  14. this.linkNodes = new ArrayList<>();
  15. this.venn = s;
  16. this.parent = p;
  17. this.hash = 0;
  18. this.children = new ArrayList<>();
  19. if (s.length() > 1)
  20. setChildren(s);
  21. if (children.isEmpty()) {
  22. hash = (venn.hashCode()*1073676287) ^ (venn.hashCode()*97);
  23. } else {
  24. for (Node child : children) {
  25. hash = hash ^ child.hash;
  26. }
  27. hash *= 33;
  28. }
  29. }
  30. public Node(Node p, char s) {
  31. this(p, ""+s);
  32. }
  33. public boolean isRoot() {
  34. return parent == null;
  35. }
  36. public boolean isLeaf() {
  37. return children.isEmpty();
  38. }
  39. public int nSiblings() {
  40. if (isRoot()) return 0;
  41. else return parent.children.size() - 1;
  42. }
  43. private void setChildren(String s) {
  44. try {
  45. String vennChildren = s.substring(1, s.length() - 1);
  46. int count = 0;
  47. while (count < vennChildren.length())
  48. if (vennChildren.charAt(count) == '(') {
  49. int start = count;
  50. count++;
  51. int end;
  52. int brackets = 1;
  53. while (true)
  54. {
  55. if (vennChildren.charAt(count) == '(') {
  56. brackets++;
  57. }
  58. if (vennChildren.charAt(count) == ')') {
  59. brackets--;
  60. if (brackets == 0) {
  61. count++;
  62. break;
  63. }
  64. }
  65. count++;
  66. }
  67. end = count;
  68. Node child = new Node(this, vennChildren.substring(start, end));
  69. this.children.add(child);
  70. } else {
  71. Node child = new Node(this, vennChildren.charAt(count));
  72. this.children.add(child);
  73. count++;
  74. }
  75. }
  76. catch (StringIndexOutOfBoundsException se) {
  77. throw new BracketException();
  78. }
  79. }
  80. String getVenn()
  81. {
  82. return this.venn;
  83. }
  84. public String toString()
  85. {
  86. return this.venn;
  87. }
  88. List<Node> getSiblings() {
  89. if (this.parent != null) {
  90. List<Node> sibs = new ArrayList<>(parent.children);
  91. sibs.remove(this);
  92. return sibs;
  93. }
  94. return new ArrayList<>();
  95. }
  96. public boolean equals(Object obj) {
  97. if (this == obj) return true; // Literally the same object
  98. if (!(obj instanceof Node)) return false; // Wrong type
  99. Node node = (Node) obj;
  100. if (hash != node.hash) return false; // equal object have equal hash codes
  101. // If above checks fall through, we need to actually look at the structure
  102. // Of the Node.
  103. String nodeVenn = node.getVenn();
  104. // Case for leaf nodes
  105. if ((nodeVenn.length() == 1) && (this.venn.length() == 1)) {
  106. return nodeVenn.equals(this.venn);
  107. }
  108. if (children.size() != node.children.size()){
  109. return false;
  110. }
  111. // Check to make sure all of my children exist in node's children
  112. for (Node theirChild : node.children) {
  113. boolean foundMatch = false;
  114. for (Node myChild : this.children) {
  115. if (myChild.equals(theirChild)) {
  116. foundMatch = true;
  117. break;
  118. }
  119. }
  120. if(!foundMatch) return false;
  121. }
  122. return true;
  123. }
  124. // @Override
  125. // public int hashCode(){
  126. // return hash;
  127. // }
  128. public static List<NodePair> deepSearch(Node nodeA, Node nodeB) {
  129. List<NodePair> result = new ArrayList<>();
  130. Stack<Node> searchNodes = new Stack<>();
  131. searchNodes.push(nodeB);
  132. while (!searchNodes.isEmpty()) {
  133. Node curr = searchNodes.pop();
  134. // res1: Occurrences of node in this tree
  135. List<NodePair> res1 = nodeA.search(curr);
  136. // res2: Occurrences of this tree in node
  137. List<NodePair> res2 = curr.search(nodeA);
  138. assert(res1.size() == 0 || res2.size() == 0 || res1.equals(res2));
  139. if(!res1.isEmpty()){
  140. result.addAll(res1);
  141. } else if(!res2.isEmpty()){
  142. result.addAll(res2);
  143. }
  144. searchNodes.addAll(curr.children);
  145. }
  146. return result;
  147. }
  148. Node root() {
  149. if (isRoot()) return this;
  150. else return this.parent.root();
  151. }
  152. private int getNumAreas() {
  153. int count = 0;
  154. for (int i = 0; i < this.venn.length(); i++) {
  155. if ((this.venn.charAt(i) != ')') && (this.venn.charAt(i) != '(')) {
  156. count++;
  157. }
  158. }
  159. return count;
  160. }
  161. /**
  162. * Search this tree for the subtree with given root
  163. * @param targetNode the root of the subtree to search for
  164. */
  165. private List<NodePair> search(Node targetNode) {
  166. List<NodePair> result = new ArrayList<>();
  167. // Use stack to avoid recursion here
  168. Stack<Node> searchNodes = new Stack<>();
  169. searchNodes.push(this);
  170. while (!searchNodes.isEmpty()) {
  171. Node curr = searchNodes.pop();
  172. if (curr.equals(targetNode)) {
  173. curr.linkNodes.add(targetNode);
  174. targetNode.linkNodes.add(curr);
  175. result.add(new NodePair(curr, targetNode));
  176. } else {
  177. searchNodes.addAll(curr.children);
  178. }
  179. }
  180. return result;
  181. }
  182. /**
  183. * Searches in this tree for the presence of the Node node.
  184. * @param node
  185. * @return
  186. */
  187. private boolean isIn(Node node) {
  188. if (this == node) {
  189. return true;
  190. }
  191. for (Node child : this.children) {
  192. if (child.isIn(node)) {
  193. return true;
  194. }
  195. }
  196. return false;
  197. }
  198. /**
  199. * Looks through this Node's siblings and returns the first one that has linkNodes. If no sibling
  200. * has linkNodes, returns null.
  201. * @return
  202. */
  203. private Node hasLink() {
  204. for (Node curr : getSiblings()) {
  205. if (!curr.linkNodes.isEmpty()) {
  206. return curr;
  207. }
  208. }
  209. return null;
  210. }
  211. private boolean unshared() {
  212. if (this.linkNodes.isEmpty()) {
  213. if(this.children.isEmpty()) {
  214. return true;
  215. } else {
  216. for (Node node : this.children) {
  217. if (!node.unshared()) {
  218. return false;
  219. }
  220. }
  221. }
  222. return true;
  223. } else {
  224. return false;
  225. }
  226. }
  227. private void resetSearch() {
  228. this.linkNodes.clear();
  229. this.linkNode = null;
  230. for (Node child : this.children) {
  231. child.resetSearch();
  232. }
  233. }
  234. /**
  235. * Searches in h for all NodePairs that contain this object as either node1 or node2
  236. * @param h
  237. * @return
  238. */
  239. private List<Node> getDuplicates(List<NodePair> h) {
  240. List<Node> result = new ArrayList<>();
  241. for (NodePair curr : h) {
  242. if (curr.node1 == this)
  243. result.add(curr.node2);
  244. else if (curr.node2 == this) {
  245. result.add(curr.node1);
  246. }
  247. }
  248. return result;
  249. }
  250. /**
  251. * Produces a reduced version of unreduced where any duplicate children have been removed. Note that this doesn't
  252. * look for duplicate sub-trees at lower levels. (ie duplicate grandchildren)
  253. * @param unreduced
  254. * @return
  255. */
  256. private static Node reduce(Node unreduced) {
  257. List<Node> uniqueChildren = new ArrayList<>();
  258. for (Node child : unreduced.children) {
  259. if (!child.inSet(uniqueChildren)) {
  260. uniqueChildren.add(child);
  261. }
  262. }
  263. if (uniqueChildren.size() == unreduced.children.size() || (unreduced.venn.length() == 1)) {
  264. return unreduced;
  265. }
  266. Iterator<Node> uIt = uniqueChildren.iterator();
  267. String result = uIt.next().getVenn();
  268. if (uIt.hasNext()) {
  269. while (uIt.hasNext()) {
  270. result += uIt.next().getVenn();
  271. }
  272. result = "(" + result + ")";
  273. }
  274. Node reduced = new Node(null, result);
  275. return reduced;
  276. }
  277. private boolean inSet(List<Node> h) {
  278. return h.contains(this);
  279. }
  280. /**
  281. * Traverses tree and collects all unshared nodes.
  282. * @return
  283. */
  284. private List<Node> collectUnshared() {
  285. Stack<Node> stack = new Stack<>();
  286. List<Node> unshared = new ArrayList();
  287. stack.push(this);
  288. while (!stack.isEmpty()){
  289. Node n = stack.pop();
  290. if (n.unshared()) {
  291. unshared.add(n);
  292. }
  293. stack.addAll(n.children);
  294. }
  295. return unshared;
  296. }
  297. static List<Node> combine(Node node1, Node node2) {
  298. System.out.println("Combining: " + node1 + ", " + node2);
  299. List<Node> result = _combine(node1, node2);
  300. System.out.println("Combining Result: " + result);
  301. return result;
  302. }
  303. static List<Node> _combine(Node node1, Node node2) {
  304. node1 = reduce(node1);
  305. node2 = reduce(node2);
  306. node2.resetSearch();
  307. node1.resetSearch();
  308. List<Node> result = new ArrayList<>();
  309. if (node1.equals(node2)) {
  310. result.add(node2);
  311. return result;
  312. }
  313. List<NodePair> sResult = deepSearch(node2, node1);
  314. if (sResult.isEmpty()) {
  315. result.add(combineAtRoot(node2, node1));
  316. return result;
  317. }
  318. List<Node> unsharedNodes = new ArrayList<>();
  319. unsharedNodes.addAll(node2.collectUnshared());
  320. unsharedNodes.addAll(node1.collectUnshared());
  321. if ((unsharedNodes.isEmpty()) && (node1.getNumAreas() == node2.getNumAreas())) {
  322. if (node1.children.size() < node2.children.size()) {
  323. Node toAdd = new Node(null, node1.getVenn());
  324. result.add(toAdd);
  325. return result;
  326. } if (node2.children.size() < node1.children.size()) {
  327. Node toAdd = new Node(null, node2.getVenn());
  328. result.add(toAdd);
  329. return result;
  330. }
  331. }
  332. List<NodePair> largest = getLargestNodePairs(sResult);
  333. if (!largest.isEmpty()) {
  334. Iterator itLargest = largest.iterator();
  335. NodePair flargest = (NodePair)itLargest.next();
  336. List<Node> lg1sibs = flargest.node1.getSiblings();
  337. List<Node> lg2sibs = flargest.node2.getSiblings();
  338. List<Node> newSibs = new ArrayList<>();
  339. List<Node> otherSibs1 = new ArrayList<>();
  340. List<Node> otherSibs2 = new ArrayList<>();
  341. sortLargestSibs(lg1sibs, flargest.node2, newSibs, otherSibs1);
  342. sortLargestSibs(lg2sibs, flargest.node1, newSibs, otherSibs2);
  343. if ((otherSibs1.isEmpty()) && (otherSibs2.isEmpty())) {
  344. unsharedNodes.addAll(newSibs);
  345. }
  346. }
  347. List<NodePair> newLinkedNodePair = getLinkedNodePair(unsharedNodes);
  348. List<List<NodePair>> polys = reviewPolys(newLinkedNodePair);
  349. if (!polys.isEmpty()) {
  350. Iterator<List<NodePair>> polyIt = polys.iterator();
  351. if (polyIt.hasNext()) {
  352. List<NodePair> polyresult = addPolys(polyIt.next());
  353. Iterator prIt = polyresult.iterator();
  354. if (prIt.hasNext()) {
  355. NodePair curr = (NodePair)prIt.next();
  356. if ((curr.node1.parent != null) && (curr.node1.linkNode.parent != null)) {
  357. String polyString1 = buildUp(curr.node1.parent, curr.node2.getVenn());
  358. String polyString2 = buildUp(curr.node1.linkNode.parent, curr.node2.getVenn());
  359. Node polyOne = new Node(null, polyString1);
  360. Node polyTwo = new Node(null, polyString2);
  361. List<Node> polyresults = combine(polyOne, polyTwo);
  362. for (Node polyResult : polyresults)
  363. result.add(polyResult);
  364. } else if (!curr.node1.isRoot()) {
  365. String polyString1 = buildUp(curr.node1.parent, curr.node2.getVenn());
  366. Node polyOne = new Node(null, polyString1);
  367. result.add(polyOne);
  368. } else if (!curr.node1.linkNode.isRoot()) {
  369. String polyString2 = buildUp(curr.node1.linkNode.parent, curr.node2.getVenn());
  370. Node polyTwo = new Node(null, polyString2);
  371. result.add(polyTwo);
  372. } else {
  373. System.out.println("What's up Houston?");
  374. }
  375. }
  376. }
  377. return result;
  378. }
  379. if (!newLinkedNodePair.isEmpty()) {
  380. List<NodePair> combined = newLinkedNodePair.get(0).combineNew();
  381. for (NodePair curr : combined) {
  382. result.addAll(combine(curr.node1, curr.node2));
  383. }
  384. return result;
  385. }
  386. if (largest.get(0).nodesSize() == 1) { // Shares only leaves
  387. List<Node> unique = getUniqueNodes(sResult);
  388. for (Node curr : unique) {
  389. List<Node> dupres = curr.getDuplicates(sResult);
  390. if (dupres.size() > 1) {
  391. List<NodePair> newDupNodePair = getLinkedNodePair(dupres);
  392. Iterator<NodePair> ndIt = newDupNodePair.iterator();
  393. while (ndIt.hasNext()) {
  394. List<NodePair> combined = ndIt.next().combineNew();
  395. Iterator cIt = combined.iterator();
  396. while (cIt.hasNext()) {
  397. NodePair curr2 = (NodePair)cIt.next();
  398. List<Node> newResults = combine(curr2.node1, curr2.node2);
  399. result.addAll(newResults);
  400. }
  401. }
  402. }
  403. else {
  404. result.add(combineAtRoot(node2, node1));
  405. }
  406. }
  407. return result;
  408. }
  409. else { // shares sub-trees
  410. for (NodePair largest_ : largest) {
  411. result.addAll(subTrees(largest_));
  412. }
  413. return result;
  414. }
  415. }
  416. public static List<Node> reducedCombine(Node node1, Node node2) {
  417. List<Node> result = new ArrayList<>();
  418. if (oneLeafShared(node1, node2)) {
  419. result.add(combineAtRoot(node1, node2));
  420. return result;
  421. }
  422. List<Node> compCombine = combine(node1, node2);
  423. int smallest = Integer.MAX_VALUE;
  424. for (Node curr : compCombine) {
  425. int currAreas = curr.getNumAreas();
  426. if (currAreas < smallest) {
  427. smallest = currAreas;
  428. result.clear();
  429. result.add(curr);
  430. } else if (currAreas == smallest) {
  431. result.add(curr);
  432. }
  433. }
  434. return removeDuplicates(result);
  435. }
  436. /**
  437. * Removes any duplicate nodes. Guarantees that
  438. * forall A, B in result, A.equals(B) == false
  439. * @param all
  440. * @return
  441. */
  442. private static List<Node> removeDuplicates(List<Node> all) {
  443. // TODO: Speed up w/ sets as soon as hash problems are sorted
  444. List<Node> result = new ArrayList<>();
  445. for (Node curr : all) {
  446. boolean foundDup = false;
  447. for (Node resNode : result) {
  448. if (resNode.equals(curr)) {
  449. foundDup = true;
  450. break;
  451. }
  452. }
  453. if (!foundDup) {
  454. result.add(curr);
  455. }
  456. }
  457. return result;
  458. }
  459. /**
  460. * Returns true if the trees with roots node1 and node1 share exactly one leaf node
  461. * @param node1
  462. * @param node2
  463. * @return
  464. */
  465. private static boolean oneLeafShared(Node node1, Node node2) {
  466. List<NodePair> result = deepSearch(node2, node1);
  467. if (result.isEmpty()) {
  468. return false;
  469. }
  470. List<NodePair> largest = getLargestNodePairs(result);
  471. return largest.size() == 1 && largest.get(0).nodesSize() == 1;
  472. }
  473. private static void sortLargestSibs(List<Node> lgsibs, Node lg, List<Node> newSibs, List<Node> os) {
  474. for (Node curr : lgsibs) {
  475. Iterator linkIt = curr.linkNodes.iterator();
  476. boolean linkFlargest = false;
  477. if (linkIt.hasNext()) {
  478. linkFlargest = true;
  479. }
  480. while (linkIt.hasNext()) {
  481. Node currLink = (Node)linkIt.next();
  482. if (!lg.isIn(currLink)) {
  483. linkFlargest = false;
  484. }
  485. }
  486. if (linkFlargest) {
  487. newSibs.add(curr);
  488. }
  489. else if (!curr.linkNodes.isEmpty())
  490. os.add(curr);
  491. }
  492. }
  493. private static List<Node> subTrees(NodePair largest) {
  494. if (largest.node1.isRoot() && largest.node2.isRoot())
  495. throw new IllegalArgumentException("Cannot calculate subtrees with two roots.");
  496. List<Node> result = new ArrayList();
  497. List<Node> combined = largest.combineSubTrees();
  498. for (Node node : combined) {
  499. String curr = node.getVenn();
  500. if ((!node.isLeaf()) && ((largest.node1.nSiblings() != 1) || (largest.node2.nSiblings() != 1))) {
  501. curr = curr.substring(1, curr.length() - 1);
  502. }
  503. String curr1 = "(" + largest.node1.getVenn() + curr + ")";
  504. String curr2 = "(" + largest.node2.getVenn() + curr + ")";
  505. Node newOne = new Node(null, buildUp(largest.node1.parent, curr1));
  506. Node newTwo = new Node(null, buildUp(largest.node2.parent, curr2));
  507. if ((!largest.node1.isRoot()) && (!largest.node2.isRoot())) {
  508. List<Node> newResult = combine(newOne, newTwo);
  509. result.addAll(newResult);
  510. }
  511. else if (!largest.node1.isRoot()) {
  512. result.add(newOne);
  513. }
  514. else if (!largest.node2.isRoot()) {
  515. result.add(newTwo);
  516. }
  517. return result;
  518. }
  519. return result;
  520. }
  521. /**
  522. *
  523. * @param h HashSet
  524. * @return The largest NodePair in h, based on the length of n1's Venn diagram
  525. */
  526. private static List<NodePair> getLargestNodePairs(List<NodePair> h) {
  527. List<NodePair> result = new ArrayList<>();
  528. int size = -1;
  529. for(NodePair curr : h){
  530. if (curr.nodesSize() > size) {
  531. size = curr.nodesSize();
  532. result.clear();
  533. result.add(curr);
  534. } else if (curr.nodesSize() == size) {
  535. result.add(curr);
  536. }
  537. }
  538. return result;
  539. }
  540. private static Node combineAtRoot(Node node1, Node node2) { // CONVERTED
  541. List<Node> uniqueNodes = new ArrayList<>();
  542. for(Node curr : node1.children) {
  543. if (!curr.inSet(uniqueNodes))
  544. uniqueNodes.add(curr);
  545. }
  546. for(Node curr : node2.children) {
  547. if (!curr.inSet(uniqueNodes))
  548. uniqueNodes.add(curr);
  549. }
  550. if (uniqueNodes.size() < (node1.children.size() + node2.children.size())) {
  551. String result_venn = "(";
  552. for (Node unique : uniqueNodes) {
  553. result_venn = result_venn + unique;
  554. }
  555. result_venn = result_venn + ")";
  556. return new Node(null, result_venn);
  557. } else {
  558. return new Node(null, "(" + node1.venn + node2.getVenn() + ")");
  559. }
  560. }
  561. private static List<NodePair> getLinkedNodePair(List<Node> h) {
  562. List<NodePair> result = new ArrayList<>();
  563. for (Node curr : h) {
  564. if (curr.hasLink() != null)
  565. result.add(new NodePair(curr, curr.hasLink()));
  566. }
  567. return result;
  568. }
  569. private static String buildUp(Node n, String s) { // CONVERTED
  570. System.out.println("buildUp: " + s);
  571. if (n.parent == null) {
  572. return s;
  573. }
  574. String result = "(" + s;
  575. List<Node> sibs = n.getSiblings();
  576. for (Node sib : sibs) {
  577. result += sib.getVenn();
  578. }
  579. result += ")";
  580. return buildUp(n.parent, result);
  581. }
  582. private static List<List<NodePair>> reviewPolys(List<NodePair> h) {
  583. List<List<NodePair>> result = new ArrayList<>();
  584. for (NodePair curr : h) {
  585. List<NodePair> curresult = new ArrayList<>();
  586. for (NodePair inCurr : h) {
  587. if (inCurr == curr) {
  588. continue;
  589. }
  590. List<Node> linkedNodePair = inCurr.node2.linkNodes;
  591. boolean found = false;
  592. for (Node currln : linkedNodePair) {
  593. if (currln == curr.node2) {
  594. found = true;
  595. inCurr.node2.linkNode = currln;
  596. break;
  597. }
  598. }
  599. if (found) {
  600. curresult.add(inCurr);
  601. }
  602. }
  603. if (!curresult.isEmpty()) {
  604. curresult.add(curr);
  605. result.add(curresult);
  606. }
  607. }
  608. return result;
  609. }
  610. private static List<NodePair> addPolys(List<NodePair> h) {
  611. List<NodePair> setResult = new ArrayList<>();
  612. NodePair first = null;
  613. String result = "";
  614. for (NodePair nodes : h) {
  615. if (first == null) {
  616. first = nodes;
  617. result = first.node2.getVenn();
  618. }
  619. result += nodes.node1.getVenn();
  620. }
  621. for (NodePair nodes : h) {
  622. NodePair toAdd = new NodePair((nodes).node2, new Node(null, "(" + result + ")"));
  623. setResult.add(toAdd);
  624. }
  625. return setResult;
  626. }
  627. private static List<Node> getUniqueNodes(List<NodePair> nodePairs) { // CONVERTED
  628. HashSet<Node> result = new HashSet<>();
  629. for (NodePair curr : nodePairs) {
  630. if (!result.contains(curr.node1)) {
  631. result.add(curr.node1);
  632. }
  633. if (!result.contains(curr.node2)) {
  634. result.add(curr.node2);
  635. }
  636. }
  637. System.out.println("result: " + result);
  638. List<Node> result_list = new ArrayList<>();
  639. for (NodePair curr : nodePairs) {
  640. result_list.add(curr.node1);
  641. result_list.add(curr.node2);
  642. }
  643. System.out.println("result_list: " + result_list);
  644. return result_list;
  645. }
  646. }