예제 #1
0
    def __init__(self, prefix='refData'):

        df = pd.read_csv(os.path.join(prefix, 'TxnCost.txt'),
                         sep=' ',
                         header=None,
                         names=['Code', 'BuyCost', 'SellCost'])

        df['Code'] = df['Code'].astype(str).str.zfill(6)

        #print buyCosts, sellCosts
        self._txnCosts = dict()
        for fundCode, buyCost, sellCost in df.itertuples(index=False):
            self._txnCosts[
                fundCode] = lambda _x, b=buyCost, s=sellCost: cvx.scalene(
                    _x, b / NORMAL_FACTOR, s / NORMAL_FACTOR)
예제 #2
0
                                                       ])),
 (lambda x: cp.power(x, -1), tuple(), [7.45], Constant([0.1342281879194631
                                                        ])),
 (lambda x: cp.power(x, -.7), tuple(), [7.45],
  Constant([0.24518314363015764])),
 (lambda x: cp.power(x, -1.34), tuple(), [7.45],
  Constant([0.06781263100321579])),
 (lambda x: cp.power(x, 1.34), tuple(), [7.45],
  Constant([14.746515290825071])),
 (cp.quad_over_lin, tuple(), [[[-1, 2, -2], [-1, 2, -2]],
                              2], Constant([2 * 4.5])),
 (cp.quad_over_lin, tuple(), [v_np, 2], Constant([4.5])),
 (lambda x: cp.norm(x, 2), tuple(), [[[2, 0], [0, 1]]], Constant([2])),
 (lambda x: cp.norm(x, 2), tuple(), [[[3, 4, 5], [6, 7, 8], [9, 10, 11]]],
  Constant([22.368559552680377])),
 (lambda x: cp.scalene(x, 2, 3), (2, 2), [[[-5, 2], [-3, 1]]],
  Constant([[15, 4], [9, 2]])),
 (cp.square, (2, 2), [[[-5, 2], [-3, 1]]], Constant([[25, 4], [9, 1]])),
 (cp.sum, tuple(), [[[-5, 2], [-3, 1]]], Constant(-5)),
 (lambda x: cp.sum(x, axis=0), (2, ), [[[-5, 2], [-3,
                                                  1]]], Constant([-3, -2])),
 (lambda x: cp.sum(x, axis=1), (2, ), [[[-5, 2], [-3,
                                                  1]]], Constant([-8, 3])),
 (lambda x:
  (x + Constant(0))**2, (2, 2), [[[-5, 2],
                                  [-3, 1]]], Constant([[25, 4], [9, 1]])),
 (lambda x: cp.sum_largest(x, 3), tuple(), [[1, 2, 3, 4,
                                             5]], Constant([5 + 4 + 3])),
 (lambda x: cp.sum_largest(x, 3), tuple(), [[[3, 4, 5], [6, 7, 8],
                                             [9, 10, 11]]],
  Constant([9 + 10 + 11])),
예제 #3
0
def main(datafile=default_data_file,
         namesfile=default_volunteers_file,
         min_staff=5,
         alpha=1.0,
         beta=0.7,
         gamma=0.28,
         verbose=1,
         solver_options=None):
    '''Notação:
	M = min_staff: número mínimo de voluntários por turno.
	i = número (código) da pessoa. vai de 1 a N (talvez 28?)
	j = número (código) do turno.  vai de 1 a T (provavelmente 14)

	A_ij = available[i, j] == True quando pessoa i está disponível no turno j
	P_ij = preference[i, j] == True quando pessoa i tem preferência pelo turno j
	w_i  = prev_week[i] == número de turnos (almoços OU jantas) alocados à pessoa i na semana anterior

	Variável a ser otimizada: Z[i, j] == True quando pessoa i é alocada para colaborar no turno j.

	Variável auxiliar: L_i = load[i] == sum_j Z[i, j] == (soma da linha i de Z) == número de turnos alocados pra pessoa i.

	OBJETIVO: minimizar o máximo dos load[i], conforme disponibilidade das pessoas, orientando-se também pelas preferências.

	* Por enquanto, não estamos usando `preference` e `prev_week`, já que poucos usaram esses recursos na planilha.
	'''
    table_string = read_data(datafile)
    names_string = read_data(namesfile)
    available, preference, prev_week, managers = data_to_array(
        table_string, names_string)
    N, T = available.shape

    Z = cp.Variable((N, T), name="Z", boolean=True)

    if verbose >= 1:
        print(
            "# Programa de otimização linear com variáveis inteiras (MIP)\n\nDados de Entrada:"
        )
        print("\n[Array: AVAILABLE]", 0 + available, sep="\n", end="\n\n")
        print("\n[Array: PREFERENCE]", 0 + preference, sep="\n", end="\n\n")

    # load[i] == 'número de turnos alocados para a pessoa i' == sum(Z[i,j] para cada j)
    load = cp.sum(Z, axis=1)

    # Variável para induzir a preferência de soluções sem muita gente contribuindo em um só turno do dia:
    same_day = cp.Variable((N, T // 2))

    constraints = [
        # Sempre que A_ij==0, impõe-se Z_ij==0:
        Z <= available,

        # Somatório em i (somatório de cada coluna) deve ser, no mínimo, min_staff:
        cp.sum(Z, axis=0) == min_staff,

        # Restrição para garantir a presença de no mínimo um dos `responsáveis` (managers) a cada turno:
        cp.sum(Z[managers, :], axis=0) >= 1,

        # Forma matricial das desigualdades same_day[:, j//2] <= min(Z[:, j], Z[:, j+1]), com j em (0, 2, 4, ..., T-2):
        same_day <= Z[:, 0::2],
        same_day <= Z[:, 1::2]
    ]

    # Expressão para a carga média por pessoa, usando a igualdade cp.sum(load) == cp.sum(Z):
    mean_load = cp.sum(Z) / N

    # Função Objetivo (função a ser MINIMIZADA):
    load_cost = cp.norm_inf(load)  # máximo das entradas do vetor `load`

    # PENALTY_1 DESATIVADO (substituído por zero), vide restrição `Z <= available` acima.
    penalty_1 = cp.Constant(
        0
    )  # alpha * cp.sum(cp.pos(Z - available))  # penalizava-se alpha para cada entrada Z[i,j] > available[i,j].
    penalty_2 = beta * cp.sum(
        cp.scalene(load - mean_load, 1.8, 1.0)
    )  # penalizar cada load[i] longe da média (especialmente acima da média)
    same_day_bonus = gamma * cp.sum(same_day)

    objective = cp.Minimize(
        load_cost + penalty_1 + penalty_2 - same_day_bonus
    )  # minimize ('máximo das entradas' do vetor load) + penalidades
    problem = cp.Problem(
        objective,
        constraints)  # <= problema de otimização sujeito às restrições acima.

    if verbose >= 1:
        print("# Solucionando problema de otimização.")

    if solver_options is None:
        solver_options = {"verbose": (verbose >= 2)}
    elif "TimeLimit" in solver_options:
        # GAMBIARRA: "cvxpy throws error when Gurobi solver encounters time limit"
        cp.settings.ERROR = [cp.settings.USER_LIMIT]
        cp.settings.SOLUTION_PRESENT = [
            cp.settings.OPTIMAL, cp.settings.OPTIMAL_INACCURATE,
            cp.settings.SOLVER_ERROR
        ]
        # CONFERIR: https://github.com/cvxgrp/cvxpy/issues/735

    if verbose >= 2: print("\n", "# # # # # " * 9, "\n", sep="")
    problem.solve(solver=cp.GUROBI, **solver_options)
    if verbose >= 2: print("\n", "# # # # # " * 9, "\n", sep="")

    results_dict = {
        "alpha": alpha,
        "beta": beta,
        "gamma": gamma,
        "Z": Z,
        "Z_array": None,
        "objective": objective,
        "constraints": constraints,
        "problem": problem,
        "load": load,
        "load_cost": load_cost,
        "penalty_1": penalty_1,
        "penalty_2": penalty_2,
        "same_day_bonus": same_day_bonus
    }

    if results_dict["Z"] is not None:
        results_dict["Z_array"] = np.asarray(Z.value + 0.1, dtype=int)
        if problem.status != cp.OPTIMAL:
            print(
                "# WARNING. Talvez tenha atingido o tempo limite sem otimalidade?"
            )
            print("Status do problema: {}".format(problem.status))
        if verbose: show_results(results_dict)

    else:
        print("# ERRO: o solver não encontrou uma solução!")
        print("Status do problema: {}".format(problem.status))
        print("# Para as disponibilidades dadas, talvez não seja")
        print("# possível obter `min_staff` pessoas por turno?")

    return results_dict
예제 #4
0
    (cp.neg, (2,), [[-3, 3]], Constant([3, 0])),


    (lambda x: cp.power(x, 1), tuple(), [7.45], Constant([7.45])),
    (lambda x: cp.power(x, 2), tuple(), [7.45], Constant([55.502500000000005])),
    (lambda x: cp.power(x, -1), tuple(), [7.45], Constant([0.1342281879194631])),
    (lambda x: cp.power(x, -.7), tuple(), [7.45], Constant([0.24518314363015764])),
    (lambda x: cp.power(x, -1.34), tuple(), [7.45], Constant([0.06781263100321579])),
    (lambda x: cp.power(x, 1.34), tuple(), [7.45], Constant([14.746515290825071])),

    (cp.quad_over_lin, tuple(), [[[-1, 2, -2], [-1, 2, -2]], 2], Constant([2 * 4.5])),
    (cp.quad_over_lin, tuple(), [v_np, 2], Constant([4.5])),
    (lambda x: cp.norm(x, 2), tuple(), [[[2, 0], [0, 1]]], Constant([2])),
    (lambda x: cp.norm(x, 2), tuple(),
     [[[3, 4, 5], [6, 7, 8], [9, 10, 11]]], Constant([22.368559552680377])),
    (lambda x: cp.scalene(x, 2, 3), (2, 2), [[[-5, 2], [-3, 1]]], Constant([[15, 4], [9, 2]])),
    (cp.square, (2, 2), [[[-5, 2], [-3, 1]]], Constant([[25, 4], [9, 1]])),
    (cp.sum, tuple(), [[[-5, 2], [-3, 1]]], Constant([-5])),
    (lambda x: cp.sum(x, axis=0), (2,), [[[-5, 2], [-3, 1]]], Constant([-3, -2])),
    (lambda x: cp.sum(x, axis=1), (2,), [[[-5, 2], [-3, 1]]], Constant([-8, 3])),
    (lambda x: (x + Constant(0))**2, (2, 2), [[[-5, 2], [-3, 1]]], Constant([[25, 4], [9, 1]])),
    (lambda x: cp.sum_largest(x, 3), tuple(), [[1, 2, 3, 4, 5]], Constant([5 + 4 + 3])),
    (lambda x: cp.sum_largest(x, 3), tuple(),
     [[[3, 4, 5], [6, 7, 8], [9, 10, 11]]], Constant([9 + 10 + 11])),
    (cp.sum_squares, tuple(), [[[-1, 2], [3, -4]]], Constant([30])),
    (cp.trace, tuple(), [[[3, 4, 5], [6, 7, 8], [9, 10, 11]]], Constant([3 + 7 + 11])),
    (cp.trace, tuple(), [[[-5, 2], [-3, 1]]], Constant([-5 + 1])),
    (cp.tv, tuple(), [[1, -1, 2]], Constant([5])),
    (cp.tv, tuple(), [[1, -1, 2]], Constant([5])),
    (cp.tv, tuple(), [[[-5, 2], [-3, 1]]], Constant([math.sqrt(53)])),
    (cp.tv, tuple(), [[[-5, 2], [-3, 1]], [[6, 5], [-4, 3]], [[8, 0], [15, 9]]],
예제 #5
0
import os.path
import pandas as pd
import cvxpy as cvx

__all__ = ['fundTransactionCost']

DEFAULT_BUYCOST = 0.12
DEFAULT_SELLCOST = 0.5
NORMAL_FACTOR = 100.

defaultTxnCost = lambda _x: cvx.scalene(_x, DEFAULT_BUYCOST / NORMAL_FACTOR,
                                        DEFAULT_SELLCOST / NORMAL_FACTOR)


class FundTransactionCostLoader(object):
    def __init__(self, prefix='refData'):

        df = pd.read_csv(os.path.join(prefix, 'TxnCost.txt'),
                         sep=' ',
                         header=None,
                         names=['Code', 'BuyCost', 'SellCost'])

        df['Code'] = df['Code'].astype(str).str.zfill(6)

        #print buyCosts, sellCosts
        self._txnCosts = dict()
        for fundCode, buyCost, sellCost in df.itertuples(index=False):
            self._txnCosts[
                fundCode] = lambda _x, b=buyCost, s=sellCost: cvx.scalene(
                    _x, b / NORMAL_FACTOR, s / NORMAL_FACTOR)