def __init__(self, fname, outfile, n_results): self.con = Constraint(fname) self.num_x = self.con.n_dim self.n_results = n_results self.outfile = outfile with open(self.outfile, 'w') as f: f.write(" ".join(map(str, self.con.example))) f.write("\n") self.ineq_cons = { 'type': 'ineq', 'fun': lambda x: self.con.eval_con(x.tolist()) } bound = [0.0, 1.0] self.bounds = np.asarray([bound] * self.num_x) # determining the magnitude of the largest initial point max_initial = max(self.con.example) if max_initial == 0.0: self.alpha = 1.0 else: self.alpha = 1.0 / max_initial
class Optimizer(): def __init__(self, input_file, N): self.input_constraints = Constraint(input_file) #print(self.input_constraints.get_ndim()) #print(self.input_constraints.get_example()) #print(self.input_constraints.get_constraints()) #exam = np.array(list(self.input_constraints.get_example()), dtype=float) #print(self.input_constraints.apply(exam)) self.x = self.sample(N) self.get_output() def sample(self, N): count = 0 ndim = int(self.input_constraints.get_ndim()) x = np.empty((0, ndim)) while (count < int(N)): n_samples = int(N) * 10 smpls = lhs(ndim, samples=n_samples) for i in range(len(smpls)): if self.input_constraints.apply(smpls[i]) and (count < int(N)): #print(smpls[i]) x = np.append(x, np.array([smpls[i]]), axis=0) count += 1 print(count) print(x.shape) return x def get_output(self): return self.x
def __init__(self, input_file, N): self.input_constraints = Constraint(input_file) #print(self.input_constraints.get_ndim()) #print(self.input_constraints.get_example()) #print(self.input_constraints.get_constraints()) #exam = np.array(list(self.input_constraints.get_example()), dtype=float) #print(self.input_constraints.apply(exam)) self.x = self.sample(N) self.get_output()
def cal_pop_fitness(self): # Calculating the fitness value of each solution in the current population. # The fitness function calculates fitness by adding the no of constraints that # the population passes. fitness = [] fname = self.get_filename() c = Constraint(fname) for p in self.pop: f = c.count_passed_constrain(p) fitness.append(f) return fitness
def __init__(self, input_path, n_results, beta_max=10**4, p_beta=1, p_rw_step=0, track_correctness=False, threshold=.999): self.input_path = input_path self.constraints = Constraint(input_path) constraints_funcs = self.constraints.get_functions() self.n_dim = self.constraints.get_ndim() self.n_results = n_results self.beta_max = beta_max self.p_beta = p_beta self.p_rw_step = p_rw_step #call sampling method scmc i_sample = init_sample(self.n_dim, self.n_results, self.constraints.bounds, self.constraints.get_example()) self.i_samples = [] self.i_samples.append(i_sample) self.histories = [] self.correctnesses = [] print(len(constraints_funcs)) for i in range(1, len(constraints_funcs) + 1): history, correctness = scmc( self.n_dim, self.n_results, self.i_samples[i - 1], constraints_funcs[0:i], beta_max, self.constraints.bounds, p_beta, p_rw_step, track_correctness=track_correctness, given_example=self.constraints.get_example(), threshold=threshold) self.i_samples.append(history[-1]) self.histories.append(history) self.correctnesses.append(correctness) self.results = self.histories[-1][-1]
def main(argv): if len(sys.argv) < 3: print( 'Please provide 3 command line arguments (e.g. input_filename, output_filename, n_results' ) exit(-1) in_filename = '' out_filename = '' niteration = 0 in_filename = sys.argv[1] out_filename = sys.argv[2] niteration = int(sys.argv[3]) c = Constraint(in_filename) v = c.get_example() print(v) n = c.get_ndim() #this is the chromosome size for each population print(n) # print(c.apply([0.5, 1.0, 0.0, 0.5])) s = 300 #population size ga = Genetic( s, n, in_filename ) #initializes ga type object with populaton size, chromosome size, input file name p = ga.get_population() print(p) print(ga.cal_pop_fitness()) temp_solution = ga.eval_ga(niteration) # print(temp_solution) # write result to the output with open(out_filename, 'w') as filehandle: for item in temp_solution: s = " ".join(str(e) for e in item) # print(s) l = s # l = item print(l) filehandle.write('%s\n' % l) filehandle.close()
def __eq__(self, other): if type(other) == str and other == '__builtins__': return False r = self - other if r.dtype != object: return all(r) if r.size == 1: return asscalar(r) == 0 # TODO: rework it return ooarray( [Constraint(elem, lb=0.0, ub=0.0) for elem in r.tolist()])
def get_constraints(input_file): """reads the input file and creates an instance of the Constraint class """ # create a new instance of the Constraint class by reading input_file # catch several errors: file not found, first two lines (number of # dimensions and starting vector) not formatted correctly, or syntax # error in the constraints try: space = Constraint(input_file) except FileNotFoundError: sys.exit("Error: input file not found") except ValueError: sys.exit("Error: input file formatted improperly") except SyntaxError: sys.exit("Error: syntax error in constraints") # get the example point and make sure it has the correct dimensionality example = space.get_example() if len(example) < space.get_ndim(): sys.exit("Error: example point does not have enough dimensions") # check and make sure the example point actually satisfies all of the # constraints. This additionally serves to make sure the constraints # are specified correctly try: check_example = space.apply(example) except IndexError: sys.exit("Error: invalid constraints") except NameError: sys.exit("Error: invalid constraints") # if space.apply(example) returned false, then throw an error if not check_example: sys.exit("Error: example point is invalid") return space
def __init__(self, input_file_name): """ Construct a Generator object and set up the log files. :param string input_file_name: Name of the constraints file """ # Setup class logger setup_logger('log_generator.log') self.log = logging.getLogger('log_generator.log') # Set up the constraints self.input_file_name = input_file_name try: self.constraints = Constraint(self.input_file_name) except FileNotFoundError: self.log.critical( f'Constraints file not found: {self.input_file_name}') else: self.log.info(f'Setup Generator for {self.input_file_name}') # Set and queue to hold and explore the required points self.point_set = set() self.points_queue = deque()
class Sampler: def __init__(self, filename, max_points, max_time): self.constraint = Constraint(filename) self.n_dim = self.constraint.n_dim self.example = self.constraint.example self.max_points = max_points self.max_time = max_time def test_inside(self, x): if np.any(np.less(x, 0.)): return False if np.any(np.greater(x, 1.)): return False return self.constraint.apply(x) def line_search(self, x, direction): tiny = 1e-6 low, high = 0., np.sqrt(self.n_dim) + tiny for _ in range(20): middle = 0.5 * (low + high) inside = self.test_inside(x + middle * direction) if inside: low = middle else: high = middle return low def random_direction(self): vector = np.random.normal(size=self.n_dim) return vector / np.linalg.norm(vector) def hit_and_run(self): assert self.test_inside(self.example) points = [np.array(self.example)] start_time = time.time() while len(points) < self.max_points and time.time( ) - start_time < self.max_time: direction = self.random_direction() factor = self.line_search(points[-1], direction) if factor > 0.: new_point = points[-1] + np.random.uniform( ) * factor * direction if self.test_inside(new_point): points.append(new_point) return points
def __init__(self): def f(X, **kwargs): return -(X[1] + 47)*np.sin(np.sqrt(np.abs(X[0]/2 + (X[1]+47)))) + \ -X[0]*np.sin(np.sqrt(np.abs(X[0] - (X[1]+ 47)))) def bound_constraint(X, **kwargs): return np.all(np.logical_or(X < -512, X > 512)) constraints = [ Constraint(bound_constraint, **{}) ] super().__init__(f, constraints, n_dimensions_in = 2, n_dimensions_out = 1, **{})
def constraint_from_string(string : str, l_deprel:str = None) -> Constraint: """ string format 'cas=N' or 'num=@' or 'gen=subj.gen' or 'num = verb.num' @ will be replaced with the lval over-write rule: num/3 means is_bare will be yes no matter what it was before, no error""" if EQUALS in string: separator = EQUALS elif OVERWRITE in string: separator = OVERWRITE else: raise Exception('Invalid constraint %s, no separator' % string) is_none_ok = (NONE_NOT_OK not in string) string = string.replace(NONE_NOT_OK, EQUALS) is_overwrite = (separator == OVERWRITE) (lstr, rstr) = string.split(separator) lstr = lstr.strip() rstr = rstr.strip() if rstr[-1] == '!': # mandatory condition score = float('Inf') rstr = rstr[:-1] elif '?' in rstr: (rstr, score) = rstr.split('?') score = float(score) if score else 0.5 else: score = DEFAULT_ERROR_SCORE # do lexp lstr = lstr.split('.') # split by period -- ie, subj.gen lexp = [l_deprel] if l_deprel else [] lexp = lexp + lstr # for item in lstr: # lexp.append(item) # do rexp rexpr = [] if rstr == '@': rexpr = lstr elif '.' in rstr: rstr = rstr.split('.') for item in rstr: rexpr.append(item) else: # plain string rexpr = rstr if is_overwrite: return OverwriteConstraint(lexp, rexpr) else: return Constraint(lexp, rexpr, score, is_none_ok)
def sampler(input_file, output_file, n_result): ct = Constraint(input_file) ndim = ct.get_ndim() current_results = [] while len(current_results) < n_result: res = np.random.random(ndim) res = (res / sum(res) * sum(ct.get_example())).round(5) if not ct.apply(res): continue current_results.append(res) print('example:', ct.get_example()) print('res:', res) with open(output_file, 'a') as f: for l, el in enumerate(current_results): string = ' '.join(map(str, el)) # for item in string: f.write(string) f.write('\n') return current_results
class SCMC(): """Use sequentially constrained Monte Carlo method to sample given constrained domains uniformly Methods ------- write_ouput: write the final sample in given path get_correctness: return the correctness of the final state get_history: return a List, the history all samples in the sequential diffusion process plot_results: scatter plot the results along two arbitrary axes params ------ comp1, int: first axis (h) comp2, int: second axis (v) n_iter, int: if want history instead of final state print_constraints: print the original constraints """ def __init__(self, input_path, n_results, beta_max=10**4, p_beta=1, p_rw_step=0, track_correctness=False, threshold=.999): self.input_path = input_path self.constraints = Constraint(input_path) constraints_funcs = self.constraints.get_functions() self.n_dim = self.constraints.get_ndim() self.n_results = n_results self.beta_max = beta_max self.p_beta = p_beta self.p_rw_step = p_rw_step #call sampling method scmc i_sample = init_sample(self.n_dim, self.n_results, self.constraints.bounds, self.constraints.get_example()) self.i_samples = [] self.i_samples.append(i_sample) self.histories = [] self.correctnesses = [] print(len(constraints_funcs)) for i in range(1, len(constraints_funcs) + 1): history, correctness = scmc( self.n_dim, self.n_results, self.i_samples[i - 1], constraints_funcs[0:i], beta_max, self.constraints.bounds, p_beta, p_rw_step, track_correctness=track_correctness, given_example=self.constraints.get_example(), threshold=threshold) self.i_samples.append(history[-1]) self.histories.append(history) self.correctnesses.append(correctness) self.results = self.histories[-1][-1] # self.history, self.correctness = scmc(self.n_dim, self.n_results, i_sample ,constraints_funcs, beta_max, self.constraints.bounds, # p_beta,p_rw_step, # track_correctness=track_correctness, # given_example = self.constraints.get_example()) # self.results = self.history[-1] # self.history, self.correctness = scmc(self.n_dim, self.n_results, constraints_funcs, beta_max, self.constraints.bounds, # p_beta,p_rw_step, # track_correctness=track_correctness, # given_example = self.constraints.get_example()) # self.results = self.history[-1] # self.write_ouput(output_path) def write_output(self, output_path): """ save the sample to a output_path """ np.savetxt(output_path, self.results) def get_correctness(self): """ get correctness """ correctness = [self.constraints.apply(x) for x in self.results] correctness = sum(correctness) / self.n_results return correctness def get_history(self): return self.history def get_results(self): """ get the sample """ return self.results def plot_results(self, comp1, comp2, n_iter=None): """ Plot the sample in x[comp1],x[comp2] """ if n_iter is None: sample = self.results else: sample = self.history[n_iter - 1] plt.figure() plt.scatter(sample[:, comp1], sample[:, comp2]) plt.xlim(0, 1) plt.ylim(0, 1) def plot_all_axis(self, n_iter=None): n_dim = self.n_dim for i in range(n_dim): for j in range(i + 1, n_dim): self.plot_results(i, j, n_iter) plt.xlabel('x_{}'.format(i)) plt.ylabel('x_{}'.format(j)) def print_constraints(self): print(self.constraints.get_exprs_string())
def _get_type_constraint(deprel:str, type_name : str, error_score = float('inf')) -> Constraint: if deprel: return Constraint([deprel, Monomial.CATEGORY], type_name, error_score) else: return Constraint([Monomial.CATEGORY], type_name, error_score)
if dists_to_resampled[new_min_dist_inds] > min_dist_history[-1]: samples[vector_ind_to_replace] = resampled return samples, min_dist_history def parse_inputs(input_args): input_fname_path, output_filename, n_results = sys.argv[1:] try: n_results = int(n_results) if n_results < 2: raise ValueError("n_results must be an integer larger than 1") except: raise ValueError("n_results must be an integer larger than 1") if not os.path.isfile(input_fname_path): raise OSError("Input file not found") return input_fname_path, output_filename, n_results if __name__ == "__main__": input_fname, output_fname, n_results = parse_inputs(sys.argv[1:]) cons = Constraint(input_fname) samples = generate_random_samples(cons, n_results=n_results) samples, _ = spread_out_samples(cons, samples, resample_attempts=max(1000, n_results)) np.savetxt(output_fname, samples, fmt='%f', delimiter=' ')
def validate_output_file(self, constraints_file_name, points_file_name, expected): """ Validates output file against constraint file to see if required number of points are available. :param string constraints_file_name: path to a file that contains the constraints :param string points_file_name: path to a file that contains the vectors to be validated :param int expected: Number of points that are expected in this file """ self.log.info( f'Running validation: {constraints_file_name} <-> {points_file_name}' ) # Return if constraints or points files are not found. try: constraints = Constraint(constraints_file_name) except FileNotFoundError: self.log.critical( f'Constraints file {constraints_file_name} not found. Skipping validation...' ) return try: points_file = open(points_file_name, 'r') except FileNotFoundError: self.log.critical( f'Points file {points_file_name} not found. Skipping validation...' ) return # Counters for number of points that were generated, passed, failed, generated = 0 passed = 0 failed = 0 for itr, line in enumerate(points_file): x = [float(_) for _ in line.strip().split(" ")] # Log how many points have been checked. if itr != 0 and (itr % pow(10, floor(log10(itr + 1))) == 0): self.log.debug(f'Checked {itr}') # Count number of points generated/passed/failed generated += 1 try: if constraints.apply(x): passed += 1 else: self.log.warning(f'Point outside constraints: {x}') failed += 1 except: self.log.error(f'{sys.exc_info()[1]}, point: {x}') points_file.close() # Points file summary self.log.info(f'{generated} generated, {expected} expected') self.log.info(f'{passed} passed, {failed} failed') if generated != expected: self.log.warning(f'Unexpected number of points') if failed > 0: self.log.warning(f'{failed} points failed') if passed == expected or passed == generated: self.log.info(f'All points are valid') self.log.info( f'Validated {constraints_file_name} <-> {points_file_name}') self.log.info(f'-- Validation complete -- ') return
def __init__(self, filename, max_points, max_time): self.constraint = Constraint(filename) self.n_dim = self.constraint.n_dim self.example = self.constraint.example self.max_points = max_points self.max_time = max_time
class Solution(): def __init__(self, fname, outfile, n_results): self.con = Constraint(fname) self.num_x = self.con.n_dim self.n_results = n_results self.outfile = outfile with open(self.outfile, 'w') as f: f.write(" ".join(map(str, self.con.example))) f.write("\n") self.ineq_cons = { 'type': 'ineq', 'fun': lambda x: self.con.eval_con(x.tolist()) } bound = [0.0, 1.0] self.bounds = np.asarray([bound] * self.num_x) # determining the magnitude of the largest initial point max_initial = max(self.con.example) if max_initial == 0.0: self.alpha = 1.0 else: self.alpha = 1.0 / max_initial def solve(self): x0_all = np.random.random_sample( (self.n_results * 2, self.num_x)) / self.alpha output = [] cnt = 0 for i in range(len(x0_all)): x0 = x0_all[i, :] if self.con.apply(x0.tolist()): x_feasible = x0 else: try: res = self.optimize_feasible(x0) x_feasible = res.x if res.status != 0 or any(x_feasible < 0.0) or any( x_feasible > 1.0) or list(x_feasible) in output: continue except: continue # if self.con.apply(x_feasible.tolist()): # print "True" with open(self.outfile, 'a') as f: f.write(" ".join(map(str, x_feasible))) f.write("\n") output.append(list(x_feasible)) cnt += 1 if cnt == self.n_results: break return output def optimize_feasible(self, x0): res = optimize.minimize(self.f, x0, method='SLSQP', constraints=[self.ineq_cons], options={ 'ftol': 1e-8, 'disp': False }, bounds=self.bounds) return res def f(self, x): constr = self.con.eval_con(x.tolist()) constr[np.where(constr > 0)] = 0 return np.sum(np.square(constr)) def constraint(self, x): constr = self.con.eval_con(x.tolist()) return constr
def get_constrain(self): fname = self.get_filename() c = Constraint(fname) self.no_of_constrain = c.get_no_of_constrain() return self.no_of_constrain
class Generator: """ Generator class to generate output_file with required number of points that satisfy constraints in input_file. """ def __init__(self, input_file_name): """ Construct a Generator object and set up the log files. :param string input_file_name: Name of the constraints file """ # Setup class logger setup_logger('log_generator.log') self.log = logging.getLogger('log_generator.log') # Set up the constraints self.input_file_name = input_file_name try: self.constraints = Constraint(self.input_file_name) except FileNotFoundError: self.log.critical( f'Constraints file not found: {self.input_file_name}') else: self.log.info(f'Setup Generator for {self.input_file_name}') # Set and queue to hold and explore the required points self.point_set = set() self.points_queue = deque() # Generate_valid_points uses a form of breadth first search to generate n points satisfying the constraints defined in input_file_name. def generate_valid_points(self, n_points, min_step_size=1E-30): """ Generate required number of points that satisfy constraints. :param int n_points: Required number of points. :param float min_step_size: Optional minimum step size (default = 1E-30) for exploration. """ # Return if constraint file is unavailable try: self.constraints except NameError: self.log.critical( f'Constraints file not found {self.input_file_name} not found. Terminating generation...' ) return self.log.info( f'Points required: {n_points}, min_step_size: {min_step_size}') self.log.info( f'Constraints file: {self.input_file_name}, Dimension: {self.constraints.get_ndim()}, Starting point: {self.constraints.get_example()}' ) # Cast as a tuple since immutability is required to put into a set. self.point_set.add(tuple(self.constraints.get_example())) # Initial step size for exploration. step_size = 1.0 # Run while more points are required. while len(self.point_set) < n_points: # Add all valid points to the queue for exploration. for _ in self.point_set: self.points_queue.append(_) # Counter to count points found at a given step size. n_new_points = 0 # Run while the queue exists and more points are required. while self.points_queue and len(self.point_set) < n_points: # Explore outward from each point in the queue and add the found valid points to the queue and set. current_point = self.points_queue.popleft() n_new_points += self.explore_point(current_point, step_size, n_points, self.constraints) # End inner while loop: Done with finding points at given step size self.log.debug( f'Found: {n_new_points} with step size: {step_size}, total in set: {len(self.point_set)}' ) # Decrease step_size and search again. step_size /= 2 if step_size < min_step_size: self.log.warning( f'Step size is too small: {step_size}, breaking search') break # End outer while loop: Done with finding required number of points. self.log.info(f'Points found: {len(self.point_set)}') self.log.info(f'-- Generation complete -- ') return def explore_point(self, current_point, step_size, n_points, constraints): """ Explore outward from the current point in all dimensions with a given step size. Points that satisfy constraints are added to the queue and the point_set. The function returns the number of valid points found from current point. :param tuple current_point: Starting point of exploration :param float step_size: extent of exploration :param int n_points: required number of points :param Constraint constraints: set of constraints to satisfy """ found_points = 0 for i_dim in range(len(current_point)): for direction in [-1, +1]: # Update the coordinates, use round() to remove floating point errors, and cast as tuple for hash-abilty. next_point = list(current_point) round_to_digit = max( self.n_digits_after_decimal(next_point[i_dim]), self.n_digits_after_decimal(step_size)) next_point[i_dim] = round( next_point[i_dim] + (direction * step_size), round_to_digit) next_point = tuple(next_point) try: # If next_point is within the unit hypercube, meets constraints, and is not already explored, add to queue and set. if self.unit_cube_check(next_point) and constraints.apply( next_point) and next_point not in self.point_set: self.points_queue.append(next_point) self.point_set.add(next_point) found_points += 1 # ZeroDivisionError exception is logged as a warning and the script continues. except ZeroDivisionError: self.log.warning( f'{sys.exc_info()[1]}, point: {next_point}') # Unexpected exceptions are logged as errors and the script continues. except: self.log.error(f'{sys.exc_info()}, point: {next_point}') # Return if the number of required points are found. if len(self.point_set) == n_points: return found_points return found_points def write_to_file(self, output_file_name): """ Setup output file and write coordinates to it. :param string output_file_name: Name of the file to write the generated points """ # If constraint file was not found, point_set is empty so there is nothing to write. if len(self.point_set) == 0: self.log.error( f'No points generated for {self.input_file_name}. Terminating writing to {output_file_name}...' ) return self.log.info(f'Writing: {self.input_file_name} -> {output_file_name}') # Warn if file already exists and will be overwritten. if path.exists(output_file_name): self.log.warning( f'{output_file_name} already exists, overwriting file') # Open file for writing and write set of points to it. # Use an iterator to remove the new line character from the last line. with open(output_file_name, "w") as output_file: itr = 0 new_line = '\n' for point in self.point_set: itr += 1 if itr == len(self.point_set): new_line = '' output_file.write(" ".join(map(str, point)) + new_line) self.log.info(f'Written {itr} lines.') self.log.info(f'-- Writing complete -- ') return def unit_cube_check(self, x): """ Check if the given vector is within the unit hypercube. :param tuple x: Object that is used to represent the vector """ for _ in x: if _ > 1 or _ < 0: return False return True def n_digits_after_decimal(self, x): """ Return the number of digits after the decimal in x. :param float x: input number x """ return len(str(x).split(".")[-1])
from constraints import Constraint from exploration import Explore # read inputs inputs = sys.argv[-3:] input_file = inputs[0] output_file = inputs[1] n_results = int(inputs[2]) # Algorithm parameters inflation = 4 crowding_distance = 0.0005 mutation_period = 4 # Defining main objects for exploration c = Constraint(input_file) e = Explore(c, n_results, inflation, output_file) # Run and return run time start = time.time() e.select(crowding_distance=crowding_distance, algorithm='hybrid', mutation_period=mutation_period) # e.deflate() e.write2file() end = time.time() print('Time', end - start) # Plotting sampling distribution just for visualization e.plotting(index=(0, 1), plot_training=True)
def main(): # Obtain input arguments parser = argparse.ArgumentParser(description='Process inputs to sampler') parser.add_argument('input_file', default=None, type=str) parser.add_argument('output_file', default="output.txt", type=str) parser.add_argument('N', default=1000, type=int) parser.add_argument('--plot_bool', action="store_true") # Parse input arguments args = parser.parse_args() input_file = args.input_file output_file = args.output_file N = args.N plot_bool = args.plot_bool np.random.seed(0) # Load file and the corresponding constraint functions and valid example if not path.isfile(input_file) and input_file: raise ValueError('Input file does not exist') elif input_file: constraint = Constraint(input_file) x0 = np.array(constraint.get_example()) constraints = constraint.eval_constraints constraint_bool = constraint.apply constraint_bools = constraint.apply_list else: # Used for local testing constraints = func_constraints constraint_bool = func_constraints_bool x0 = x0 # Obtain bounds of input space from which initial sample guesses will # be uniformly drawn bounds = get_bounds(x0, constraint_bools) # Find valid uniformly distributed samples with constrained SMC N_star = int(N * 1.1) run = RunSMC(N=N_star, bounds=bounds, type="constrained_smc", tau_T=1e7, constraints=constraints) x, x0 = run.get_x(), run.get_x0() # Evaluate validity. uniqueness, and spread of results # Subsample result acc, x_valid = get_accuracy(x, constraint_bool) idx_x, idx_x_valid = np.arange(x.shape[0]), np.arange(x_valid.shape[0]) x = x_valid[np.random.choice(idx_x_valid, N, replace=False)] if x_valid.shape[0] >= N else \ x[np.random.choice(idx_x, N, replace=False)] std = np.std(x, axis=0) uniq_nums = np.unique(x, axis=0).shape[0] print('accuracy: {acc} std: {std} unique candidates: {uniq}'.format( acc=acc, std=std, uniq=uniq_nums)) # Save output and plot if 2D and plot_bool np.savetxt(output_file, x, delimiter=' ') if x.shape[1] == 2 and plot_bool: plt.plot(x0[:, 0], x0[:, 1], 'o', x[:, 0], x[:, 1], '*') plt.show()