def _write_results(elements, charges, equality_constraints, charge_type, log): fname = "results/charges_" + charge_type + "_full.out" result_path = Path(fname) with result_path.open("w") as f: for element, charge in zip(elements, charges): f.write(f"{element:5s}{charge:12.8f}\n") log.log(f"\n\nFull precision charges have been saved to '{fname}'.") # Round charges to 3 decimals # This may violate symmetry; need to edit by hand charges = saferound(charges, 3) fname = "results/charges_" + charge_type + "_rounded.out" result_path = Path(fname) with result_path.open("w") as f: for element, charge in zip(elements, charges): f.write(f"{element:5s}{charge:12.3f}\n") log.log(f"Rounded charges (3 decimals) have been saved to '{fname}'.") warn_log = False for constraint in equality_constraints: for atomi in constraint: chargei = charges[atomi - 1] for atomj in constraint: chargej = charges[atomj - 1] if chargei != chargej: warn_log = True if warn_log: log.log(f"Rounded charges in '{fname}' violate the specified " "equality constraints and need to be corrected by hand.")
def fit(self): # ETANA: Training self.A = [dict() for _ in range(self.K)] J = self.g_w.copy() start = time.time() # start time for i in range(self.K - 1, -1, -1): f_order = self.ordering[i] J_next = J.copy() for key in self.W: pi = np.array(key) / self.neta sigma = self.feat_cost for j in range(self.bins): delta = self.feat_prob[f_order, :, j] a = np.dot(pi, delta) next_pi = np.multiply(pi, delta) / a next_pi_key = np.array(saferound(next_pi, 1)) * self.neta next_pi_key = tuple(next_pi_key.astype(int)) sigma += a * J_next[next_pi_key] self.A[i][key] = sigma J[key] = min(self.g_w[key], sigma) train_time = time.time() - start # training time return train_time
def steady_state_MC(simT, simN, b_policy, d_policy, c_policy, e_grid, b_grid, d_grid, e_ergodic, Pi_e): """ simulate forward to steady-state """ np.random.seed(100) # unpack e_cum = np.cumsum(Pi_e[:], axis=1) ergodic = np.asarray(saferound(e_ergodic * simN, places=0)) Ne = len(e_grid) sim_shape = (simT, simN) sim_p = np.zeros(sim_shape) sim_b = np.zeros(sim_shape) sim_b[0, :] = b_policy[0, 0, 0] # initial state sim_d = np.zeros(sim_shape) sim_d[0, :] = d_policy[0, 0, 0] # initial state sim_c = np.zeros(sim_shape) sim_c[0, :] = c_policy[0, 0, 0] # initial state unif = np.random.uniform(size=(simT, simN)) # random uniform shocks ergodic = e_ergodic sim_b, sim_d, sim_c = run(simT, simN, b_policy, d_policy, c_policy, e_grid, b_grid, d_grid, ergodic, e_cum, Ne, sim_p, sim_b, sim_d, sim_c, unif) return sim_b, sim_d, sim_c
def predict(self, Xtest): # ETANA: Joint Feature Selection and Classification self.predictions = [] self.n_feat = [] start = time.time() # start time for z in range(np.size(Xtest, axis=0)): obs = Xtest[z, :] # test instance pi = np.ones(self.L) / self.L # initial belief for k in range(self.K): pi_key = np.array(saferound(pi, 1)) * self.neta pi_key = tuple(pi_key.astype(int)) if self.g_w[pi_key] <= self.A[k][pi_key]: break f_order = self.ordering[k] # features f = obs[f_order] # observing a feature assignment f_index = find_range( f, self.edges[f_order] [1:]) # index after discretization the feature delta = self.feat_prob[f_order, :, f_index] pi = np.multiply(pi, delta) / np.dot(pi, delta) D_opt = np.argmin(np.dot(self.MC, pi)) self.n_feat.append(k) # number of features used self.predictions.append(self.C[D_opt]) # predictions fs_and_c_time = time.time( ) - start # joint feature selection and classification time return fs_and_c_time
def report(self): print('Name:', self.name) sorted_weights = sorted(iteround.saferound( self.weights[self.parent.name], self.precision).items(), key=operator.itemgetter(1), reverse=True) for k, v in sorted_weights: print('\t{}: {}'.format(k, v)) print()
def normalize_and_bound(self, data, dec_digits=1): data = data.copy() for i in range(len(data)): nd = None if data[i].sum() != 0: nd = data[i] / data[i].sum() else: nd = np.array([1 / len(data[i])] * len(data[i])) data[i] = iteround.saferound(nd, dec_digits) return data
def get_trip_generation(self): self.data['Attraction'] = (self.data['Employment'] * self.data.sum()['Production'] / self.data.sum()['Employment']) df = pd.DataFrame(columns=['Production', 'Attraction']) df['Production'] = self.data['Production'] round_attraction = (saferound(self.data['Attraction'], places=0)) mod_attraction = ([int(x) for x in round_attraction]) df['Attraction'] = mod_attraction return df
def survey(results, category_names, total_capacity): """ Courtesy of https://matplotlib.org/3.1.1/gallery/lines_bars_and_markers/horizontal_barchart_distribution.html Parameters ---------- results : dict A mapping from question labels to a list of answers per category. It is assumed all lists contain the same number of entries and that it matches the length of *category_names*. category_names : list of str The category labels. """ labels = list(results.keys()) data = np.array(list(results.values()), dtype=float) # normalize the data data = data / np.array(total_capacity)[:, None] * 100 data = np.array([saferound(row, 0) for row in data]).astype(int) data_cum = data.cumsum(axis=1) category_colors = list( plt.get_cmap('RdYlGn')(np.linspace( 0.2, 0.8, data.shape[1] - 1))) + ['lightgray'] fig, ax = plt.subplots(figsize=(10, 5)) ax.invert_yaxis() ax.xaxis.set_visible(False) ax.set_xlim(0, np.sum(data, axis=1).max()) for i, (colname, color) in enumerate(zip(category_names, category_colors)): widths = data[:, i] starts = data_cum[:, i] - widths ax.barh(labels, widths, left=starts, height=0.5, label=colname, color=color) xcenters = starts + widths / 2 text_color = 'black' for y, (x, c) in enumerate(zip(xcenters, widths)): if c > 2: # if space is sufficient to print percentages ax.text(x, y, f'{c}%', ha='center', va='center', color=text_color) ax.legend(ncol=len(category_names), bbox_to_anchor=(0, 1), loc='lower left', fontsize=12) ax.set_ylabel('Percent of kernels frozen by each task') return fig, ax
def print(self, distribution: Dict[Player, float]): palette = sns.color_palette(None, len(distribution)) labels = [] sizes = [] colors = [] i = 0 for player in sorted(distribution.keys(), key=lambda item: item.value): likelihood = distribution[player] if likelihood != 0: labels.append(get_name(player)) sizes.append(likelihood) colors.append(palette[i]) i += 1 sizes_sum = sum(sizes) sizes = saferound([size / sizes_sum for size in sizes], self.__PRECISION) wedges, names, percentages = plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%') kw = dict(arrowprops=dict(arrowstyle="-"), zorder=0, va="center") previous_angle = None for i, it in enumerate(zip(wedges, names, percentages, sizes)): wedge, name, percentage, size = it if size < self.__THRESHOLD_LIKELIHOOD: name.update({'visible': False}) percentage.update({'visible': False}) angle = (wedge.theta2 - wedge.theta1) / 2 + wedge.theta1 text_angle = angle if previous_angle is not None and self.__angle_distance( angle, previous_angle) < self.__THRESHOLD_MIN_ANGLE_INC: text_angle = (previous_angle + self.__THRESHOLD_MIN_ANGLE_INC + 360) % 360 x, y = np.cos(np.deg2rad(angle)), np.sin(np.deg2rad(angle)) x_text = (1 + self.__THRESHOLD_LINE_LENGTH) * np.cos( np.deg2rad(text_angle)) y_text = (1 + self.__THRESHOLD_LINE_LENGTH) * np.sin( np.deg2rad(text_angle)) horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))] plt.annotate(name.get_text() + ": " + percentage.get_text(), xy=(x, y), xytext=(x_text, y_text), horizontalalignment=horizontalalignment, **kw) previous_angle = angle if self.__file_name is None: plt.show() else: plt.savefig(self.__file_name) plt.clf()
def calculate_composition_in_group(elements, column, threshold=0): """Calculate composition of elements in a given column""" logger.info( f"Calculate {column} composition based on {len(elements)} elements") return (elements.groupby(column).size().to_frame("col_count").assign( ratio=lambda df: 100 * df.col_count / (df.col_count.sum() or 1) ).query("ratio > @threshold").assign( ratio=lambda df: 100 * df.col_count / (df.col_count.sum() or 1)).apply( lambda col: saferound(0 if col.empty else col.astype(float), 0), axis="index", ).loc[:, "ratio"].astype(int).to_dict())
def homeGoalsFor(): pl["Home(Dif)"] = pl["Home(F)"] - pl["Home(A)"] # created league table based on home form home = pl[["Home(F)", "Home(A)", "Home(Dif)", "Points(H)"]] pl_ran = pd.read_csv( "league_table_blank.csv", index_col="Team", names=["Team", "Home(F)", "Home(A)", "Away(F)", "Away(A)"]) home = home.sort_values(by="Team") # array of home team's goals scored home_ac = home["Home(F)"] # divided goals by number of games home_ac = np.divide(home_ac, 19) # divided by average of goal per game and multiplied by average goals home_ac = (np.divide(home_ac, 1.57)) * 29.8 #generated home values and added to dataset pl_ran["Home(F)"] = np.random.poisson(lam=home_ac, size=(20)) # added new column with away goal difference pl["Away(Dif)"] = pl["Away(F)"] - pl["Away(A)"] away = pl[["Away(F)", "Away(A)", "Away(Dif)", "Points(A)"]] away = away.sort_values(by="Team") # array containing number of goals each team conceded in the previous season away_dc = away["Away(A)"] # divided contents of array by number of games played away_dc = np.divide(away_dc, 19) # divided contents of array by average goals conceded per match and multiplied by average goals away_dc = (np.divide(away_dc, 1.57)) * 29.8 # total home goals scored thf = pl_ran["Home(F)"].sum() # generated random goals conceded data for each team awa = np.random.poisson(lam=away_dc, size=(20)) # calculated sum of random array awasum = awa.sum() # divide array by its sum awa = np.divide(awa, awasum) # multiplied by sum of total goals scored at home awa = awa * thf # round floats to integers while maintaining sum awa = saferound(awa, places=0) # converted list to array awa = np.asarray(awa) # converted type from float to array awa = awa.astype(int) # added new column to data frame of goals conceded away from home pl_ran["Away(A)"] = awa return pl_ran[["Home(F)", "Away(A)"]]
def homeGoalsAgainst(): # created league table based on home form home = pl[["Home(F)", "Home(A)", "Home(Dif)", "Points(H)"]] pl_ran = pd.read_csv( "league_table_blank.csv", index_col="Team", names=["Team", "Home(F)", "Home(A)", "Away(F)", "Away(A)"]) # real world values of goals conceded by teams at home home = home.sort_values(by="Team") # array of goals conceded by home teams home_dc = home["Home(A)"] # divided goals by number of games home_dc = np.divide(home_dc, 19) # divided by average goals per game and multiplied by average goals conceded at home home_dc = (np.divide(home_dc, 1.25)) * 23.8 # added goals conceded at home to dataframe pl_ran["Home(A)"] = np.random.poisson(lam=home_dc, size=(20)) # created league table based on home form away = pl[["Away(F)", "Away(A)", "Away(Dif)", "Points(A)"]] # real world values of goals scored by away teams away = away.sort_values(by="Team") # away team attacking coefficient in alphabetical order away_ac = away["Away(F)"] away_ac = np.divide(away_ac, 19) away_ac = (np.divide(away_ac, 1.25)) * 23.8 # total home goals conceded tha = pl_ran["Home(A)"].sum() # generated random goals scored data for each team awf = np.random.poisson(lam=away_ac, size=(20)) # calculated sum of random array awfsum = awf.sum() # divide array by its sum awf = np.divide(awf, awfsum) # multiplied by sum of total goals conceded at home awf = awf * tha # round floats to integers while maintaining sum awf = saferound(awf, places=0) # converted list to array awf = np.asarray(awf) # converted type from float to array awf = awf.astype(int) # added new column to array of goals scored away from home pl_ran["Away(F)"] = awf return pl_ran[["Home(A)", "Away(F)"]]
def get_stratified_sampling(list_IDs, mask_coverage, batch_size): ''' :param list_IDs: list of image indexes :param mask_coverage: corresponding mask coverage as a dictionary imageId-mask coverage values :param batch_size: :return: indexes of the batch size stratified ''' n_bins = [0, 0.2, 0.4, 0.6, 0.8, 1.0] # 5 bins hist, val = np.histogram(np.fromiter(mask_coverage.values(), dtype=float), bins=n_bins, normed=1) bin1 = [key for key, val in mask_coverage.items() if float(val) <= 0.2] bin2 = [ key for key, val in mask_coverage.items() if float(val) > 0.2 and float(val) <= 0.4 ] bin3 = [ key for key, val in mask_coverage.items() if float(val) > 0.4 and float(val) <= 0.6 ] bin4 = [ key for key, val in mask_coverage.items() if float(val) > 0.6 and float(val) <= 0.8 ] bin5 = [key for key, val in mask_coverage.items() if float(val) > 0.8] random.shuffle(bin1) random.shuffle(bin2) # shuffle all mini dict random.shuffle(bin3) random.shuffle(bin4) random.shuffle(bin5) samples_per_bin = saferound(hist / sum(hist) * batch_size, places=0) indexes = [] for i in bin1[:int(samples_per_bin[0])]: indexes.append(list_IDs.index(i)) for i in bin2[:int(samples_per_bin[1])]: indexes.append(list_IDs.index(i)) for i in bin3[:int(samples_per_bin[2])]: indexes.append(list_IDs.index(i)) for i in bin4[:int(samples_per_bin[3])]: indexes.append(list_IDs.index(i)) for i in bin5[:int(samples_per_bin[4])]: indexes.append(list_IDs.index(i)) return indexes
def print(self, distribution: Dict[Player, float]): distribution = { player: value * self.__multiplier for player, value in distribution.items() } distribution = saferound(distribution, self.__precision) sorted_distribution = [] for player, likelihood in distribution.items(): sorted_distribution.append((get_name(player), likelihood)) sorted_distribution.sort(key=lambda x: x[1], reverse=True) for row in sorted_distribution: player_name = row[0] likelihood = row[1] print(player_name + ": " + str(likelihood))
def roulette(population, fit, num_parents=4): # izracunamo P_i fitness_rel = (fit) / np.sum(fit) * 100 # zaokrozujemo tako, da je vsota se vedno enaka 100!!! fitn_rel_round = iteround.saferound(list(fitness_rel[:, 0]), 0) # naredimo array s stotimi elementi, glede na P_i priredimo vrednosti # Npr. Če je P_i za 1 kromosom enak 40, potem bo imel array 40 elementov z vrednostjo 1... To naredimo za vse trenutne kromosome # najboljsi kromosom bo imel najvec vnosov -> najvecja verjetnost, da bo izbran kot starš a = [] for i in range(num_parents): a = a + [i] * int(fitn_rel_round[i]) a = np.array(a) # nakljucno premešamo array np.random.shuffle(a) # izberemo prve 4 unikatne vrednosti # podoben princip kot da vrtimo kolo, le da ga ne vrtimo n-krat, ampak samo naključno premešamo vrednosti # in poiščemo prve 4 unikatne unique = [] for el in a: if not el in unique: unique.append(el) return population[unique[:num_parents]], fit[unique[:num_parents]]
def test_basic_smallest(self): out = [4.0, 3.24, 3.23, 6.45, 5.35, 7.34] self.assertListEqual( iteround.saferound(self.in_list, 2, iteround.SMALLEST), out)
def test_huge(self): out = [400000.0, 324000.0, 323000.0, 645000.0, 535000.0, 734000.0] self.assertListEqual(iteround.saferound(self.huge_in_list, -3), out)
def tern(p, names=["L", "R"], ax=None): names = process_names(names) plt.style.use('classic') if ax is None: fig, ax = plt.subplots() fig.patch.set_alpha(0) ax.set_aspect('equal', 'box') ax.axis('off') ax.set_xlim(-.1, 1.1) ax.set_ylim(-.1, 1.1) # inner lines cx, cy = project(np.array([[1 / 3, 1 / 3, 1 / 3]]))[0] # central point for x, y in project(np.array([[.5, .5, 0], [.5, 0, .5], [0, .5, .5]])): ax.add_line(Line2D([cx, x], [cy, y], color='k', lw=2)) # outer border of the triangle vert_coords = [(0., 0.), (.5, sqrt(3) / 2), (1., 0.), (0., 0.)] codes = [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY] triangle = Path(vert_coords, codes) patch = patches.PathPatch(triangle, facecolor='none', lw=3) ax.add_patch(patch) # vertices texts probs = saferound(list(p.probs()), places=4) # L ax.text(-.04, -.02, r'$\mathrm{%s}$' % names[0], ha='center', va='top', fontsize=25) ax.text(-.04, -.15, r'$\mathbf{(%.4f)}$' % probs[0], ha='center', va='top', fontsize=30) # ROPE ax.text(.5, 1, r'$\mathrm{ROPE}$', ha='center', va='bottom', fontsize=25) ax.text(.5, .84, r'$\mathbf{(%.4f)}$' % probs[1], ha='center', va='bottom', fontsize=30) # R ax.text(1.04, -.02, r'$\mathrm{%s}$' % names[1], ha='center', va='top', fontsize=25) ax.text(1.04, -.15, r'$\mathbf{(%.4f)}$' % probs[2], ha='center', va='top', fontsize=30) # draw points tripts = project(p.sample[:, [0, 2, 1]]) data, xe, ye = np.histogram2d(tripts[:, 0], tripts[:, 1], bins=30) z = interpn((.5 * (xe[1:] + xe[:-1]), .5 * (ye[1:] + ye[:-1])), data, np.vstack([tripts[:, 0], tripts[:, 1]]).T, method='splinef2d', bounds_error=False) idx = z.argsort() ax.scatter(tripts[:, 0][idx], tripts[:, 1][idx], c=z[idx], clip_path=patch, s=50, linewidth=0, cmap=BLUES_CMAP, rasterized=True) return ax
def test_dict(self): out = {'foo': 60.0, 'bar': 16.0, 'baz': 24.0} self.assertDictEqual(iteround.saferound(self.in_dict, 0), out)
def test_odict(self): out = OrderedDict({'foo': 60.0, 'bar': 16.0, 'baz': 24.0}) self.assertDictEqual(iteround.saferound(self.in_odict, 0), out)
def next_update(self, timestep, state): M = np.asarray( [np.identity(len(self.nodes)) for mol in self.molecule_ids]) # construct M matrix based off of graph, all edges assumed bidirectional for edge_id, edge in self.edges.items(): node_index_1 = np.where(self.nodes == edge['nodes'][0])[0][0] node_index_2 = np.where(self.nodes == edge['nodes'][1])[0][0] cross_sectional_area = edge['cross_sectional_area'] vol_1 = state[edge['nodes'][0]]['volume'] vol_2 = state[edge['nodes'][1]]['volume'] dx = state[edge['nodes'][0]]['length'] / 2 + state[ edge['nodes'][1]]['length'] / 2 diffusion_constants = array_from(self.diffusion_constants[edge_id]) alpha = diffusion_constants * (cross_sectional_area / dx) * timestep M[:, node_index_1, node_index_1] += alpha / vol_1 M[:, node_index_2, node_index_2] += alpha / vol_2 M[:, node_index_1, node_index_2] -= alpha / vol_1 M[:, node_index_2, node_index_1] -= alpha / vol_2 # Calculates final concentration after one timestep c_initial = np.asarray([ np.multiply(array_from(state[node]['molecules']), array_from(self.mw)) / state[node]['volume'] for node in state ]) c_final = np.asarray([ np.matmul(np.linalg.inv(a), c_initial[:, i]) for i, a in enumerate(M) ]).T # Calculates final counts volumes = np.asarray([state[node]['volume'] for node in state]) count_initial = np.asarray( [array_from(state[node]['molecules']) for node in state]) count_final_unrounded = np.asarray([ np.divide(node * volumes[i], array_from(self.mw)) for i, node in enumerate(c_final) ]) + self.remainder count_final = np.asarray( [saferound(col, 0) for col in count_final_unrounded.T]).T # Keeps track of remainder after rounding counts to integers self.remainder = count_final_unrounded - count_final delta = np.subtract(count_final, count_initial) # Ensures conservation of molecules assert (np.array_equal( np.ndarray.sum(count_initial, axis=0), np.ndarray.sum(count_final, axis=0))), 'Molecule count is not conserved' update = { node_id: { 'molecules': array_to( self.molecule_ids, delta[np.where(self.nodes == node_id)[0][0]].astype(int)), } for node_id in self.nodes } return update
def test_error_bad_float(self): bad = ['a', 3.2345, 3.2321, 6.4523, 5.3453, 7.3422] with self.assertRaises(AssertionError): iteround.saferound(bad, 2)
def test_tuple(self): out = (60., 16., 24.) self.assertTupleEqual(iteround.saferound(self.in_tuple, 0), out)
def test_error_bad_places(self): with self.assertRaises(AssertionError): iteround.saferound(self.in_list, 2.5)
def print(self, motifs, file): # http://meme-suite.org/doc/alphabet-format.html#ordering meme_alphabet = string.ascii_uppercase + \ string.ascii_lowercase+string.digits+"*-." ordering = dict(zip(meme_alphabet, range(len(meme_alphabet)))) first = True for motif in motifs: if first: # def print_header(): alphabet = motif.get_alphabet() alphabet_sorted = sorted( alphabet, key=lambda word: [ordering[c] for c in word]) file.write("MEME version 4\n\n") file.write("ALPHABET= {}\n\n".format(''.join(alphabet_sorted))) background = motif.get_background() if background: source_file = motif.get_source() if source_file: file.write( "Background letter frequencies (from {}):\n". format(source_file)) else: file.write("Background letter frequencies\n") safe_background = saferound(background, places=6) for letter in alphabet_sorted: file.write("{} {} ".format(letter, safe_background[letter])) file.write("\n\n") # if first: # print_header() # # Motif name line (required) # # The motif name line indicates the start of a new motif and designates an identifier for it that must be unique to the file. It also allows for an alternate name that does not have to be unique. Neither the identifier nor the alternate name may contain spaces or equal signs (=). # # MOTIF identifier alternate name # # For example: # # MOTIF MA0002.1 RUNX1 def escape_name(name): if not name: return "" # as defined above return name.replace(" ", "_").replace("=", "_") file.write("MOTIF {} {}\n\n".format( escape_name(motif.get_identifier()), escape_name(motif.get_alternate_name()))) # The letter probability matrix is a table of probabilities where the rows are positions in the motif and the columns are letters in the alphabet. The columns are ordered alphabetically so for DNA the first column is A, the second is C, the third is G and the last is T. For protein motifs the columns come in the order A, C, D, E, F, G, H, I, K, L, M, N, P, Q, R, S, T, V, W and Y (see also custom alphabet ordering). As each row contains the probability of each letter in the alphabet the probabilities in the row must sum to 1. # letter-probability matrix: alength= alphabet length w= motif length nsites= source sites E= source E-value alphabet_length = len(alphabet) motif_length = motif.get_length() source_sites = motif.get_number_of_sites() source_sites = source_sites if source_sites != None else 20 e = motif.get_e() file.write( "letter-probability matrix: alength= {} w= {} nsites= {} E= {}\n" .format(alphabet_length, motif_length, source_sites, e)) # ... (letter-probability matrix goes here) ... matrix = motif.get_PPM() for row in matrix: safe_row = saferound(row, places=6) # do not forget on custom ordering file.write("{}\n".format(" ".join([ str(safe_row[alphabet.index(letter)]) for letter in alphabet_sorted ]))) file.write("\n\n") # All the "key= value" pairs after the "letter-probability matrix:" text are optional. The "alength= alphabet length" and "w= motif length" can be derived from the matrix if they are not specified, provided there is an empty line following the letter probability matrix. The "nsites= source sites" will default to 20 if it is not provided and the "E= source E-value" will default to zero. The source sites is used to apply pseudocounts to the motif and the source E-value is used for filtering the motifs input to some MEME Suite programs (see MAST's -mev option). first = False
def test_error_bad_strategy(self): with self.assertRaises(AssertionError): iteround.saferound(self.in_list, 2, strategy='foo')
def test_error_bad_rounder(self): with self.assertRaises(TypeError): iteround.saferound(self.in_list, 2, rounder=lambda x: x)
def test_over_with_sum(self): out = [0.0, 0.0, 0.0, 10.0, 10.0, 10.0] self.assertListEqual(iteround.saferound(self.in_list, -1), out)
def test_overround(self): out = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.assertListEqual(iteround.saferound(self.in_list, -3), out)
def test_negative(self): out = [-4.0, -3.24, -3.23, -6.45, -5.35, -7.34] self.assertListEqual(iteround.saferound(self.neg_in_list, 2), out)