solver.py 5.38 KB
Newer Older
1 2 3 4 5 6 7
import importlib
import json
import os
import requests
import sys
import time
import threading
8
import traceback
9

10
from collections import OrderedDict
11
from utils import Problem
12

Kento HASEGAWA's avatar
Kento HASEGAWA committed
13 14 15 16 17
class Solver(object):

    def __init__(self, config):
        self.type = 'solver'

18 19 20
        self.host = config['host']
        self.address = config['address']
        self.name = config['name']
21
        self.partial_mode = config['partial_mode']
22
        self.solver = importlib.import_module(f"solvers.{config['solver']}")
23 24
        self.queue = OrderedDict()

25 26
        self.solving = None

Kento HASEGAWA's avatar
Kento HASEGAWA committed
27
        self.status = None
28 29 30

        self.thread = threading.Thread(name='solver', target=self.solver_thread, daemon=True)
        self.thread.start()
Kento HASEGAWA's avatar
Kento HASEGAWA committed
31 32

        self.set_status('Ready')
33 34 35
    
    def __del__(self):
        self.stop_solver()
36

Kento HASEGAWA's avatar
Kento HASEGAWA committed
37 38
    def __repr__(self):
        return "Solver"
39
    
40
    def set_status(self, status, params=dict()):
Kento HASEGAWA's avatar
Kento HASEGAWA committed
41
        self.status = status
42
        self.post('worker/status', {'address': self.address, 'status': self.status, 'params': params})
Kento HASEGAWA's avatar
Kento HASEGAWA committed
43
    
44 45 46 47 48 49
    def solver_thread(self):

        while True:
            if len(self.queue) > 0:
                print("I: Solver started")
                _, params = self.queue.popitem(last=False)
50
                self.solving = params
51
                self.set_status(f'Running ({len(self.queue)} in queue)', params={'request_id': params['request_id']})
52 53 54 55
                try:
                    self.solve(params)
                except Exception as e:
                    print("E: An error has occurred in the solver thread")
56
                    print(traceback.format_exc())
57
                self.solving = None
Kento HASEGAWA's avatar
Kento HASEGAWA committed
58
                self.set_status('Ready')
59 60 61
            else:
                time.sleep(0.5)
    
62 63
    def solve(self, params):

64
        if self.partial_mode and len(params['group_problems']) > 1:
65

66
            for i, (gproblem, gline_map, gblock_map) in enumerate(params['group_problems']):
67

68 69 70 71 72 73
                data = params.copy()
                data['problem'] = gproblem
                
                start_time = time.time()
                solution = self.solver.solve(data)
                end_time = time.time()
74

75 76 77 78 79 80 81 82 83 84
                elapsed_time = end_time - start_time

                if not 'elapsed_time' in solution:
                    solution['elapsed_time'] = elapsed_time
                
                solution['part_id'] = i
                solution['line_map'] = gline_map
                solution['block_map'] = gblock_map

                self.submit_solution(data, solution)
85 86 87

                if self.solver.stop_flag:
                    break
88 89 90 91 92 93 94 95 96 97 98
        else:
            start_time = time.time()
            solution = self.solver.solve(params)
            end_time = time.time()

            elapsed_time = end_time - start_time

            if not 'elapsed_time' in solution:
                solution['elapsed_time'] = elapsed_time

            self.submit_solution(params, solution)
99

100 101 102
        return True
    
    def post(self, path, data):
Kento HASEGAWA's avatar
Kento HASEGAWA committed
103 104 105 106 107 108 109 110 111
        try:
            response = requests.post(
                f'http://{self.host}/api/{path}',
                json.dumps(data),
                headers={'Content-Type': 'application/json'})
            print(f"I: Post to {self.host}, API Cmd: {path}")
        except Exception as e:
            print(f"W: Failed to connect to the host")
            response = None
112 113 114 115 116
        return response

    def submit_solution(self, params, solution):
        data = {
            'request_id': params['request_id'],
117
            'problem': params['name'],
118 119
            'worker': self.address,
            'merge_solvers': params['merge_solvers']
120 121
        }
        data.update(solution)
122
        self.post('problem/solution', data)
123 124 125

    def start_solver(self, params):

126 127 128
        print("I: Problem queued")
        _id = params['request_id']
        self.queue[_id] = params
Kento HASEGAWA's avatar
Kento HASEGAWA committed
129 130
        self.set_status(f'Running ({len(self.queue)} in queue)')
        return {'status': self.status}
131
        
132
    def stop_solver(self):
133

134 135 136
        # if self.thread is not None:
        #     self.solver.stop()
        self.solver.stop()
137
        
Kento HASEGAWA's avatar
Kento HASEGAWA committed
138
        return {'status': self.status}
139 140 141 142 143 144 145 146
    
    def cancel_queue(self, params):

        if 'request_id' in params:
            request_id = params['request']
            for k, v in self.queue.items():
                if k == request_id:
                    self.queue.pop(k, None)
147 148
            if self.solving is not None and self.solving['request_id'] == request_id:
                self.solver.stop()
149 150 151 152 153
        elif 'problem' in params:
            problem_name = params['problem']
            for k, v in self.queue.items():
                if v['name'] == problem_name:
                    self.queue.pop(k, None)
154 155
            if self.solving is not None and self.solving['name'] == problem_name:
                self.solver.stop()
156 157

        return {'status': 'canceled'}
Kento HASEGAWA's avatar
Kento HASEGAWA committed
158 159 160 161

    def call_api(self, method, cmd, params):
        if cmd == 'role':
            return {'role': self.type}
162 163
        elif cmd == 'solve':
            return self.start_solver(params)
164 165
        elif cmd == 'stop':
            return self.stop_solver()
166 167
        elif cmd == 'cancel':
            return self.cancel_queue(params)
168
        elif cmd == 'status':
Kento HASEGAWA's avatar
Kento HASEGAWA committed
169
            return {'status': self.status}
Kento HASEGAWA's avatar
Kento HASEGAWA committed
170 171
        else:
            return None