Commit 3ea53e47 authored by Josef Brandt's avatar Josef Brandt

RandomBoxSampling

Also Quarter RandomBoxSampling
parent c070f4ab
......@@ -43,6 +43,7 @@ def get_methods_to_test(dataset: dataset.DataSet, fractions: list = []) -> list:
boxCreator: gmeth.BoxSelectionCreator = gmeth.BoxSelectionCreator(dataset)
methods += boxCreator.get_crossBoxSubsamplers_for_fraction(fraction)
methods += boxCreator.get_spiralBoxSubsamplers_for_fraction(fraction)
methods += boxCreator.get_randomBoxSubsamplers_for_fraction(fraction)
# methods.append(cmeth.ChemometricSubsampling(particleContainer, fraction))
return methods
......
import numpy as np
from itertools import combinations
from methods import SubsamplingMethod
from copy import deepcopy
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard import dataset
import helpers
def box_overlaps_other_box(topLeft1: list, topLeft2: list, boxSize: float) -> bool:
"""
Returns true if the two specified boxes overlap
:param topLeft1:
:param topLeft2:
:param boxSize:
:return:
"""
return abs(topLeft1[0] - topLeft2[0]) < boxSize and abs(topLeft1[1] - topLeft2[1]) < boxSize
class BoxSelectionSubsamplingMethod(SubsamplingMethod):
possibleBoxNumbers: list = [7, 10, 15]
def __init__(self, *args):
super(BoxSelectionSubsamplingMethod, self).__init__(*args)
self.filterDiameter: float = 500
self.offset: tuple = (0, 0)
self.numBoxes: int = 1
self.maxFractions: dict = {}
@property
def label(self) -> str:
......@@ -22,6 +37,16 @@ class BoxSelectionSubsamplingMethod(SubsamplingMethod):
def filterArea(self) -> float:
return np.pi * (self.filterDiameter / 2) ** 2
@property
def boxSize(self) -> float:
totalBoxArea: float = self.filterArea * self.fraction
boxArea: float = totalBoxArea / self.numBoxes
return boxArea ** 0.5
@property
def noBoxOverlap(self) -> bool:
return not self._boxes_are_overlapping(self.get_topLeft_of_boxes())
def apply_subsampling_method(self) -> list:
def distanceToCnt(topleft: tuple):
return abs(topleft[0] - cntStart[0]) + abs(topleft[1] - cntStart[1])
......@@ -55,8 +80,48 @@ class BoxSelectionSubsamplingMethod(SubsamplingMethod):
newTopLefts.append((topLeft[0] + self.offset[0], topLeft[1] + self.offset[1]))
return newTopLefts
def equals(self, otherMethod) -> bool:
raise NotImplementedError
def _boxes_are_overlapping(self, topLefts: list) -> bool:
"""
Calculates if there is any overlap of the boxes
:return:
"""
overlaps: bool = False
boxSize = self.boxSize
for topLeft1, topLeft2 in combinations(topLefts, 2):
if box_overlaps_other_box(topLeft1, topLeft2, boxSize):
overlaps = True
break
return overlaps
def _get_max_distance_of_box_to_center(self, boxCenter: tuple, center: tuple = (0, 0)) -> float:
"""
Calculates the maximal distance of all point in a box to the given center
:param boxCenter:
:param center:
:return:
"""
center = np.array(center)
boxSize = self.boxSize
coords: np.ndarray = np.array([[boxCenter[0] - 0.5 * boxSize, boxCenter[1] - 0.5 * boxSize],
[boxCenter[0] + 0.5 * boxSize, boxCenter[1] - 0.5 * boxSize],
[boxCenter[0] - 0.5 * boxSize, boxCenter[1] + 0.5 * boxSize],
[boxCenter[0] + 0.5 * boxSize, boxCenter[1] + 0.5 * boxSize]])
distances: np.ndarray = np.linalg.norm(coords - center, axis=1)
return np.max(distances)
def get_maximum_achievable_fraction(self) -> float:
if len(self.maxFractions) == 0:
self.update_max_fractions()
if self.numBoxes not in self.maxFractions.keys():
self.maxFractions[self.numBoxes] = determine_max_achievable_frac(self, self.numBoxes)
return self.maxFractions[self.numBoxes]
def update_max_fractions(self) -> None:
for boxNum in self.possibleBoxNumbers:
self.maxFractions[boxNum] = determine_max_achievable_frac(self, boxNum)
class BoxSelectionCreator(object):
......@@ -82,8 +147,7 @@ class BoxSelectionCreator(object):
newBoxSelector.offset = offset
newBoxSelector.numBoxesAcross = numBoxesAcross
maxFraction: float = newBoxSelector.get_maximum_achievable_fraction()
if desiredFraction <= maxFraction:
if newBoxSelector.config_is_valid():
crossBoxSubsamplers.append(newBoxSelector)
return crossBoxSubsamplers
......@@ -106,11 +170,24 @@ class BoxSelectionCreator(object):
newBoxSelector.offset = offset
newBoxSelector.numBoxes = numBoxes
if newBoxSelector.noBoxOverlap:
if newBoxSelector.config_is_valid():
spiralBoxSubsamplers.append(newBoxSelector)
return spiralBoxSubsamplers
def get_randomBoxSubsamplers_for_fraction(self, desiredFraction: float) -> list:
randomBoxSamplers: list = []
randomBoxSampler: RandomBoxSampling = RandomBoxSampling(None, desiredFraction)
randomBoxSampler.update_max_fractions()
for numBoxes in randomBoxSampler.possibleBoxNumbers:
randomBoxSampler.numBoxes = numBoxes
if randomBoxSampler.config_is_valid():
newSampler: RandomBoxSampling = deepcopy(randomBoxSampler)
newSampler.particleContainer = self.dataset.particleContainer
randomBoxSamplers.append(newSampler)
return randomBoxSamplers
class CrossBoxSubSampling(BoxSelectionSubsamplingMethod):
def __init__(self, particleContainer, desiredFraction: float = 0.1) -> None:
......@@ -199,8 +276,6 @@ class CrossBoxSubSampling(BoxSelectionSubsamplingMethod):
class SpiralBoxSubsampling(BoxSelectionSubsamplingMethod):
possibleBoxNumbers: list = [7, 10, 15]
def __init__(self, particleContainer, desiredFraction: float = 0.1) -> None:
super(SpiralBoxSubsampling, self).__init__(particleContainer, desiredFraction)
self.numBoxes = 10
......@@ -209,16 +284,6 @@ class SpiralBoxSubsampling(BoxSelectionSubsamplingMethod):
def label(self) -> str:
return f'Boxes SpiralLayout ({self.numBoxes} boxes)'
@property
def noBoxOverlap(self) -> bool:
return not self._boxes_are_overlapping(self.get_topLeft_of_boxes())
@property
def boxSize(self) -> float:
totalBoxArea: float = self.filterArea * self.fraction
boxArea: float = totalBoxArea / self.numBoxes
return boxArea ** 0.5
@property
def spiralSlope(self) -> float:
return self.armDistance / (2 * np.pi)
......@@ -243,8 +308,8 @@ class SpiralBoxSubsampling(BoxSelectionSubsamplingMethod):
topLefts.append(newPoint)
theta += boxDistance / (slope * np.sqrt(1 + theta ** 2))
boxDistance *= 1.05
topLefts = self._move_and_scale_toplefts(topLefts)
if len(topLefts) > 1:
topLefts = self._move_and_scale_toplefts(topLefts)
return self._apply_offset_to_toplefts(topLefts)
def equals(self, otherMethod) -> bool:
......@@ -268,7 +333,7 @@ class SpiralBoxSubsampling(BoxSelectionSubsamplingMethod):
lastBoxCenter: tuple = (xCoordsBoxMiddles[-1], yCoordsBoxMiddles[-1])
distanceLastCenter: float = np.linalg.norm(lastBoxCenter)
maxDistanceInLastBox: float = self._get_max_distance_of_boxCenter_to_center(lastBoxCenter)
maxDistanceInLastBox: float = self._get_max_distance_of_box_to_center(lastBoxCenter)
halfBoxDistance: float = maxDistanceInLastBox - distanceLastCenter
desiredDistanceTotal: float = self.filterDiameter / 2
desiredDistanceCenter: float = desiredDistanceTotal - halfBoxDistance
......@@ -283,37 +348,102 @@ class SpiralBoxSubsampling(BoxSelectionSubsamplingMethod):
newTopLefts = zip(np.round(xCoords), np.round(yCoords))
return list(tuple(newTopLefts))
def _get_max_distance_of_boxCenter_to_center(self, boxCenter: tuple, center: tuple = (0, 0)) -> float:
"""
Calculates the maximal distance of a box to the given center
:param topLeft:
:param boxSize:
:return:
"""
center = np.array(center)
boxSize = self.boxSize
coords: np.ndarray = np.array([[boxCenter[0] - 0.5 * boxSize, boxCenter[1] - 0.5 * boxSize],
[boxCenter[0] + 0.5 * boxSize, boxCenter[1] - 0.5 * boxSize],
[boxCenter[0] - 0.5 * boxSize, boxCenter[1] + 0.5 * boxSize],
[boxCenter[0] + 0.5 * boxSize, boxCenter[1] + 0.5 * boxSize]])
distances: np.ndarray = np.linalg.norm(coords - center, axis=1)
return np.max(distances)
def _get_xy_at_angle(self, theta: float, centerXY: tuple = (0, 0)) -> tuple:
distance: float = self.spiralSlope * theta
return distance * np.cos(theta) + centerXY[0], distance * np.sin(theta) + centerXY[1]
def _boxes_are_overlapping(self, topLefts: list) -> bool:
"""
Calculates if there is any overlap of the boxes
:return:
"""
overlaps: bool = False
for topLeft1, topLeft2 in combinations(topLefts, 2):
if abs(topLeft1[0] - topLeft2[0]) < self.boxSize and abs(topLeft1[1] - topLeft2[1]) < self.boxSize:
overlaps = True
break
class RandomBoxSampling(BoxSelectionSubsamplingMethod):
def __init__(self, particleContainer, desiredFraction=0.1, maxAngle=2*np.pi):
super(RandomBoxSampling, self).__init__(particleContainer, desiredFraction)
self.numBoxes: int = 10
self.maxTries: int = 50
self.__maxAngle: float = maxAngle
return overlaps
@property
def label(self) -> str:
return f'Boxes random layout ({self.numBoxes} boxes)'
def get_topLeft_of_boxes(self) -> list:
def get_random_topleft() -> list:
angle = np.random.rand() * self.__maxAngle
dist = np.random.rand() * maxDist
x: float = dist * np.cos(angle) + radius - boxSize/2
y: float = dist * np.sin(angle) + radius - boxSize/2
return [x, y]
np.random.seed(self.randomSeed)
topLefts: list = []
boxSize: float = self.boxSize
radius: float = self.filterDiameter/2
maxDist: float = radius - np.sqrt((boxSize/2)**2 + (boxSize/2)**2)
outerCounter: int = 0
validSolutionFound: bool = False
while not validSolutionFound and outerCounter < self.maxTries:
topLefts = []
for i in range(self.numBoxes):
if i == 0:
topLefts.append(get_random_topleft())
else:
counter: int = 0
while counter < 50:
newTopLeft: list = get_random_topleft()
overlaps: list = [box_overlaps_other_box(newTopLeft, topLeft2, boxSize) for topLeft2 in topLefts]
if not True in overlaps:
topLefts.append(newTopLeft)
break
counter += 1
if len(topLefts) == self.numBoxes:
validSolutionFound = True
else:
outerCounter += 1
if not validSolutionFound:
raise AttributeError
return topLefts
class RandomQuarterBoxes(RandomBoxSampling):
def __init__(self, particleContainer, desiredFraction=0.1, maxAngle=0.5*np.pi):
super(RandomQuarterBoxes, self).__init__(particleContainer, desiredFraction, maxAngle)
@property
def label(self) -> str:
return f'Boxes random layout (quarter) ({self.numBoxes} boxes)'
def determine_max_achievable_frac(method: BoxSelectionSubsamplingMethod, numBoxes: int) -> float:
"""
Takes a boxsampling method and iteratively increases the covered fraction for the given number of boxes.
If boxes start to overlap, the last valid fraction is returned
:param method:
:param numBoxes:
:return:
"""
assert type(method) != CrossBoxSubSampling # setting of numBoxes is not possible in that case..
origFrac: float = method.fraction
origBoxNum: int = method.numBoxes
method.numBoxes = numBoxes
frac: float = 0.0
lastvalidFrac: float = 0.0
for frac in np.linspace(0.05, 0.6, 50):
method.fraction = frac
valid: bool = False
try:
valid = method.noBoxOverlap
except AttributeError:
valid = False
if valid:
lastvalidFrac = frac
else:
break
method.fraction = origFrac
method.numBoxes = origBoxNum
return lastvalidFrac
......@@ -4,7 +4,7 @@ sys.path.append("C://Users//xbrjos//Desktop//Python")
import gepard
from gepard import dataset
from gui.filterView import FilterView
from gui.measureModes import MeasureMode, CrossBoxMode, CrossBoxesControls, SpiralBoxMode
from gui.measureModes import *
import helpers
from evaluation import SubsamplingResult
......@@ -55,10 +55,17 @@ class MainView(QtWidgets.QWidget):
self._switch_to_default_mode()
def _add_measure_modes(self) -> None:
self.measureModes['spiralSelection'] = SpiralBoxMode(self.filterView)
self.measureModes['crossSelection'] = CrossBoxMode(self.filterView)
self.modeSelector.addItem('spiralSelection')
self.modeSelector.addItem('crossSelection')
self.measureModes['Random Particle Selection'] = RandomMeasureMode(self.filterView)
self.measureModes['Spiral Box Selection'] = SpiralBoxMode(self.filterView)
self.measureModes['Cross Box Selection'] = CrossBoxMode(self.filterView)
self.measureModes['Random Box Selection'] = RandomBoxMode(self.filterView)
self.measureModes['Quarter Random Box Selection'] = QuarterRandomBoxMode(self.filterView)
self.modeSelector.addItem('Random Particle Selection')
self.modeSelector.addItem('Spiral Box Selection')
self.modeSelector.addItem('Cross Box Selection')
self.modeSelector.addItem('Random Box Selection')
self.modeSelector.addItem('Quarter Random Box Selection')
for mode in self.measureModes.values():
mode.updatedResult.connect(self.infoWidget.update_results)
......@@ -101,8 +108,8 @@ class MainView(QtWidgets.QWidget):
self.filterView.filter.update_filterSize(width, height, diameter, (offsetx, offsety))
for mode in self.measureModes.values():
mode.boxSelectionMethod.particleContainer = dset.particleContainer
mode.boxSelectionMethod.offset = (offsetx, offsety)
mode.method.particleContainer = dset.particleContainer
mode.method.offset = (offsetx, offsety)
self.filterView.update_from_dataset(dset)
self.activeMode.update_measure_viewItems()
......
from PyQt5 import QtCore, QtWidgets
from gui.filterView import FilterView, MeasureBoxGraphItem
from geometricMethods import BoxSelectionSubsamplingMethod, CrossBoxSubSampling, SpiralBoxSubsampling
from methods import *
from geometricMethods import *
from evaluation import SubsamplingResult
class MeasureMode(QtCore.QObject):
updatedResult: QtCore.pyqtSignal = QtCore.pyqtSignal(SubsamplingResult)
def __init__(self, relatedFilterView: FilterView):
def __init__(self, relatedFilterView: FilterView) -> None:
super(MeasureMode, self).__init__()
self.filterView: FilterView = relatedFilterView
self.uiControls: QtWidgets.QGroupBox = QtWidgets.QGroupBox()
self.boxSelectionMethod: BoxSelectionSubsamplingMethod = None
self.subsamplingResult: SubsamplingResult = SubsamplingResult(self.boxSelectionMethod)
self.method: SubsamplingMethod = None
self.subsamplingResult: SubsamplingResult = SubsamplingResult(self.method)
self.subParticles: list = []
def get_control_groupBox(self) -> QtWidgets.QGroupBox:
return self.uiControls
def update_measure_viewItems(self) -> None:
raise NotImplementedError
self.method.filterDiameter = self.filterView.filter.diameter
self.method.numBoxes = self.uiControls.numBoxesSpinbox.value()
self.method.fraction = self.uiControls.coverageSpinbox.value() / 100
topLefts: list = self.method.get_topLeft_of_boxes()
boxSize = self.method.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize)
self.send_measuredParticles_to_filterview()
def send_measuredParticles_to_filterview(self) -> None:
if self.boxSelectionMethod.particleContainer is not None:
subParticles = self.boxSelectionMethod.apply_subsampling_method()
self.subsamplingResult.method = self.boxSelectionMethod
if self.method.particleContainer is not None:
subParticles = self.method.apply_subsampling_method()
self.subsamplingResult.method = self.method
self.subsamplingResult.reset_results()
self.subsamplingResult.add_result(self.boxSelectionMethod.particleContainer.particles, subParticles)
self.subsamplingResult.add_result(self.method.particleContainer.particles, subParticles)
self.updatedResult.emit(self.subsamplingResult)
self.filterView.update_measured_particles(subParticles)
class RandomMeasureMode(MeasureMode):
updatedResult: QtCore.pyqtSignal = QtCore.pyqtSignal(SubsamplingResult)
def __init__(self, filterView: FilterView):
super(RandomMeasureMode, self).__init__(filterView)
self.method: RandomSampling = RandomSampling(None)
self.uiControls = ParticleModeControlGroup(self, 'Random Particle Measurement')
def update_measure_viewItems(self) -> None:
self.method.fraction = self.uiControls.coverageSpinbox.value() / 100
self.filterView.update_measure_boxes([], 0.0)
self.send_measuredParticles_to_filterview()
class ParticleModeControlGroup(QtWidgets.QGroupBox):
def __init__(self, measureModeParent: MeasureMode, title: str) -> None:
super(ParticleModeControlGroup, self).__init__()
self.measureModeParent = measureModeParent
self.setTitle(title)
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
layout.addWidget(QtWidgets.QLabel('Desired Coverage (%)'))
self.coverageSpinbox = QtWidgets.QSpinBox()
self.coverageSpinbox.setFixedWidth(50)
self.coverageSpinbox.setMinimum(0)
self.coverageSpinbox.setMaximum(100)
self.coverageSpinbox.setValue(10)
self.coverageSpinbox.valueChanged.connect(self._config_changed)
layout.addWidget(self.coverageSpinbox)
def _config_changed(self) -> None:
self.measureModeParent.update_measure_viewItems()
class CrossBoxMode(MeasureMode):
def __init__(self, *args):
super(CrossBoxMode, self).__init__(*args)
self.uiControls = CrossBoxesControls(self)
self.boxSelectionMethod: CrossBoxSubSampling = CrossBoxSubSampling(None)
self.method: CrossBoxSubSampling = CrossBoxSubSampling(None)
self.update_measure_viewItems()
def update_measure_viewItems(self) -> None:
self.boxSelectionMethod.filterDiameter = self.filterView.filter.diameter
self.boxSelectionMethod.numBoxesAcross = int(self.uiControls.numBoxesSelector.currentText())
self.method.filterDiameter = self.filterView.filter.diameter
self.method.numBoxesAcross = int(self.uiControls.numBoxesSelector.currentText())
desiredCoverage: int = self.uiControls.coverageSpinbox.value()
maxCoverage: int = int(self.boxSelectionMethod.get_maximum_achievable_fraction() * 100)
maxCoverage: int = int(self.method.get_maximum_achievable_fraction() * 100)
self.uiControls.set_to_max_possible_coverage(maxCoverage)
if desiredCoverage > maxCoverage:
desiredCoverage = maxCoverage
self.boxSelectionMethod.fraction = desiredCoverage / 100
self.method.fraction = desiredCoverage / 100
topLefts: list = self.boxSelectionMethod.get_topLeft_of_boxes()
boxSize = self.boxSelectionMethod.boxSize
topLefts: list = self.method.get_topLeft_of_boxes()
boxSize = self.method.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize)
self.send_measuredParticles_to_filterview()
......@@ -96,33 +141,14 @@ class CrossBoxesControls(QtWidgets.QGroupBox):
self.coverageSpinbox.valueChanged.connect(self._config_changed)
class SpiralBoxMode(MeasureMode):
def __init__(self, *args):
super(SpiralBoxMode, self).__init__(*args)
self.uiControls: SpiralBoxControls = SpiralBoxControls(self)
self.boxSelectionMethod: SpiralBoxSubsampling = SpiralBoxSubsampling(None)
self.update_measure_viewItems()
def update_measure_viewItems(self) -> None:
self.boxSelectionMethod.filterDiameter = self.filterView.filter.diameter
self.boxSelectionMethod.numBoxes = self.uiControls.numBoxesSpinbox.value()
self.boxSelectionMethod.fraction = self.uiControls.coverageSpinbox.value() / 100
topLefts: list = self.boxSelectionMethod.get_topLeft_of_boxes()
boxSize = self.boxSelectionMethod.boxSize
self.filterView.update_measure_boxes(topLefts, boxSize)
self.send_measuredParticles_to_filterview()
class SpiralBoxControls(QtWidgets.QGroupBox):
class BoxControlGroup(QtWidgets.QGroupBox):
"""
Gives a groupbox with the controls for setting up the cross boxes.
"""
def __init__(self, measureModeParent: MeasureMode):
super(SpiralBoxControls, self).__init__()
self.setTitle('Spiral Box Controls')
def __init__(self, measureModeParent: MeasureMode, title: str) -> None:
super(BoxControlGroup, self).__init__()
self.setTitle(title)
self.measureModeParent = measureModeParent
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
......@@ -144,6 +170,46 @@ class SpiralBoxControls(QtWidgets.QGroupBox):
self.coverageSpinbox.valueChanged.connect(self._config_changed)
layout.addWidget(self.coverageSpinbox)
def _config_changed(self):
def _config_changed(self) -> None:
if self.numBoxesSpinbox.value() > 0:
numBoxes: int = self.numBoxesSpinbox.value()
self.measureModeParent.method.numBoxes = numBoxes
maxCoverage: float = self.measureModeParent.method.get_maximum_achievable_fraction()
self.set_to_max_possible_coverage(round(maxCoverage * 100))
self.measureModeParent.update_measure_viewItems()
def set_to_max_possible_coverage(self, maxCoverage: int) -> None:
"""
Adjusts maximum of coverage spinbox and, if necessary, caps the current value.
:param maxCoverage: the maximum pssible converage IN PERCENT!!
:return:
"""
self.coverageSpinbox.setMaximum(maxCoverage)
if maxCoverage < self.coverageSpinbox.value():
self.coverageSpinbox.valueChanged.disconnect()
self.coverageSpinbox.setValue(maxCoverage)
self.coverageSpinbox.valueChanged.connect(self._config_changed)
class SpiralBoxMode(MeasureMode):
def __init__(self, *args):
super(SpiralBoxMode, self).__init__(*args)
self.uiControls: BoxControlGroup = BoxControlGroup(self, 'Spiral Box Controls')
self.method: SpiralBoxSubsampling = SpiralBoxSubsampling(None)
self.update_measure_viewItems()
class RandomBoxMode(MeasureMode):
def __init__(self, *args):
super(RandomBoxMode, self).__init__(*args)
self.uiControls: BoxControlGroup = BoxControlGroup(self, 'Random Box Controls')
self.method: RandomBoxSampling = RandomBoxSampling(None)
self.update_measure_viewItems()
class QuarterRandomBoxMode(MeasureMode):
def __init__(self, *args):
super(QuarterRandomBoxMode, self).__init__(*args)
self.uiControls: BoxControlGroup = BoxControlGroup(self, 'Quarter Random Box Controls')
self.method: RandomQuarterBoxes = RandomQuarterBoxes(None)
self.update_measure_viewItems()
......@@ -11,6 +11,8 @@ from helpers import ParticleBinSorter
class SubsamplingMethod(object):
randomSeed = 15203018
def __init__(self, particleConatainer, desiredFraction: float = 0.2):
super(SubsamplingMethod, self).__init__()
self.particleContainer = particleConatainer
......@@ -65,6 +67,14 @@ class SubsamplingMethod(object):
matches = (self.label.lower().find(pattern.lower()) != -1)
return matches
def config_is_valid(self) -> bool:
isValid: bool = False
if self.fraction <= self.get_maximum_achievable_fraction():
isValid = True
return isValid
def get_maximum_achievable_fraction(self) -> float:
raise NotImplementedError
class RandomSampling(SubsamplingMethod):
@property
......@@ -82,6 +92,9 @@ class RandomSampling(SubsamplingMethod):
def equals(self, otherMethod) -> bool:
return type(otherMethod) == type(self) and otherMethod.fraction == self.fraction
def get_maximum_achievable_fraction(self) -> float:
return 1.0
class SizeBinFractioning(SubsamplingMethod):
......@@ -117,3 +130,6 @@ class SizeBinFractioning(SubsamplingMethod):
def equals(self, otherMethod) -> bool:
return type(otherMethod) == type(self) and otherMethod.fraction == self.fraction
def get_maximum_achievable_fraction(self) -> float:
return 1.0
\ No newline at end of file
......@@ -28,3 +28,4 @@ def get_default_ParticleContainer() -> ParticleContainer:
contours.append(np.array([[[x, 0]], [[x+10, 0]], [[x+10, 10]], [[x, 10]]], dtype=np.int32))
particleContainer.setParticleContours(contours)
return particleContainer
......@@ -258,14 +258,18 @@ class TestSampleResult(unittest.TestCase):
possibleRandomMethods = 2
possibleCrossBoxMethods = 2
possibleSpiralBoxMethods = 3
possibleRandomBoxMethods = 3
possibleChemometricMethods = 0
totalPossible = possibleCrossBoxMethods + possibleRandomMethods + \
possibleSpiralBoxMethods + possibleChemometricMethods
possibleSpiralBoxMethods + possibleChemometricMethods + \
possibleRandomBoxMethods
self.assertEqual(len(methods), totalPossible)
self.assertTrue(containsMethod(methods, meth.RandomSampling(dset, desiredFraction)))
self.assertTrue(containsMethod(methods, meth.SizeBinFractioning(dset, desiredFraction)))
self.assertTrue(containsMethod(methods, gmeth.CrossBoxSubSampling(dset, desiredFraction)))
self.assertTrue(containsMethod(methods, gmeth.SpiralBoxSubsampling(dset, desiredFraction)))