def _check_ooo_durations(layout): for i in range(layout.data.shape[0]): for j, _, _ in layout.out_of_order[i]: error_message = 'Out of order cell cannot be placed in {}-{} cell.'.format(i + 1, j + 1) if j >= layout.data[layout_config.OUT_DATES_COL].shape[0]: raise ErrorMessage(OOO_ILLEGAL_PLACE_ERROR_CODE, error_message) delta = (layout.data[layout_config.OUT_DATES_COL][j] - layout.data[layout_config.IN_DATES_COL][i]).days if np.isnan(delta) or delta > layout.duration_limit or layout.min_days <= delta <= layout.max_days: raise ErrorMessage(OOO_ILLEGAL_PLACE_ERROR_CODE, error_message)
def _find_in_dates_to_remove_losses(layout: Layout, available_in_places): layout_data = layout.data height = layout_data.shape[0] width = layout.width losses = [] cur_vertex_idx = 0 for i in range(height): if pd.isnull(layout_data[layout_config.IN_PLACES_COL][i]): continue cur_sum = 0 cur_idx = i % width for j in range(i, min(i + layout.max_days + 1, height)): delta = (layout_data[layout_config.OUT_DATES_COL][j] - layout_data[layout_config.IN_DATES_COL][i]).days if np.isnan(delta) or delta < layout.min_days: continue if delta > layout.max_days: break if not layout_data[get_required_col(cur_idx)][j] and not pd.isnull(layout_data[get_layout_col(cur_idx)][j]): cur_sum += int(layout_data[get_layout_col(cur_idx)][j]) in_max_places = available_in_places[i] if in_max_places is not None and cur_sum > in_max_places: raise ErrorMessage(RESTRICTION_VIOLATION_ERROR_CODE, 'Sum of places is bigger than maximum of available {} in-places'.format(i)) if in_max_places is not None and in_max_places - cur_sum > 0 and layout.no_losses[i][0]: losses.append((cur_vertex_idx, int(in_max_places - cur_sum))) cur_vertex_idx += 1 return losses
def _update_places(layout_data: LayoutData, layout: Layout): # transform new places values to dict to increase searching time new_places = {} for places in layout_data.places: in_date = layout_data.dates[places.in_date].in_date out_date = layout_data.dates[places.out_date].out_date new_places[in_date + '-' + out_date] = (places.amount, places.required) places = PlacesNumber.objects.filter(layout=layout).order_by( 'in_max_places_id', 'out_max_places_id').select_related('in_max_places', 'out_max_places') # update places values in db for pl in places: in_date = pl.in_max_places.date.strftime(DATE_FORMAT) out_date = pl.out_max_places.date.strftime(DATE_FORMAT) key = in_date + '-' + out_date try: (amount, required) = new_places[key] except KeyError: raise ErrorMessage( DATA_INTEGRITY_ERROR_CODE, 'Amount value was not provided for {}-{} places'.format( in_date, out_date)) if pl.required != required or pl.amount != amount: pl.required = required pl.amount = amount pl.save()
def _get_avail_in_places(layout): out_of_order = layout.out_of_order layout_data = layout.data height = layout_data.shape[0] width = layout.width out_of_order_places = [0] * height for i, data_list in enumerate(out_of_order): for _, amount, _ in data_list: out_of_order_places[i] += amount in_places = [] for i in range(height): cur_sum = 0 cur_idx = i % width for j in range(i, min(i + layout.max_days + 1, height)): delta = (layout_data[layout_config.OUT_DATES_COL][j] - layout_data[layout_config.IN_DATES_COL][i]).days if np.isnan(delta) or delta < layout.min_days: continue if delta > layout.max_days: break if layout_data[get_required_col(cur_idx)][j]: cur_sum += layout_data[get_layout_col(cur_idx)][j] cur_sum += out_of_order_places[i] in_max_places = layout_data[layout_config.IN_PLACES_COL][i] if in_max_places is not None and cur_sum > in_max_places: raise ErrorMessage( RESTRICTION_VIOLATION_ERROR_CODE, 'Sum of places is bigger than maximum of available {} in-places' .format(i)) in_places.append(None if in_max_places is None else in_max_places - cur_sum) return in_places
def _get_avail_out_places(layout): out_of_order = layout.out_of_order layout_data = layout.data height = layout_data.shape[0] width = layout.width out_of_order_places = [0] * height for data_list in out_of_order: for i, amount, _ in data_list: out_of_order_places[i] += amount out_places = [] for i in range(height): cur_sum = 0 for j in range(width): cur_idx = get_layout_col(j) cur_req_idx = get_required_col(j) if layout_data[cur_req_idx][i]: cur_sum += layout_data[cur_idx][i] cur_sum += out_of_order_places[i] out_max_places = layout_data[layout_config.OUT_PLACES_COL][i] if out_max_places is not None and cur_sum > out_max_places: raise ErrorMessage( RESTRICTION_VIOLATION_ERROR_CODE, 'Sum of places is bigger than maximum of available {} out-places' .format(i)) out_places.append(None if out_max_places is None else out_max_places - cur_sum) return out_places
def _get_corrected_relations(layout, i, height, column_idx): data = layout.data max_places = data[layout_config.IN_PLACES_COL][i] if max_places is None: return max_places, None, [], 0 _check_ooo_durations(layout, i) cur_idx = get_layout_col(column_idx) cur_req_idx = get_required_col(column_idx) relations = layout.relations if layout.date_relations[ i] is None else layout.date_relations[i] relations_sum = 0 used_sum = sum((amount for _, amount, _ in layout.out_of_order[i])) if len( layout.out_of_order[i]) > 0 else 0 vars_num = 0 for j in range(i, min(i + param_config.MAX_DAYS + 1, height)): delta = (data[layout_config.OUT_DATES_COL][j] - data[layout_config.IN_DATES_COL][i]).days if np.isnan(delta) or delta < layout.min_days: continue if delta > layout.max_days: break if not data[cur_req_idx][j]: vars_num += 1 relations_sum += relations[delta - layout.min_days] else: used_sum += data[cur_idx][j] if relations_sum > 0: coef = 1. / relations_sum else: coef = 0 corrected_relations = [rel * coef for rel in relations] if used_sum > max_places: raise ErrorMessage( RESTRICTION_VIOLATION_ERROR_CODE, 'Sum of places is bigger than maximum of available {} in-places'. format(i)) else: avail_places = max_places - used_sum return max_places, avail_places, corrected_relations, vars_num
def _find_out_dates_to_remove_losses(layout: Layout, available_out_places): layout_data = layout.data height = layout_data.shape[0] width = layout.width losses = [] cur_vertex_idx = 0 for i in range(height): if pd.isnull(layout_data[layout_config.OUT_PLACES_COL][i]): continue cur_sum = 0 for j in range(width): cur_idx = get_layout_col(j) cur_req_idx = get_required_col(j) if pd.isnull(layout_data[cur_idx][i]) or layout_data[cur_req_idx][i]: continue cur_sum += int(layout_data[cur_idx][i]) out_max_places = available_out_places[i] if out_max_places is not None and cur_sum > out_max_places: raise ErrorMessage(RESTRICTION_VIOLATION_ERROR_CODE, 'Sum of places is bigger than maximum of available {} out-places'.format(i)) if out_max_places is not None and out_max_places - cur_sum > 0 and layout.no_losses[i][1]: losses.append((cur_vertex_idx, int(out_max_places - cur_sum))) cur_vertex_idx += 1 return losses