local.laer.app.knapsack.support.OffsetIntMatrix.java Source code

Java tutorial

Introduction

Here is the source code for local.laer.app.knapsack.support.OffsetIntMatrix.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package local.laer.app.knapsack.support;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.Converter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Logger;
import static java.util.stream.Collectors.toList;
import local.laer.app.knapsack.domain.Cell;
import local.laer.app.knapsack.domain.ImmutablePosition;
import local.laer.app.knapsack.domain.Position;
import local.laer.app.knapsack.domain.support.Matrix;
import static local.laer.app.knapsack.support.IntFunctions.col;
import static local.laer.app.knapsack.support.IntFunctions.partial;
import local.laer.app.knapsack.support.matrix.IntMatrix;

/**
 *
 * @author Lars Eriksson (larsq.eriksson@gmail.com)
 */
@JsonSerialize(converter = OffsetIntMatrix.JsonConverter.class)
public class OffsetIntMatrix implements IntMatrix {

    private final static Logger LOG = Logger.getLogger(OffsetIntMatrix.class.getPackage().getName());

    public static class JsonConverter implements Converter<OffsetIntMatrix, Matrix> {

        private static Matrix.Stripe defineRowStripe(OffsetIntMatrix matrix, int row) {
            Matrix.Stripe stripe = new Matrix.Stripe();
            stripe.setDirection(Matrix.Direction.Row);
            stripe.setOffset(new ImmutablePosition(row, matrix.colOffset));

            int[] rowData = matrix.extractRow(matrix.colOffset, matrix.cols(), row);

            String[] converted = Arrays.stream(rowData).mapToObj(String::valueOf).collect(toList())
                    .toArray(new String[0]);

            stripe.setData(converted);

            return stripe;
        }

        @Override
        public Matrix convert(OffsetIntMatrix value) {
            List<Matrix.Stripe> stripes = new ArrayList<>();

            value.consume(
                    partial(col(value.colOffset), cell -> stripes.add(defineRowStripe(value, cell.getRow()))));

            Matrix m = new Matrix();
            m.setContent(stripes.toArray(new Matrix.Stripe[stripes.size()]));
            m.setDefaultValue(value.defaultValue);

            return m;
        }

        @Override
        public JavaType getInputType(TypeFactory typeFactory) {
            return typeFactory.constructType(OffsetIntMatrix.class);
        }

        @Override
        public JavaType getOutputType(TypeFactory typeFactory) {
            return typeFactory.constructType(Matrix.class);
        }

    }

    protected int[] extractCol(int lowerRowIndexInclusive, int nRows, int col) {
        int[] data = new int[nRows];
        for (int i = 0; i < nRows; i++) {
            data[i] = getInt(i + lowerRowIndexInclusive, col);
        }

        return data;
    }

    protected int[] extractRow(int lowerColIndexInclusive, int nCols, int row) {
        int[] data = new int[nCols];
        for (int i = 0; i < nCols; i++) {
            data[i] = getInt(row, i + lowerColIndexInclusive);
        }

        return data;
    }

    protected static boolean within(int n, int lowerInclusive, int size) {
        int upperExclusive = lowerInclusive + size;

        return lowerInclusive <= n && n < upperExclusive;
    }

    protected static int[][] copy(int[][] value) {
        int[][] clone = new int[value.length][value[0].length];

        for (int i = 0; i < clone.length; i++) {
            System.arraycopy(value[i], 0, clone[i], 0, value[i].length);
        }

        return clone;
    }

    private final int rowOffset;
    private final int colOffset;
    private final int[][] value;
    private final int defaultValue;

    protected int lowerRow() {
        return rowOffset;
    }

    protected int lowerCol() {
        return colOffset;
    }

    protected OffsetIntMatrix(int row, int col, int[][] value, Integer defaultValue) {
        this.rowOffset = row;
        this.colOffset = col;
        this.value = copy(value);
        this.defaultValue = (defaultValue == null) ? 0 : defaultValue;
    }

    public OffsetIntMatrix(int row, int col, int rows, int cols, Integer defaulValue) {
        this.rowOffset = row;
        this.colOffset = col;
        this.value = new int[rows][cols];
        this.defaultValue = (defaulValue == null) ? 0 : defaulValue;
    }

    public OffsetIntMatrix transform(Function<Cell<Integer>, Integer> callback) {
        OffsetIntMatrix matrix = new OffsetIntMatrix(rowOffset, colOffset, value, defaultValue);
        matrix.mutableTransform(callback);
        return matrix;
    }

    public void consume(Consumer<Cell<Integer>> callback) {
        SimpleCell<Integer> cell = new SimpleCell<>();

        for (int row = 0; row < rows(); row++) {
            for (int col = 0; col < cols(); col++) {
                cell.col = col + colOffset;
                cell.row = row + rowOffset;
                cell.value = value[row][col];

                callback.accept(cell);
            }
        }
    }

    protected void mutableTransform(Function<Cell<Integer>, Integer> callback) {
        SimpleCell<Integer> cell = new SimpleCell<>();

        for (int row = 0; row < rows(); row++) {
            for (int col = 0; col < cols(); col++) {
                cell.col = col + colOffset;
                cell.row = row + rowOffset;
                cell.value = value[row][col];

                Integer newValue = callback.apply(cell);

                value[row][col] = (newValue == null) ? defaultValue : newValue;
            }
        }
    }

    public OffsetIntMatrix translateTo(Position pos) {
        return new OffsetIntMatrix(pos.getRow(), pos.getCol(), value, defaultValue);
    }

    @Override
    public int getInt(int row, int col) {
        if (!isDefined(row, col)) {
            return defaultValue;
        }

        return value[row - rowOffset][col - colOffset];
    }

    protected boolean isDefined(int row, int col) {
        return within(row, rowOffset, rows()) && within(col, colOffset, cols());
    }

    protected int cols() {
        return value[0].length;
    }

    protected int rows() {
        return value.length;
    }

    public static OffsetIntMatrix concat(OffsetIntMatrix first, OffsetIntMatrix other, Integer defaultValue) {
        int lowerCol = Math.min(first.lowerCol(), other.lowerCol());
        int lowerRow = Math.min(first.lowerRow(), other.lowerRow());

        int upperColExclusive = Math.max(first.lowerCol() + first.cols(), other.lowerCol() + other.cols());
        int upperRowExclusive = Math.max(first.lowerRow() + first.rows(), other.lowerRow() + other.rows());

        OffsetIntMatrix matrix = new OffsetIntMatrix(lowerRow, lowerCol, upperRowExclusive - lowerRow,
                upperColExclusive - lowerCol, defaultValue);
        matrix.mutableTransform(IntFunctions.merge(first, (f, o) -> (o != other.defaultValue) ? o : f));
        matrix.mutableTransform(IntFunctions.merge(other, (f, o) -> (o != other.defaultValue) ? o : f));

        return matrix;
    }
}