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

org.dishevelled.matrix.impl.AbstractMatrix2D 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.impl;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.dishevelled.matrix.BitMatrix2D;
import org.dishevelled.matrix.Matrix1D;
import org.dishevelled.matrix.Matrix2D;

import org.dishevelled.functor.UnaryPredicate;
import org.dishevelled.functor.UnaryProcedure;
import org.dishevelled.functor.UnaryFunction;
import org.dishevelled.functor.BinaryFunction;
import org.dishevelled.functor.TernaryPredicate;
import org.dishevelled.functor.TernaryProcedure;

/**
 * Abstract implementation of Matrix2D.
 *
 * @param  type of this abstract 2D matrix
 * @author  Michael Heuer
 * @version $Revision: 1059 $ $Date: 2012-01-03 14:03:02 -0600 (Tue, 03 Jan 2012) $
 */
abstract class AbstractMatrix2D
    implements Matrix2D
{
    /** Number of rows. */
    protected long rows;

    /** Number of columns. */
    protected long columns;

    /** Row of the first element. */
    protected long rowZero;

    /** Column of the first element. */
    protected long columnZero;

    /** Number of rows between two elements. */
    protected long rowStride;

    /** Number of columns between two elements. */
    protected long columnStride;

    /** True if this instance is a view. */
    protected boolean isView;


    /**
     * Protected no-arg constructor, to support serialization.
     */
    protected AbstractMatrix2D()
    {
        // empty
    }

    /**
     * Create a new abstract 2D matrix with the specified number of
     * rows and columns.
     *
     * @param rows rows, must be >= 0
     * @param columns columns, must be >= 0
     * @throws IllegalArgumentException if either rows or
     *    columns is negative
     */
    protected AbstractMatrix2D(final long rows, final long columns)
    {
        if (rows < 0)
        {
            throw new IllegalArgumentException("rows must be >= 0");
        }
        if (columns < 0)
        {
            throw new IllegalArgumentException("columns must be >= 0");
        }

        this.rows = rows;
        this.columns = columns;
        this.rowZero = 0L;
        this.columnZero = 0L;
        this.rowStride = columns;
        this.columnStride = 1L;
        this.isView = false;
    }

    /**
     * Create a new abstract 2D matrix with the specified parameters.
     *
     * @param rows rows, must be >= 0
     * @param columns columns, must be >= 0
     * @param rowZero row of the first element
     * @param columnZero column of the first element
     * @param rowStride number of rows between two elements
     * @param columnStride number of columns between two elements
     * @param isView true if this instance is a view
     */
    protected AbstractMatrix2D(final long rows,
                                     final long columns,
                                     final long rowZero,
                                     final long columnZero,
                                     final long rowStride,
                                     final long columnStride,
                                     final boolean isView)
    {
        if (rows < 0)
        {
            throw new IllegalArgumentException("rows must be >= 0");
        }
        if (columns < 0)
        {
            throw new IllegalArgumentException("columns must be >= 0");
        }

        this.rows = rows;
        this.columns = columns;
        this.rowZero = rowZero;
        this.columnZero = columnZero;
        this.rowStride = rowStride;
        this.columnStride = columnStride;
        this.isView = isView;
    }


    /** {@inheritDoc} */
    public long size()
    {
        return (rows * columns);
    }

    /** {@inheritDoc} */
    public long rows()
    {
        return rows;
    }

    /** {@inheritDoc} */
    public long columns()
    {
        return columns;
    }

    /** {@inheritDoc} */
    public long cardinality()
    {
        long cardinality = 0;
        for (E e : this)
        {
            if (e != null)
            {
                cardinality++;
            }
        }
        return cardinality;
    }

    /** {@inheritDoc} */
    public boolean isEmpty()
    {
        return (0 == cardinality());
    }

    /** {@inheritDoc} */
    public void clear()
    {
        forEach(new TernaryProcedure()
            {
                public void run(final Long row, final Long column, final E e)
                    {
                        if (e != null)
                        {
                            set(row, column, null);
                        }
                    }
            });
    }

    /** {@inheritDoc} */
    public Iterator iterator()
    {
        return new ObjectMatrix2DIterator();
    }

    /** {@inheritDoc} */
    public E get(final long row, final long column)
    {
        if (row < 0)
        {
            throw new IndexOutOfBoundsException(row + "< 0");
        }
        if (column < 0)
        {
            throw new IndexOutOfBoundsException(column + "< 0");
        }
        if (row >= rows)
        {
            throw new IndexOutOfBoundsException(row + " >= " + rows);
        }
        if (column >= columns)
        {
            throw new IndexOutOfBoundsException(column + " >= " + columns);
        }

        return getQuick(row, column);
    }

    /** {@inheritDoc} */
    public void set(final long row, final long column, final E e)
    {
        if (row < 0)
        {
            throw new IndexOutOfBoundsException(row + "< 0");
        }
        if (column < 0)
        {
            throw new IndexOutOfBoundsException(column + "< 0");
        }
        if (row >= rows)
        {
            throw new IndexOutOfBoundsException(row + " >= " + rows);
        }
        if (column >= columns)
        {
            throw new IndexOutOfBoundsException(column + " >= " + columns);
        }

        setQuick(row, column, e);
    }

    /** {@inheritDoc} */
    public void setQuick(final long row, final long column, final E e)
    {
        throw new UnsupportedOperationException();
    }

    /** {@inheritDoc} */
    public Matrix2D assign(final E e)
    {
        forEach(new TernaryProcedure()
            {
                public void run(final Long row, final Long column, final E ignore)
                {
                    setQuick(row, column, e);
                }
            });

        return this;
    }

    /** {@inheritDoc} */
    public Matrix2D assign(final UnaryFunction function)
    {
        if (function == null)
        {
            throw new IllegalArgumentException("function must not be null");
        }

        forEach(new TernaryProcedure()
            {
                public void run(final Long row, final Long column, final E e)
                {
                    setQuick(row, column, function.evaluate(e));
                }
            });

        return this;
    }

    /** {@inheritDoc} */
    public Matrix2D assign(final Matrix2D other)
    {
        if (other == null)
        {
            throw new IllegalArgumentException("other must not be null");
        }
        if ((size() != other.size()) || (rows != other.rows()) || (columns != other.columns()))
        {
            throw new IllegalArgumentException("this and other must have the same dimensions");
        }

        forEach(new TernaryProcedure()
            {
                public void run(final Long row, final Long column, final E ignore)
                {
                    setQuick(row, column, other.getQuick(row, column));
                }
            });
        return this;
    }

    /** {@inheritDoc} */
    public Matrix2D assign(final Matrix2D other,
                                    final BinaryFunction function)
    {
        if (other == null)
        {
            throw new IllegalArgumentException("other must not be null");
        }
        if ((size() != other.size()) || (rows != other.rows()) || (columns != other.columns()))
        {
            throw new IllegalArgumentException("this and other must have the same dimensions");
        }
        if (function == null)
        {
            throw new IllegalArgumentException("function must not be null");
        }

        forEach(new TernaryProcedure()
            {
                public void run(final Long row, final Long column, final E e)
                {
                    E result = function.evaluate(e, other.getQuick(row, column));
                    setQuick(row, column, result);
                }
            });

        return this;
    }

    /** {@inheritDoc} */
    public E aggregate(final BinaryFunction aggr, final UnaryFunction function)
    {
        if (aggr == null)
        {
            throw new IllegalArgumentException("aggr must not be null");
        }
        if (function == null)
        {
            throw new IllegalArgumentException("function must not be null");
        }
        if (size() == 0)
        {
            return null;
        }
        E a = function.evaluate(getQuick(rows - 1L, columns - 1L));
        long skip = 1L;
        for (long row = rows; --row >= 0;)
        {
            for (long column = (columns - skip); --column >= 0;)
            {
                a = aggr.evaluate(a, function.evaluate(getQuick(row, column)));
            }
            skip = 0L;
        }
        return a;
    }

    /** {@inheritDoc} */
    public E aggregate(final Matrix2D other,
                       final BinaryFunction aggr,
                       final BinaryFunction function)
    {
        if (other == null)
        {
            throw new IllegalArgumentException("other must not be null");
        }
        if ((size() != other.size()) || (rows != other.rows()) || (columns != other.columns()))
        {
            throw new IllegalArgumentException("this and other must have the same dimensions");
        }
        if (aggr == null)
        {
            throw new IllegalArgumentException("aggr must not be null");
        }
        if (function == null)
        {
            throw new IllegalArgumentException("function must not be null");
        }

        if (size() == 0)
        {
            return null;
        }

        long lastRow = (rows - 1L);
        long lastColumn = (columns - 1L);
        E a = function.evaluate(getQuick(lastRow, lastColumn), other.getQuick(lastRow, lastColumn));
        long skip = 1L;
        for (long row = rows; --row >= 0;)
        {
            for (long column = (columns - skip); --column >= 0;)
            {
                a = aggr.evaluate(a, function.evaluate(getQuick(row, column), other.getQuick(row, column)));
            }
            skip = 0L;
        }
        return a;
    }

    /**
     * Create a new view.
     *
     * @return a new view
     */
    protected AbstractMatrix2D view()
    {
        try
        {
            AbstractMatrix2D m = (AbstractMatrix2D) clone();
            return m;
        }
        catch (CloneNotSupportedException e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * Self-modifying version of viewDice().
     *
     * @return modified version of this
     */
    protected AbstractMatrix2D vDice()
    {
        long tmp;

        tmp = rows;
        rows = columns;
        columns = tmp;

        tmp = rowStride;
        rowStride = columnStride;
        columnStride = tmp;

        tmp = rowZero;
        rowZero = columnZero;
        columnZero = tmp;

        isView = true;
        return this;
    }

    /** {@inheritDoc} */
    public Matrix2D viewDice()
    {
        return view().vDice();
    }

    /**
     * Self-modifying version of viewRowFlip().
     *
     * @return modified version of this
     */
    protected AbstractMatrix2D vRowFlip()
    {
        if (rows > 0)
        {
            rowZero += (rows - 1) * rowStride;
            rowStride = -rowStride;
            isView = true;
        }

        return this;
    }

    /** {@inheritDoc} */
    public Matrix2D viewRowFlip()
    {
        return view().vRowFlip();
    }

    /**
     * Self-modifying version of viewColumnFlip().
     *
     * @return modified version of this
     */
    protected AbstractMatrix2D vColumnFlip()
    {
        if (columns > 0)
        {
            columnZero += (columns - 1) * columnStride;
            columnStride = -columnStride;
            isView = true;
        }

        return this;
    }

    /** {@inheritDoc} */
    public Matrix2D viewColumnFlip()
    {
        return view().vColumnFlip();
    }

    /**
     * Self-modifying version of viewPart(long, long, long, long).
     *
     * @param row row
     * @param column column
     * @param height height
     * @param width width
     * @return modified version of this
     */
    protected AbstractMatrix2D vPart(final long row, final long column,
                                              final long height, final long width)
    {
        rowZero += (rowStride * row);
        columnZero += (columnStride * column);
        rows = height;
        columns = width;
        isView = true;

        return this;
    }

    /** {@inheritDoc} */
    public Matrix2D viewPart(final long row, final long column,
                                      final long height, final long width)
    {
        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);
        }
        if ((row + height) > rows)
        {
            throw new IndexOutOfBoundsException("(row + height), " + (row + height) + " > " + rows);
        }
        if ((column + width) > columns)
        {
            throw new IndexOutOfBoundsException("(column + width), " + (column + width) + " > " + columns);
        }
        return view().vPart(row, column, height, width);
    }

    /** {@inheritDoc} */
    public Matrix2D viewSelection(final long[] rows, final long[] columns)
    {
        return null;
    }

    /** {@inheritDoc} */
    public Matrix2D viewSelection(final UnaryPredicate> predicate)
    {
        return null;
    }

    /** {@inheritDoc} */
    public Matrix2D viewSelection(final BitMatrix2D mask)
    {
        return null;
    }

    /**
     * Self-modifying version of viewStrides(long, long).
     *
     * @param rowStride row stride
     * @param columnStride column stride
     * @return modified version of this
     */
    protected AbstractMatrix2D vStrides(final long rowStride, final long columnStride)
    {
        this.rowStride *= rowStride;
        this.columnStride *= columnStride;

        if (this.rows != 0)
        {
            this.rows = (((this.rows - 1L) / rowStride) + 1L);
        }
        if (this.columns != 0)
        {
            this.columns = (((this.columns - 1L) / columnStride) + 1L);
        }
        isView = true;

        return this;
    }

    /** {@inheritDoc} */
    public Matrix2D viewStrides(final long rowStride, final long columnStride)
    {
        return view().vStrides(rowStride, columnStride);
    }

    /** {@inheritDoc} */
    public void forEach(final UnaryProcedure procedure)
    {
        if (procedure == null)
        {
            throw new IllegalArgumentException("procedure must not be null");
        }

        for (long row = 0; row < rows; row++)
        {
            for (long column = 0; column < columns; column++)
            {
                E e = getQuick(row, column);
                procedure.run(e);
            }
        }
    }

    /** {@inheritDoc} */
    public void forEach(final UnaryPredicate predicate,
                        final UnaryProcedure procedure)
    {
        if (predicate == null)
        {
            throw new IllegalArgumentException("predicate must not be null");
        }
        if (procedure == null)
        {
            throw new IllegalArgumentException("procedure must not be null");
        }

        for (long row = 0; row < rows; row++)
        {
            for (long column = 0; column < columns; column++)
            {
                E e = getQuick(row, column);
                if (predicate.test(e))
                {
                    procedure.run(e);
                }
            }
        }
    }

    /** {@inheritDoc} */
    public void forEachNonNull(final UnaryProcedure procedure)
    {
        forEach(new UnaryPredicate()
            {
                public boolean test(final E e)
                {
                    return (e != null);
                }
            }, procedure);
    }

    /** {@inheritDoc} */
    public void forEach(final TernaryProcedure procedure)
    {
        if (procedure == null)
        {
            throw new IllegalArgumentException("procedure must not be null");
        }

        for (long row = 0; row < rows; row++)
        {
            for (long column = 0; column < columns; column++)
            {
                E e = getQuick(row, column);
                procedure.run(row, column, e);
            }
        }
    }

    /** {@inheritDoc} */
    public void forEach(final TernaryPredicate predicate,
                        final TernaryProcedure procedure)
    {
        if (predicate == null)
        {
            throw new IllegalArgumentException("predicate must not be null");
        }
        if (procedure == null)
        {
            throw new IllegalArgumentException("procedure must not be null");
        }

        for (long row = 0; row < rows; row++)
        {
            for (long column = 0; column < columns; column++)
            {
                E e = getQuick(row, column);
                if (predicate.test(row, column, e))
                {
                    procedure.run(row, column, e);
                }
            }
        }
    }

    /**
     * Return the row of the first element.
     *
     * @return the row of the first element
     */
    protected long rowZero()
    {
        return rowZero;
    }

    /**
     * Return the column of the first element.
     *
     * @return the column of this first element
     */
    protected long columnZero()
    {
        return columnZero;
    }

    /**
     * Return the number of rows between two elements.
     *
     * @return the number of rows between two elements
     */
    protected long rowStride()
    {
        return rowStride;
    }

    /**
     * Return the number of columns between two elements.
     *
     * @return the number of columns between two elements
     */
    protected long columnStride()
    {
        return columnStride;
    }

    /**
     * Return true if this instance is a view.
     *
     * @return true if this instance is a view
     */
    protected boolean isView()
    {
        return isView;
    }

    /** {@inheritDoc} */
    public String toString()
    {
        final StringBuffer sb = new StringBuffer();
        sb.append(rows);
        sb.append(" x ");
        sb.append(columns);
        sb.append(" matrix\n");

        forEach(new TernaryProcedure() {
            public void run(final Long row, final Long column, final E e)
                {
                    sb.append((e == null) ? "null" : e.toString());
                    if (column == (columns() - 1))
                    {
                        sb.append("\n");
                    }
                    else
                    {
                        sb.append(" ");
                    }
                }
        });

        return sb.toString();
    }

    /**
     * Matrix2D iterator.
     */
    private class ObjectMatrix2DIterator
        implements Iterator
    {
        /** Row. */
        private long row = 0L;

        /** Column. */
        private long column = 0L;


        /** {@inheritDoc} */
        public boolean hasNext()
        {
            return ((row < rows) && (column < columns));
        }

        /** {@inheritDoc} */
        public E next()
        {
            if ((row < rows) && (column < columns))
            {
                E e = getQuick(row, column);

                column++;
                if (column == columns)
                {
                    column = 0L;
                    row++;
                }

                return e;
            }
            else
            {
                throw new NoSuchElementException("row=" + row + " column=" + column);
            }
        }

        /** {@inheritDoc} */
        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy