Ejemplo n.º 1
0
def tree_search(tree, instance_file, return_dict, time_limit, storing_vals):
    '''
	Performs MCTS with time limit (seconds)
	'''
    global m

    start_time = datetime.datetime.now().strftime("%d.%m.%Y_%H:%M:%S")

    graph_sols = False
    graph_root_ucb = False

    store_stats, store_root_ucb, store_root_wins, store_root_visits, store_every_n, folder_name, filename = storing_vals

    # GRAPHING
    plt.ion()
    plt.show()
    if graph_sols:
        plt.xlabel("Nb domain changes")
        plt.ylabel("Feasible solution")
    elif graph_root_ucb:
        plt.xlabel("UCB value")
        plt.ylabel("Root candidate")

    start = time.time()
    nb_dives = 0

    # Problem with presolving when not freed before starting
    m.freeProb()
    m.readProblem(f"{instance_file}")

    # Stopped with thread timeout
    av_rollout_sols = []
    all_sols = []

    create_cols = True

    create_dfs = True

    while True:
        # Rollout + dive
        m.optimize()

        if create_dfs:
            if not os.path.exists(folder_name):
                os.makedirs(folder_name)
            colnames = tree.get_root().candidates
            create_dfs = False
            if store_stats:
                if store_root_ucb:
                    df_root_ucb = pd.DataFrame(columns=colnames)
                if store_root_wins:
                    df_root_wins = pd.DataFrame(columns=colnames)
                if store_root_visits:
                    df_root_visits = pd.DataFrame(columns=colnames)

        # If already optimized
        if not tree.scip_has_branched:
            print("Problem already optimized")
            print(m.getObjVal())
            break

        tree.rollout_tree_nodes.append(tree.curr_node)

        # Initiate solution
        sol = None

        # If feasible, add sol to list
        if m.getStatus() == 'optimal':
            sol = m.getObjVal()
            all_sols.append(sol)

            tree.rollout_sols[tree.rollout_nb - 1] = sol
            if sol < tree.curr_best_sol:
                # Add sol and brancher nb to list for graph
                tree.best_sol_list.append(sol)
                tree.nb_lp_solves.append(tree.ndomchgs)

                tree.curr_best_sol = sol

                tree.update_graph = True
        else:
            tree.increment_to_root(node=tree.curr_node, sol=sol)

            m.freeProb()

            m.readProblem(f"{instance_file}")

            utilities.init_scip_params(m,
                                       seed=seed,
                                       heuristics=False,
                                       presolving=False,
                                       separating=False,
                                       conflict=False)

            m.setIntParam('timing/clocktype',
                          1)  # 1: CPU user seconds, 2: wall clock time
            m.setRealParam('limits/time', time_limit)

            tree.phase = 'rollout'

            if tree.created_node:
                print("CREATED NODE PROBLEM")

            tree.curr_node = tree.get_root()

            # print("NOT OPTIMAL")
            continue

        # GRAPHING SOL VS DOM CHANGES
        if graph_sols:
            if tree.ndomchgs_graph > 500 and tree.update_graph:
                plt.plot(tree.nb_lp_solves, tree.best_sol_list, 'red')
                plt.draw()
                plt.pause(0.001)

                tree.update_graph = False

                tree.ndomchgs_graph = 0

        # GRAPHING ROOT CHILD UCB
        elif graph_root_ucb:
            if random.random() < 0.1:
                plt.bar(list(range(len(tree.root_node.child_ucb[:25]))),
                        tree.root_node.child_ucb[:25],
                        color='red')
                plt.draw()
                plt.title(f"{nb_dives} dives")
                plt.ylim(min(tree.root_node.child_ucb),
                         max(tree.root_node.child_ucb))
                plt.pause(0.001)

        # Increment nb of runs
        tree.increment_to_root(node=tree.curr_node, sol=sol)

        tree.phase = 'rollout'

        if nb_dives % store_every_n == 0:
            if store_stats:
                if store_root_ucb:
                    df_root_ucb.loc[nb_dives] = pd.Series(
                        tree.get_root_ucb(), index=df_root_ucb.columns)
                    utilities.log_stats(df_root_ucb, folder_name, filename,
                                        'ucb', start_time)
                if store_root_wins:
                    df_root_wins.loc[nb_dives] = pd.Series(
                        tree.get_root().child_nb_wins,
                        index=df_root_wins.columns)
                    utilities.log_stats(df_root_wins, folder_name, filename,
                                        'wins', start_time)
                if store_root_visits:
                    df_root_visits.loc[nb_dives] = pd.Series(
                        tree.get_root().child_nb_visits,
                        index=df_root_visits.columns)
                    utilities.log_stats(df_root_visits, folder_name, filename,
                                        'visits', start_time)

        nb_dives += 1

        # Add new nodes
        if tree.rollout_nb == tree.max_rollout_nb:
            tree.rollout_nb = 1

            if tree.adding_new_nodes == 'all':
                tree.add_all_nodes()
            elif tree.adding_new_nodes == 'best':
                tree.add_best_node()
            elif tree.adding_new_nodes == 'random':
                tree.add_rand_node()

            best_sol = min(tree.rollout_sols)
            av_rollout_sol = sum(tree.rollout_sols) / len(tree.rollout_sols)
            print(
                f"{tree.rollout_sols}, Best: {tree.get_best_sol()}, Av Sol: {av_rollout_sol}"
            )
            best_node = tree.rollout_tree_nodes[
                tree.rollout_sols.tolist().index(best_sol)]
            tree.increment_to_root(best_node, wins=True, sol=best_sol)

            # Reset lists
            tree.rollout_sols = np.ones(tree.max_rollout_nb) * np.inf
            tree.rollout_tree_nodes = []

            time_elapsed = (time.time() - start)

            print(
                f"AV TIME PER DIVE: {round((time_elapsed/nb_dives),2)}, {nb_dives} dives, {utilities.get_mins_left(time_elapsed, time_limit)} left\n"
            )

            tree.start_var = False
            av_rollout_sols.append(av_rollout_sol)

        else:
            # Only for the first n rollouts
            if nb_dives < tree.max_rollout_nb:
                tree.start_var = True
            tree.rollout_nb += 1

        faulthandler.enable()

        # Restart problem
        m.freeProb()

        m.readProblem(f"{instance_file}")

        utilities.init_scip_params(m,
                                   seed=seed,
                                   heuristics=False,
                                   presolving=False,
                                   separating=False,
                                   conflict=False)

        m.setIntParam('timing/clocktype',
                      1)  # 1: CPU user seconds, 2: wall clock time
        m.setRealParam('limits/time', time_limit)

        tree.curr_node = tree.get_root()

        return_dict['feas_sols_graph'], return_dict[
            'nb_lp_solves_graph'] = tree.get_graph_vals()
        return_dict['root_child_ucb'] = tree.get_root_ucb()
        return_dict['root_nb_wins'], return_dict[
            'root_nb_visits'] = tree.get_root_stats()
        return_dict['all_feas_sols'] = all_sols
Ejemplo n.º 2
0
            m = scip.Model()

            # print(a)

            m.setIntParam('display/verblevel', 0)

            m.readProblem(f"{instance['path']}")

            m.includeEventhdlr(SolvingStatsRecorder(brancher.solving_stats),
                               "SolvingStatsRecorder", "")

            # AGGRESSIVE MODE FOR INTERNAL BRANCHING
            if policy['type'] == 'internal':
                utilities.init_scip_params(m,
                                           seed=seed,
                                           heuristics='agg',
                                           presolving=False,
                                           separating=False,
                                           conflict=False)
            else:
                utilities.init_scip_params(m,
                                           seed=seed,
                                           heuristics=False,
                                           presolving=False,
                                           separating=False,
                                           conflict=False)

            # if policy['type'] == 'MCTS_coef_diving':
            # 	utilities.disable_all_but_coef(m)
            # elif policy['type'] == 'MCTS_fract_diving':
            # 	utilities.disable_all_but_fract(m)
Ejemplo n.º 3
0
    ]
    os.makedirs('results', exist_ok=True)
    with open(f"results/{result_file}", 'w', newline='') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writeheader()

        for instance in instances:
            print(f"{instance['type']}: {instance['path']}...")

            for policy in branching_policies:
                tf.set_random_seed(policy['seed'])

                m = scip.Model()
                m.setIntParam('display/verblevel', 0)
                m.readProblem(f"{instance['path']}")
                utilities.init_scip_params(m, seed=policy['seed'])
                m.setIntParam('timing/clocktype',
                              1)  # 1: CPU user seconds, 2: wall clock time
                m.setRealParam('limits/time', time_limit)

                brancher = PolicyBranching(policy)
                m.includeBranchrule(branchrule=brancher,
                                    name=f"{policy['type']}:{policy['name']}",
                                    desc=f"Custom PySCIPOpt branching policy.",
                                    priority=666666,
                                    maxdepth=-1,
                                    maxbounddist=1)

                walltime = time.perf_counter()
                proctime = time.process_time()
Ejemplo n.º 4
0
def exp_main(args):
    result_file = f"{args.problem}_{time.strftime('%Y%m%d-%H%M%S')}.csv"
    instances = []
    seeds = [0, 1, 2, 3, 4]
    # seeds = range(5,20)
    gcnn_models = ['baseline']
    # gcnn_models = []
    # other_models = ['extratrees_gcnn_agg', 'lambdamart_khalil', 'svmrank_khalil'] # TODO
    other_models = []
    # internal_branchers = ['relpscost']
    internal_branchers = []
    time_limit = 3600

    if args.problem == 'setcover':
        # instances += [{'type': 'small', 'path': f"data/instances/setcover/transfer_500r_1000c_0.05d/instance_{i+1}.lp"} for i in range(20)]
        instances += [{
            'type':
            'medium',
            'path':
            f"data/instances/setcover/transfer_1000r_1000c_0.05d/instance_{i+1}.lp"
        } for i in range(20)]
        # instances += [{'type': 'big', 'path': f"data/instances/setcover/transfer_2000r_1000c_0.05d/instance_{i+1}.lp"} for i in range(20)]
        # gcnn_models += ['mean_convolution', 'no_prenorm']

    elif args.problem == 'cauctions':
        instances += [{
            'type':
            'small',
            'path':
            f"data/instances/cauctions/transfer_100_500/instance_{i+1}.lp"
        } for i in range(20)]
        instances += [{
            'type':
            'medium',
            'path':
            f"data/instances/cauctions/transfer_200_1000/instance_{i+1}.lp"
        } for i in range(20)]
        instances += [{
            'type':
            'big',
            'path':
            f"data/instances/cauctions/transfer_300_1500/instance_{i+1}.lp"
        } for i in range(20)]

    elif args.problem == 'facilities':
        instances += [{
            'type':
            'small',
            'path':
            f"data/instances/facilities/transfer_100_100_5/instance_{i+1}.lp"
        } for i in range(20)]
        instances += [{
            'type':
            'medium',
            'path':
            f"data/instances/facilities/transfer_200_100_5/instance_{i+1}.lp"
        } for i in range(20)]
        # instances += [{'type': 'big', 'path': f"data/instances/facilities/transfer_400_100_5/instance_{i+1}.lp"} for i in range(20)]

    elif args.problem == 'indset':
        instances += [{
            'type':
            'small',
            'path':
            f"data/instances/indset/transfer_500_4/instance_{i+1}.lp"
        } for i in range(20)]
        instances += [{
            'type':
            'medium',
            'path':
            f"data/instances/indset/transfer_1000_4/instance_{i+1}.lp"
        } for i in range(20)]
        # instances += [{'type': 'big', 'path': f"data/instances/indset/transfer_1500_4/instance_{i+1}.lp"} for i in range(20)]

    else:
        raise NotImplementedError

    branching_policies = []

    # SCIP internal brancher baselines
    for brancher in internal_branchers:
        for seed in seeds:
            branching_policies.append({
                'type': 'internal',
                'name': brancher,
                'seed': seed,
                'sampling_strategy': NaN,
            })
    # ML baselines
    for model in other_models:
        for seed in seeds:
            branching_policies.append({
                'type':
                'ml-competitor',
                'name':
                model,
                'seed':
                seed,
                'model':
                f'trained_models/{args.problem}/{model}/{seed}',
            })
    # GCNN models
    for sampling_Strategy in args.sampling_strategies:
        for model in gcnn_models:
            for seed in seeds:
                branching_policies.append({
                    'type':
                    'gcnn',
                    'name':
                    model,
                    'seed':
                    seed,
                    'sampling_strategy':
                    sampling_Strategy,
                    'parameters':
                    f'trained_models/{args.problem}/{sampling_Strategy}/ss{args.sample_seed}/ts{seed}/best_params.pkl'
                })

    print(f"problem: {args.problem}")
    print(f"gpu: {args.gpu}")
    print(f"time limit: {time_limit} s")

    if args.gpu == -1:
        tf.config.set_visible_devices(
            tf.config.list_physical_devices('CPU')[0])
    else:
        cpu_devices = tf.config.list_physical_devices('CPU')
        gpu_devices = tf.config.list_physical_devices('GPU')
        tf.config.set_visible_devices([cpu_devices[0], gpu_devices[args.gpu]])
        tf.config.experimental.set_memory_growth(gpu_devices[args.gpu], True)

    # load and assign tensorflow models to policies (share models and update parameters)
    loaded_models = {}
    for policy in branching_policies:
        if policy['type'] == 'gcnn':
            if policy['name'] not in loaded_models:
                model_module = importlib.import_module(f'models.{model}.model')
                loaded_models[policy['name']] = model_module.GCNPolicy()
            policy['model'] = loaded_models[policy['name']]

    # load ml-competitor models
    for policy in branching_policies:
        if policy['type'] == 'ml-competitor':
            try:
                with open(f"{policy['model']}/normalization.pkl", 'rb') as f:
                    policy['feat_shift'], policy['feat_scale'] = pickle.load(f)
            except:
                policy['feat_shift'], policy['feat_scale'] = 0, 1

            with open(f"{policy['model']}/feat_specs.pkl", 'rb') as f:
                policy['feat_specs'] = pickle.load(f)

            if policy['name'].startswith('svmrank'):
                policy['model'] = svmrank.Model().read(
                    f"{policy['model']}/model.txt")
            else:
                with open(f"{policy['model']}/model.pkl", 'rb') as f:
                    policy['model'] = pickle.load(f)

    print("running SCIP...")

    fieldnames = [
        'policy',
        'sampling_strategy',
        'seed',
        'type',
        'instance',
        'nnodes',
        'nlps',
        'stime',
        'gap',
        'status',
        'ndomchgs',
        'ncutoffs',
        'walltime',
        'proctime',
    ]
    os.makedirs('results', exist_ok=True)
    with open(f"results/{result_file}", 'w', newline='') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writeheader()

        for instance in instances:
            print(f"{instance['type']}: {instance['path']}...")

            for policy in branching_policies:
                tf.random.set_seed(policy['seed'])

                m = scip.Model()
                m.setIntParam('display/verblevel', 0)
                m.readProblem(f"{instance['path']}")
                utilities.init_scip_params(m, seed=policy['seed'])
                m.setIntParam('timing/clocktype',
                              1)  # 1: CPU user seconds, 2: wall clock time
                m.setRealParam('limits/time', time_limit)

                brancher = PolicyBranching(policy)
                m.includeBranchrule(branchrule=brancher,
                                    name=f"{policy['type']}:{policy['name']}",
                                    desc=f"Custom PySCIPOpt branching policy.",
                                    priority=666666,
                                    maxdepth=-1,
                                    maxbounddist=1)

                walltime = time.perf_counter()
                proctime = time.process_time()

                m.optimize()

                walltime = time.perf_counter() - walltime
                proctime = time.process_time() - proctime

                stime = m.getSolvingTime()
                nnodes = m.getNNodes()
                nlps = m.getNLPs()
                gap = m.getGap()
                status = m.getStatus()
                ndomchgs = brancher.ndomchgs
                ncutoffs = brancher.ncutoffs

                writer.writerow({
                    'policy':
                    f"{policy['type']}:{policy['name']}",
                    'sampling_strategy':
                    policy['sampling_strategy'],
                    'seed':
                    policy['seed'],
                    'type':
                    instance['type'],
                    'instance':
                    instance['path'],
                    'nnodes':
                    nnodes,
                    'nlps':
                    nlps,
                    'stime':
                    stime,
                    'gap':
                    gap,
                    'status':
                    status,
                    'ndomchgs':
                    ndomchgs,
                    'ncutoffs':
                    ncutoffs,
                    'walltime':
                    walltime,
                    'proctime':
                    proctime,
                })

                csvfile.flush()
                m.freeProb()

                print(
                    f"  {policy['type']}:{policy['name']}:{policy['sampling_strategy']} {policy['seed']} - {nnodes} ({nnodes+2*(ndomchgs+ncutoffs)}) nodes {nlps} lps {stime:.2f} ({walltime:.2f} wall {proctime:.2f} proc) s. {status}"
                )
Ejemplo n.º 5
0
def make_samples(in_queue, out_queue):
    """
    Worker loop: fetch an instance, run an episode and record samples.

    Parameters
    ----------
    in_queue : multiprocessing.Queue
        Input queue from which orders are received.
    out_queue : multiprocessing.Queue
        Output queue in which to send samples.
    """
    while True:
        episode, instance, seed, time_limit, outdir, rng = in_queue.get()

        m = scip.Model()
        m.setIntParam('display/verblevel', 0)
        m.readProblem(f'{instance}')
        utilities.init_scip_params(m, seed=seed)
        m.setIntParam('timing/clocktype', 2)
        m.setRealParam('limits/time', time_limit)
        m.setLongintParam('limits/nodes', node_limit)

        branchrule = VanillaFullstrongBranchingDataCollector(
            rng, node_record_prob)
        m.includeBranchrule(branchrule=branchrule,
                            name="Sampling branching rule",
                            desc="",
                            priority=666666,
                            maxdepth=-1,
                            maxbounddist=1)

        m.setBoolParam('branching/vanillafullstrong/integralcands', True)
        m.setBoolParam('branching/vanillafullstrong/scoreall', True)
        m.setBoolParam('branching/vanillafullstrong/collectscores', True)
        m.setBoolParam('branching/vanillafullstrong/donotbranch', True)
        m.setBoolParam('branching/vanillafullstrong/idempotent', True)

        out_queue.put({
            "type": 'start',
            "episode": episode,
            "instance": instance,
            "seed": seed
        })

        m.optimize()
        # data storage - root and node data are saved separately.
        # node data carries a reference to the root filename.
        if m.getNNodes() >= 1 and len(branchrule.obss) > 0:
            filenames = []
            max_depth = max(x['depth'] for x in branchrule.obss_feats)
            stats = {
                'nnodes': m.getNNodes(),
                'time': m.getSolvingTime(),
                'gap': m.getGap(),
                'nobs': len(branchrule.obss)
            }

            # prepare root data
            sample_state, sample_khalil_state, root_obss = branchrule.state
            sample_cand_scores = branchrule.obss_feats[0]['scores']
            sample_cands = np.where(sample_cand_scores != -1)[0]
            sample_cand_scores = sample_cand_scores[sample_cands]
            cand_choice = np.where(sample_cands == branchrule.targets[0])[0][0]

            root_filename = f"{outdir}/sample_root_0_{episode}.pkl"

            filenames.append(root_filename)
            with gzip.open(root_filename, 'wb') as f:
                pickle.dump(
                    {
                        'type':
                        'root',
                        'episode':
                        episode,
                        'instance':
                        instance,
                        'seed':
                        seed,
                        'stats':
                        stats,
                        'root_state': [
                            sample_state, sample_khalil_state, sample_cands,
                            cand_choice, sample_cand_scores
                        ],
                        'obss': [
                            branchrule.obss[0], branchrule.targets[0],
                            branchrule.obss_feats[0], None
                        ],
                        'max_depth':
                        max_depth
                    }, f)

            # node data
            for i in range(1, len(branchrule.obss)):
                iteration_counter = branchrule.obss_feats[i]['iteration']
                filenames.append(
                    f"{outdir}/sample_node_{iteration_counter}_{episode}.pkl")
                with gzip.open(filenames[-1], 'wb') as f:
                    pickle.dump(
                        {
                            'type':
                            'node',
                            'episode':
                            episode,
                            'instance':
                            instance,
                            'seed':
                            seed,
                            'stats':
                            stats,
                            'root_state':
                            f"{outdir}/sample_root_0_{episode}.pkl",
                            'obss': [
                                branchrule.obss[i], branchrule.targets[i],
                                branchrule.obss_feats[i], None
                            ],
                            'max_depth':
                            max_depth
                        }, f)

            out_queue.put({
                "type": "done",
                "episode": episode,
                "instance": instance,
                "seed": seed,
                "filenames": filenames,
                "nnodes": len(filenames),
            })

        m.freeProb()
Ejemplo n.º 6
0
def make_samples(in_queue, out_queue):
    """
    Worker loop: fetch an instance, run an episode and record samples.

    Parameters
    ----------
    in_queue : multiprocessing.Queue
        Input queue from which orders are received.
    out_queue : multiprocessing.Queue
        Output queue in which to send samples.
    """

    while True:
        episode, instance, seed, exploration_policy, query_expert_prob, time_limit, out_dir = in_queue.get()
        print(f'[w {os.getpid()}] episode {episode}, seed {seed}, processing instance \'{instance}\'...')

        m = scip.Model()
        m.setIntParam('display/verblevel', 0)
        m.readProblem(f'{instance}')
        utilities.init_scip_params(m, seed=seed)
        m.setIntParam('timing/clocktype', 2)
        m.setRealParam('limits/time', time_limit)

        branchrule = SamplingAgent(
            episode=episode,
            instance=instance,
            seed=seed,
            out_queue=out_queue,
            exploration_policy=exploration_policy,
            query_expert_prob=query_expert_prob,
            out_dir=out_dir)

        m.includeBranchrule(
            branchrule=branchrule,
            name="Sampling branching rule", desc="",
            priority=666666, maxdepth=-1, maxbounddist=1)

        m.setBoolParam('branching/vanillafullstrong/integralcands', True)
        m.setBoolParam('branching/vanillafullstrong/scoreall', True)
        m.setBoolParam('branching/vanillafullstrong/collectscores', True)
        m.setBoolParam('branching/vanillafullstrong/donotbranch', True)
        m.setBoolParam('branching/vanillafullstrong/idempotent', True)

        out_queue.put({
            'type': 'start',
            'episode': episode,
            'instance': instance,
            'seed': seed,
        })

        m.optimize()
        m.freeProb()

        print(f"[w {os.getpid()}] episode {episode} done, {branchrule.sample_counter} samples")

        out_queue.put({
            'type': 'done',
            'episode': episode,
            'instance': instance,
            'seed': seed,
        })