001/*
002 * @author Francesco.Kriegel@gmx.de
003 */
004package conexp.fx.core.math;
005
006/*
007 * #%L
008 * Concept Explorer FX
009 * %%
010 * Copyright (C) 2010 - 2019 Francesco Kriegel
011 * %%
012 * This program is free software: you can redistribute it and/or modify
013 * it under the terms of the GNU General Public License as
014 * published by the Free Software Foundation, either version 3 of the
015 * License, or (at your option) any later version.
016 * 
017 * This program is distributed in the hope that it will be useful,
018 * but WITHOUT ANY WARRANTY; without even the implied warranty of
019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
020 * GNU General Public License for more details.
021 * 
022 * You should have received a copy of the GNU General Public
023 * License along with this program.  If not, see
024 * <http://www.gnu.org/licenses/gpl-3.0.html>.
025 * #L%
026 */
027
028import java.util.Arrays;
029import java.util.Collection;
030import java.util.Iterator;
031
032import org.ujmp.core.booleanmatrix.BooleanMatrix;
033import org.ujmp.core.booleanmatrix.BooleanMatrix2D;
034import org.ujmp.core.calculation.Calculation.Ret;
035
036public final class BooleanMatrices {
037
038  public static final BooleanMatrix clone(final BooleanMatrix m) {
039    return m.clone().toBooleanMatrix();
040  }
041
042  public static final BooleanMatrix empty(final long size) {
043    return empty(size, size);
044  }
045
046  public static final BooleanMatrix empty(final long rows, final long columns) {
047    return BooleanMatrix2D.Factory.zeros(rows, columns);
048  }
049
050  public static final BooleanMatrix full(final long size) {
051    return full(size, size);
052  }
053
054  public static final BooleanMatrix full(final long rows, final long columns) {
055    return complement(empty(rows, columns));
056  }
057
058  public static final BooleanMatrix identity(final long size) {
059    final BooleanMatrix m = empty(size);
060    for (int i = 0; i < size; i++)
061      m.setBoolean(true, i, i);
062    return m;
063  }
064
065  public static final BooleanMatrix negativeIdentity(final long size) {
066    return complement(identity(size));
067  }
068
069  public static final BooleanMatrix lowerDiagonal(final long size) {
070    return dual(upperDiagonal(size));
071  }
072
073  public static final BooleanMatrix upperDiagonal(final long size) {
074    final BooleanMatrix m = empty(size);
075    for (int i = 0; i < size; i++)
076      for (int j = i; j < size; j++)
077        m.setBoolean(true, i, j);
078    return m;
079  }
080
081  public static final BooleanMatrix strictLowerDiagonal(final long size) {
082    return complement(upperDiagonal(size));
083  }
084
085  public static final BooleanMatrix strictUpperDiagonal(final long size) {
086    return complement(lowerDiagonal(size));
087  }
088
089  public static final BooleanMatrix apposition(final BooleanMatrix... ms) {
090    if (ms.length == 0)
091      return null;
092    BooleanMatrix m = ms[0];
093    for (int i = 1; i < ms.length; i++)
094      m = apposition(m, ms[i]);
095    return m;
096  }
097
098  public static final BooleanMatrix apposition(final BooleanMatrix left, final BooleanMatrix right) {
099    if (left == null)
100      return (BooleanMatrix) right.clone();
101    if (right == null)
102      return (BooleanMatrix) left.clone();
103    return (BooleanMatrix) left.appendHorizontally(Ret.NEW, right);
104  }
105
106  public static final BooleanMatrix subposition(final BooleanMatrix... ms) {
107    if (ms.length == 0)
108      return null;
109    BooleanMatrix m = ms[0];
110    for (int i = 1; i < ms.length; i++)
111      m = subposition(m, ms[i]);
112    return m;
113  }
114
115  public static final BooleanMatrix subposition(final BooleanMatrix upper, final BooleanMatrix lower) {
116    if (upper == null)
117      return (BooleanMatrix) lower.clone();
118    if (lower == null)
119      return (BooleanMatrix) upper.clone();
120    return (BooleanMatrix) upper.appendVertically(Ret.NEW, lower);
121  }
122
123  public static final BooleanMatrix quadPosition(
124      final BooleanMatrix leftUpper,
125      final BooleanMatrix rightUpper,
126      final BooleanMatrix leftLower,
127      final BooleanMatrix rightLower) {
128    return subposition(apposition(leftUpper, rightUpper), apposition(leftLower, rightLower));
129  }
130
131  public static final BooleanMatrix complement(final BooleanMatrix m) {
132    return (BooleanMatrix) m.not(Ret.NEW);
133  }
134
135  public static final BooleanMatrix dual(final BooleanMatrix m) {
136    return (BooleanMatrix) m.transpose(Ret.NEW);
137  }
138
139  public static final BooleanMatrix booleann(final long size) {
140    if (size < 0)
141      return null;
142    else if (size == 0)
143      return identity(1);
144    final BooleanMatrix m = booleann(size - 1);
145    return subposition(apposition(m, m), apposition(empty((long) Math.pow(2, size - 1)), m));
146  }
147
148  public static final BooleanMatrix directSum(final BooleanMatrix leftUpper, final BooleanMatrix rightLower) {
149    return subposition(
150        apposition(leftUpper, full(leftUpper.getRowCount(), rightLower.getColumnCount())),
151        apposition(full(rightLower.getRowCount(), leftUpper.getColumnCount()), rightLower));
152  }
153
154  public static final BooleanMatrix horizontalSum(final BooleanMatrix leftUpper, final BooleanMatrix rightLower) {
155    return subposition(
156        apposition(leftUpper, empty(leftUpper.getRowCount(), rightLower.getColumnCount())),
157        apposition(empty(rightLower.getRowCount(), leftUpper.getColumnCount()), rightLower));
158  }
159
160  public static final BooleanMatrix verticalSum(final BooleanMatrix leftUpper, final BooleanMatrix rightLower) {
161    return subposition(
162        apposition(leftUpper, full(leftUpper.getRowCount(), rightLower.getColumnCount())),
163        apposition(empty(rightLower.getRowCount(), leftUpper.getColumnCount()), rightLower));
164  }
165
166  public static final BooleanMatrix substitutionSum(
167      final BooleanMatrix outer,
168      final BooleanMatrix inner,
169      final long row,
170      final long column,
171      final Collection<Integer> gI,
172      final Collection<Integer> mI) {
173    final BooleanMatrix lu, ru, ll, rl;
174    // ( G\{g}, M\{m}, I )
175    lu = outer;
176    System.out.println(lu);
177    // ( H, N, J )
178    rl = inner;
179    System.out.println(rl);
180    // ( G\{g}, N, (m'\{g}) x N )
181    ru = empty(lu.getRowCount(), rl.getColumnCount());
182    ru.selectRows(Ret.LINK, mI).not(Ret.ORIG);
183    System.out.println(ru);
184    // ( H, M\{m}, H x (g'\{m}) )
185    ll = empty(rl.getRowCount(), lu.getColumnCount());
186    ll.selectColumns(Ret.LINK, gI).not(Ret.ORIG);
187    System.out.println(ll);
188    return quadPosition(lu, ru, ll, rl).deleteRows(Ret.NEW, row).deleteColumns(Ret.NEW, column).toBooleanMatrix();
189  }
190
191  public static final BooleanMatrix directProduct(final BooleanMatrix m1, final BooleanMatrix m2) {
192    return (BooleanMatrix) scale(m1, m2.getRowCount(), m2.getColumnCount())
193        .or(Ret.NEW, duplicate(m2, m1.getRowCount(), m1.getColumnCount()));
194  }
195
196  public static final BooleanMatrix biProduct(final BooleanMatrix m1, final BooleanMatrix m2) {
197    return (BooleanMatrix) scale(m1, m2.getRowCount(), m2.getColumnCount())
198        .and(Ret.NEW, duplicate(m2, m1.getRowCount(), m1.getColumnCount()));
199  }
200
201  public static final BooleanMatrix semiProduct(final BooleanMatrix m1, final BooleanMatrix m2) {
202    return apposition(scaleV(m1, m2.getRowCount()), duplicateV(m2, m1.getRowCount()));
203  }
204
205  private static final BooleanMatrix duplicate(final BooleanMatrix m, final long rowFactor, final long columnFactor) {
206    return duplicateV(duplicateH(m, columnFactor), rowFactor);
207  }
208
209  private static final BooleanMatrix duplicateH(final BooleanMatrix m, final long columnFactor) {
210    BooleanMatrix h = null;
211    for (int i = 0; i < columnFactor; i++)
212      h = apposition(h, m);
213    return h;
214  }
215
216  private static final BooleanMatrix duplicateV(final BooleanMatrix m, final long rowFactor) {
217    BooleanMatrix v = null;
218    for (int i = 0; i < rowFactor; i++)
219      v = subposition(v, m);
220    return v;
221  }
222
223  private static final BooleanMatrix scale(final BooleanMatrix m, final long rowFactor, final long columnFactor) {
224    return scaleV(scaleH(m, columnFactor), rowFactor);
225  }
226
227  private static final BooleanMatrix scaleH(final BooleanMatrix m, final long columnFactor) {
228    BooleanMatrix h = null;
229    for (long j = 0; j < m.getColumnCount(); j++)
230      for (int f = 0; f < columnFactor; f++)
231        h = apposition(h, (BooleanMatrix) m.selectColumns(Ret.NEW, j));
232    return h;
233  }
234
235  private static final BooleanMatrix scaleV(final BooleanMatrix m, final long rowFactor) {
236    BooleanMatrix v = null;
237    for (long i = 0; i < m.getRowCount(); i++)
238      for (int f = 0; f < rowFactor; f++)
239        v = subposition(v, (BooleanMatrix) m.selectRows(Ret.NEW, i));
240    return v;
241  }
242
243  public static final BooleanMatrix andCol(final BooleanMatrix m, final Iterable<Integer> columns) {
244//    return StreamSupport.stream(columns.spliterator(), false).map(column -> m.selectColumns(Ret.NEW, column)).collect(
245//        () -> full(m.getRowCount(), 1),
246//        (x, y) -> x.and(Ret.ORIG, y),
247//        (x, y) -> x.and(Ret.ORIG, y));
248    final Iterator<Integer> it = columns.iterator();
249    if (it.hasNext()) {
250      final BooleanMatrix andCol = (BooleanMatrix) m.selectColumns(Ret.NEW, it.next());
251      while (it.hasNext())
252        andCol.and(Ret.ORIG, m.selectColumns(Ret.LINK, it.next()));
253      return andCol;
254    }
255    return full(m.getRowCount(), 1);
256  }
257
258  public static final BooleanMatrix andRow(final BooleanMatrix m, final Iterable<Integer> rows) {
259//    return StreamSupport.stream(rows.spliterator(), false).map(row -> m.selectRows(Ret.NEW, row)).collect(
260//        () -> full(1, m.getColumnCount()),
261//        (x, y) -> x.and(Ret.ORIG, y),
262//        (x, y) -> x.and(Ret.ORIG, y));
263    final Iterator<Integer> it = rows.iterator();
264    if (it.hasNext()) {
265      final BooleanMatrix andRow = (BooleanMatrix) m.selectRows(Ret.NEW, it.next());
266      while (it.hasNext())
267        andRow.and(Ret.ORIG, m.selectRows(Ret.LINK, it.next()));
268      return andRow;
269    }
270    return full(1, m.getColumnCount());
271  }
272
273  public static final BooleanMatrix andCol(final BooleanMatrix m, final Integer... columns) {
274    return andCol(m, Arrays.<Integer> asList(columns));
275  }
276
277  public static final BooleanMatrix andRow(final BooleanMatrix m, final Integer... rows) {
278    return andRow(m, Arrays.<Integer> asList(rows));
279  }
280
281  private static final boolean isSquare(final BooleanMatrix m) {
282    return m.getRowCount() == m.getColumnCount();
283  }
284
285  public static final BooleanMatrix product(final BooleanMatrix m1, final BooleanMatrix m2) {
286    return m1.mtimes(Ret.NEW, false, m2).toBooleanMatrix();
287  }
288
289  public static final BooleanMatrix power(final BooleanMatrix m, final int n) {
290    if (!isSquare(m))
291      throw new IllegalArgumentException();
292    if (n < 0)
293      throw new IllegalArgumentException();
294    if (n == 0)
295      return identity(m.getRowCount());
296    if (n == 1)
297      return clone(m);
298    if (n == 2)
299      return product(m, m);
300    return product(power(m, n - 1), m);
301  }
302
303  public static final BooleanMatrix reflexiveClosure(final BooleanMatrix m) {
304    if (!isSquare(m))
305      return null;
306    return m.or(Ret.NEW, identity(m.getRowCount())).toBooleanMatrix();
307  }
308
309  public static final BooleanMatrix reflexiveReduction(final BooleanMatrix m) {
310    if (!isSquare(m))
311      return null;
312    return m.and(Ret.NEW, negativeIdentity(m.getRowCount())).toBooleanMatrix();
313  }
314
315  public static final BooleanMatrix transitiveClosure(final BooleanMatrix m) {
316    if (!isSquare(m))
317      return null;
318    BooleanMatrix t = clone(m);
319    BooleanMatrix power = clone(m);
320    BooleanMatrix last = null;
321    do {
322      power = product(power, m);
323      last = clone(t);
324      t = t.or(Ret.NEW, power).toBooleanMatrix();
325    } while (!t.equals(last));
326    return t;
327  }
328
329  public static final BooleanMatrix transitiveReduction(final BooleanMatrix m) {
330    if (!isSquare(m))
331      return null;
332    return m.and(Ret.NEW, m.mtimes(Ret.NEW, false, transitiveClosure(m)).not(Ret.NEW)).toBooleanMatrix();
333  }
334}