def optimize(self):
        """
        If CPLEX is installed locally, we can use that to solve the problem.
        Otherwise, we can use DOcplexcloud. For docloud solve, we need valid 'url' and 'key'.
        Note, that if 'url' and 'key' parameters are present,
        the solve will be started on DOcplexcloud even if CPLEX is available.
            e.g. this forces the solve on DOcplexcloud:
            model.solve(url='https://foo.com', key='bar')

        Using 'docplex.mp.context.Context', it is possible to control how to solve.
        """

        if model_params['write_lp']:
            logger.info('Writing the lp file!')
            self.model.export_as_lp('./{}.lp'.format(self.model.name))

        ctx = Context()
        ctx.solver.docloud.url = model_params['url']
        ctx.solver.docloud.key = model_params['api_key']
        agent = 'docloud' if model_params['cplex_cloud'] else 'local'

        # There are several ways to set the parameters. Here are two ways:
        # method 1:
        if model_params['mip_gap']:
            self.model.parameters.mip.tolerances.mipgap = model_params[
                'mip_gap']
        if model_params['time_limit']:
            self.model.set_time_limit(model_params['time_limit'])

        # # method 2:
        # cplex_parameters = {'mip.tolerances.mipgap': model_params['mip_gap'],
        #                     'timelimit': model_params['time_limit']}
        # ctx.update(cplex_parameters, create_missing_nodes=True)

        logger.info('Optimization starts!')
        if model_params['write_log']:
            with open("cplex.log", "w") as outs:
                # prints CPLEX output to file "cplex.log"
                self.model.solve(context=ctx, agent=agent, log_output=outs)
        else:
            self.model.solve(context=ctx,
                             agent=agent,
                             log_output=model_params['display_log'])

        if self.model.solve_details.status == 'optimal':
            logger.info('The solution is optimal and the objective value '
                        'is ${:,.2f}!'.format(self.model.objective_value))
Example #2
0
def run_command(prog, argv, url=None, key=None):
    description = '''Command line client for DOcplexcloud.'''
    epilog = '''Command details:
  info           Get and display information for the jobs which ids are
                 specified as ARG.
  download       Download the attachment to the the current directory.
  rm             Delete the jobs which ids are specfied as ARG.
  rm all         Delete all jobs.
  logs           Download and display the logs for the jobs which id are specified.
  ls             Lists the jobs.'''
    epilog_cli = '''
  execute        Submit a job and wait for end of execution. Each ARG that
                 is a file is uploaded as the job input. Example:
                    Example: python run.py execute model.py model.data -v
                      executes a job which input files are model.py and
                      model.dada, in verbose mode.
'''
    filter_help = '''

   Within filters, the following variables are defined:
      now: current date and time as timestamp in millisec
      minute: 60 sec in millisec
      hour: 60 minutes in millisec
      day: 24 hour in millisec
      job: The current job being filtered

    Example filter usage:
        Delete all jobs older than 3 hour
        python -m docplex.cli --filter "now-job['startedAt'] > 3*hour " rm
'''
    if ip is None:
        epilog += epilog_cli
    epilog += filter_help
    parser = argparse.ArgumentParser(prog=prog, description=description, epilog=epilog,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('command',
                        metavar='COMMAND',
                        help='DOcplexcloud command')
    parser.add_argument('arguments', metavar='ARG', nargs='*',
                        help='Arguments for the command')
    parser.add_argument('--no-delete', action='store_true', default=False,
                        dest='nodelete',
                        help="If specified, jobs are not deleted after execution")
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='Verbose mode')
    parser.add_argument('--as', nargs=1, metavar='HOST',
                        dest="host_config", default=None,
                        help="'as host' - use the cplex_config_<HOST>.py configuration file found in PYTHONPATH")
    parser.add_argument('--url', nargs=1, metavar='URL',
                        dest="url", default=None,
                        help="The DOcplexcloud connection URL. If not specified, will use those found in docplex config files")
    parser.add_argument('--key', nargs=1, metavar='API_KEY',
                        dest="key", default=None,
                        help="The DOcplexcloud connection key. If not specified, will use those found in docplex config files")
    parser.add_argument('--details', action='store_true', default=False,
                        help='Display solve details as they are available')
    parser.add_argument('--filter', metavar='FILTER',  default=None,
                        help='filter on job. Example: --filter "True if (now-job.createdAt) > 3600"')
    parser.add_argument('--quiet', '-q', action='store_true', default=False,
                        help='Only show numeric IDs as output')
    args = parser.parse_args(argv)

    program_result = ProgramResults()

    # Get the context here so that we have some credentials at hand
    context = Context.make_default_context()

    if args.host_config is not None:
        config_name = "cplex_config_%s.py" % args.host_config[0]
        config_file = list(filter(os.path.isfile, [os.path.join(x, config_name) for x in sys.path]))
        if len(config_file) == 0:
            print("Could not find config file for host: %s" % args.host_config[0])
            program_result.return_code = -1
            return(program_result)
        if args.verbose:
            print("Overriding host config with: %s" % config_file[0])
        context.read_settings(config_file[0])

    # use credentials in context unless they are given to this function
    client_url = context.solver.docloud.url if url is None else url
    client_key = context.solver.docloud.key if key is None else key
    # but if there are some credentials in arguments (--url, --key), use them
    if args.url:
        client_url = args.url
    if args.key:
        client_key = args.key
    if args.verbose:
        print('**** Connecting to %s with key %s' % (client_url, client_key))
        print('Will send command %s' % args.command)
        print('Arguments:')
        for i in args.arguments:
            print('  -> %s' % i)
        print('verbose = %s' % args.verbose)

    client = JobClient(client_url, client_key)

    target_jobs = []
    if args.filter:
        jobs = client.get_all_jobs()
        now = (datetime.datetime.now() - datetime.datetime(1970,1,1)).total_seconds() * 1000.0
        minute = 60 * 1000
        hour = 60 * minute
        day = 24 * hour
        context = {'now': now,
                   'minute': minute,
                   'hour': hour,
                   'day': day,
                  }
        for j in jobs:
            context['job'] = j
            keep = False
            try:
                keep = eval(args.filter, globals(), context)
            except KeyError:  # if a key was not foud, just assume expression is false
                keep = False
            if keep:
                target_jobs.append(j)

    if target_jobs:
        for i in target_jobs:
            print('applying to %s' % i['_id'])

    if args.command == 'ls':
        ls_jobs(client, program_result, quiet=args.quiet, selected_jobs=target_jobs)
    elif args.command == 'info':
        if target_jobs:
            args.arguments = [x["_id"] for x in target_jobs]
        elif len(args.arguments) == 1 and args.arguments[0] == 'all':
            args.arguments = [x["_id"] for x in client.get_all_jobs()]
        for id in args.arguments:
            info_text = "NOT FOUND"
            try:
                job = client.get_job(id)
                info_text = json.dumps(job, indent=3)
            except:
                pass
            print("%s:\n%s" % (id, info_text))
    elif args.command == 'rm':
        if target_jobs:
            joblist = [x["_id"] for x in target_jobs]
        elif args.arguments:
            joblist = args.arguments
        else:
            joblist = shlex.split(sys.stdin.read())
        rm_job(client, joblist, verbose=args.verbose)
    elif args.command == 'logs':
        if target_jobs:
            if len(target_jobs) != 1:
                print('Logs can only be retrieved when filter select one job (actual selection count = %s)' % len(target_jobs))
                program_result.return_code = -1
                return(program_result)
            args.arguments = [x["_id"] for x in target_jobs]
        if not args.arguments:
            print('Please specify job list in arguments or using filter.')
            program_result.return_code = -1
            return(program_result)
        for jid in args.arguments:
            log_items = client.get_log_items(jid)
            for log in log_items:
                for record in log["records"]:
                    print(record["message"])
    elif args.command == 'download':
        if target_jobs:
            if len(target_jobs) != 1:
                print('Jobs can only be downloaded when filter select one job (actual selection count = %s)' % len(target_jobs))
                program_result.return_code = -1
                return(program_result)
            args.arguments = [x["_id"] for x in target_jobs]
        for jid in args.arguments:
            job = client.get_job(jid)
            for attachment in job['attachments']:
                print('downloading %s' % attachment['name'])
                with open(attachment['name'], 'wb') as f:
                    f.write(client.download_job_attachment(id, attachment['name']))
    elif args.command == 'execute':
        if target_jobs:
            print('Execute command does not support job filtering')
            program_result.return_code = -1
            return(program_result)
        inputs = [{'name': basename(a), 'filename': a} for a in args.arguments]
        if args.verbose:
            for i in inputs:
                print("Uploading %s as attachment name %s" % (i['filename'], i['name']))
        execute_job(client, inputs, args.verbose, args.details, args.nodelete)
    else:
        print("Unknown command: %s" % args.command)
        program_result.return_code = -1
        return(program_result)
    return(program_result)
    def get(self):

        global communities
        global policeDistricts
        global distances
        global deployments
        global crimecounts
        global totalCoverage
        global mapCoverage
        global mapCrimes
        global mapDeploys
        global distanceCost
        global fairness
        global n_crimes_per_patrol
        global crimetype_weights

        if (deployments is None) or (communities is None) or (
                policeDistricts is None) or (distances is None) or not loaded:
            return {
                'message': 'No deployment plan loaded.',
                'result': 'failed'
            }

        # Get the passed arguments
        argparser = reqparse.RequestParser()
        argparser.add_argument('useFairness')
        argparser.add_argument('minOnePatrolPerComm')
        args = argparser.parse_args()

        if json.loads(args['useFairness']) == 'yes':
            useFairness = True
        else:
            useFairness = False

        if json.loads(args['minOnePatrolPerComm']) == 'yes':
            minOnePatrolPerComm = True
        else:
            minOnePatrolPerComm = False

        print("Building model...")
        # Create model
        context = Context.make_default_context()
        model = Model(name="CrimeDeployment", context=context)

        print("Creating variables...")
        # Create model variables
        # Assignment of patrols from each district to each community is a separate variable
        deployments_cpx = {}
        deployed_cpx = defaultdict(int)
        ethnicity_count = {0: 0, 1: 0}
        for community in communities:
            comm_id = communities[community]['id']
            deployments_cpx[comm_id] = {'total': 0}
            if (communities[community]['ethnicity']
                    == 0) or (communities[community]['ethnicity'] == 1):
                ethnicity_count[1] += 1
            else:
                ethnicity_count[0] += 1
            for district in policeDistricts:
                dist_id = policeDistricts[district]['id']
                max_patrols = policeDistricts[district]['total_patrols']
                deployments_cpx[comm_id][dist_id] = model.integer_var(
                    lb=0,
                    ub=max_patrols,
                    name="c" + str(comm_id) + "d" + str(dist_id))
                deployed_cpx[dist_id] += deployments_cpx[comm_id][dist_id]
                deployments_cpx[comm_id]['total'] += deployments_cpx[comm_id][
                    dist_id]

        print("Creating constraints...")
        # Add model constraints
        # Sum of deployed units over all communities can't be higher than number of available patrols
        for district in policeDistricts:
            dist_id = policeDistricts[district]['id']
            max_patrols = policeDistricts[district]['total_patrols']
            model.add_constraint(deployed_cpx[dist_id] <= max_patrols)
            model.add_constraint(deployed_cpx[dist_id] >= 0)

        # At least one patrol per community
        if minOnePatrolPerComm:
            for community in communities:
                comm_id = communities[community]['id']
                model.add_constraint(deployments_cpx[comm_id]['total'] >= 1)

        print("Calculating objective...")
        print("     - Crime Coverage")
        # Calculate crime coverage in this deployment
        # We check the coverage, but also apply a penalty for coverages larger than a set threshold
        coverages = []
        totalDeployed = []
        totalCrimes = []
        penalties = []
        ethnicityDeployed = {0: [], 1: []}
        for community in communities:
            if crimecounts[communities[community]
                           ['code']]['weighted_count'] != 0:
                coverage = ((deployments_cpx[community]['total'] *
                             n_crimes_per_patrol) /
                            crimecounts[communities[community]
                                        ['code']]['weighted_count'])
                coverages.append(coverage)
                penalty = model.max(
                    0, coverage - (upper_penalty_threshold / 100)) + model.max(
                        0, (lower_penalty_threshold / 100) - coverage)
                penalties.append(penalty)
                totalDeployed.append(deployments_cpx[community]['total'] *
                                     n_crimes_per_patrol)
                totalCrimes.append(crimecounts[communities[community]['code']]
                                   ['weighted_count'])
                if (communities[community]['ethnicity']
                        == 0) or (communities[community]['ethnicity'] == 1):
                    ethnicityDeployed[1].append(
                        deployments_cpx[community]['total'])
                else:
                    ethnicityDeployed[0].append(
                        deployments_cpx[community]['total'])

        avg_coverage = sum(coverages) / len(coverages)
        avg_penalty = sum(penalties) / len(penalties)
        citywideCoverage = sum(totalDeployed) / sum(totalCrimes)
        citywidePenalty = model.max(
            0, citywideCoverage - (upper_penalty_threshold / 100)) + model.max(
                0, (lower_penalty_threshold / 100) - citywideCoverage)
        fairness = model.abs((sum(ethnicityDeployed[0]) / ethnicity_count[0]) -
                             (sum(ethnicityDeployed[1]) / ethnicity_count[1]))

        print("     - Distances")
        # Calculate the distances units have to drive to fulfill deployments
        distances_cpx = []
        for comm in deployments_cpx:
            for dist in deployments_cpx[comm]:
                if (dist != 'total'):
                    distance = distances[(dist,
                                          comm)] * deployments_cpx[comm][dist]
                    distances_cpx.append(distance)
        distanceCost_cpx = sum(distances_cpx)

        print("     - Combined Objective")
        # Now build the objective function
        obj = 1000000000 * citywidePenalty - 1000000000 * citywideCoverage + 1000000 * avg_penalty - 100000 * avg_coverage + distanceCost_cpx
        if useFairness:
            print("     - Add Fairness Statistic to Combined Objective")
            # Add model objective
            # First calculate the fairness of the deployment
            obj = 10000 * fairness + obj

        #model.add(maximize(obj))
        model.minimize(obj)

        print("Adding KPIs...")
        # Add the KPIs we're interested in tracking
        model.add_kpi(citywideCoverage, publish_name="City-wide Coverage")
        model.add_kpi(citywidePenalty,
                      publish_name="City-wide Coverage Penalty")
        model.add_kpi(avg_coverage, publish_name="Avg. Coverage")
        model.add_kpi(avg_penalty, publish_name="Avg. Coverage Penalty")
        model.add_kpi(distanceCost_cpx, publish_name="Total Distance")
        if useFairness:
            model.add_kpi(fairness,
                          publish_name="Fairness Simple Mean Difference")
        model.add_kpi(obj, publish_name="Combined Objective")

        print("Model ready:")
        model.print_information()

        print("Solving problem...")
        # Solve the problem
        msol = model.solve()

        print("Done! Getting results...")
        # Get result from solve
        # if msol.solve_details['status']:
        #     return {'solve_status':msol.get_solve_status(),'message':'Optimization executed but aborted due to exceeding maximum run time.','result':'failed'}

        # Get solution and place in deployments
        model.report()
        print(msol.solve_details)

        # First reset any plan existing in memory and its KPIs
        deployments = {}
        mapCoverage = {}
        mapDeploys = {}
        totalCoverage = 0
        distanceCost = 0
        fairness = 0
        for pd in db.session.query(PoliceDistrict):
            policeDistricts[pd.id] = {
                'id': pd.id,
                'name': pd.name,
                'total_patrols': pd.patrols,
                'available_patrols': pd.patrols,
                'deployed_patrols': 0
            }

        for community in communities:
            comm_id = communities[community]['id']
            deployments[comm_id] = defaultdict(int)
            deployments[comm_id]['total'] = 0
            for district in policeDistricts:
                dist_id = policeDistricts[district]['id']
                n_patrols = msol['c' + str(comm_id) + 'd' + str(dist_id)]
                deployments[comm_id][dist_id] += n_patrols
                deployments[comm_id]['total'] += n_patrols
                policeDistricts[dist_id]['available_patrols'] -= n_patrols
                policeDistricts[dist_id]['deployed_patrols'] += n_patrols
                if crimecounts[communities[comm_id]
                               ['code']]['weighted_count'] != 0:
                    mapCoverage[communities[comm_id]['code']] = ((deployments[comm_id]['total']*n_crimes_per_patrol)/ \
                                                                crimecounts[communities[comm_id]['code']]['weighted_count'])*100
                else:
                    mapCoverage[communities[comm_id]['code']] = 0
                mapDeploys[communities[comm_id]
                           ['code']] = deployments[comm_id]['total']
                distanceCost += n_patrols * distances[(dist_id, comm_id)]

        # Calculate the total coverage of Crimes
        totalcrimes = 0
        totaldeploys = 0
        for comm in deployments:
            totalcrimes += crimecounts[communities[comm]
                                       ['code']]['weighted_count']
            totaldeploys += deployments[comm]['total']
            totalCoverage = (
                (totaldeploys * n_crimes_per_patrol) / totalcrimes) * 100

        # Calculate the deployment Fairness
        # First calculate the t-statistic
        t_stat, df = calculateFairnessTStat(communities, deployments)
        # Now assign the p-value as the fairness
        fairness = (1 - t.cdf(abs(t_stat), df)) * 2
        # Convert to percentage value
        fairness = fairness * 100

        return {
            'communities': communities,
            'districts': policeDistricts,
            'mapCoverage': mapCoverage,
            'mapCrimes': mapCrimes,
            'mapDeploys': mapDeploys,
            'distanceCost': distanceCost,
            'fairness': fairness,
            'totalCoverage': totalCoverage,
            'solve_status': msol.solve_details.status,
            'message': 'Optimization executed succesfully.',
            'result': 'success'
        }
    return mdl.objective_value


if __name__ == '__main__':
    """DOcloud credentials can be specified with url and api_key in the code block below.

    Alternatively, Context.make_default_context() searches the PYTHONPATH for
    the following files:

        * cplex_config.py
        * cplex_config_<hostname>.py
        * docloud_config.py (must only contain context.solver.docloud configuration)

    These files contain the credentials and other properties. For example,
    something similar to::

       context.solver.docloud.url = "https://docloud.service.com/job_manager/rest/v1"
       context.solver.docloud.key = "example api_key"
    """
    url = None
    key = None
    ctx = Context.make_default_context(url=url, key=key)
    ctx.solver.docloud.print_information()

    from docplex.mp.environment import Environment

    env = Environment()
    env.print_information()

    solve_sports(context=ctx)
Example #5
0
def ilp(graph, num_buses, size_bus, constraints):
    edges = graph.edges()
    buses = range(0, num_buses)
    num_students = graph.nodes()

    cxt = Context.make_default_context()
    cxt.timeout = 1
    with Model(name="solver", context=cxt) as mdl:
        X_dict = {}
        es = []
        for s in graph.nodes():
            name = "x" + str(s)
            xslist = mdl.binary_var_list(keys=num_buses, name=name)
            X_dict[s] = xslist
        for s in graph.nodes():
            cons = find_student_in_constraints(s, constraints)
            xslist = X_dict[s]
            constraining_values = []
            for b in buses:
                for C in cons:
                    relevant_dvs_names = ["x" + s + "_" + str(b) for s in C]
                    relevant_dvs = [
                        mdl.get_var_by_name(name)
                        for name in relevant_dvs_names
                    ]
                    constraining_values.append(len(C) - mdl.sum(relevant_dvs))
            rs = mdl.integer_var(name="r" + s)
            expr = (rs <= mdl.min(constraining_values))
            mdl.add_constraint(expr)
        for e in edges:
            name = "e" + e[0] + e[1]
            edge_indic = mdl.binary_var_list(keys=num_buses, name=name)
            es.extend(edge_indic)
        obj = mdl.sum(es)
        mdl.set_objective("max", obj)
        for e in edges:
            for b in buses:
                u = e[0]
                v = e[1]
                name = "e" + u + v + "_" + str(b)
                uexists = "x" + u + "_" + str(b)
                vexists = "x" + v + "_" + str(b)
                rsnameu = "r" + u
                rsnamev = "r" + v

                euvi = mdl.get_var_by_name(name)
                xui = mdl.get_var_by_name(uexists)
                xvi = mdl.get_var_by_name(vexists)
                rsu = mdl.get_var_by_name(rsnameu)
                rsv = mdl.get_var_by_name(rsnamev)
                mdl.add_constraint((euvi <= xui))
                mdl.add_constraint((euvi <= xvi))
                mdl.add_constraint((euvi <= rsu))
                mdl.add_constraint((euvi <= rsv))

        for xslist in X_dict.values():
            expr = (mdl.sum(xslist) == 1)
            mdl.add_constraint(expr)

        for b in buses:
            relevant_list = [xslist[b] for xslist in X_dict.values()]
            expr = (mdl.sum(relevant_list) <= size_bus)
            expr2 = (mdl.sum(relevant_list) >= 1)
            mdl.add_constraint(expr)
            mdl.add_constraint(expr2)

        mdl.set_time_limit(90)
        solution = mdl.solve(log_output=True)
        solved = []
        for i in range(0, num_buses):
            solved.append([])
        iterv = solution.iter_var_values()
        v = next(iterv)
        i = 0
        while i < (len(graph.nodes())):
            name = str(v[0])
            index = name.find('_')

            student = name[1:index]
            bus = int(name[index + 1:])
            solved[bus].append(student)

            i += 1
            v = next(iterv)
        print(solved)

        assignment = utils.groups_to_assignment(solved)
        if not (utils.is_valid(graph, num_buses, size_bus, assignment)):
            print('\n')
            print('NEET')
            print('\n')
            return None
        print('yeet')
        return assignment
to_arcs = []
from_arcs = []
for i in Arcs_modified2:
    if (i[1] not in to_arcs):
        to_arcs.append(i[1])
    if (i[0] not in from_arcs):
        from_arcs.append(i[0])

#print(Arcs_modified2)
#print(to_arcs)

# using doCloud Trial version Validity till 18th december
url = "https://api-oaas.docloud.ibmcloud.com/job_manager/rest/v1"
key = "api_b14a53e6-482a-44b7-b1e2-83b44d232ba0"

ctx = Context.make_default_context(url=url, key=key)

# model Objective function and constraints
mdl3 = Model(name='min_distance3', context=ctx)
x = mdl3.binary_var_dict(Arcs_modified2, name='x')
#print(x)
mdl3.minimize(mdl3.sum(c[i, j] * x[i, j] for i, j in Arcs_modified2))
# origin constraint
mdl3.add_constraint(
    mdl3.sum(x[i, j] for i, j in Arcs_modified2 if i == origin) == 1)
#destination constraint
mdl3.add_constraint(
    mdl3.sum(x[i, j] for i, j in Arcs_modified2 if j == destination) == 1)

#flow balancing Eq
for i, j in Arcs_modified2:
Example #7
0
    the following files:

        * cplex_config.py
        * cplex_config_<hostname>.py
        * docloud_config.py (must only contain context.solver.docloud configuration)

    These files contain the credentials and other properties. For example,
    something similar to::

       context.solver.docloud.url = 'https://docloud.service.com/job_manager/rest/v1'
       context.solver.docloud.key = 'example api_key'
    '''
    url = None
    key = None

    if url is None or key is None:
        # create a default context and use credentials defined in there.
        context = Context.make_default_context()
        url = context.solver.docloud.url
        key = context.solver.docloud.key

    client = JobClient(url=url, api_key=key)

    resp = client.execute(input=[
        'diet_pandas.py', 'diet_food.csv', 'diet_nutrients.csv',
        'diet_food_nutrients.csv'
    ],
                          output='solution.json',
                          load_solution=True,
                          log='logs.txt')