/* * Copyright (c) 2011-2015 EPFL DATA Laboratory * Copyright (c) 2014-2015 The Squall Collaboration (see NOTICE) * * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ch.epfl.data.squall.ewh.algorithms; import ch.epfl.data.squall.ewh.algorithms.optimality.WeightFunction; import ch.epfl.data.squall.ewh.data_structures.Region; import ch.epfl.data.squall.ewh.data_structures.SimpleMatrix; /* * Answer weight queries for arbitrary regions within the inputMatrix * To reduce complexity to O(1), it uses precomputation */ public class DenseWeightPrecomputation implements WeightPrecomputation { private WeightFunction _wf; private SimpleMatrix _inputMatrix; private int[][] _prefixSum; private int _xSize, _ySize; // dimension of the prefix sum public DenseWeightPrecomputation(WeightFunction wf, SimpleMatrix inputMatrix) { _wf = wf; _inputMatrix = inputMatrix; _xSize = _inputMatrix.getXSize(); _ySize = _inputMatrix.getYSize(); _prefixSum = new int[_xSize][_ySize]; precompute(); } @Override public WeightFunction getWeightFunction() { return _wf; } @Override public int getXSize() { return _xSize; } @Override public int getYSize() { return _ySize; } /* * this method does *not* use region._frequency, as it is 0 */ @Override public double getWeight(Region region) { return _wf.getWeight(region.getHalfPerimeter(), getFrequency(region)); } @Override public boolean isEmpty(Region region) { return getFrequency(region) == 0; } @Override public int getFrequency(Region region) { int corner0x = region.getCorner(0).get_x() - 1; int corner0y = region.getCorner(0).get_y() - 1; int corner1x = region.getCorner(1).get_x() - 1; int corner1y = region.getCorner(1).get_y(); int corner2x = region.getCorner(2).get_x(); int corner2y = region.getCorner(2).get_y() - 1; int corner3x = region.getCorner(3).get_x(); // this point is inclusive int corner3y = region.getCorner(3).get_y(); return getPrefixSum(corner3x, corner3y) - getPrefixSum(corner2x, corner2y) - getPrefixSum(corner1x, corner1y) + getPrefixSum(corner0x, corner0y); } @Override public int getTotalFrequency() { return _prefixSum[_xSize - 1][_ySize - 1]; } @Override public String toString() { return _wf.toString(); } // This works for non-monotonic queries private void precompute() { int currentRowSum; for (int i = 0; i < _xSize; i++) { currentRowSum = 0; for (int j = 0; j < _ySize; j++) { currentRowSum += _inputMatrix.getElement(i, j); if (i == 0) { _prefixSum[i][j] = currentRowSum; } else { _prefixSum[i][j] = _prefixSum[i - 1][j] + currentRowSum; } } } } @Override public int getPrefixSum(int x, int y) { if (x < 0 || y < 0) { return 0; } else { return _prefixSum[x][y]; } } @Override public int getMinHalfPerimeterForWeight(double weight) { // hp is halfPerimeter // Weight = a * hp + b * freq // hp >= 2 * (sqrt(freq) - 1); the minimum halfPerimeter is for // cross-product // Weight <= a * 2 * (sqrt(freq) - 1) + b * freq // Solve this quadratic equation to get freq // Then hp >= 2 * (sqrt(freq) - 1) throw new RuntimeException("Not implemented for now!"); } }