/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jena.rdfxml.xmloutput.impl; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.jena.util.iterator.Map1Iterator ; import org.apache.jena.util.iterator.WrappedIterator ; /** * A sparse 2 dimensional array of boolean indexed by Object. * * Complete with transitive closure algorithm. */ class Relation<T> { final private Map<T, Set<T>> rows; final private Map<T, Set<T>> cols; final private Set<T> index; /** The empty Relation. */ public Relation() { rows = new HashMap<>(); cols = new HashMap<>(); index = new HashSet<>(); } /** <code>a</code> is now related to <code>b</code> * */ synchronized public void set(T a, T b) { index.add(a); index.add(b); innerAdd(rows, a, b); innerAdd(cols, b, a); } /** Uniquely <code>a</code> is now related to uniquely <code>b</code>. * * When this is called any other <code>a</code> related to this <code>b</code> is removed. * When this is called any other <code>b</code> related to this <code>a</code> is removed. * */ synchronized public void set11(T a, T b) { clearX(a, forward(a)); clearX(backward(b), b); set(a, b); } /** Uniquely <code>a</code> is now related to <code>b</code>. * Many <code>b</code>'s can be related to each <code>a</code>. * When this is called any other <code>a</code> related to this <code>b</code> is removed. */ synchronized public void set1N(T a, T b) { clearX(backward(b), b); set(a, b); } /** <code>a</code> is now related to uniquely <code>b</code>. * Many <code>a</code>'s can be related to each <code>b</code>. * When this is called any other <code>b</code> related to this <code>a</code> is removed. */ synchronized public void setN1(T a, T b) { clearX(a, forward(a)); set(a, b); } /** <code>a</code> is now related to <code>b</code> * */ synchronized public void setNN(T a, T b) { set(a, b); } /** <code>a</code> is now <em>not</em> related to <code>b</code> * */ synchronized public void clear(T a, T b) { innerClear(rows, a, b); innerClear(cols, b, a); } private void clearX(Set<T> s, T b) { if (s == null) return; for ( T value : s ) { clear( value, b ); } } private void clearX(T a, Set<T> s) { if (s == null) return; for ( T value : s ) { clear( a, value ); } } static private <T> void innerAdd(Map<T, Set<T>> s, T a, T b) { Set<T> vals = s.get(a); if (vals == null) { vals = new HashSet<>(); s.put(a, vals); } vals.add(b); } static private <T> void innerClear(Map<T, Set<T>> s, T a, T b) { Set<T> vals = s.get(a); if (vals != null) { vals.remove(b); } } /** Is <code>a</code> related to <code>b</code>? * */ public boolean get(T a, T b) { Set <T> vals = rows.get(a); return vals != null && vals.contains(b); } /** * Takes this to its transitive closure. See B. Roy. <b>Transitivit� et connexit�.</b> <i>C.R. Acad. Sci.</i> Paris <b>249</b>, 1959 pp 216-218. or S. Warshall, <b>A theorem on Boolean matrices</b>, <i>Journal of the ACM</i>, <b>9</b>(1), 1962, pp11-12 */ synchronized public void transitiveClosure() { for ( T oj : index ) { Set<T> si = cols.get( oj ); Set<T> sk = rows.get( oj ); if ( si != null && sk != null ) { Iterator<T> i = si.iterator(); while ( i.hasNext() ) { T oi = i.next(); if ( oi != oj ) { Iterator<T> k = sk.iterator(); while ( k.hasNext() ) { T ok = k.next(); if ( ok != oj ) { set( oi, ok ); } } } } } } } /** * The set of <code>a</code> such that <code>a</code> is related to <code>a</code>. * */ synchronized public Set<T> getDiagonal() { Set<T> rslt = new HashSet<>(); for ( T o : index ) { if ( get( o, o ) ) { rslt.add( o ); } } return rslt; } synchronized public Relation<T> copy() { Relation<T> rslt = new Relation<>(); Iterator<PairEntry<T, T>> it = iterator(); while ( it.hasNext() ) { Map.Entry<T, T> e = it.next(); rslt.set(e.getKey(),e.getValue()); } return rslt; } /** * The set of <code>b</code> such that <code>a</code> is related to <code>b</code>. * */ public Set<T> forward(T a) { return rows.get(a); } /** * The set of <code>a</code> such that <code>a</code> is related to <code>b</code>. * */ public Set<T> backward(T b) { return cols.get(b); } private static <T> Iterator<PairEntry<T, T>> pairEntry(Map.Entry<T, Set<T>> pair) { final T a = pair.getKey() ; Set<T> bs = pair.getValue() ; return new Map1Iterator<>(b -> new PairEntry<>(a, b), bs.iterator()) ; } /** * An Iterator over the pairs of the Relation. * Each pair is returned as a java.util.Map.Entry. * The first element is accessed through <code>getKey()</code>, * the second through <code>getValue()</code>. *@see java.util.Map.Entry */ public Iterator<PairEntry<T, T>> iterator() { Map1Iterator<Map.Entry<T, Set<T>>,Iterator<PairEntry<T, T>>> iter1 = new Map1Iterator<>( entry -> pairEntry(entry) , rows.entrySet().iterator()) ; // And now flatten it. Iterator<PairEntry<T, T>> iter2 = WrappedIterator.createIteratorIterator(iter1) ; return iter2 ; } } // Old version - exactly as original except with the generics. // Hard(er) to read. // return new IteratorIterator<PairEntry<T, T>>(new Map1Iterator<Map.Entry<T, Set<T>>, Iterator<PairEntry<T, T>>>(new Map1<Map.Entry<T, Set<T>>, Iterator<PairEntry<T, T>>>() { // // Convert a Map.Entry into an iterator over Map.Entry // public Iterator<PairEntry<T, T>> map1(Map.Entry<T, Set<T>> pair) // { // final T a = pair.getKey() ; // Set<T> bs = pair.getValue() ; // return new Map1Iterator<T, PairEntry<T, T>>( // // Converts a b into a Map.Entry pair. // new Map1<T, PairEntry<T, T>>() { // public PairEntry<T, T> map1(T b) // { // return new PairEntry<T, T>(a, b) ; // } // }, bs.iterator()) ; // } // //Map<T, Set<T>> // }