def solve(self, decider=None, initial_state=None): start_time = datetime.now() solved_count = 0 best_solved_count = 0 dead_end_count = 0 max_child_count = 64 # INIT ROOT/ZERO NODE current_node = Node(id=Node.next_id(), parent_id=None, state=initial_state.clone(), recursion_depth=0, decider=decider, max_child_count=max_child_count) current_node.upsert() # LOG INITITAL STATE logging.info(datetime.now()) logging.info('root node {%i} instantiated.' % current_node.id) logging.info('with initial state = ') logging.info(str(initial_state)) target_depth = initial_state.target_depth() # CREATE FIRST GENERATION OF CHILDREN logging.info('creating child states...') current_node.create_children() logging.info('%i created.' % current_node.child_count) decision_path = [] exit_criteria = { 'timed_out' : False, 'request_cancel' : False, 'is_solved' : False, 'solution_space_exhausted' : False, } rotator_counter = 0 rotator_interval = 100000 exhaust_solution_space = True skip_solution = False while (True not in exit_criteria.values()): current_time = datetime.now() total_elapsed_time = current_time - start_time total_elapsed_seconds = total_elapsed_time.total_seconds() approx_total_elapsed_minutes = total_elapsed_seconds / 60 approx_total_elapsed_hours = total_elapsed_seconds / (60 * 60) approx_total_elapsed_days = total_elapsed_seconds / (60 * 60 * 24) # INDICATE PROGRESS rotator_counter = rotator_counter + 1 if (rotator_counter % rotator_interval == 0): print('=-'*10) print('started @ %s, now @ %s]' % (start_time, current_time)) print('%i seconds ~ %i minutes ~ %i hours ~ %i days' % (total_elapsed_seconds, approx_total_elapsed_minutes, approx_total_elapsed_hours, approx_total_elapsed_days)) print('node %i - current {%i}/{%i} vs. best {%i}/{%i}' % (current_node.id, solved_count, target_depth, best_solved_count, target_depth)) print('total solution count - %i' % len(self.solution_nodes)) print('tree node count - %i' % len(Node.tree.keys())) print('dead-end count - %i' % dead_end_count) phys_usage = psutil.phymem_usage() print('%d %% of physical memory used' % phys_usage.percent) virt_usage = psutil.virtmem_usage() print('%d %% of virtual memory used' % virt_usage.percent) # SOLVED if (decider.solution_status(current_node.state) == True) and (skip_solution == False): exit_criteria['is_solved'] = True current_node.is_solution = True self.solution_nodes.append(current_node) logging.info('node {%i} solves.' % current_node.id) logging.info('state:') logging.info(str(current_node.state)) print('solved') print(str(current_node.state)) if (exhaust_solution_space == True): exit_criteria['is_solved'] = False skip_solution = True # CONTINUE [current_node is not solution] else: skip_solution = False logging.info('solution not yet reached.') # NEED TO GENERATE CHILDREN FOR NODE if (current_node.next_child_idx == None): logging.info('need to generate children for node {%i} ...' % current_node.id) current_node.create_children() if (current_node.child_count == 0): dead_end_count = dead_end_count + 1 logging.info('done. %i children created.' % current_node.child_count) # MOVE FORWARD [IF THE CURRENT NODE HAS AN UNEVALUATED CHILD, THEN MOVE TO IT] if (current_node.next_child_idx != -1): logging.info('current node {%i} has an unevaluated child' % current_node.id) # get next child next_node_id = current_node.child_ids[current_node.next_child_idx] next_node = current_node.get(next_node_id) logging.info('moved fwd to unevaluated child node {%i} of parent node {%i} [child no. %i of %i]' % (next_node.id, current_node.id, current_node.next_child_idx + 1, current_node.child_count)) # increment next child idx if (current_node.next_child_idx < current_node.child_count - 1): current_node.next_child_idx = current_node.next_child_idx + 1 # ALL CHILDREN EXHAUSTED else: current_node.next_child_idx = -1 current_node.upsert() # NOTE MOVE FWD solved_count = solved_count + 1 if (solved_count > best_solved_count): best_solved_count = solved_count logging.info("current completeness = {%i}/{%i}" % (solved_count, target_depth)) logging.info("vs. best completeness = {%i}/{%i}" % (best_solved_count, target_depth)) change_loc = current_node.state.locate_fwd_change(next_node.state) logging.info('change loc %s' % str(change_loc)) decision_path.append(change_loc) logging.info('updated decision path') logging.info(decision_path) logging.info('new state') logging.info(next_node.state) # update completeness # current_completeness = solved_count / target_count * 100) # best_completeness = best_solved_count / target_count * 100) # increment pointer to next unevaluated remaining child (dec ## of remaining uneval children) current_node = next_node # current_node.has_available_children() == False else: logging.info("no unevaluated children, i.e. dead-end reached.") # MOVE BACKWARDS # if current node has a parent, and thus it is actually possible to move backwards if (current_node.parent_id != None): # retrieve parent node next_node = Node.tree[current_node.parent_id] logging.info('moving back to parent node {%i}' % next_node.id) # locate change change_loc = current_node.state.locate_bwd_change(next_node.state) solved_count = solved_count - 1 decision_path.pop() logging.info("current completeness = {%i}/{%i}" % (solved_count, target_depth)) logging.info("vs. best completeness = {%i}/{%i}" % (best_solved_count, target_depth)) node_to_discard = current_node current_node = next_node Node.purge_node(node_to_discard) ## CanMoveBackwards() == False else: exit_criteria['solution_space_exhausted'] = True logging.info('node i% has no parent.' % current_node.id) logging.info('solution space exhausted.') for exit_criterion in exit_criteria.keys(): logging.info('%s - %s' % (exit_criterion, exit_criteria[exit_criterion])) return exit_criteria
def solve(self, decider=None, initial_state=None, max_child_count=None): n = 5 initial_state = State(n) decision_path = [] seed = datetime.now().microsecond logging.info('seed for random number generator - %i' % seed) exit_criteria = { 'timed_out' : False, 'request_cancel' : False, 'is_solved' : False, 'solution_space_exhausted' : False, } decider = Decider(random_seed=seed) zero_node = Node(id=Node.next_id(), parent_id=None, state=initial_state, recursion_depth=0, decider=decider, max_child_count=max_child_count) zero_node.upsert() zero_node.create_children() zero_node.upsert() first_generation_count = zero_node.child_count total_processor_count = psutil.cpu_count() max_count = total_processor_count - 1 # use all CPUs, with one reserved for us #max_count = 1 active_procs = {} terminated_proc_ids = [] remaining_count = first_generation_count procs_instructed_to_terminate = [] cancel = False start_time = time.time() time_limit = None timed_limit_exceeded = False update_period = 0.5 # second solutions = [] solution_counts = {} solution_count_time_evolution = {} next_proc_id = 1 while ((cancel == True) and (len(active_procs.keys()) > 0)) or ((cancel == False) and ((remaining_count > 0) or (len(active_procs.keys()) > 0))): if (time_limit != None): if (time.time() - start_time > time_limit): timed_limit_exceeded = True if (timed_limit_exceeded == True): cancel = True '''# ISSUE TERMINATION INSTRUCTIONS''' if (cancel == True): for proc_id in active_procs.keys(): if (proc_id not in procs_instructed_to_terminate): connxn = active_procs[proc_id] term_msg = TerminationMessage(proc_id=0) connxn.send(term_msg) print('proc %i instructed to terminate' % proc_id) procs_instructed_to_terminate.append(proc_id) new_solutions_arrived = False '''# HANDLE INCOMING MESSAGES''' for proc_id in active_procs.keys(): connxn = active_procs[proc_id] while (connxn.poll() == True): msg = connxn.recv() '''# SOLUTION MSG''' if (isinstance(msg, SolutionMessage)): new_solutions_arrived = True solutions.append(msg.solution) if (msg.proc_id in solution_counts.keys()): solution_counts[msg.proc_id] = solution_counts[msg.proc_id] + 1 else: solution_counts[msg.proc_id] = 1 '''# STATUS MSG''' '''# TERMINATION MSG''' if (isinstance(msg, TerminationMessage)): print('TerminationNotice received from process %i' % msg.proc_id) active_procs.pop(msg.proc_id) terminated_proc_ids.append(msg.proc_id) '''# SPAWN NEW PROCESS IF NOT YET DONE''' if ((cancel == False) and (len(active_procs.keys()) < max_count) and (remaining_count > 0)): print(zero_node.next_child_idx) '''# GET NEXT UNUSED STATE, IF ANY ''' if (zero_node.next_child_idx != -1): node_idx = zero_node.child_ids[zero_node.next_child_idx] node = Node.tree[node_idx] '''# ADJUST next_child_idx ''' if (zero_node.next_child_idx < zero_node.child_count - 1): zero_node.next_child_idx = zero_node.next_child_idx + 1 else: zero_node.next_child_idx = -1 zero_node.upsert() proc_id = next_proc_id next_proc_id = next_proc_id + 1 (parent_connxn, child_connxn) = Pipe() active_procs[proc_id] = parent_connxn proc = Process(target=tracker_process, args=(proc_id, node, child_connxn)) proc.start() remaining_count = remaining_count - 1 if (new_solutions_arrived): cls() counts = [('%i - %i' % (pid, solution_counts[pid])) for pid in solution_counts.keys()] print(str(len(solutions)) + ' : ' + (','.join(counts)) ) print('active - ' + str(active_procs.keys())) print('completed' + str(terminated_proc_ids)) d = {} d[0] = [len(solutions)] for pid in solution_counts.keys(): d[pid] = solution_counts[pid] solution_count_time_evolution[datetime.now()] = d time.sleep(update_period) print('all done') print('writing solutions to disk') f = open('solutions.txt', 'w') for state in solutions: f.write('\n') f.write(str(state)) f.close() print('writing solution count time-evolution to disk') sorted_keys = sorted([x for x in solution_counts.keys()]) f = open('solution_count_time_evolution.csv', 'w') for key in sorted_keys: f.write(str(key) + ',' + ','.join([str(x) for x in solution_count_time_evolution[key]]) + '\n') counts = solution_count_time_evolution[key] s = '' for i in range(first_generation_count): n = i + 1 if (n not in counts.keys()): s = s + '0' + ',' else: s = s + str(counts[n]) + ',' f.write(s + '\n') f.close()
def solve(self, decider=None, initial_state=None): solved_count = 0 best_solved_count = 0 max_child_count = 64 # init root/zero node current_node = Node(id=Node.next_id(), parent_id=None, state=initial_state.clone(), recursion_depth=0, decider=decider, max_child_count=max_child_count) current_node.upsert() logging.info(datetime.now()) logging.info('root node {%i} instantiated.' % current_node.id) logging.info('with initial state = ') logging.info(str(initial_state)) target_depth = initial_state.target_depth() # log initial state logging.info('creating child states...') current_node.create_children() logging.info('%i created.' % current_node.child_count) decision_path = [] exit_criteria = { 'timed_out' : False, 'request_cancel' : False, 'is_solved' : False, 'solution_space_exhausted' : False, } rotator_counter = 0 rotator_interval = 10000 exhaust_solution_space = True skip_solution = False while (True not in exit_criteria.values()): # INDICATE PROGRESS rotator_counter = rotator_counter + 1 if (rotator_counter % rotator_interval == 0): print('node %i - current {%i}/{%i} vs. best {%i}/{%i}' % (current_node.id, solved_count, target_depth, best_solved_count, target_depth)) # SOLVED if (decider.solution_status(current_node.state) == True) and (skip_solution == False): exit_criteria['is_solved'] = True current_node.is_solution = True Node.tree[current_node.id] = current_node logging.info('node {%i} solves.' % current_node.id) logging.info('state:') logging.info(str(current_node.state)) print('solved') print(str(current_node.state)) if (exhaust_solution_space == True): exit_criteria['is_solved'] = False skip_solution = True # CONTINUE else: skip_solution = False logging.info('solution not yet reached.') # NEED TO GENERATE CHILDREN FOR NODE if (current_node.next_child_idx == None): logging.info('need to generate children for node {%i} ...' % current_node.id) current_node.create_children() logging.info('done. %i children created.' % current_node.child_count) # IF THE CURRENT NODE HAS AN UNEVALUATED CHILD, THEN MOVE TO IT if (current_node.next_child_idx != -1): logging.info('current node {%i} has an unevaluated child' % current_node.id) # get next child next_node_id = current_node.child_ids[current_node.next_child_idx] next_node = current_node.get(next_node_id) logging.info('moved fwd to unevaluated child node {%i} of parent node {%i} [child no. %i of %i]' % (next_node.id, current_node.id, current_node.next_child_idx + 1, current_node.child_count)) # increment next child idx if (current_node.next_child_idx < current_node.child_count - 1): current_node.next_child_idx = current_node.next_child_idx + 1 # ALL CHILDREN EXHAUSTED else: current_node.next_child_idx = -1 current_node.upsert() # NOTE MOVE FWD solved_count = solved_count + 1 if (solved_count > best_solved_count): best_solved_count = solved_count logging.info("current completeness = {%i}/{%i}" % (solved_count, target_depth)) logging.info("vs. best completeness = {%i}/{%i}" % (best_solved_count, target_depth)) change_loc = current_node.state.locate_fwd_change(next_node.state) logging.info('change loc %s' % str(change_loc)) decision_path.append(change_loc) logging.info('updated decision path') logging.info(decision_path) logging.info('new state') logging.info(next_node.state) # update completeness # current_completeness = solved_count / target_count * 100) # best_completeness = best_solved_count / target_count * 100) # increment pointer to next unevaluated remaining child (dec ## of remaining uneval children) current_node = next_node # current_node.has_available_children() == False else: logging.info("no unevaluated children, i.e. dead-end reached.") # move backwards # if current node has a parent, and thus it is actually possible to move backwards if (current_node.parent_id != None): # retrieve parent node next_node = Node.tree[current_node.parent_id] logging.info('moving back to parent node {%i}' % next_node.id) # locate change change_loc = current_node.state.locate_bwd_change(next_node.state) solved_count = solved_count - 1 decision_path.pop() logging.info("current completeness = {%i}/{%i}" % (solved_count, target_depth)) logging.info("vs. best completeness = {%i}/{%i}" % (best_solved_count, target_depth)) current_node = next_node ## CanMoveBackwards() == False else: exit_criteria['solution_space_exhausted'] = True logging.info('node {i%} has no parent.' % current_node.id) logging.info('solution space exhausted.') for exit_criterion in exit_criteria.keys(): logging.info('%s - %s' % (exit_criterion, exit_criteria[exit_criterion])) return exit_criteria