org.nmdp.ngs.fca.CrossTable.java Source code

Java tutorial

Introduction

Here is the source code for org.nmdp.ngs.fca.CrossTable.java

Source

/*
    
ngs-fca  Formal concept analysis for genomics.
Copyright (c) 2014-2015 National Marrow Donor Program (NMDP)
    
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.
    
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
License for more details.
    
You should have received a copy of the GNU Lesser General Public License
along with this library;  if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
    
> http://www.gnu.org/licenses/lgpl.html
    
*/
package org.nmdp.ngs.fca;

import static com.google.common.base.Preconditions.checkArgument;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;

import org.dishevelled.bitset.MutableBitSet;

import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Range;
import com.tinkerpop.blueprints.Graph;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.dishevelled.bitset.AbstractBitSet;
import static org.nmdp.ngs.fca.Poset.MAGIC;

/**
 * CrossTable.
 * @param <G> object type
 * @param <M> attribute type
 */
public final class CrossTable implements Iterable<CrossTable.Row> {
    private long nrow, ncol;
    private List<Row> table;

    public final static class Row {
        public final long index;
        public final MutableBitSet intent;

        public Row(int index, final MutableBitSet intent) {
            checkNotNull(index, intent);

            this.index = index;
            this.intent = intent;
        }

        public Concept asConcept() {
            return this.asConcept(MutableBitSet.DEFAULT_NUM_BITS);
        }

        public Concept asConcept(long size) {
            MutableBitSet extent = new MutableBitSet(size);
            extent.flip(index);
            return new Concept(extent, intent);
        }

        @Override
        public String toString() {
            return this.asConcept().toString();
        }

        @Override
        public boolean equals(final Object right) {
            if (!(right instanceof Row)) {
                return false;
            }

            if (right == this) {
                return true;
            }

            Row row = (Row) right;
            return this.index == row.index && this.intent.equals(row.intent);
        }
    }

    public final static class Decomposition implements Map.Entry<CrossTable, CrossTable> {
        CrossTable key, value;

        @Override
        public CrossTable getKey() {
            return key;
        }

        @Override
        public CrossTable getValue() {
            return value;
        }

        @Override
        public CrossTable setValue(CrossTable value) {
            this.value = value;
            return this.value;
        }
    }

    public CrossTable() {
        nrow = ncol = 0;
        table = new ArrayList<>();
    }

    public CrossTable(final CrossTable that) {
        this();

        for (long i = 0; i < that.nrow; i++) {
            this.addRow(new MutableBitSet().or(that.getRow((int) i).intent));
        }
    }

    public CrossTable(final CrossTable that, long plus) {
        this(that);
        ncol += plus;
    }

    public static <G extends Relatable, M extends Relatable> CrossTable fromContext(final Context<G, M> context) {
        checkNotNull(context);

        CrossTable table = new CrossTable();

        List<G> objects = context.getObjects();
        List<M> attributes = context.getAttributes();
        BinaryRelation relation = context.getRelation();

        for (int i = 0; i < objects.size(); i++) {
            MutableBitSet bits = new MutableBitSet(attributes.size());
            for (int j = 0; j < attributes.size(); j++) {
                if (relation.apply(objects.get((int) i), attributes.get((int) j))) {
                    bits.flip(j);
                }
            }
            table.addRow(bits);
        }

        return table;
    }

    public long getNumberOfRows() {
        return nrow;
    }

    public long getNumberOfColumns() {
        return ncol;
    }

    public void addRow(final MutableBitSet bits) {
        long n = bits.prevSetBit(bits.capacity());

        if (ncol <= n) {
            ncol = n + 1;
        }

        table.add(new Row((int) nrow++, bits));
    }

    public Row getRow(int index) {
        checkArgument(Range.closedOpen(0, (int) nrow).contains(index));
        return table.get(index);
    }

    public static CrossTable complement(final CrossTable that) {
        checkNotNull(that);
        CrossTable complement = new CrossTable();

        for (int i = 0; i < that.getNumberOfRows(); i++) {
            MutableBitSet ones = new MutableBitSet(that.ncol);
            ones.set(0, that.ncol);
            complement.addRow(new MutableBitSet().andNot(ones, that.getRow(i).intent));
        }

        return complement;
    }

    public static CrossTable horizontalSum(final CrossTable that, final CrossTable other) {
        checkNotNull(that, other);
        CrossTable sum = new CrossTable(that, other.getNumberOfColumns());

        for (int i = 0; i < other.nrow; i++) {
            MutableBitSet bits = new MutableBitSet(that.ncol + other.ncol);
            MutableBitSet intent = other.getRow(i).intent;
            for (long j = intent.nextSetBit(0); j >= 0; j = intent.nextSetBit(j + 1)) {
                bits.set(that.ncol + j);
            }
            sum.addRow(bits);
        }

        return sum;
    }

    public static CrossTable verticalSum(final CrossTable that, final CrossTable other) {
        CrossTable sum = CrossTable.horizontalSum(that, other);

        for (int i = 0; i < that.nrow; i++) {
            sum.getRow(i).intent.set(that.ncol, that.ncol + other.ncol);
        }

        return sum;
    }

    public static CrossTable directProduct(final CrossTable that, final CrossTable other) {
        CrossTable product = CrossTable.verticalSum(that, other);

        for (long i = that.nrow; i < product.nrow; i++) {
            product.getRow((int) i).intent.set(0, that.ncol);
        }

        return product;
    }

    public Decomposition parallelDecomposition() {
        return new Decomposition();
    }

    public Decomposition seriesDecomposition() {
        return new Decomposition();
    }

    public ConceptLattice asConceptLattice(final Graph graph) {
        ConceptLattice lattice = new ConceptLattice(graph, ncol);

        Iterator it = this.iterator();
        while (it.hasNext()) {
            CrossTable.Row row = (CrossTable.Row) it.next();
            lattice.insert(row.asConcept(ncol));
        }

        return lattice;
    }

    @Override
    public Iterator<Row> iterator() {
        return table.iterator();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();

        for (Row row : table) {
            sb.append(row.toString()).append("\n");
        }

        return sb.toString();
    }

    @Override
    public boolean equals(final Object right) {
        if (!(right instanceof CrossTable)) {
            return false;
        }

        if (right == this) {
            return true;
        }

        CrossTable table = (CrossTable) right;
        return this.nrow == table.nrow && this.ncol == table.ncol && this.table.equals(table.table);
    }
}