/drools-core/src/main/java/org/drools/core/util/AbstractBitwiseHierarchyImpl.java

https://github.com/esteban-aliverti/drools · Java · 549 lines · 400 code · 104 blank · 45 comment · 92 complexity · 240eaf35a74848625642415f8f47bc86 MD5 · raw file

  1. package org.drools.core.util;
  2. import org.drools.core.factmodel.traits.LatticeElement;
  3. import java.io.Externalizable;
  4. import java.io.IOException;
  5. import java.io.ObjectInput;
  6. import java.io.ObjectOutput;
  7. import java.util.ArrayList;
  8. import java.util.BitSet;
  9. import java.util.Collection;
  10. import java.util.Comparator;
  11. import java.util.LinkedHashMap;
  12. import java.util.List;
  13. import java.util.LinkedList;
  14. import java.util.Map;
  15. import java.util.SortedMap;
  16. import java.util.TreeMap;
  17. public abstract class AbstractBitwiseHierarchyImpl<H ,J extends LatticeElement<H>> implements Externalizable, CodedHierarchy<H> {
  18. protected SortedMap<BitSet,J> line = new TreeMap<BitSet,J>( new HierCodeComparator() );
  19. protected boolean fixedRoot = false;
  20. public int size() {
  21. return fixedRoot ? line.size() - 1 : line.size();
  22. }
  23. protected J getNodeByKey( BitSet key ) {
  24. return line.get( key );
  25. }
  26. protected abstract J getNode( H name );
  27. protected void remove( J node ) {
  28. line.remove( node.getBitMask() );
  29. }
  30. protected boolean contains( J node ) {
  31. return line.containsKey( node.getBitMask() );
  32. }
  33. public BitSet getCode( H val ) {
  34. if ( val == null ) {
  35. return null;
  36. }
  37. J node = getNode( val );
  38. return node != null ? node.getBitMask() : null;
  39. }
  40. public BitSet metMembersCode( Collection<H> vals ) {
  41. BitSet x = new BitSet( this.size() );
  42. for ( H val : vals ) {
  43. x.or( getNode( val ).getBitMask() );
  44. }
  45. return x;
  46. }
  47. public BitSet jointMembersCode( Collection<H> vals ) {
  48. BitSet x = new BitSet( this.size() );
  49. boolean first = true;
  50. for ( H val : vals ) {
  51. if ( first ) {
  52. first = false;
  53. x.or( getNode( val ).getBitMask() );
  54. } else {
  55. x.and( getNode( val ).getBitMask() );
  56. }
  57. }
  58. return x;
  59. }
  60. public BitSet meetCode( Collection<BitSet> codes ) {
  61. BitSet x = new BitSet( this.size() );
  62. for ( BitSet code : codes ) {
  63. x.or( code );
  64. }
  65. return x;
  66. }
  67. public BitSet joinCode( Collection<BitSet> codes ) {
  68. BitSet x = new BitSet( this.size() );
  69. boolean first = true;
  70. for ( BitSet code : codes ) {
  71. if ( first ) {
  72. first = false;
  73. x.or( code );
  74. } else {
  75. x.and( code );
  76. }
  77. }
  78. return x;
  79. }
  80. public List<H> getSortedMembers() {
  81. List<H> anx = new ArrayList<H>( size() );
  82. for ( J node : getNodes() ) {
  83. if ( node.getValue() != null ) {
  84. anx.add( node.getValue() );
  85. }
  86. }
  87. return anx;
  88. }
  89. public Collection<H> upperAncestors( BitSet key ) {
  90. List<H> vals = new LinkedList<H>();
  91. int l = key.length();
  92. //System.out.println( key );
  93. BitSet start = new BitSet( l );
  94. BitSet end = new BitSet( l );
  95. int index = 0;
  96. H rootVal = getMember( new BitSet() );
  97. if ( rootVal != null ) {
  98. vals.add( rootVal );
  99. }
  100. while ( index >= 0 ) {
  101. int s = index;
  102. int t = key.nextClearBit( s );
  103. start.clear();
  104. start.set( s, true );
  105. end.set( s, t, true );
  106. // System.out.println( "X >> " + s + " << " + t );
  107. // System.out.println( "S >> " + start );
  108. // System.out.println( "E >> " + end );
  109. // System.out.println( "E+1>> " + nextKey( end ) );
  110. if ( t > 0 ) {
  111. for ( J val : line.subMap( start, nextKey( end ) ).values() ) {
  112. // System.out.println( "\t " + val.getValue() );
  113. vals.add( val.getValue() );
  114. }
  115. }
  116. index = key.nextSetBit( t );
  117. }
  118. return vals;
  119. }
  120. /**
  121. * @param key a key, possibly the meet of a number of member keys
  122. * @return
  123. */
  124. public Collection<H> lowerBorder( BitSet key ) {
  125. return gcs( key, true );
  126. }
  127. /**
  128. * @param key a key, possibly the meet of a number of member keys
  129. * @return
  130. */
  131. public Collection<H> immediateChildren( BitSet key ) {
  132. return gcs( key, false );
  133. }
  134. /**
  135. * @param key a key, possibly the meet of a number of member keys
  136. * @return
  137. */
  138. Collection<H> gcs( BitSet key, boolean includeEquals ) {
  139. List<H> vals = new LinkedList<H>();
  140. List<J> border = gcsBorderNodes( key, includeEquals );
  141. for ( int j = 0; j < border.size(); j++ ) {
  142. J node = border.get( j );
  143. if ( node != null ) {
  144. vals.add( node.getValue() );
  145. }
  146. }
  147. return vals;
  148. }
  149. List<J> gcsBorderNodes( BitSet key, boolean includeEquals ) {
  150. List<J> border = new LinkedList<J>();
  151. int l = key.length();
  152. int n = line.size() != 0 ? line.lastKey().length() : 0;
  153. BitSet start = new BitSet( n );
  154. BitSet end = new BitSet( n );
  155. start.or( key );
  156. // for ( int j = l; j <= n; j++ ) {
  157. if ( l > n ) { return border; }
  158. if ( l > 0 ) {
  159. start.set( l - 1 );
  160. }
  161. end.set( n );
  162. // end.set( j );
  163. for ( J val : line.subMap( start, end ).values() ) {
  164. BitSet candidate = val.getBitMask();
  165. boolean minimal = true;
  166. int check = superset( candidate, key );
  167. if ( ( includeEquals && check >= 0 ) || ( ! includeEquals && check > 0 ) ) {
  168. // it is a descendant of the probe key
  169. for ( int k = 0; k < border.size(); k++ ) {
  170. // current border
  171. J ex = border.get( k );
  172. if ( ex != null ) {
  173. if ( superset( candidate, ex.getBitMask() ) >= 0 ) {
  174. // System.out.println( "Skipping " + val + " due to " + ex );
  175. minimal = false;
  176. break;
  177. } else if ( superset( ex.getBitMask(), candidate ) > 0 ) {
  178. // System.out.println( "Clearing " + ex + " due to " + val );
  179. border.set( k, null );
  180. }
  181. } // else cleared border member, continue
  182. }
  183. if ( minimal ) {
  184. border.add( val );
  185. }
  186. } // else no desc, ignore
  187. }
  188. // if ( j > 0 ) {
  189. // start.clear( j - 1 );
  190. // }
  191. // end.clear( j );
  192. //
  193. // }
  194. return border;
  195. }
  196. /**
  197. * @param key a key, possibly the meet of a number of member keys
  198. * @return
  199. */
  200. Collection<H> lcs( BitSet key, boolean includeEquals ) {
  201. List<H> vals = new LinkedList<H>();
  202. List<J> border = lcsBorderNodes( key, includeEquals );
  203. for ( int j = 0; j < border.size(); j++ ) {
  204. J node = border.get( j );
  205. if ( node != null ) {
  206. vals.add( node.getValue() );
  207. }
  208. }
  209. return vals;
  210. }
  211. List<J> lcsBorderNodes( BitSet key, boolean includeEquals ) {
  212. List<J> border = new ArrayList<J>();
  213. if ( key == null ) { return border; }
  214. // System.out.println( key );
  215. int l = key.length();
  216. BitSet start = new BitSet( l + 1 );
  217. BitSet end = new BitSet( l + 1 );
  218. int index = 0;
  219. J root = line.get( new BitSet() );
  220. if ( root != null ) {
  221. border.add( root );
  222. }
  223. while ( index >= 0 ) {
  224. int s = index;
  225. int t = key.nextClearBit( s );
  226. start.clear();
  227. start.set( s, true );
  228. end.set( s, t, true );
  229. for ( J val : line.subMap( start, nextKey( end ) ).values() ) {
  230. BitSet candidate = val.getBitMask();
  231. int comp = superset( key, candidate );
  232. if ( ( includeEquals && comp >= 0 ) || ( ! includeEquals && comp > 0 ) ) {
  233. border.add( val );
  234. for ( int j = 0; j < border.size(); j++ ) {
  235. J ex = border.get( j );
  236. if ( ex != null ) {
  237. if ( superset( candidate, ex.getBitMask() ) > 0 ) {
  238. // System.out.println( "Clearing " + ex + " due to " + val );
  239. border.set( j, null );
  240. }
  241. }
  242. }
  243. }
  244. // System.out.println( "\t\t " + border );
  245. }
  246. index = key.nextSetBit( t );
  247. }
  248. return border;
  249. }
  250. //------------------------------
  251. protected String toBinaryString( BitSet mask ) {
  252. return toBinaryString(mask, mask.length());
  253. }
  254. protected String toBinaryString( BitSet mask, int len ) {
  255. StringBuilder sb = new StringBuilder();
  256. for ( int j = len - 1; j >= 0; j-- ) {
  257. sb.append( mask.get( j ) ? "1 " : "0 " );
  258. }
  259. return sb.toString();
  260. }
  261. BitSet prevKey( BitSet key ) {
  262. BitSet b = new BitSet( key.length() );
  263. b.or( key );
  264. int x = key.nextSetBit( 0 );
  265. if ( x == 0 ) {
  266. b.clear( 0 );
  267. } else {
  268. b.set( 0, x, true );
  269. b.clear( x );
  270. }
  271. return b;
  272. }
  273. BitSet nextKey( BitSet key ) {
  274. int l = key.length();
  275. if ( l == 0 ) {
  276. BitSet b = new BitSet( 1 );
  277. b.set( 0 );
  278. return b;
  279. }
  280. BitSet b = new BitSet( l + 1 );
  281. b.or( key );
  282. int x = key.nextSetBit( 0 );
  283. if ( x == 0 ) {
  284. int y = b.nextClearBit( 0 );
  285. b.set( x, y, false );
  286. b.set(y);
  287. } else {
  288. b.set(0);
  289. }
  290. return b;
  291. }
  292. public static boolean supersetOrEqualset( BitSet n1, BitSet n2 ) {
  293. BitSet x;
  294. int l1 = n1.length();
  295. int l2 = n2.length();
  296. if ( l1 > l2 ) {
  297. x = new BitSet( l2 );
  298. x.or( n2 );
  299. x.and( n1 );
  300. } else {
  301. x = new BitSet( l1 );
  302. x.or( n1 );
  303. x.and( n2 );
  304. }
  305. return x.equals( n2 );
  306. }
  307. int superset( J n1, J n2 ) {
  308. return superset( n1.getBitMask(), n2.getBitMask() );
  309. }
  310. public int superset( BitSet n1, BitSet n2 ) {
  311. if ( n1.equals( n2 ) ) {
  312. return 0;
  313. }
  314. return supersetOrEqualset(n1, n2) ? 1 : -1;
  315. }
  316. protected int numBit( BitSet x ) {
  317. return x.length();
  318. }
  319. public void writeExternal( ObjectOutput objectOutput ) throws IOException {
  320. objectOutput.writeBoolean( this.fixedRoot );
  321. objectOutput.writeObject( this.line );
  322. }
  323. public void readExternal( ObjectInput objectInput ) throws IOException, ClassNotFoundException {
  324. this.fixedRoot = objectInput.readBoolean();
  325. this.line = (SortedMap<BitSet, J>) objectInput.readObject();
  326. }
  327. protected static class HierCodeComparator implements Comparator<BitSet>, Externalizable {
  328. public HierCodeComparator() {
  329. }
  330. public int compare( BitSet bitMask, BitSet yset ) {
  331. int lx = bitMask.length();
  332. int ly = yset.length();
  333. if ( lx == 0 && ly == 0 ) { return 0; }
  334. if ( lx > ly ) { return 1; }
  335. if ( ly > lx ) { return -1; }
  336. BitSet x;
  337. x = new BitSet( ly );
  338. x.or( yset );
  339. x.xor( bitMask );
  340. if ( x.isEmpty() ) { return 0; }
  341. int ix = x.length() - 1;
  342. if ( bitMask.get( ix ) ) {
  343. return 1;
  344. } else if ( yset.get( ix ) ) {
  345. return -1;
  346. } else {
  347. return 0;
  348. }
  349. }
  350. public void writeExternal(ObjectOutput objectOutput) throws IOException {
  351. }
  352. public void readExternal(ObjectInput objectInput) throws IOException, ClassNotFoundException {
  353. }
  354. }
  355. public static BitSet stringToBitSet( String s ) {
  356. BitSet b = new BitSet();
  357. int n = s.length();
  358. for( int j = 0; j < s.length(); j++ ) {
  359. if ( s.charAt( j ) == '1' ) {
  360. b.set( n - j - 1 );
  361. } else if ( s.charAt( j ) != '0' ) {
  362. throw new IllegalStateException( "The string " + s + " is not a valid bitset encoding" );
  363. }
  364. }
  365. return b;
  366. }
  367. //---------------needed by sub classes of TypeHierarchy---------------
  368. // public void addMember(LatticeElement<H> val, BitSet key) {
  369. // System.out.println(">>>>>>************* it should not happen");
  370. // }
  371. public void removeMember( H val ) {
  372. System.out.println(">>>>>>************* it should not happen");
  373. }
  374. public void removeMember(BitSet key) {
  375. J node = line.get(key);
  376. remove(node);
  377. }
  378. public Map<H, BitSet> getSortedMap() {
  379. Map<H,BitSet> anx = new LinkedHashMap<H, BitSet>( size() );
  380. for ( J node : getNodes() ) {
  381. if ( node.getValue() != null ) {
  382. anx.put( node.getValue(), node.getBitMask() );
  383. }
  384. }
  385. return anx;
  386. }
  387. public boolean hasKey(BitSet key) {
  388. return line.containsKey( key );
  389. }
  390. // public Collection<J> children(BitSet key) {
  391. // return null; //To change body of implemented methods use File | Settings | File Templates.
  392. // }
  393. public Collection<H> lowerDescendants( BitSet key ) {
  394. List<H> vals = new LinkedList<H>();
  395. int l = key.length();
  396. if ( l == 0 || line.isEmpty() ) {
  397. return new ArrayList( getSortedMembers() );
  398. }
  399. int n = line.lastKey().length();
  400. if ( l > n ) { return vals; }
  401. BitSet start = new BitSet( n );
  402. BitSet end = new BitSet( n );
  403. start.or( key );
  404. start.set( l - 1 );
  405. end.set( n );
  406. for ( J val : line.subMap( start, end ).values() ) {
  407. BitSet x = val.getBitMask();
  408. if ( superset( x, key ) >= 0 ) {
  409. vals.add( val.getValue() );
  410. }
  411. }
  412. start.clear( l - 1 );
  413. return vals;
  414. }
  415. protected abstract Collection<H> parentValues( J node );
  416. public Collection<H> parents(H x) {
  417. J node = getNode( x );
  418. return parentValues(node);
  419. }
  420. public Collection<H> parents(BitSet x) {
  421. J node = getNodeByKey( x );
  422. return parentValues( node );
  423. }
  424. public Collection<H> upperBorder(BitSet key) {
  425. return lcs( key, true );
  426. }
  427. public Collection<H> immediateParents(BitSet key) {
  428. return lcs( key, false );
  429. }
  430. public boolean isEmpty() {
  431. return line.isEmpty();
  432. }
  433. public void clear() {
  434. line.clear();
  435. }
  436. protected void add( J node ) {
  437. line.put(node.getBitMask(), node);
  438. }
  439. protected Collection<J> getNodes() {
  440. return line.values();
  441. }
  442. public H getMember( BitSet key ) {
  443. return line.containsKey( key ) ? line.get( key ).getValue() : null;
  444. }
  445. }