Index: /framspy/FramsticksLib.py
===================================================================
--- /framspy/FramsticksLib.py	(revision 1176)
+++ /framspy/FramsticksLib.py	(revision 1177)
@@ -57,5 +57,5 @@
 		print('OK.')
 		if not self.DETERMINISTIC:
-			frams.Math.randomize();
+			frams.Math.randomize()
 		frams.Simulator.expdef = "standard-eval"  # this expdef (or fully compatible) must be used by EVALUATION_SETTINGS_FILE
 		if sim_settings_files is not None:
@@ -78,5 +78,5 @@
 			partially empty and may not have the fields you expected, so handle such cases properly.
 		"""
-		assert isinstance(genotype_list, list)  # because in python str has similar capabilities as list and here it would pretend to work too, so to avoid any ambiguity
+		assert isinstance(genotype_list, list)  # because in python, str has similar capabilities as list and here it would pretend to work too, so to avoid any ambiguity
 
 		if not self.PRINT_FRAMSTICKS_OUTPUT:
@@ -107,5 +107,5 @@
 		for g in frams.GenePools[0]:
 			serialized_dict = frams.String.serialize(g.data[frams.ExpProperties.evalsavedata._value()])
-			evaluations = json.loads(serialized_dict._string()) # Framsticks native ExtValue's get converted to native python types such as int, float, list, str.
+			evaluations = json.loads(serialized_dict._string())  # Framsticks native ExtValue's get converted to native python types such as int, float, list, str.
 			# now, for consistency with FramsticksCLI.py, add "num" and "name" keys that are missing because we got data directly from Genotype, not from the file produced by standard-eval.expdef's function printStats(). What we do below is what printStats() does.
 			result = {"num": g.num._value(), "name": g.name._value(), "evaluations": evaluations}
@@ -120,5 +120,5 @@
 			The genotype(s) of the mutated source genotype(s). self.GENOTYPE_INVALID for genotypes whose mutation failed (for example because the source genotype was invalid).
 		"""
-		assert isinstance(genotype_list, list)  # because in python str has similar capabilities as list and here it would pretend to work too, so to avoid any ambiguity
+		assert isinstance(genotype_list, list)  # because in python, str has similar capabilities as list and here it would pretend to work too, so to avoid any ambiguity
 
 		mutated = []
@@ -137,13 +137,12 @@
 
 
-	def dissimilarity(self, genotype_list: List[str]) -> np.ndarray:
-		"""
-		Returns:
-			A square array with dissimilarities of each pair of genotypes.
-		"""
-		assert isinstance(genotype_list, list)  # because in python str has similar capabilities as list and here it would pretend to work too, so to avoid any ambiguity
+	def dissimilarity(self, genotype_list: List[str], method: int) -> np.ndarray:
+		"""
+			:param method: -1 = genetic Levenshtein distance; 0, 1, 2 = phenetic dissimilarity (SimilMeasureGreedy, SimilMeasureHungarian, SimilMeasureDistribution)
+			:return: A square array with dissimilarities of each pair of genotypes.
+		"""
+		assert isinstance(genotype_list, list)  # because in python, str has similar capabilities as list and here it would pretend to work too, so to avoid any ambiguity
 
 		# if you want to override what EVALUATION_SETTINGS_FILE sets, you can do it below:
-		# frams.SimilMeasure.simil_type = 1
 		# frams.SimilMeasureHungarian.simil_partgeom = 1
 		# frams.SimilMeasureHungarian.simil_weightedMDS = 1
@@ -151,11 +150,21 @@
 		n = len(genotype_list)
 		square_matrix = np.zeros((n, n))
-		genos = []  # prepare an array of Geno objects so that we don't need to convert raw strings to Geno objects all the time in loops
-		for g in genotype_list:
-			genos.append(frams.Geno.newFromString(g))
-		frams_evaluateDistance = frams.SimilMeasure.evaluateDistance  # cache function reference for better performance in loops
-		for i in range(n):
-			for j in range(n):  # maybe calculate only one triangle if you really need a 2x speedup
-				square_matrix[i][j] = frams_evaluateDistance(genos[i], genos[j])._double()
+
+		if method in (0, 1, 2):  # Framsticks phenetic dissimilarity methods
+			frams.SimilMeasure.simil_type = method
+			genos = []  # prepare an array of Geno objects so that we don't need to convert raw strings to Geno objects all the time in loops
+			for g in genotype_list:
+				genos.append(frams.Geno.newFromString(g))
+			frams_evaluateDistance = frams.SimilMeasure.evaluateDistance  # cache function reference for better performance in loops
+			for i in range(n):
+				for j in range(n):  # maybe calculate only one triangle if you really need a 2x speedup
+					square_matrix[i][j] = frams_evaluateDistance(genos[i], genos[j])._double()
+		elif method == -1:
+			import Levenshtein
+			for i in range(n):
+				for j in range(n):  # maybe calculate only one triangle if you really need a 2x speedup
+					square_matrix[i][j] = Levenshtein.distance(genotype_list[i], genotype_list[j])
+		else:
+			raise Exception("Don't know what to do with dissimilarity method = %d" % method)
 
 		for i in range(n):
@@ -165,7 +174,7 @@
 		if non_symmetric_count > 0:
 			non_symmetric_diff_abs = np.abs(non_symmetric_diff)
-			max_pos1d = np.argmax(non_symmetric_diff_abs)  # location of largest discrepancy
-			max_pos2d_XY = np.unravel_index(max_pos1d, non_symmetric_diff_abs.shape)  # 2D coordinates of largest discrepancy
-			max_pos2d_YX = max_pos2d_XY[1], max_pos2d_XY[0]  # 2D coordinates of largest discrepancy mirror
+			max_pos1d = np.argmax(non_symmetric_diff_abs)  # location of the largest discrepancy
+			max_pos2d_XY = np.unravel_index(max_pos1d, non_symmetric_diff_abs.shape)  # 2D coordinates of the largest discrepancy
+			max_pos2d_YX = max_pos2d_XY[1], max_pos2d_XY[0]  # 2D coordinates of the largest discrepancy mirror
 			worst_guy_XY = square_matrix[max_pos2d_XY]  # this distance and the other below (its mirror) are most different
 			worst_guy_YX = square_matrix[max_pos2d_YX]
@@ -179,5 +188,5 @@
 
 	def isValid(self, genotype_list: List[str]) -> List[bool]:
-		assert isinstance(genotype_list, list)  # because in python str has similar capabilities as list and here it would pretend to work too, so to avoid any ambiguity
+		assert isinstance(genotype_list, list)  # because in python, str has similar capabilities as list and here it would pretend to work too, so to avoid any ambiguity
 		valid = []
 		for g in genotype_list:
@@ -226,5 +235,5 @@
 	offspring = framsLib.crossOver(parent1, parent2)
 	print("\tCrossover (Offspring):", offspring)
-	print('\tDissimilarity of Parent1 and Offspring:', framsLib.dissimilarity([parent1, offspring])[0, 1])
+	print('\tDissimilarity of Parent1 and Offspring:', framsLib.dissimilarity([parent1, offspring], 1)[0, 1])
 	print('\tPerformance of Offspring:', framsLib.evaluate([offspring]))
 	print('\tValidity of Parent1, Parent 2, and Offspring:', framsLib.isValid([parent1, parent2, offspring]))
