/* * 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.data_structures; import java.util.List; import ch.epfl.data.squall.ewh.algorithms.DenseWeightPrecomputation; import ch.epfl.data.squall.ewh.algorithms.ShallowCoarsener; import ch.epfl.data.squall.ewh.algorithms.WeightPrecomputation; import ch.epfl.data.squall.ewh.algorithms.optimality.OptimalityMetricInterface; import ch.epfl.data.squall.ewh.algorithms.optimality.WeightFunction; import ch.epfl.data.squall.utilities.SystemParameters; public class Region { // region is defined with two opposite edge points private int _x1, _y1, _x2, _y2; private int _frequency; /* * All boundaries are inclusive */ public Region(int x1, int y1, int x2, int y2) { _x1 = x1; _y1 = y1; _x2 = x2; _y2 = y2; } public Region(int x1, int y1, int x2, int y2, int frequency) { this(x1, y1, x2, y2); _frequency = frequency; } public Region(Region r) { this(r._x1, r._y1, r._x2, r._y2, r._frequency); } public Region(String regionHash) { final String[] splits = regionHash.split("-"); _x1 = Integer.parseInt(new String(splits[0])); _y1 = Integer.parseInt(new String(splits[1])); _x2 = Integer.parseInt(new String(splits[2])); _y2 = Integer.parseInt(new String(splits[3])); } public Region(Point origUpperLeft, Point origLowerRight) { this(origUpperLeft.get_x(), origUpperLeft.get_y(), origLowerRight .get_x(), origLowerRight.get_y()); } public int get_x1() { return _x1; } public void set_x1(int x1) { _x1 = x1; } public int get_y1() { return _y1; } public void set_y1(int y1) { _y1 = y1; } public int get_x2() { return _x2; } public void set_x2(int x2) { _x2 = x2; } public int get_y2() { return _y2; } public void set_y2(int y2) { _y2 = y2; } public int getFrequency() { return _frequency; } public void setFrequency(int frequency) { _frequency = frequency; } // unique hash string per region public String getHashString() { return _x1 + "-" + _y1 + "-" + _x2 + "-" + _y2; } public static boolean equalPosition(Region first, Region second) { return first._x1 == second._x1 && first._y1 == second._y1 && first._x2 == second._x2 && first._y2 == second._y2; } /* * These points are not part of the Region, but are generated when needed * Corners are organized as here: 01 23 */ public Point getCorner(int cornerNum) { switch (cornerNum) { case 0: return new Point(_x1, _y1); case 1: return new Point(_x1, _y2); case 2: return new Point(_x2, _y1); case 3: return new Point(_x2, _y2); default: throw new RuntimeException("Corner number " + cornerNum + " does not exist in a rectangle. Allowed are 0, 1, 2, 3."); } } /* * Corner cornerNum is exchanged with newCorner */ public Region shiftCorner(int cornerNum, Point newCorner) { int x1 = -1, y1 = -1, x2 = -1, y2 = -1; switch (cornerNum) { case 0: x1 = newCorner.get_x(); y1 = newCorner.get_y(); break; case 1: x1 = newCorner.get_x(); y2 = newCorner.get_y(); break; case 2: x2 = newCorner.get_x(); y1 = newCorner.get_y(); break; case 3: x2 = newCorner.get_x(); y2 = newCorner.get_y(); break; default: throw new RuntimeException("Corner number " + cornerNum + " does not exist in a rectangle. Allowed are 0, 1, 2, 3."); } return new Region(x1, y1, x2, y2); } public int getHalfPerimeter() { return getSizeX() + getSizeY(); } /* * all the boundaries are inclusive */ public int getSizeX() { return (_x2 - _x1 + 1); } /* * all the boundaries are inclusive */ public int getSizeY() { return (_y2 - _y1 + 1); } @Override public String toString() { return "Upper Left corner is (" + _x1 + ", " + _y1 + "), Lower Right corner is (" + _x2 + ", " + _y2 + ")"; } public static String toString(List<Region> regions, OptimalityMetricInterface opt, String prefix) { StringBuilder sb = new StringBuilder(); double minWeight = Double.MAX_VALUE, maxWeight = 0; sb.append("\nThe number of regions is ").append(regions.size()); for (Region region : regions) { double regionWeight = opt.getWeight(region); if (regionWeight < minWeight) { minWeight = regionWeight; } if (regionWeight > maxWeight) { maxWeight = regionWeight; } sb.append("\nRegion is ").append(region); sb.append(", weight = ").append(regionWeight).append("\n"); } sb.append("\n") .append(prefix) .append(" region weights are in range [" + minWeight + ", " + maxWeight + "]\n"); return sb.toString(); } public static String toString(List<Region> regions, String prefix) { StringBuilder sb = new StringBuilder(); sb.append("\nThe number of regions is ").append(regions.size()); for (Region region : regions) { sb.append("\nRegion is ").append(region).append("\n"); } return sb.toString(); } /* * Could be done more efficiently for enclosing scc regions, but as we * empirically found out that the majority of regions do not move their * bounds much no need for this optimization */ public void minimizeToNotEmpty(WeightPrecomputation wp) { if (wp.isEmpty(this)) { throw new RuntimeException( "Should not try to minimize a region with no candidate cells! \nRegion is " + toString()); } // better when regions are mostly filled eliminateEmptyTopExpGrowth(wp, null); eliminateEmptyLeftExpGrowth(wp, null); eliminateEmptyBottomExpGrowth(wp, null); eliminateEmptyRightExpGrowth(wp, null); /* * // better when regions are mostly empty * eliminateEmptyTopBinarySearch(wp); * eliminateEmptyLeftBinarySearch(wp); * eliminateEmptyBottomBinarySearch(wp); * eliminateEmptyRightBinarySearch(wp); */ } // ****************************************************************************************************** public void minimizeToNotEmptyCoarsened(WeightPrecomputation wp, ShallowCoarsener coarsener) { Region region = this; if (!SystemParameters.COARSE_PRECOMPUTATION) { region = coarsener.translateCoarsenedToOriginalRegion(region); } if (wp.isEmpty(region)) { throw new RuntimeException( "Should not try to minimize a region with no candidate cells! \nRegion is " + toString()); } // better when regions are mostly filled eliminateEmptyTopExpGrowth(wp, coarsener); eliminateEmptyLeftExpGrowth(wp, coarsener); eliminateEmptyBottomExpGrowth(wp, coarsener); eliminateEmptyRightExpGrowth(wp, coarsener); } private Region translateCoarsenedToOriginalRegion(Region region, ShallowCoarsener coarsener) { if (coarsener != null) { // if we are here, the coordinates of this region are coarsened; // we need to invoke wp method on the original points return coarsener.translateCoarsenedToOriginalRegion(region); } else { return region; } } // ****************************************************************************************************** /* * These calls are more efficient -||-BinarySearch (e.g. * eliminateNonCandidatesTopBinarySearch) */ private void eliminateEmptyTopExpGrowth(WeightPrecomputation wp, ShallowCoarsener coarsener) { int lowerBound = _x1; int delta = 1; int currentPos = lowerBound; Region region = new Region(_x1, _y1, currentPos, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } while (currentPos <= _x2 && wp.isEmpty(region)) { lowerBound = currentPos; currentPos += delta; delta *= 2; if (!(currentPos <= _x2)) { break; } region = new Region(_x1, _y1, currentPos, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } } int upperBound = currentPos; if (upperBound > _x2) { upperBound = _x2; } eliminateEmptyTopRange(lowerBound, upperBound, wp, coarsener); } private void eliminateEmptyBottomExpGrowth(WeightPrecomputation wp, ShallowCoarsener coarsener) { int upperBound = _x2; int delta = -1; int currentPos = upperBound; Region region = new Region(currentPos, _y1, _x2, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } while (currentPos >= _x1 && wp.isEmpty(region)) { upperBound = currentPos; currentPos += delta; delta *= 2; if (!(currentPos >= _x1)) { break; } region = new Region(currentPos, _y1, _x2, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } } int lowerBound = currentPos; if (lowerBound < _x1) { lowerBound = _x1; } eliminateEmptyBottomRange(lowerBound, upperBound, wp, coarsener); } private void eliminateEmptyLeftExpGrowth(WeightPrecomputation wp, ShallowCoarsener coarsener) { int lowerBound = _y1; int delta = 1; int currentPos = lowerBound; Region region = new Region(_x1, _y1, _x2, currentPos); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } while (currentPos <= _y2 && wp.isEmpty(region)) { lowerBound = currentPos; currentPos += delta; delta *= 2; if (!(currentPos <= _y2)) { break; } region = new Region(_x1, _y1, _x2, currentPos); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } } int upperBound = currentPos; if (upperBound > _y2) { upperBound = _y2; } eliminateEmptyLeftRange(lowerBound, upperBound, wp, coarsener); } private void eliminateEmptyRightExpGrowth(WeightPrecomputation wp, ShallowCoarsener coarsener) { int upperBound = _y2; int delta = -1; int currentPos = upperBound; Region region = new Region(_x1, currentPos, _x2, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } while (currentPos >= _y1 && wp.isEmpty(region)) { upperBound = currentPos; currentPos += delta; delta *= 2; if (!(currentPos >= _y1)) { break; } region = new Region(_x1, currentPos, _x2, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } } int lowerBound = currentPos; if (lowerBound < _y1) { lowerBound = _y1; } eliminateEmptyRightRange(lowerBound, upperBound, wp, coarsener); } /* * Search only in range */ private void eliminateEmptyTopRange(int lowerBound, int upperBound, WeightPrecomputation wp, ShallowCoarsener coarsener) { int new_x1 = lowerBound; while (lowerBound <= upperBound) { int currentPos = (lowerBound + upperBound) / 2; Region region = new Region(_x1, _y1, currentPos, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } if (!wp.isEmpty(region)) { upperBound = currentPos - 1; } else { lowerBound = currentPos + 1; new_x1 = lowerBound; } } _x1 = new_x1; } private void eliminateEmptyBottomRange(int lowerBound, int upperBound, WeightPrecomputation wp, ShallowCoarsener coarsener) { int new_x2 = upperBound; while (lowerBound <= upperBound) { int currentPos = (lowerBound + upperBound) / 2; Region region = new Region(currentPos, _y1, _x2, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } if (!wp.isEmpty(region)) { lowerBound = currentPos + 1; } else { upperBound = currentPos - 1; new_x2 = upperBound; } } _x2 = new_x2; } private void eliminateEmptyLeftRange(int lowerBound, int upperBound, WeightPrecomputation wp, ShallowCoarsener coarsener) { int new_y1 = lowerBound; while (lowerBound <= upperBound) { int currentPos = (lowerBound + upperBound) / 2; Region region = new Region(_x1, _y1, _x2, currentPos); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } if (!wp.isEmpty(region)) { upperBound = currentPos - 1; } else { lowerBound = currentPos + 1; new_y1 = lowerBound; } } _y1 = new_y1; } private void eliminateEmptyRightRange(int lowerBound, int upperBound, WeightPrecomputation wp, ShallowCoarsener coarsener) { int new_y2 = upperBound; while (lowerBound <= upperBound) { int currentPos = (lowerBound + upperBound) / 2; Region region = new Region(_x1, currentPos, _x2, _y2); if (!SystemParameters.COARSE_PRECOMPUTATION) { region = translateCoarsenedToOriginalRegion(region, coarsener); } if (!wp.isEmpty(region)) { lowerBound = currentPos + 1; } else { upperBound = currentPos - 1; new_y2 = upperBound; } } _y2 = new_y2; } public static void main(String[] args) { JoinMatrix joinMatrix = new UJMPAdapterByteMatrix(100, 100); joinMatrix.setElement(1, 12, 15); joinMatrix.setElement(1, 17, 30); joinMatrix.setElement(1, 17, 29); joinMatrix.setElement(1, 16, 29); joinMatrix.setElement(1, 15, 10); // WeightPrecomputation wf = new DenseMonotonicWeightPrecomputation(new // WeightFunction(1, 1), joinMatrix, new HashMap()); WeightPrecomputation wf = new DenseWeightPrecomputation( new WeightFunction(1, 1), joinMatrix); Region region = new Region(1, 3, 50, 60); region.minimizeToNotEmpty(wf); System.out.println(region); } /* * public void minimizeToNonEmpty(int cornerNum, DenseWeightPrecomputation * wp) { if (wp.isEmpty(this)){ throw new RuntimeException( * "Should not try to minimize a region with no candidate cells!"); } * switch(cornerNum){ case 0: eliminateEmptyTopExpGrowth(wp); * eliminateEmptyLeftExpGrowth(wp); break; case 1: * eliminateEmptyTopExpGrowth(wp); eliminateEmptyRightExpGrowth(wp); break; * case 2: eliminateEmptyBottomExpGrowth(wp); * eliminateEmptyLeftExpGrowth(wp); break; case 3: * eliminateEmptyBottomExpGrowth(wp); eliminateEmptyRightExpGrowth(wp); * break; default: throw new RuntimeException("Corner number " + cornerNum + * " does not exist in a rectangle. Allowed are 0, 1, 2, 3."); } } */ /* * These calls are less efficient (unless region is almost completely empty) */ /* * private void eliminateEmptyTopBinarySearch(WeightPrecomputation wp){ int * lowerBound = _x1; int upperBound = _x2; * eliminateEmptyTopRange(lowerBound, upperBound, wp); } * * private void eliminateEmptyBottomBinarySearch(WeightPrecomputation wp){ * int lowerBound = _x1; int upperBound = _x2; * eliminateEmptyBottomRange(lowerBound, upperBound, wp); } * * private void eliminateEmptyLeftBinarySearch(WeightPrecomputation wp){ int * lowerBound = _y1; int upperBound = _y2; * eliminateEmptyLeftRange(lowerBound, upperBound, wp); } * * private void eliminateEmptyRightBinarySearch(WeightPrecomputation wp){ * int lowerBound = _y1; int upperBound = _y2; * eliminateEmptyRightRange(lowerBound, upperBound, wp); } */ }