def test_debug(self): """ Test the debugging output of the MSC """ self.setup() test_file = "msc_test_debug.txt" sys.stdout = open(test_file, "w") self.test_object = topopy.MorseSmaleComplex(debug=True, graph=self.graph) self.test_object.build(self.X, self.Y) sys.stdout.close() lines = [ "Graph Preparation:", "Decomposition:", "Stable Decomposition:", "Unstable Decomposition:", ] with open(test_file, "r") as fp: debug_output = fp.read() for line in lines: self.assertIn(line, debug_output) os.remove(test_file) # Restore stdout sys.stdout = sys.__stdout__
def test_unstructured(self): """ Tests functionality on something other than a regular grid """ self.X = np.array([[0, 0], [1, 1], [1, 0], [0, 1], [0.25, 0.25], [0.25, 0.75], [0.75, 0.75], [0.75, 0.25], [0.0, 0.6], [0.0, 0.25], [0.0, 0.75], [0.25, 0.0], [0.6, 0.0], [0.6, 0.25], [0.625, 0.55], [0.6, 0.75], [0.75, 0.0], [0.25, 0.55], [1, 0.25], [0.65, 1], [1, 0.55], [1, 0.75], [0.75, 1], [0.25, 1], [0.75, 0.6]]) self.Y = gerber(self.X) self.test_object = topopy.MorseSmaleComplex( gradient="steepest", normalization=None, simplification="difference", aggregator=None, debug=False, ) self.test_object.build(self.X, self.Y) self.assertEqual( 13, len(self.test_object.get_merge_sequence()), "The merge sequence does not match the expected output.", )
def setup(self): """ Setup function will create a fixed point set and parameter settings for testing different aspects of this library. """ self.X = generate_test_grid_2d(40) self.Y = gerber(self.X) self.graph = ngl.EmptyRegionGraph(max_neighbors=10) self.norm_x = {} scaler = sklearn.preprocessing.MinMaxScaler() self.norm_x["feature"] = scaler.fit_transform(np.atleast_2d(self.X)) self.norm_x["zscore"] = sklearn.preprocessing.scale(self.X, axis=0, with_mean=True, with_std=True, copy=True) self.norm_x["none"] = self.X # Methods covered here: # __init__ # build # __set_data self.test_object = topopy.MorseSmaleComplex(debug=False, graph=self.graph) self.test_object.build(self.X, self.Y) gold_path = os.path.join("topopy", "tests", "msc_gold.json") with open(gold_path, "r") as data_file: gold_json = data_file.read() gold_json = json.loads(gold_json) self.gold = gold_json
def test_load_data_and_build(self): """ Tests that loading the same test data from file yields an equivalent result """ self.setup() local_object = topopy.MorseSmaleComplex() np.savetxt( "test_file.csv", np.hstack((self.X, np.atleast_2d(self.Y).T)), delimiter=",", header="x0,x1,y", ) local_object.load_data_and_build("test_file.csv", delimiter=",") os.remove("test_file.csv") self.assertDictEqual( self.test_object.merge_sequence, local_object.merge_sequence, "loading from file should produce the same hierarchy", ) self.assertSetEqual( set(self.test_object.base_partitions.keys()), set(local_object.base_partitions.keys()), "loading from file should produce the base partitions.", ) for key in self.test_object.base_partitions.keys(): self.assertListEqual( self.test_object.base_partitions[key].tolist(), local_object.base_partitions[key].tolist(), "loading from file should produce the base partitions.", )
def color_msc(X, Y, p): msc = topopy.MorseSmaleComplex(max_neighbors=8, graph="beta skeleton") msc.build(X, Y) partitions = msc.get_partitions(p) unique_keys = partitions.keys() encoded_keys = {} next_value = 0 for key in unique_keys: encoded_keys[key] = next_value next_value = (next_value + 1) % unique_colors C = np.zeros(len(X)) for key, items in partitions.items(): C[list(items)] = encoded_keys[key] return C
def test_get_partitions(self): self.setup() gold_msc_partitions = {} gold_stable_partitions = {} gold_unstable_partitions = {} for i, (min_label, max_label) in enumerate(self.gold["Partitions"]): if max_label not in gold_stable_partitions: gold_stable_partitions[max_label] = [] gold_stable_partitions[max_label].append(i) if min_label not in gold_unstable_partitions: gold_unstable_partitions[min_label] = [] gold_unstable_partitions[min_label].append(i) if (min_label, max_label) not in gold_msc_partitions: gold_msc_partitions[(min_label, max_label)] = [] gold_msc_partitions[(min_label, max_label)].append(i) partitions = self.test_object.get_partitions() self.assertEqual( 16, len(partitions), "The number of partitions " "without specifying the " "persistence should be the " "same as requesting the base " "(0) persistence level", ) self.assertDictEqual( gold_msc_partitions, partitions, "The base partitions of the Morse-Smale complex should match", ) partitions = self.test_object.get_stable_manifolds() self.assertEqual( 4, len(partitions), "The number of stable manifolds should be 4 at the base level", ) self.assertDictEqual( gold_stable_partitions, partitions, "The base partitions of the stable manifolds should match", ) partitions = self.test_object.get_unstable_manifolds() self.assertEqual( 9, len(partitions), "The number of unstable manifolds should be 9 at the base level", ) self.assertDictEqual( gold_unstable_partitions, partitions, "The base partitions of the unstable manifolds should match", ) test_p = 0.5 merge_pattern = {} # Initialize every extrema to point to itself for merge in self.gold["Hierarchy"]: merge_pattern[merge["Dying"]] = merge["Dying"] # Now point to the correct label for the specified persistence for merge in self.gold["Hierarchy"]: if merge["Persistence"] < test_p: if merge["Surviving"] not in merge_pattern: merge_pattern[merge["Surviving"]] = merge["Surviving"] merge_pattern[merge["Dying"]] = merge_pattern[ merge["Surviving"]] gold_msc_partitions = {} gold_stable_partitions = {} gold_unstable_partitions = {} for i, (min_label, max_label) in enumerate(self.gold["Partitions"]): min_label = merge_pattern[min_label] max_label = merge_pattern[max_label] if max_label not in gold_stable_partitions: gold_stable_partitions[max_label] = [] gold_stable_partitions[max_label].append(i) if min_label not in gold_unstable_partitions: gold_unstable_partitions[min_label] = [] gold_unstable_partitions[min_label].append(i) if (min_label, max_label) not in gold_msc_partitions: gold_msc_partitions[(min_label, max_label)] = [] gold_msc_partitions[(min_label, max_label)].append(i) partitions = self.test_object.get_partitions(test_p) self.assertEqual( 4, len(partitions), "The number of partitions at the 0.5 level should be 4", ) self.assertDictEqual( gold_msc_partitions, partitions, "The partitions of the Morse-Samle complex should match at " "the test level p={}".format(test_p), ) partitions = self.test_object.get_stable_manifolds(test_p) self.assertEqual( 1, len(partitions), "The number of stable manifolds should be 1 at the test " "level p={}".format(test_p), ) self.assertDictEqual( gold_stable_partitions, partitions, "The base partitions of the stable manifolds should match " "at the test level p={}".format(test_p), ) partitions = self.test_object.get_unstable_manifolds(0.5) self.assertEqual( 4, len(partitions), "The number of unstable manifolds should be 9 at the test " "level p={}".format(test_p), ) self.assertDictEqual( gold_unstable_partitions, partitions, "The base partitions of the unstable manifolds should " "match at the test level p={}".format(test_p), ) self.test_object = topopy.MorseSmaleComplex() partitions = self.test_object.get_partitions() self.assertEqual( {}, partitions, "Requesting partitions on an unbuilt object should return " "an empty dict", )
mag = np.linalg.norm(grad_x) if mag < stopping_crieterion: return np.array([0, 0]).flatten() return grad_x / mag * step_size x, y = np.mgrid[min_x:max_x:(resolution * 1j), min_x:max_x:(resolution * 1j)] X = np.vstack([x.ravel(), y.ravel()]).T Z = np.empty(X.shape[0]) for i, xi in enumerate(X): Z[i] = test_function(xi) z = Z.reshape(x.shape) start = time.time() msc = topopy.MorseSmaleComplex(max_neighbors=8, graph="beta skeleton") msc.build(X, Z) msc.set_persistence(p) end = time.time() print("Build MSC: {} s".format(end - start)) start = time.time() mins = [] maxs = [] saddles = [] saddle_ptrs = {} for key in msc.get_partitions().keys(): mins.append(key[0]) maxs.append(key[1]) json_object = json.loads(msc.to_json())