All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dishevelled.matrix.BitMatrix3D Maven / Gradle / Ivy

The newest version!
/*

    dsh-matrix  long-addressable bit and typed object matrix implementations.
    Copyright (c) 2004-2012 held jointly by the individual authors.

    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.fsf.org/licensing/licenses/lgpl.html
    > http://www.opensource.org/licenses/lgpl-license.php

*/
package org.dishevelled.matrix;

import org.dishevelled.bitset.MutableBitSet;

import org.dishevelled.functor.TernaryProcedure;

/**
 * Fixed size bit matrix in three dimensions, indexed by longs.
 *
 * @author  Michael Heuer
 * @version $Revision: 1065 $ $Date: 2012-01-04 22:01:07 -0600 (Wed, 04 Jan 2012) $
 */
public final class BitMatrix3D
{
    /** Bit set. */
    private final MutableBitSet bitset;

    /** Number of slices. */
    private final long slices;

    /** Number of rows. */
    private final long rows;

    /** Number of columns. */
    private final long columns;

    /** Size. */
    private final long size;


    /**
     * Create a new 3D bit matrix with the specified number of
     * slices, rows, and columns.
     *
     * @param slices number of slices, must be >= 0
     * @param rows number of rows, must be >= 0
     * @param columns number of columns, must be >= 0
     * @throws IllegalArgumentException if any of slices,
     *    rows, or columns is negative
     */
    public BitMatrix3D(final long slices, final long rows, final long columns)
    {
        if (slices < 0)
        {
            throw new IllegalArgumentException("slices must be >= 0");
        }
        if (rows < 0)
        {
            throw new IllegalArgumentException("rows must be >= 0");
        }
        if (columns < 0)
        {
            throw new IllegalArgumentException("columns must be >= 0");
        }
        this.slices = slices;
        this.rows = rows;
        this.columns = columns;
        this.size = (slices * rows * columns);
        this.bitset = new MutableBitSet(size);
    }


    /**
     * Return the size of this 3D bit matrix.
     *
     * @return the size of this 3D bit matrix
     */
    public long size()
    {
        return size;
    }

    /**
     * Return the number of slices in this 3D bit matrix.
     *
     * @return the number of slices in this 3D bit matrix
     */
    public long slices()
    {
        return slices;
    }

    /**
     * Return the number of rows in this 3D bit matrix.
     *
     * @return the number of rows in this 3D bit matrix
     */
    public long rows()
    {
        return rows;
    }

    /**
     * Return the number of columns in this 3D bit matrix.
     *
     * @return the number of columns in this 3D bit matrix
     */
    public long columns()
    {
        return columns;
    }

    /**
     * Return the cardinality of this 3D bit matrix, the
     * number of bits set to true.
     *
     * @return the cardinality of this 3D bit matrix
     */
    public long cardinality()
    {
        return bitset.cardinality();
    }

    /**
     * Return true if the cardinality of this 3D bit matrix is zero.
     *
     * @return true if the cardinality of this 3D bit matrix is zero
     */
    public boolean isEmpty()
    {
        return (0 == cardinality());
    }

    /**
     * Clear all the values in this 3D bit matrix.
     */
    public void clear()
    {
        for (long i = bitset.nextSetBit(0); i >= 0; i = bitset.nextSetBit(i + 1))
        {
            bitset.clear(i);
        }
    }

    /**
     * Return the bit value at the specified slice, row, and column.
     *
     * @param slice slice index, must be > 0 and < slices()
     * @param row row index, must be > 0 and < rows()
     * @param column column index, must be > 0 and < columns()
     * @return the bit value at the specified slice, row, and column
     * @throws IndexOutOfBoundsException if any of slice, row, or
     *    column are negative or if any of slice, row,
     *    or column are greater than or equal to slices(),
     *    rows(), or columns(), respectively
     */
    public boolean get(final long slice, final long row, final long column)
    {
        if (slice < 0)
        {
            throw new IndexOutOfBoundsException(slice + " < 0");
        }
        if (slice >= slices)
        {
            throw new IndexOutOfBoundsException(slice + " >= " + slices);
        }
        if (row < 0)
        {
            throw new IndexOutOfBoundsException(row + " < 0");
        }
        if (row >= rows)
        {
            throw new IndexOutOfBoundsException(row + " >= " + rows);
        }
        if (column < 0)
        {
            throw new IndexOutOfBoundsException(column + " < 0");
        }
        if (column >= columns)
        {
            throw new IndexOutOfBoundsException(column + " >= " + columns);
        }
        return getQuick(slice, row, column);
    }

    /**
     * Return the bit value at the specified slice, row, and column without checking bounds.
     *
     * @param slice slice index
     * @param row row index
     * @param column column index
     * @return the bit value at the specified slice, row, and column
     */
    public boolean getQuick(final long slice, final long row, final long column)
    {
        return bitset.getQuick(index(slice, row, column));
    }

    /**
     * Set the bit value at the specified slice, row, and column to value.
     *
     * @param slice slice index, must be >= 0 and < slices()
     * @param row row index, must be >= 0 and < rows()
     * @param column column index, must be >= 0 and < columns()
     * @param value value
     * @throws IndexOutOfBoundsException if any of slice, row, or
     *    column are negative or if any of slice, row,
     *    or column are greater than or equal to slices(),
     *    rows(), or columns(), respectively
     */
    public void set(final long slice, final long row, final long column, final boolean value)
    {
        if (slice < 0)
        {
            throw new IndexOutOfBoundsException(slice + " < 0");
        }
        if (slice >= slices)
        {
            throw new IndexOutOfBoundsException(slice + " >= " + slices);
        }
        if (row < 0)
        {
            throw new IndexOutOfBoundsException(row + " < 0");
        }
        if (row >= rows)
        {
            throw new IndexOutOfBoundsException(row + " >= " + rows);
        }
        if (column < 0)
        {
            throw new IndexOutOfBoundsException(column + " < 0");
        }
        if (column >= columns)
        {
            throw new IndexOutOfBoundsException(column + " >= " + columns);
        }
        setQuick(slice, row, column, value);
    }

    /**
     * Set the bit value at the specified slice, row, and column to value without checking bounds.
     *
     * @param slice slice index
     * @param row row index
     * @param column column index
     * @param value value
     */
    public void setQuick(final long slice, final long row, final long column, final boolean value)
    {
        long index = index(slice, row, column);
        if (value)
        {
            bitset.setQuick(index);
        }
        else
        {
            bitset.clearQuick(index);
        }
    }

    /**
     * Set all of the bit values from (slice0, row0, column0), inclusive,
     * to (slice1, row1, column1), exclusive, to the specified value.
     *
     * @param slice0 first slice, must be >= 0 and < slices()
     * @param row0 first row, must be >= 0 and < rows()
     * @param column0 first column, must be >= 0 and < columns()
     * @param slice1 second slice, must be >= 0, <= slices()
     *    and >= slice0
     * @param row1 second row, must be >= 0, <= rows()
     *    and >= row0
     * @param column1 second column, must be >= 0, <= columns()
     *    and >= column0
     * @param value value
     * @throws IllegalArgumentException if any of slice1, row1, or
     *    column1 are less than slice0, row0, or
     *    column0, respectively
     * @throws IndexOutOfBoundsException if any of slice0, row0,
     *    column0, slice1, row1, or column1
     *    are negative or if any of slice0, row0, or column0
     *    are greater than or equal to slices(), rows(), or
     *    columns(), respectively, or if any of slice1, row1, or
     *    column1 are strictly greater than slices(), rows(),
     *    or columns(), respectively
     */
    public void set(final long slice0, final long row0, final long column0,
                    final long slice1, final long row1, final long column1, final boolean value)
    {
        if (slice0 < 0)
        {
            throw new IndexOutOfBoundsException(slice0 + " < 0");
        }
        if (slice0 >= slices)
        {
            throw new IndexOutOfBoundsException(slice0 + " >= " + slices);
        }
        if (row0 < 0)
        {
            throw new IndexOutOfBoundsException(row0 + " < 0");
        }
        if (row0 >= rows)
        {
            throw new IndexOutOfBoundsException(row0 + " >= " + rows);
        }
        if (column0 < 0)
        {
            throw new IndexOutOfBoundsException(column0 + " < 0");
        }
        if (column0 >= columns)
        {
            throw new IndexOutOfBoundsException(column0 + " >= " + columns);
        }
        if (slice1 < 0)
        {
            throw new IndexOutOfBoundsException(slice1 + " < 0");
        }
        if (slice1 > slices)
        {
            throw new IndexOutOfBoundsException(slice1 + " > " + slices);
        }
        if (row1 < 0)
        {
            throw new IndexOutOfBoundsException(row1 + " < 0");
        }
        if (row1 > rows)
        {
            throw new IndexOutOfBoundsException(row1 + " > " + rows);
        }
        if (column1 < 0)
        {
            throw new IndexOutOfBoundsException(column1 + " < 0");
        }
        if (column1 > columns)
        {
            throw new IndexOutOfBoundsException(column1 + " > " + columns);
        }

        for (long slice = slice0; slice < slice1; slice++)
        {
            for (long row = row0; row < row1; row++)
            {
                for (long column = column0; column < column1; column++)
                {
                    setQuick(slice, row, column, value);
                }
            }
        }
    }

    /**
     * Set the bit value at the specified slice, row, and column to the complement
     * of its current bit value.
     *
     * @param slice slice index, must be >= 0 and < slices()
     * @param row row index, must be >= 0 and < rows()
     * @param column column index, must be >= 0 and < columns()
     * @throws IndexOutOfBoundsException if any of slice, row, or
     *    column are negative or if any of slice, row,
     *    or column are greater than or equal to slices(),
     *    rows(), or columns(), respectively
     */
    public void flip(final long slice, final long row, final long column)
    {
        if (slice < 0)
        {
            throw new IndexOutOfBoundsException(slice + " < 0");
        }
        if (slice >= slices)
        {
            throw new IndexOutOfBoundsException(slice + " >= " + slices);
        }
        if (row < 0)
        {
            throw new IndexOutOfBoundsException(row + " < 0");
        }
        if (row >= rows)
        {
            throw new IndexOutOfBoundsException(row + " >= " + rows);
        }
        if (column < 0)
        {
            throw new IndexOutOfBoundsException(column + " < 0");
        }
        if (column >= columns)
        {
            throw new IndexOutOfBoundsException(column + " >= " + columns);
        }
        flipQuick(slice, row, column);
    }

    /**
     * Set the bit value at the specified slice, row, and column to the complement
     * of its current bit value without checking bounds.
     *
     * @param slice slice index
     * @param row row index
     * @param column column index
     */
    public void flipQuick(final long slice, final long row, final long column)
    {
        bitset.flipQuick(index(slice, row, column));
    }

    /**
     * Set all of the bit values from (slice0, row0, column0), inclusive,
     * to (slice1, row1, column1), exclusive, to the complement of their
     * current bit values.
     *
     * @param slice0 first slice, must be >= 0 and < slices()
     * @param row0 first row, must be >= 0 and < rows()
     * @param column0 first column, must be >= 0 and < columns()
     * @param slice1 second slice, must be >= 0, <= slices()
     *    and >= slice0
     * @param row1 second row, must be >= 0, <= rows()
     *    and >= row0
     * @param column1 second column, must be >= 0, <= columns()
     *    and >= column0
     * @throws IllegalArgumentException if any of slice1, row1, or
     *    column1 are less than slice0, row0, or
     *    column0, respectively
     * @throws IndexOutOfBoundsException if any of slice0, row0,
     *    column0, slice1, row1, or column1
     *    are negative or if any of slice0, row0, or column0
     *    are greater than or equal to slices(), rows(), or
     *    columns(), respectively, or if any of slice1, row1, or
     *    column1 are strictly greater than slices(), rows(),
     *    or columns(), respectively
     */
    public void flip(final long slice0, final long row0, final long column0,
                     final long slice1, final long row1, final long column1)
    {
        if (slice0 < 0)
        {
            throw new IndexOutOfBoundsException(slice0 + " < 0");
        }
        if (slice0 >= slices)
        {
            throw new IndexOutOfBoundsException(slice0 + " >= " + slices);
        }
        if (row0 < 0)
        {
            throw new IndexOutOfBoundsException(row0 + " < 0");
        }
        if (row0 >= rows)
        {
            throw new IndexOutOfBoundsException(row0 + " >= " + rows);
        }
        if (column0 < 0)
        {
            throw new IndexOutOfBoundsException(column0 + " < 0");
        }
        if (column0 >= columns)
        {
            throw new IndexOutOfBoundsException(column0 + " >= " + columns);
        }
        if (slice1 < 0)
        {
            throw new IndexOutOfBoundsException(slice1 + " < 0");
        }
        if (slice1 > slices)
        {
            throw new IndexOutOfBoundsException(slice1 + " > " + slices);
        }
        if (row1 < 0)
        {
            throw new IndexOutOfBoundsException(row1 + " < 0");
        }
        if (row1 > rows)
        {
            throw new IndexOutOfBoundsException(row1 + " > " + rows);
        }
        if (column1 < 0)
        {
            throw new IndexOutOfBoundsException(column1 + " < 0");
        }
        if (column1 > columns)
        {
            throw new IndexOutOfBoundsException(column1 + " > " + columns);
        }

        for (long slice = slice0; slice < slice1; slice++)
        {
            for (long row = row0; row < row1; row++)
            {
                for (long column = column0; column < column1; column++)
                {
                    flipQuick(slice, row, column);
                }
            }
        }
    }

    /**
     * Assign all values in this 3D bit matrix to value.
     *
     * @param value value
     * @return this 3D bit matrix, for convenience
     */
    public BitMatrix3D assign(final boolean value)
    {
        if (size > 0)
        {
            set(0, 0, 0, slices, rows, columns, value);
        }
        return this;
    }

    /**
     * Return true if the specified 3D bit matrix has any bits set
     * to true that are also set to true in this 3D bit matrix.
     *
     * @param other other 3D bit matrix, must not be null and must
     *    have the same dimensions as this 3D bit matrix
     * @return true if the specified 3D bit matrix has any bits set
     *    to true that are also set to true in this 3D bit matrix
     */
    public boolean intersects(final BitMatrix3D other)
    {
        if (other == null)
        {
            throw new IllegalArgumentException("other must not be null");
        }
        if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
            || (columns != other.columns()))
        {
            throw new IllegalArgumentException("this and other must have the same dimensions");
        }
        return bitset.intersects(other.bitset);
    }

    /**
     * Perform a logical AND of this 3D bit matrix
     * and the specified 3D bit matrix.
     *
     * @param other other 3D bit matrix, must not be null and must
     *    have the same dimensions as this 3D bit matrix
     * @return this 3D bit matrix, for convenience
     */
    public BitMatrix3D and(final BitMatrix3D other)
    {
        if (other == null)
        {
            throw new IllegalArgumentException("other must not be null");
        }
        if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
            || (columns != other.columns()))
        {
            throw new IllegalArgumentException("this and other must have the same dimensions");
        }
        bitset.and(other.bitset);
        return this;

    }

    /**
     * Clear all the bits in this 3D bit matrix whose corresponding
     * bit is set in the specified 3D bit matrix.
     *
     * @param other other 3D bit matrix, must not be null and must
     *    have the same dimensions as this 3D bit matrix
     * @return this 3D bit matrix, for convenience
     */
    public BitMatrix3D andNot(final BitMatrix3D other)
    {
        if (other == null)
        {
            throw new IllegalArgumentException("other must not be null");
        }
        if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
            || (columns != other.columns()))
        {
            throw new IllegalArgumentException("this and other must have the same dimensions");
        }
        bitset.andNot(other.bitset);
        return this;
    }

    /**
     * Perform a logical OR of this 3D bit matrix
     * and the specified 3D bit matrix.
     *
     * @param other other 3D bit matrix, must not be null and must
     *    have the same dimensions as this 3D bit matrix
     * @return this 3D bit matrix, for convenience
     */
    public BitMatrix3D or(final BitMatrix3D other)
    {
        if (other == null)
        {
            throw new IllegalArgumentException("other must not be null");
        }
        if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
            || (columns != other.columns()))
        {
            throw new IllegalArgumentException("this and other must have the same dimensions");
        }
        bitset.or(other.bitset);
        return this;
    }

    /**
     * Perform a logical XOR of this 3D bit matrix
     * and the specified 3D bit matrix.
     *
     * @param other other 3D bit matrix, must not be null and must
     *    have the same dimensions as this 3D bit matrix
     * @return this 3D bit matrix, for convenience
     */
    public BitMatrix3D xor(final BitMatrix3D other)
    {
        if (other == null)
        {
            throw new IllegalArgumentException("other must not be null");
        }
        if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
            || (columns != other.columns()))
        {
            throw new IllegalArgumentException("this and other must have the same dimensions");
        }
        bitset.xor(other.bitset);
        return this;
    }

    /**
     * Apply the specified procedure to each slice, row, and column
     * in this 3D bit matrix with a bit equal to the specified value.
     *
     * @param value value
     * @param procedure procedure, must not be null
     */
    public void forEach(final boolean value,
                        final TernaryProcedure procedure)
    {
        if (procedure == null)
        {
            throw new IllegalArgumentException("procedure must not be null");
        }

        for (long slice = 0; slice < slices; slice++)
        {
            for (long row = 0; row < rows; row++)
            {
                for (long column = 0; column < columns; column++)
                {
                    if (getQuick(slice, row, column) == value)
                    {
                        procedure.run(Long.valueOf(slice), Long.valueOf(row), Long.valueOf(column));
                    }
                }
            }
        }
    }

    /** {@inheritDoc} */
    public boolean equals(final Object o)
    {
        if (o == null)
        {
            return false;
        }
        if (!(o instanceof BitMatrix3D))
        {
            return false;
        }

        BitMatrix3D bm = (BitMatrix3D) o;

        if ((size != bm.size()) || (slices != bm.slices()) || (rows != bm.rows()) || (columns != bm.columns()))
        {
            return false;
        }
        return bitset.equals(bm.bitset);
    }

    /** {@inheritDoc} */
    public int hashCode()
    {
        int hashCode = 37;
        hashCode = 17 * hashCode + (int) (size ^ (size >>> 32));
        hashCode = 17 * hashCode + (int) (slices ^ (slices >>> 32));
        hashCode = 17 * hashCode + (int) (rows ^ (rows >>> 32));
        hashCode = 17 * hashCode + (int) (columns ^ (columns >>> 32));
        hashCode = 17 * hashCode + bitset.hashCode();
        return hashCode;
    }


    /**
     * Return the index for the specified slice, row, and column.
     *
     * @param slice slice inddex
     * @param row row index
     * @param column column index
     * @return the index for the specified slice, row, and column
     */
    private long index(final long slice, final long row, final long column)
    {
        return (rows * columns * slice) + (columns * row) + column;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy