pythonoptimizationmathematical-optimizationbrute-force

Multiaxis System of Equations Optimizations in Python


My System is as follows:

Optimize the value of O_t based on each value of L_t from 1 to 240 according to the below equations.

O_t = O1+O2+O3+O4
O1= LS1+3×D
O2=3×LS2+4×S
O3=S+3×D
O4= LS4×4+7×D
L_t = LS1+LS2+LS3+LS4+LS5+LS6
L_t = (S+D)/5

Desired outputs: Values of S, D, LS1, LS2, LS3, LS4, LS5, LS6 that result in the highest possible value of O_t for each value of L_t

Constraints:

  1. Variable to be maximized is O_t
  2. LS1, LS2, LS3, LS4, LS5, LS6, S, and D must all be whole numbers.
  3. LS1+LS2+LS3+LS4+LS5+LS6=L_t
  4. O_t=O1+O2+O3+O4
  5. output prints optimal values of LS1, LS2, LS3, LS4, LS5, LS6, S, and D for each value of L_t
  6. output in the form of a table
  7. L_t<15 then LS1,2,3,4,5,6 cannot exceed 5 L_t<30 then LS1,2,3,4,5,6 cannot exceed 10 L_t<50 then LS1,2,3,4,5,6 cannot exceed 15 L_t<60 then LS1,2,3,4,5,6 cannot exceed 17 L_t<90 then LS1,2,3,4,5,6 cannot exceed 20 L_t<120 then LS1,2,3,4,5,6 cannot exceed 25 L_t<150 then LS1,2,3,4,5,6 cannot exceed 30 L_t<180 then LS1,2,3,4,5,6 cannot exceed 35 L_t<210 then LS1,2,3,4,5,6 cannot exceed 40 L_t<240 then LS1,2,3,4,5,6 cannot exceed 45

How I am currently attempting to solve the system of equations: Optimized brute force. Generate a list of all possible S, D, and LS1-6 values, calculate O_t, and check against the previous maximum.

My code currently works (I am assuming since has been tested on smaller numbers and works well) but takes multiple days of running to solve for any large numbers. Here is my current code optimized as much as I can.

import numpy as np
import numba as nb
from tqdm import tqdm


@nb.njit
def calculate_O(LS1, LS2, LS3, LS4, LS5, LS6, S, D):
    O1 = LS1 + 3 * D
    O2 = 3 * LS2 + 4 * S
    O3 = S + 3 * D
    O4 = LS4 * 4 + 7 * D
    return O1 + O2 + O3 + O4


@nb.njit
def find_optimal_value(L_t, possible_S_values, possible_D_values):
    max_O = -np.inf
    max_LS1 = 0
    max_LS2 = 0
    max_LS3 = 0
    max_LS4 = 0
    max_LS5 = 0
    max_LS6 = 0
    max_S = 0
    max_D = 0

    LS1_init = 11
    LS2_init = 11
    LS3_init = 11
    LS4_init = 11
    LS5_init = 11
    LS6_init = 11
    S_init = 2
    D_init = 0

    if L_t < 15:
        LS_max = 5
    elif L_t < 30:
        LS_max = 10
    elif L_t < 50:
        LS_max = 15
    elif L_t < 60:
        LS_max = 17
    elif L_t < 90:
        LS_max = 20
    elif L_t < 120:
        LS_max = 25
    elif L_t < 150:
        LS_max = 30
    elif L_t < 180:
        LS_max = 35
    elif L_t < 210:
        LS_max = 40
    elif L_t < 240:
        LS_max = 45

    for LS1 in range(L_t + 1):
        if LS1 > LS_max:
            continue
        if LS1 + LS1_init > 50:
            continue
        for LS2 in range(L_t + 1 - LS1):
            if LS2 > LS_max:
                continue
            if LS2 + LS2_init > 50:
                continue
            for LS3 in range(L_t + 1 - LS1 - LS2):
                if LS3 > LS_max:
                    continue
                if LS3 + LS3_init > 50:
                    continue
                for LS5 in range(L_t + 1 - LS1 - LS2 - LS3):
                    if LS5 > LS_max:
                        continue
                    if LS5 + LS5_init > 50:
                        continue
                    for LS6 in range(L_t + 1 - LS1 - LS2 - LS3 - LS5):
                        if LS6 > LS_max:
                            continue
                        if LS6 + LS6_init > 50:
                            continue
                        LS4 = L_t - LS1 - LS2 - LS3 - LS5 - LS6
                        if LS4 > LS_max:
                            continue
                        if LS4 + LS4_init > 50:
                            continue
                        for S in possible_S_values:
                            D = 5 * L_t - S
                            if D < 0:
                                break
                            if S > 5 * L_t:
                                continue
                            if LS4 >= 0 and S >= 0 and LS1 + LS2 + LS3 + LS4 + LS5 + LS6 == L_t:
                                O = calculate_O(LS1+LS1_init, LS2+LS2_init, LS3+LS3_init, LS4+LS4_init, LS5+LS5_init, LS6+LS6_init, S+S_init, D+D_init)
                                if O > max_O:
                                    max_O = O
                                    max_LS1 = LS1
                                    max_LS2 = LS2
                                    max_LS3 = LS3
                                    max_LS4 = LS4
                                    max_LS5 = LS5
                                    max_LS6 = LS6
                                    max_S = S
                                    max_D = D
    return (max_LS1+LS1_init, max_LS2+LS2_init, max_LS3+LS3_init, max_LS4+LS4_init, max_LS5+LS5_init, max_LS6+LS6_init, max_S+S_init, max_D+D_init, max_O)


L_t_values = range(1, 100)

optimal_values = {}

for L_t in tqdm(L_t_values):
    possible_S_values = np.arange(0, 5 * L_t + 1)
    possible_D_values = np.arange(0, 5 * L_t + 1)
    max_LS1, max_LS2, max_LS3, max_LS4, max_LS5, max_LS6, max_S, max_D, max_O = find_optimal_value(L_t, possible_S_values, possible_D_values)
    optimal_values[L_t] = {'LS1': max_LS1, 'LS2': max_LS2, 'LS3': max_LS3, 'LS4': max_LS4, 'LS5': max_LS5,'LS6': max_LS6, 'S': max_S, 'D': max_D, 'O_t': max_O}
                                                                                                                                        
print('{:<5s}{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}'.format('L_t', 'LS1', 'LS2', 'LS3', 'LS4', 'LS5', 'LS6', 'S', 'D', 'O_t'))
for L_t in L_t_values:
    values = optimal_values[L_t]
    print('{:<5d}{:<10d}{:<10d}{:<10d}{:<10d}{:<10d}{:<10d}{:<10d}{:<10d}{:<10.2f}'.format(L_t, values['LS1'], values['LS2'], values['LS3'], values['LS4'], values['LS5'], values['LS6'], values['S'], values['D'], values['O_t']))

Note: this isn't for a class so any module for optimization is on the table as well as any other language - as long as it accurately completes the task in a reasonable timeframe.


Solution

  • Do not brute-force this problem. This is a classic (and somewhat easy) linear programming problem.

    Your written constraints fail to mention that L, S and D have a lower bound of 0, and S and D have an upper bound of 5Lt. If these constraints are not enforced then the problem is unbounded.

    You have not specified the upper bound of LS when L_t == 240. I assume that it continues the trend and is 50.

    The following executes in 0.08 s. It should not take "multiple days" nor should it take multiple minutes.

    import pandas as pd
    import pulp
    
    '''
    O_t = O1+O2+O3+O4
    O1= LS1+3×D
    O2=3×LS2+4×S
    O3=S+3×D
    O4= LS4×4+7×D
    L_t = LS1+LS2+LS3+LS4+LS5+LS6
    L_t = (S+D)/5
    
    Variable to be maximized is O_t
    LS1, LS2, LS3, LS4, LS5, LS6, S, and D must all be whole numbers.
    LS1+LS2+LS3+LS4+LS5+LS6=L_t
    O_t=O1+O2+O3+O4
    output prints optimal values of LS1, LS2, LS3, LS4, LS5, LS6, S, and D for each value of L_t
    
    L_t<15 then LS1,2,3,4,5,6 cannot exceed 5
    L_t<30 then LS1,2,3,4,5,6 cannot exceed 10
    L_t<50 then LS1,2,3,4,5,6 cannot exceed 15
    L_t<60 then LS1,2,3,4,5,6 cannot exceed 17
    L_t<90 then LS1,2,3,4,5,6 cannot exceed 20
    L_t<120 then LS1,2,3,4,5,6 cannot exceed 25
    L_t<150 then LS1,2,3,4,5,6 cannot exceed 30
    L_t<180 then LS1,2,3,4,5,6 cannot exceed 35
    L_t<210 then LS1,2,3,4,5,6 cannot exceed 40
    L_t<240 then LS1,2,3,4,5,6 cannot exceed 45
    '''
    
    pd.set_option('display.max_columns', None)
    
    df = pd.DataFrame(index=pd.RangeIndex(start=1, stop=241, name='L_t'))
    
    maxima = pd.Series(
        name='L_smax',
        index=pd.Index(name='L_t', data=(
             15, 30, 50, 60, 90, 120, 150, 180, 210, 240, 270)),
        data=(5, 10, 15, 17, 20,  25,  30,  35,  40,  45,  50))
    df['L_smax'] = pd.merge_asof(
        left=df, right=maxima,
        left_index=True, right_index=True,
        direction='forward', allow_exact_matches=False)
    
    
    def make_L(row: pd.Series) -> pd.Series:
        L_t = row.name
        suffix = f'({L_t:03d})'
        LS1, LS2, LS3, LS4, LS5, LS6 = LS = [
            pulp.LpVariable(name=f'LS{i}{suffix}', cat=pulp.LpInteger, lowBound=0, upBound=row.L_smax)
            for i in range(1, 7)]
        S = pulp.LpVariable(name='S' + suffix, cat=pulp.LpInteger, lowBound=0, upBound=5*L_t)
        D = pulp.LpVariable(name='D' + suffix, cat=pulp.LpInteger, lowBound=0, upBound=5*L_t)
        O1 = LS1 + 3*D
        O2 = 3*LS2 + 4*S
        O3 = S + 3*D
        O4 = 4*LS4 + 7*D
        O_t = O1 + O2 + O3 + O4
    
        prob.addConstraint(name='L_tsum' + suffix, constraint=L_t == pulp.lpSum(LS))
        prob.addConstraint(name='L_tSD' + suffix, constraint=L_t*5 == S + D)
    
        return pd.Series(
            data=(*LS, S, D, O_t),
            index=('LS1', 'LS2', 'LS3', 'LS4', 'LS5', 'LS6', 'S', 'D', 'O_t'))
    
    
    prob = pulp.LpProblem(name='multiaxis', sense=pulp.LpMaximize)
    df = pd.concat((df, df.apply(make_L, axis=1)), axis=1)
    prob.objective = pulp.lpSum(df.O_t)
    
    print(df)
    print()
    print(prob)
    prob.solve()
    assert prob.status == pulp.LpStatusOptimal
    
    result = pd.concat((
        df.L_smax,
        df.iloc[:, 1:-1].applymap(pulp.LpVariable.value),
        df.O_t.apply(pulp.LpAffineExpression.value),
    ), axis=1)
    
    with pd.option_context('display.max_rows', None):
        print(result)
    
         L_smax       LS1       LS2       LS3       LS4       LS5       LS6  \
    L_t                                                                       
    1         5  LS1(001)  LS2(001)  LS3(001)  LS4(001)  LS5(001)  LS6(001)   
    2         5  LS1(002)  LS2(002)  LS3(002)  LS4(002)  LS5(002)  LS6(002)   
    3         5  LS1(003)  LS2(003)  LS3(003)  LS4(003)  LS5(003)  LS6(003)   
    4         5  LS1(004)  LS2(004)  LS3(004)  LS4(004)  LS5(004)  LS6(004)   
    5         5  LS1(005)  LS2(005)  LS3(005)  LS4(005)  LS5(005)  LS6(005)   
    ..      ...       ...       ...       ...       ...       ...       ...   
    236      45  LS1(236)  LS2(236)  LS3(236)  LS4(236)  LS5(236)  LS6(236)   
    237      45  LS1(237)  LS2(237)  LS3(237)  LS4(237)  LS5(237)  LS6(237)   
    238      45  LS1(238)  LS2(238)  LS3(238)  LS4(238)  LS5(238)  LS6(238)   
    239      45  LS1(239)  LS2(239)  LS3(239)  LS4(239)  LS5(239)  LS6(239)   
    240      50  LS1(240)  LS2(240)  LS3(240)  LS4(240)  LS5(240)  LS6(240)   
    
              S       D                                                O_t  
    L_t                                                                     
    1    S(001)  D(001)  {LS1(001): 1, D(001): 13, LS2(001): 3, S(001):...  
    2    S(002)  D(002)  {LS1(002): 1, D(002): 13, LS2(002): 3, S(002):...  
    3    S(003)  D(003)  {LS1(003): 1, D(003): 13, LS2(003): 3, S(003):...  
    4    S(004)  D(004)  {LS1(004): 1, D(004): 13, LS2(004): 3, S(004):...  
    5    S(005)  D(005)  {LS1(005): 1, D(005): 13, LS2(005): 3, S(005):...  
    ..      ...     ...                                                ...  
    236  S(236)  D(236)  {LS1(236): 1, D(236): 13, LS2(236): 3, S(236):...  
    237  S(237)  D(237)  {LS1(237): 1, D(237): 13, LS2(237): 3, S(237):...  
    238  S(238)  D(238)  {LS1(238): 1, D(238): 13, LS2(238): 3, S(238):...  
    239  S(239)  D(239)  {LS1(239): 1, D(239): 13, LS2(239): 3, S(239):...  
    240  S(240)  D(240)  {LS1(240): 1, D(240): 13, LS2(240): 3, S(240):...  
    
    [240 rows x 10 columns]
    multiaxis:
    MAXIMIZE
    13*D(001) + ... + 5*S(239) + 5*S(240) + 0
    SUBJECT TO
    L_tsum(001): LS1(001) + LS2(001) + LS3(001) + LS4(001) + LS5(001) + LS6(001)
     = 1
    ...
    0 <= S(236) <= 1180 Integer
    0 <= S(237) <= 1185 Integer
    0 <= S(238) <= 1190 Integer
    0 <= S(239) <= 1195 Integer
    0 <= S(240) <= 1200 Integer
    
    Welcome to the CBC MILP Solver 
    Version: 2.10.3 
    Build Date: Dec 15 2019 
    
    command line - .venv\lib\site-packages\pulp\solverdir\cbc\win\64\cbc.exe Temp\5c4bdbccaed24aafaf2911972835bd01-pulp.mps max timeMode elapsed branch printingOptions all solution Temp\5c4bdbccaed24aafaf2911972835bd01-pulp.sol (default strategy 1)
    At line 2 NAME          MODEL
    At line 3 ROWS
    At line 485 COLUMNS
    At line 7446 RHS
    At line 7927 BOUNDS
    At line 9848 ENDATA
    Problem MODEL has 480 rows, 1920 columns and 1920 elements
    Coin0008I MODEL read with 0 errors
    Option for timeMode changed from cpu to elapsed
    Continuous objective value is 1.93204e+06 - 0.01 seconds
    Cgl0003I 0 fixed, 66 tightened bounds, 0 strengthened rows, 0 substitutions
    Cgl0004I processed model has 232 rows, 727 columns (727 integer (0 of which binary)) and 727 elements
    Cutoff increment increased from 1e-05 to 0.9999
    Cbc0038I Initial state - 0 integers unsatisfied sum - 5.40012e-13
    Cbc0038I Solution found of -1.93204e+06
    Cbc0038I Cleaned solution of -1.93204e+06
    Cbc0038I Before mini branch and bound, 727 integers at bound fixed and 0 continuous of which 39 were internal integer and 0 internal continuous
    Cbc0038I Mini branch and bound did not improve solution (0.04 seconds)
    Cbc0038I After 0.04 seconds - Feasibility pump exiting with objective of -1.93204e+06 - took 0.00 seconds
    Cbc0012I Integer solution of -1932044 found by feasibility pump after 0 iterations and 0 nodes (0.04 seconds)
    Cbc0001I Search completed - best objective -1932044, took 0 iterations and 0 nodes (0.04 seconds)
    Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost
    Cuts at root node changed objective from -1.93204e+06 to -1.93204e+06
    Probing was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
    Gomory was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
    Knapsack was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
    Clique was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
    MixedIntegerRounding2 was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
    FlowCover was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
    TwoMirCuts was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
    ZeroHalf was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
    
    Result - Optimal solution found
    
    Objective value:                1932044.00000000
    Enumerated nodes:               0
    Total iterations:               0
    Time (CPU seconds):             0.05
    Time (Wallclock seconds):       0.05
    
    Option for printingOptions changed from normal to all
    Total time (CPU seconds):       0.08   (Wallclock seconds):       0.08
    
         L_smax   LS1   LS2   LS3   LS4   LS5   LS6    S       D      O_t
    L_t                                                                  
    1         5   0.0   0.0   0.0   1.0   0.0   0.0  0.0     5.0     69.0
    2         5   0.0   0.0   0.0   2.0   0.0   0.0  0.0    10.0    138.0
    3         5   0.0   0.0   0.0   3.0   0.0   0.0  0.0    15.0    207.0
    ...
    239      45  45.0  45.0  45.0  45.0  14.0  45.0  0.0  1195.0  15895.0
    240      50  50.0  50.0  50.0  50.0   0.0  40.0  0.0  1200.0  16000.0
    

    Initial Conditions

    To model your initial conditions is somewhat easy - just modify the variable bounds and add offsets to some of the affine expressions. However. For any Lt >= 235 the problem is infeasible. Do you see why?

    import pandas as pd
    import pulp
    
    
    pd.set_option('display.max_columns', None)
    
    df = pd.DataFrame(index=pd.RangeIndex(start=1, stop=235, name='L_t'))
    
    maxima = pd.Series(
        name='L_smax',
        index=pd.Index(name='L_t', data=(
             15, 30, 50, 60, 90, 120, 150, 180, 210, 240, 270)),
        data=(5, 10, 15, 17, 20,  25,  30,  35,  40,  45,  50))
    df['L_smax'] = pd.merge_asof(
        left=df, right=maxima,
        left_index=True, right_index=True,
        direction='forward', allow_exact_matches=False)
    
    
    def make_L(row: pd.Series) -> pd.Series:
        L_t = row.name
        suffix = f'({L_t:03d})'
    
        L_init = 11
        S_init = 2
        D_init = 0
    
        LS = [
            pulp.LpVariable(
                name=f'LS{i}{suffix}', cat=pulp.LpInteger, lowBound=0,
                upBound=min(50 - L_init, row.L_smax))
            for i in range(1, 7)]
        S = pulp.LpVariable(name='S' + suffix, cat=pulp.LpInteger, lowBound=0, upBound=5*L_t)
        D = pulp.LpVariable(name='D' + suffix, cat=pulp.LpInteger, lowBound=0, upBound=5*L_t)
    
        prob.addConstraint(name='L_tsum' + suffix, constraint=L_t == pulp.lpSum(LS))
        prob.addConstraint(name='L_tSD' + suffix, constraint=L_t*5 == S + D)
    
        Lo = [L + L_init for L in LS]
        Lo1, Lo2, Lo3, Lo4, Lo5, Lo6 = Lo
        Do = D + D_init
        So = S + S_init
    
        O1 = Lo1 + 3*Do
        O2 = 3*Lo2 + 4*So
        O3 = So + 3*Do
        O4 = 4*Lo4 + 7*Do
        O_t = O1 + O2 + O3 + O4
    
        return pd.Series(
            data=(*Lo, So, Do, O_t),
            index=('LS1', 'LS2', 'LS3', 'LS4', 'LS5', 'LS6', 'S', 'D', 'O_t'))
    
    
    prob = pulp.LpProblem(name='multiaxis', sense=pulp.LpMaximize)
    df = pd.concat((df, df.apply(make_L, axis=1)), axis=1)
    prob.objective = pulp.lpSum(df.O_t)
    
    print(df)
    print()
    print(prob)
    prob.solve()
    assert prob.status == pulp.LpStatusOptimal
    
    result = pd.concat((
        df.L_smax,
        df.iloc[:, 1:].applymap(pulp.LpAffineExpression.value),
    ), axis=1)
    
    with pd.option_context('display.max_rows', None):
        print(result)
    
         L_smax   LS1   LS2   LS3   LS4   LS5   LS6    S       D      O_t
    L_t                                                                  
    1         5  11.0  11.0  11.0  12.0  11.0  11.0  2.0     5.0    167.0
    2         5  11.0  11.0  11.0  13.0  11.0  11.0  2.0    10.0    236.0
    3         5  11.0  11.0  11.0  14.0  11.0  11.0  2.0    15.0    305.0
    4         5  11.0  11.0  11.0  15.0  11.0  11.0  2.0    20.0    374.0
    5         5  11.0  11.0  11.0  16.0  11.0  11.0  2.0    25.0    443.0
    6         5  11.0  12.0  11.0  16.0  11.0  11.0  2.0    30.0    511.0
    7         5  11.0  13.0  11.0  16.0  11.0  11.0  2.0    35.0    579.0
    8         5  11.0  14.0  11.0  16.0  11.0  11.0  2.0    40.0    647.0
    9         5  11.0  15.0  11.0  16.0  11.0  11.0  2.0    45.0    715.0
    10        5  11.0  16.0  11.0  16.0  11.0  11.0  2.0    50.0    783.0
    11        5  12.0  16.0  11.0  16.0  11.0  11.0  2.0    55.0    849.0
    12        5  13.0  16.0  11.0  16.0  11.0  11.0  2.0    60.0    915.0
    13        5  14.0  16.0  11.0  16.0  11.0  11.0  2.0    65.0    981.0
    14        5  15.0  16.0  11.0  16.0  11.0  11.0  2.0    70.0   1047.0
    15       10  11.0  16.0  11.0  21.0  11.0  11.0  2.0    75.0   1128.0
    16       10  11.0  17.0  11.0  21.0  11.0  11.0  2.0    80.0   1196.0
    17       10  11.0  18.0  11.0  21.0  11.0  11.0  2.0    85.0   1264.0
    18       10  11.0  19.0  11.0  21.0  11.0  11.0  2.0    90.0   1332.0
    19       10  11.0  20.0  11.0  21.0  11.0  11.0  2.0    95.0   1400.0
    20       10  11.0  21.0  11.0  21.0  11.0  11.0  2.0   100.0   1468.0
    21       10  12.0  21.0  11.0  21.0  11.0  11.0  2.0   105.0   1534.0
    22       10  13.0  21.0  11.0  21.0  11.0  11.0  2.0   110.0   1600.0
    23       10  14.0  21.0  11.0  21.0  11.0  11.0  2.0   115.0   1666.0
    24       10  15.0  21.0  11.0  21.0  11.0  11.0  2.0   120.0   1732.0
    25       10  16.0  21.0  11.0  21.0  11.0  11.0  2.0   125.0   1798.0
    26       10  17.0  21.0  11.0  21.0  11.0  11.0  2.0   130.0   1864.0
    27       10  18.0  21.0  11.0  21.0  11.0  11.0  2.0   135.0   1930.0
    28       10  19.0  21.0  11.0  21.0  11.0  11.0  2.0   140.0   1996.0
    29       10  20.0  21.0  11.0  21.0  11.0  11.0  2.0   145.0   2062.0
    30       15  11.0  26.0  11.0  26.0  11.0  11.0  2.0   150.0   2153.0
    31       15  12.0  26.0  11.0  26.0  11.0  11.0  2.0   155.0   2219.0
    32       15  13.0  26.0  11.0  26.0  11.0  11.0  2.0   160.0   2285.0
    33       15  14.0  26.0  11.0  26.0  11.0  11.0  2.0   165.0   2351.0
    34       15  15.0  26.0  11.0  26.0  11.0  11.0  2.0   170.0   2417.0
    35       15  16.0  26.0  11.0  26.0  11.0  11.0  2.0   175.0   2483.0
    36       15  17.0  26.0  11.0  26.0  11.0  11.0  2.0   180.0   2549.0
    37       15  18.0  26.0  11.0  26.0  11.0  11.0  2.0   185.0   2615.0
    38       15  19.0  26.0  11.0  26.0  11.0  11.0  2.0   190.0   2681.0
    39       15  20.0  26.0  11.0  26.0  11.0  11.0  2.0   195.0   2747.0
    40       15  21.0  26.0  11.0  26.0  11.0  11.0  2.0   200.0   2813.0
    41       15  22.0  26.0  11.0  26.0  11.0  11.0  2.0   205.0   2879.0
    42       15  23.0  26.0  11.0  26.0  11.0  11.0  2.0   210.0   2945.0
    43       15  24.0  26.0  11.0  26.0  11.0  11.0  2.0   215.0   3011.0
    44       15  25.0  26.0  11.0  26.0  11.0  11.0  2.0   220.0   3077.0
    45       15  26.0  26.0  11.0  26.0  11.0  11.0  2.0   225.0   3143.0
    46       15  26.0  26.0  11.0  26.0  12.0  11.0  2.0   230.0   3208.0
    47       15  26.0  26.0  13.0  26.0  11.0  11.0  2.0   235.0   3273.0
    48       15  26.0  26.0  14.0  26.0  11.0  11.0  2.0   240.0   3338.0
    49       15  26.0  26.0  15.0  26.0  11.0  11.0  2.0   245.0   3403.0
    50       17  27.0  28.0  11.0  28.0  11.0  11.0  2.0   250.0   3483.0
    51       17  28.0  28.0  11.0  28.0  11.0  11.0  2.0   255.0   3549.0
    52       17  28.0  28.0  12.0  28.0  11.0  11.0  2.0   260.0   3614.0
    53       17  28.0  28.0  13.0  28.0  11.0  11.0  2.0   265.0   3679.0
    54       17  28.0  28.0  11.0  28.0  14.0  11.0  2.0   270.0   3744.0
    55       17  28.0  28.0  11.0  28.0  11.0  15.0  2.0   275.0   3809.0
    56       17  28.0  28.0  11.0  28.0  16.0  11.0  2.0   280.0   3874.0
    57       17  28.0  28.0  17.0  28.0  11.0  11.0  2.0   285.0   3939.0
    58       17  28.0  28.0  18.0  28.0  11.0  11.0  2.0   290.0   4004.0
    59       17  28.0  28.0  19.0  28.0  11.0  11.0  2.0   295.0   4069.0
    60       20  31.0  31.0  11.0  31.0  11.0  11.0  2.0   300.0   4158.0
    61       20  31.0  31.0  11.0  31.0  12.0  11.0  2.0   305.0   4223.0
    62       20  31.0  31.0  11.0  31.0  13.0  11.0  2.0   310.0   4288.0
    63       20  31.0  31.0  11.0  31.0  14.0  11.0  2.0   315.0   4353.0
    64       20  31.0  31.0  11.0  31.0  15.0  11.0  2.0   320.0   4418.0
    65       20  31.0  31.0  11.0  31.0  11.0  16.0  2.0   325.0   4483.0
    66       20  31.0  31.0  11.0  31.0  17.0  11.0  2.0   330.0   4548.0
    67       20  31.0  31.0  18.0  31.0  11.0  11.0  2.0   335.0   4613.0
    68       20  31.0  31.0  19.0  31.0  11.0  11.0  2.0   340.0   4678.0
    69       20  31.0  31.0  20.0  31.0  11.0  11.0  2.0   345.0   4743.0
    70       20  31.0  31.0  21.0  31.0  11.0  11.0  2.0   350.0   4808.0
    71       20  31.0  31.0  22.0  31.0  11.0  11.0  2.0   355.0   4873.0
    72       20  31.0  31.0  23.0  31.0  11.0  11.0  2.0   360.0   4938.0
    73       20  31.0  31.0  24.0  31.0  11.0  11.0  2.0   365.0   5003.0
    74       20  31.0  31.0  25.0  31.0  11.0  11.0  2.0   370.0   5068.0
    75       20  31.0  31.0  11.0  31.0  26.0  11.0  2.0   375.0   5133.0
    76       20  31.0  31.0  11.0  31.0  11.0  27.0  2.0   380.0   5198.0
    77       20  31.0  31.0  11.0  31.0  28.0  11.0  2.0   385.0   5263.0
    78       20  31.0  31.0  29.0  31.0  11.0  11.0  2.0   390.0   5328.0
    79       20  31.0  31.0  30.0  31.0  11.0  11.0  2.0   395.0   5393.0
    80       20  31.0  31.0  11.0  31.0  11.0  31.0  2.0   400.0   5458.0
    81       20  31.0  31.0  11.0  31.0  31.0  12.0  2.0   405.0   5523.0
    82       20  31.0  31.0  13.0  31.0  31.0  11.0  2.0   410.0   5588.0
    83       20  31.0  31.0  31.0  31.0  11.0  14.0  2.0   415.0   5653.0
    84       20  31.0  31.0  11.0  31.0  31.0  15.0  2.0   420.0   5718.0
    85       20  31.0  31.0  16.0  31.0  11.0  31.0  2.0   425.0   5783.0
    86       20  31.0  31.0  11.0  31.0  17.0  31.0  2.0   430.0   5848.0
    87       20  31.0  31.0  31.0  31.0  11.0  18.0  2.0   435.0   5913.0
    88       20  31.0  31.0  19.0  31.0  31.0  11.0  2.0   440.0   5978.0
    89       20  31.0  31.0  31.0  31.0  20.0  11.0  2.0   445.0   6043.0
    90       25  36.0  36.0  26.0  36.0  11.0  11.0  2.0   450.0   6148.0
    91       25  36.0  36.0  27.0  36.0  11.0  11.0  2.0   455.0   6213.0
    92       25  36.0  36.0  11.0  36.0  11.0  28.0  2.0   460.0   6278.0
    93       25  36.0  36.0  11.0  36.0  11.0  29.0  2.0   465.0   6343.0
    94       25  36.0  36.0  11.0  36.0  30.0  11.0  2.0   470.0   6408.0
    95       25  36.0  36.0  11.0  36.0  31.0  11.0  2.0   475.0   6473.0
    96       25  36.0  36.0  11.0  36.0  32.0  11.0  2.0   480.0   6538.0
    97       25  36.0  36.0  11.0  36.0  11.0  33.0  2.0   485.0   6603.0
    98       25  36.0  36.0  34.0  36.0  11.0  11.0  2.0   490.0   6668.0
    99       25  36.0  36.0  35.0  36.0  11.0  11.0  2.0   495.0   6733.0
    100      25  36.0  36.0  11.0  36.0  36.0  11.0  2.0   500.0   6798.0
    101      25  36.0  36.0  11.0  36.0  36.0  12.0  2.0   505.0   6863.0
    102      25  36.0  36.0  11.0  36.0  36.0  13.0  2.0   510.0   6928.0
    103      25  36.0  36.0  11.0  36.0  36.0  14.0  2.0   515.0   6993.0
    104      25  36.0  36.0  36.0  36.0  11.0  15.0  2.0   520.0   7058.0
    105      25  36.0  36.0  36.0  36.0  16.0  11.0  2.0   525.0   7123.0
    106      25  36.0  36.0  36.0  36.0  17.0  11.0  2.0   530.0   7188.0
    107      25  36.0  36.0  36.0  36.0  18.0  11.0  2.0   535.0   7253.0
    108      25  36.0  36.0  11.0  36.0  36.0  19.0  2.0   540.0   7318.0
    109      25  36.0  36.0  20.0  36.0  36.0  11.0  2.0   545.0   7383.0
    110      25  36.0  36.0  36.0  36.0  11.0  21.0  2.0   550.0   7448.0
    111      25  36.0  36.0  36.0  36.0  22.0  11.0  2.0   555.0   7513.0
    112      25  36.0  36.0  23.0  36.0  11.0  36.0  2.0   560.0   7578.0
    113      25  36.0  36.0  36.0  36.0  24.0  11.0  2.0   565.0   7643.0
    114      25  36.0  36.0  36.0  36.0  25.0  11.0  2.0   570.0   7708.0
    115      25  36.0  36.0  26.0  36.0  11.0  36.0  2.0   575.0   7773.0
    116      25  36.0  36.0  27.0  36.0  11.0  36.0  2.0   580.0   7838.0
    117      25  36.0  36.0  36.0  36.0  28.0  11.0  2.0   585.0   7903.0
    118      25  36.0  36.0  36.0  36.0  29.0  11.0  2.0   590.0   7968.0
    119      25  36.0  36.0  30.0  36.0  36.0  11.0  2.0   595.0   8033.0
    120      30  41.0  41.0  11.0  41.0  41.0  11.0  2.0   600.0   8138.0
    121      30  41.0  41.0  11.0  41.0  12.0  41.0  2.0   605.0   8203.0
    122      30  41.0  41.0  13.0  41.0  41.0  11.0  2.0   610.0   8268.0
    123      30  41.0  41.0  41.0  41.0  14.0  11.0  2.0   615.0   8333.0
    124      30  41.0  41.0  15.0  41.0  41.0  11.0  2.0   620.0   8398.0
    125      30  41.0  41.0  41.0  41.0  16.0  11.0  2.0   625.0   8463.0
    126      30  41.0  41.0  17.0  41.0  11.0  41.0  2.0   630.0   8528.0
    127      30  41.0  41.0  41.0  41.0  11.0  18.0  2.0   635.0   8593.0
    128      30  41.0  41.0  41.0  41.0  19.0  11.0  2.0   640.0   8658.0
    129      30  41.0  41.0  20.0  41.0  41.0  11.0  2.0   645.0   8723.0
    130      30  41.0  41.0  11.0  41.0  41.0  21.0  2.0   650.0   8788.0
    131      30  41.0  41.0  11.0  41.0  41.0  22.0  2.0   655.0   8853.0
    132      30  41.0  41.0  11.0  41.0  41.0  23.0  2.0   660.0   8918.0
    133      30  41.0  41.0  11.0  41.0  41.0  24.0  2.0   665.0   8983.0
    134      30  41.0  41.0  41.0  41.0  25.0  11.0  2.0   670.0   9048.0
    135      30  41.0  41.0  41.0  41.0  26.0  11.0  2.0   675.0   9113.0
    136      30  41.0  41.0  27.0  41.0  41.0  11.0  2.0   680.0   9178.0
    137      30  41.0  41.0  28.0  41.0  11.0  41.0  2.0   685.0   9243.0
    138      30  41.0  41.0  41.0  41.0  11.0  29.0  2.0   690.0   9308.0
    139      30  41.0  41.0  41.0  41.0  11.0  30.0  2.0   695.0   9373.0
    140      30  41.0  41.0  31.0  41.0  11.0  41.0  2.0   700.0   9438.0
    141      30  41.0  41.0  11.0  41.0  32.0  41.0  2.0   705.0   9503.0
    142      30  41.0  41.0  41.0  41.0  11.0  33.0  2.0   710.0   9568.0
    143      30  41.0  41.0  34.0  41.0  41.0  11.0  2.0   715.0   9633.0
    144      30  41.0  41.0  35.0  41.0  41.0  11.0  2.0   720.0   9698.0
    145      30  41.0  41.0  36.0  41.0  11.0  41.0  2.0   725.0   9763.0
    146      30  41.0  41.0  41.0  41.0  11.0  37.0  2.0   730.0   9828.0
    147      30  41.0  41.0  41.0  41.0  38.0  11.0  2.0   735.0   9893.0
    148      30  41.0  41.0  39.0  41.0  41.0  11.0  2.0   740.0   9958.0
    149      30  41.0  41.0  11.0  41.0  41.0  40.0  2.0   745.0  10023.0
    150      35  46.0  46.0  46.0  46.0  21.0  11.0  2.0   750.0  10128.0
    151      35  46.0  46.0  46.0  46.0  11.0  22.0  2.0   755.0  10193.0
    152      35  46.0  46.0  11.0  46.0  46.0  23.0  2.0   760.0  10258.0
    153      35  46.0  46.0  46.0  46.0  24.0  11.0  2.0   765.0  10323.0
    154      35  46.0  46.0  46.0  46.0  11.0  25.0  2.0   770.0  10388.0
    155      35  46.0  46.0  26.0  46.0  11.0  46.0  2.0   775.0  10453.0
    156      35  46.0  46.0  46.0  46.0  27.0  11.0  2.0   780.0  10518.0
    157      35  46.0  46.0  46.0  46.0  11.0  28.0  2.0   785.0  10583.0
    158      35  46.0  46.0  46.0  46.0  11.0  29.0  2.0   790.0  10648.0
    159      35  46.0  46.0  30.0  46.0  11.0  46.0  2.0   795.0  10713.0
    160      35  46.0  46.0  11.0  46.0  31.0  46.0  2.0   800.0  10778.0
    161      35  46.0  46.0  32.0  46.0  46.0  11.0  2.0   805.0  10843.0
    162      35  46.0  46.0  33.0  46.0  46.0  11.0  2.0   810.0  10908.0
    163      35  46.0  46.0  46.0  46.0  11.0  34.0  2.0   815.0  10973.0
    164      35  46.0  46.0  46.0  46.0  11.0  35.0  2.0   820.0  11038.0
    165      35  46.0  46.0  36.0  46.0  11.0  46.0  2.0   825.0  11103.0
    166      35  46.0  46.0  46.0  46.0  11.0  37.0  2.0   830.0  11168.0
    167      35  46.0  46.0  46.0  46.0  38.0  11.0  2.0   835.0  11233.0
    168      35  46.0  46.0  11.0  46.0  39.0  46.0  2.0   840.0  11298.0
    169      35  46.0  46.0  40.0  46.0  11.0  46.0  2.0   845.0  11363.0
    170      35  46.0  46.0  41.0  46.0  46.0  11.0  2.0   850.0  11428.0
    171      35  46.0  46.0  11.0  46.0  46.0  42.0  2.0   855.0  11493.0
    172      35  46.0  46.0  11.0  46.0  46.0  43.0  2.0   860.0  11558.0
    173      35  46.0  46.0  44.0  46.0  46.0  11.0  2.0   865.0  11623.0
    174      35  46.0  46.0  46.0  46.0  11.0  45.0  2.0   870.0  11688.0
    175      35  46.0  46.0  46.0  46.0  46.0  11.0  2.0   875.0  11753.0
    176      35  46.0  46.0  46.0  46.0  46.0  12.0  2.0   880.0  11818.0
    177      35  46.0  46.0  46.0  46.0  46.0  13.0  2.0   885.0  11883.0
    178      35  46.0  46.0  46.0  46.0  46.0  14.0  2.0   890.0  11948.0
    179      35  46.0  46.0  46.0  46.0  46.0  15.0  2.0   895.0  12013.0
    180      40  50.0  50.0  50.0  50.0  35.0  11.0  2.0   900.0  12110.0
    181      40  50.0  50.0  50.0  50.0  11.0  36.0  2.0   905.0  12175.0
    182      40  50.0  50.0  50.0  50.0  11.0  37.0  2.0   910.0  12240.0
    183      40  50.0  50.0  50.0  50.0  38.0  11.0  2.0   915.0  12305.0
    184      40  50.0  50.0  50.0  50.0  39.0  11.0  2.0   920.0  12370.0
    185      40  50.0  50.0  50.0  50.0  11.0  40.0  2.0   925.0  12435.0
    186      40  50.0  50.0  50.0  50.0  11.0  41.0  2.0   930.0  12500.0
    187      40  50.0  50.0  11.0  50.0  42.0  50.0  2.0   935.0  12565.0
    188      40  50.0  50.0  43.0  50.0  11.0  50.0  2.0   940.0  12630.0
    189      40  50.0  50.0  11.0  50.0  50.0  44.0  2.0   945.0  12695.0
    190      40  50.0  50.0  50.0  50.0  45.0  11.0  2.0   950.0  12760.0
    191      40  50.0  50.0  50.0  50.0  46.0  11.0  2.0   955.0  12825.0
    192      40  50.0  50.0  11.0  50.0  50.0  47.0  2.0   960.0  12890.0
    193      40  50.0  50.0  50.0  50.0  48.0  11.0  2.0   965.0  12955.0
    194      40  50.0  50.0  11.0  50.0  50.0  49.0  2.0   970.0  13020.0
    195      40  50.0  50.0  50.0  50.0  50.0  11.0  2.0   975.0  13085.0
    196      40  50.0  50.0  12.0  50.0  50.0  50.0  2.0   980.0  13150.0
    197      40  50.0  50.0  50.0  50.0  50.0  13.0  2.0   985.0  13215.0
    198      40  50.0  50.0  14.0  50.0  50.0  50.0  2.0   990.0  13280.0
    199      40  50.0  50.0  50.0  50.0  15.0  50.0  2.0   995.0  13345.0
    200      40  50.0  50.0  50.0  50.0  50.0  16.0  2.0  1000.0  13410.0
    201      40  50.0  50.0  50.0  50.0  17.0  50.0  2.0  1005.0  13475.0
    202      40  50.0  50.0  50.0  50.0  50.0  18.0  2.0  1010.0  13540.0
    203      40  50.0  50.0  50.0  50.0  19.0  50.0  2.0  1015.0  13605.0
    204      40  50.0  50.0  50.0  50.0  20.0  50.0  2.0  1020.0  13670.0
    205      40  50.0  50.0  50.0  50.0  21.0  50.0  2.0  1025.0  13735.0
    206      40  50.0  50.0  50.0  50.0  50.0  22.0  2.0  1030.0  13800.0
    207      40  50.0  50.0  50.0  50.0  50.0  23.0  2.0  1035.0  13865.0
    208      40  50.0  50.0  24.0  50.0  50.0  50.0  2.0  1040.0  13930.0
    209      40  50.0  50.0  25.0  50.0  50.0  50.0  2.0  1045.0  13995.0
    210      45  50.0  50.0  50.0  50.0  50.0  26.0  2.0  1050.0  14060.0
    211      45  50.0  50.0  50.0  50.0  50.0  27.0  2.0  1055.0  14125.0
    212      45  50.0  50.0  28.0  50.0  50.0  50.0  2.0  1060.0  14190.0
    213      45  50.0  50.0  50.0  50.0  29.0  50.0  2.0  1065.0  14255.0
    214      45  50.0  50.0  50.0  50.0  30.0  50.0  2.0  1070.0  14320.0
    215      45  50.0  50.0  50.0  50.0  50.0  31.0  2.0  1075.0  14385.0
    216      45  50.0  50.0  50.0  50.0  50.0  32.0  2.0  1080.0  14450.0
    217      45  50.0  50.0  50.0  50.0  50.0  33.0  2.0  1085.0  14515.0
    218      45  50.0  50.0  50.0  50.0  34.0  50.0  2.0  1090.0  14580.0
    219      45  50.0  50.0  50.0  50.0  50.0  35.0  2.0  1095.0  14645.0
    220      45  50.0  50.0  50.0  50.0  36.0  50.0  2.0  1100.0  14710.0
    221      45  50.0  50.0  50.0  50.0  50.0  37.0  2.0  1105.0  14775.0
    222      45  50.0  50.0  38.0  50.0  50.0  50.0  2.0  1110.0  14840.0
    223      45  50.0  50.0  50.0  50.0  39.0  50.0  2.0  1115.0  14905.0
    224      45  50.0  50.0  50.0  50.0  50.0  40.0  2.0  1120.0  14970.0
    225      45  50.0  50.0  50.0  50.0  41.0  50.0  2.0  1125.0  15035.0
    226      45  50.0  50.0  42.0  50.0  50.0  50.0  2.0  1130.0  15100.0
    227      45  50.0  50.0  50.0  50.0  43.0  50.0  2.0  1135.0  15165.0
    228      45  50.0  50.0  44.0  50.0  50.0  50.0  2.0  1140.0  15230.0
    229      45  50.0  50.0  50.0  50.0  45.0  50.0  2.0  1145.0  15295.0
    230      45  50.0  50.0  50.0  50.0  46.0  50.0  2.0  1150.0  15360.0
    231      45  50.0  50.0  50.0  50.0  47.0  50.0  2.0  1155.0  15425.0
    232      45  50.0  50.0  50.0  50.0  50.0  48.0  2.0  1160.0  15490.0
    233      45  50.0  50.0  50.0  50.0  50.0  49.0  2.0  1165.0  15555.0
    234      45  50.0  50.0  50.0  50.0  50.0  50.0  2.0  1170.0  15620.0