def adjoining_cuts(cuts, bit, board): ''' Given the cuts on an edge, computes the cuts on the adjoining edge. cuts: An array of Cut objects bit: A Router_Bit object board: A Board object Returns an array of Cut objects ''' nc = len(cuts) adjCuts = [] # if the left-most input cut does not include the left edge, add an # adjoining cut that includes the left edge if cuts[0].xmin > 0: left = 0 right = my_round(cuts[0].xmin + bit.offset) - board.dheight if right - left >= board.dheight: adjCuts.append(Cut(left, right)) # loop through the input cuts and form an adjoining cut, formed # by looking where the previous cut ended and the current cut starts for i in lrange(1, nc): left = my_round(cuts[i-1].xmax - bit.offset + board.dheight) right = max(left + bit.width, my_round(cuts[i].xmin + bit.offset) - board.dheight) adjCuts.append(Cut(left, right)) # if the right-most input cut does not include the right edge, add an # adjoining cut that includes this edge if cuts[-1].xmax < board.width: left = my_round(cuts[-1].xmax - bit.offset) + board.dheight right = board.width if right - left >= board.dheight: adjCuts.append(Cut(left, right)) return adjCuts
def adjoining_cuts(cuts, bit, board): ''' Given the cuts on an edge, computes the cuts on the adjoining edge. cuts: An array of Cut objects bit: A Router_Bit object board: A Board object Returns an array of Cut objects ''' nc = len(cuts) adjCuts = [] # if the left-most input cut does not include the left edge, add an # adjoining cut that includes the left edge if cuts[0].xmin > 0: left = 0 right = my_round(cuts[0].xmin + bit.offset) - board.dheight if right - left >= board.dheight: adjCuts.append(Cut(left, right)) # loop through the input cuts and form an adjoining cut, formed # by looking where the previous cut ended and the current cut starts for i in lrange(1, nc): left = my_round(cuts[i - 1].xmax - bit.offset + board.dheight) right = max(left + bit.width, my_round(cuts[i].xmin + bit.offset) - board.dheight) adjCuts.append(Cut(left, right)) # if the right-most input cut does not include the right edge, add an # adjoining cut that includes this edge if cuts[-1].xmax < board.width: left = my_round(cuts[-1].xmax - bit.offset) + board.dheight right = board.width if right - left >= board.dheight: adjCuts.append(Cut(left, right)) return adjCuts
def set_cuts(self): ''' Sets the cuts to make the joint ''' spacing = self.params['Spacing'].v - 2 * self.dhtot width = self.params['Width'].v centered = self.params['Centered'].v board_width = self.boards[0].width units = self.bit.units label = units.increments_to_string(spacing, True) self.labels = self.keys[:] self.labels[0] += ': ' + label self.labels[1] += ': ' + units.increments_to_string(width, True) self.description = 'Equally spaced (' + self.labels[0] + \ ', ' + self.labels[1] + ')' self.cuts = [] # return value neck_width = utils.my_round(self.bit.neck + width - self.bit.width + spacing) if neck_width < 1: raise Spacing_Exception('Specified bit paramters give a zero' ' or negative cut width (%d increments) at' ' the surface! Please change the' ' bit parameters width, depth, or angle.' % neck_width) # put a cut at the center of the board xMid = board_width // 2 if centered or \ self.bit.angle > 0: # always symm. for dovetail left = max(0, xMid - width // 2) else: left = max(0, (xMid // width) * width) right = min(board_width, left + width) self.cuts.append(router.Cut(left, right)) # do left side of board i = left - neck_width min_interior = utils.my_round(self.dhtot + self.bit.offset) while i > 0: li = max(i - width, 0) if i - li > self.config.min_finger_width and i > min_interior: self.cuts.append(router.Cut(li, i)) i = li - neck_width # do right side of board i = right + neck_width while i < board_width: ri = min(i + width, board_width) if ri - i > self.config.min_finger_width and board_width - i > min_interior: self.cuts.append(router.Cut(i, ri)) i = ri + neck_width # If we have only one cut the entire width of the board, then # the board width is too small for the bit if self.cuts[0].xmin == 0 and self.cuts[0].xmax == board_width: raise Spacing_Exception('Unable to compute a equally-spaced'\ ' joint for the board and bit parameters'\ ' specified. This is likely because'\ ' the board width is too small for the'\ ' bit width specified.') # sort the cuts in increasing x self.cuts = sorted(self.cuts, key=attrgetter('xmin')) if self.config.debug: print('e-s cuts:') dump_cuts(self.cuts)
def dovetail_correction(self): ''' Correction for rounding the offset ''' if utils.my_round(self.neck) + 2 * utils.my_round(self.offset) < self.width: return 1 else: return 0
def change_units(self, new_units): '''Changes units to new_units''' s = self.units.get_scaling(new_units) if s == 1: return self.width = my_round(self.width * s) self.height = my_round(self.height * s) self.thickness = my_round(self.thickness * s) self.units = new_units
def change_units(self, new_units): '''Changes units to new_units''' s = self.units.get_scaling(new_units) if s == 1: return self.width = my_round(self.width * s) self.width += self.width % 2 # ensure even self.depth = my_round(self.depth * s) self.units = new_units self.reinit()
def paint_all(self, painter, dpi=None): ''' Paints all the objects. painter: A QPainter object dpi: The resolution of the painter, in dots-per-inch. If None, then the image is maximized in the window, but maintaining aspect ratio. ''' rw = painter.window() window_width = rw.width() window_height = rw.height() units = self.geom.bit.units if dpi is None: # transform the painter to maintain the figure aspect ratio in the current # window window_ar = float(window_width) / window_height fig_ar = float(self.fig_width) / self.fig_height if fig_ar < window_ar: w = utils.my_round(fig_ar * window_height) painter.translate((window_width - w) // 2, window_height) scale = float(window_height) / self.fig_height else: h = utils.my_round(window_width / fig_ar) painter.translate(0, (window_height + h) // 2) scale = float(window_width) / self.fig_width else: # Scale so that the image is the correct size on the page painter.translate(0, window_height) scale = float(dpi) / units.increments_per_inch painter.scale(scale, -scale) # Save the inverse of the un-zoomed transform (self.base_transform, dummy_invertable) = painter.transform().inverted() # Apply the zoom, zooming on the current figure center painter.scale(self.scaling, self.scaling) factor = 0.5 - 0.5 / self.scaling x = self.translate[0] - self.fig_width * factor y = self.translate[1] - self.fig_height * factor painter.translate(x, y) self.transform = painter.transform() # draw the objects self.draw_boards(painter) self.draw_template(painter) self.draw_title(painter) # self.draw_finger_sizes(painter) if self.config.show_finger_widths: self.draw_finger_sizes(painter) return (window_width, window_height)
def paint_all(self, painter, dpi=None): ''' Paints all the objects. painter: A QPainter object dpi: The resolution of the painter, in dots-per-inch. If None, then the image is maximized in the window, but maintaining aspect ratio. ''' rw = painter.window() window_width = rw.width() window_height = rw.height() units = self.geom.bit.units if dpi is None: # transform the painter to maintain the figure aspect ratio in the current # window window_ar = float(window_width) / window_height fig_ar = float(self.fig_width) / self.fig_height if fig_ar < window_ar: w = utils.my_round(fig_ar * window_height) painter.translate((window_width - w) // 2, window_height) scale = float(window_height) / self.fig_height else: h = utils.my_round(window_width / fig_ar) painter.translate(0, (window_height + h) // 2) scale = float(window_width) / self.fig_width else: # Scale so that the image is the correct size on the page painter.translate(0, window_height) scale = float(dpi) / units.increments_per_inch painter.scale(scale, -scale) # Save the inverse of the un-zoomed transform (self.base_transform, invertable) = painter.transform().inverted() # Apply the zoom, zooming on the current figure center painter.scale(self.scaling, self.scaling) factor = 0.5 - 0.5 / self.scaling x = self.translate[0] - self.fig_width * factor y = self.translate[1] - self.fig_height * factor painter.translate(x, y) self.transform = painter.transform() # draw the objects self.draw_boards(painter) self.draw_template(painter) self.draw_title(painter) if self.config.show_finger_widths: self.draw_finger_sizes(painter) return (window_width, window_height)
def image_fig(self, template, boards, bit, spacing, woods, min_width): ''' Prints the figure to a QImage object ''' self.woods = woods self.set_fig_dimensions(template, boards) self.geom = router.Joint_Geometry(template, boards, bit, spacing, self.margins,\ self.config.caul_trim) self.current_background = self.background s = self.size() window_ar = float(s.width()) / s.height() fig_ar = float(self.fig_width) / self.fig_height if window_ar < fig_ar: w = max(min_width, s.width()) else: w = max(min_width, int(s.height() * fig_ar)) h = utils.my_round(w / fig_ar) sNew = QtCore.QSize(w, h) image = QtGui.QImage(sNew, QtGui.QImage.Format_RGB32) painter = QtGui.QPainter() painter.begin(image) size = image.size() painter.fillRect(0, 0, size.width(), size.height(), self.background) self.paint_all(painter) painter.end() return image
def image(self, template, boards, bit, spacing, woods, description): ''' Prints the figure to a QImage object ''' self.woods = woods self.description = description self.set_fig_dimensions(template, boards) self.geom = router.Joint_Geometry(template, boards, bit, spacing, self.margins, self.config) self.set_colors(True) s = self.size() window_ar = float(s.width()) / s.height() fig_ar = float(self.fig_width) / self.fig_height if window_ar < fig_ar: w = s.width() else: w = int(s.height() * fig_ar) w = max(self.config.min_image_width, min(self.config.max_image_width, w)) h = utils.my_round(w / fig_ar) sNew = QtCore.QSize(w, h) im = QtGui.QImage(sNew, QtGui.QImage.Format_RGB32) painter = QtGui.QPainter() painter.begin(im) size = im.size() if self.colors['canvas_background'] is not None: b = QtGui.QBrush(self.colors['canvas_background']) painter.fillRect(0, 0, size.width(), size.height(), b) self.paint_all(painter) painter.end() return im
def __str__(self): result = ['ellipsoid:'] #result.append('lengths measured in meters') for (k, v) in sorted(self.__dict__.items()): if k == 'phi_0': continue result.append(' ' + k + ' = ' + str(my_round(v, 15))) return "\n".join(result)
def set_font_size(self, painter, param): ''' Sets the font size for type param ''' font_inches = self.font_size[param] / 32.0 * self.geom.bit.units.increments_per_inch font = painter.font() xx = self.transform.map(font_inches, 0)[0] - self.transform.dx() font.setPixelSize(utils.my_round(xx)) painter.setFont(font)
def set_font_size(self, painter, param): ''' Sets the font size for type param ''' font_inches = self.font_size[ param] / 32.0 * self.geom.bit.units.increments_per_inch font = painter.font() xx = self.transform.map(font_inches, 0)[0] - self.transform.dx() font.setPixelSize(utils.my_round(xx)) painter.setFont(font)
def __init__(self, bit, boards, config): Base_Spacing.__init__(self, bit, boards, config) # eff_width is the effective width, an average of the bit width # and the neck width self.eff_width = utils.my_round(0.5 * (self.bit.width + self.bit.neck)) + 2 * self.dhtot self.wb = self.boards[0].width // self.eff_width self.alpha = (self.wb + 1) % 2 # min and max number of fingers self.mMin = max(3 - self.alpha, utils.my_round(math.ceil(math.sqrt(self.wb)))) self.mMax = utils.my_round((self.wb - 1.0 + self.alpha) // 2) if self.mMax < self.mMin: raise Spacing_Exception('Unable to compute a variable-spaced'\ ' joint for the board and bit parameters'\ ' specified. This is likely because'\ ' the board width is too small for the'\ ' bit width specified.') self.mDefault = (self.mMin + self.mMax) // 2 self.params = {'Fingers':Spacing_Param(self.mMin, self.mMax, self.mDefault)}
def paint_all(self, painter, dpi=None): ''' Paints all the objects. painter: A QPainter object dpi: The resolution of the painter, in dots-per-inch. If None, then the image is maximized in the window, but maintaining aspect ratio. ''' rw = painter.window() window_width = rw.width() window_height = rw.height() units = self.geom.bit.units if dpi is None: # transform the painter to maintain the figure aspect ratio in the current # window window_ar = float(window_width) / window_height fig_ar = float(self.fig_width) / self.fig_height if fig_ar < window_ar: w = utils.my_round(fig_ar * window_height) painter.translate((window_width - w) // 2, window_height) scale = float(window_height) / self.fig_height else: h = utils.my_round(window_width / fig_ar) painter.translate(0, (window_height + h) // 2) scale = float(window_width) / self.fig_width else: # Scale so that the image is the correct size on the page painter.translate(0, window_height) scale = float(dpi) / units.increments_per_inch painter.scale(scale, -scale) self.transform = painter.transform() painter.setPen(QtCore.Qt.black) # draw the objects self.draw_boards(painter) self.draw_template(painter) self.draw_title(painter) self.draw_cut_sizes(painter) return (window_width, window_height)
def get_limits(self, f): ''' Returns the x-coordinate limits of the cut index f ''' xmin = 0 xmax = self.boards[0].width neck_width = utils.my_round(self.bit.neck) if f > 0: xmin = self.cuts[f - 1].xmax + neck_width if f < len(self.cuts) - 1: xmax = self.cuts[f + 1].xmin - neck_width return (xmin, xmax)
def get_limits(self, f): """ Returns the x-coordinate limits of the cut index f """ xmin = 0 xmax = self.boards[0].width neck_width = utils.my_round(self.bit.neck) if f > 0: xmin = self.cuts[f - 1].xmax + neck_width if f < len(self.cuts) - 1: xmax = self.cuts[f + 1].xmin - neck_width return (xmin, xmax)
def upgrade(self): eff_width = self.bit.midline + self.dhtot * 2 wb = self.boards[0].width // eff_width alpha = (wb + 1) % 2 m = self.params['Fingers'].v c = eff_width * ((m - 1) * wb - m * (m + 1) + alpha * m) / D(m * m - 2 * m - 1 + alpha) d = utils.my_round((c - eff_width) / (m - 1)) self.params[Variable_Spaced.keys[1]] = Spacing_Param(0, d, d) self.params[Variable_Spaced.keys[2]] = Spacing_Param( 0, 0, False) # No inverse in previous version
def set_height(self, bit, dheight=None): ''' Sets the height from the router bit depth of cut ''' if dheight is None: if self.dheight > 0: h = self.dheight else: h = my_round(0.5 * bit.depth) else: self.dheight = dheight h = dheight self.height = bit.depth + h
def get_limits(self, f): ''' Returns the x-coordinate limits of the cut index f ''' xmin = 0 xmax = self.boards[0].width midline = utils.my_round(self.bit.midline) overhang = self.bit.overhang if f > 0: xmin = self.cuts[f - 1].xmax + midline - overhang * 2 if f < len(self.cuts) - 1: xmax = self.cuts[f + 1].xmin - midline + overhang * 2 return (xmin, xmax)
def __init__(self, bit, boards, config): Base_Spacing.__init__(self, bit, boards, config) # eff_width is the effective width, an average of the bit width # and the neck width self.eff_width = utils.my_round( 0.5 * (self.bit.width + self.bit.neck)) + 2 * self.dhtot self.wb = self.boards[0].width // self.eff_width self.alpha = (self.wb + 1) % 2 # min and max number of fingers self.mMin = max(3 - self.alpha, utils.my_round(math.ceil(math.sqrt(self.wb)))) self.mMax = utils.my_round((self.wb - 1.0 + self.alpha) // 2) if self.mMax < self.mMin: raise Spacing_Exception('Unable to compute a variable-spaced'\ ' joint for the board and bit parameters'\ ' specified. This is likely because'\ ' the board width is too small for the'\ ' bit width specified.') self.mDefault = (self.mMin + self.mMax) // 2 self.params = { 'Fingers': Spacing_Param(self.mMin, self.mMax, self.mDefault) }
def cut_add(self): ''' Adds a cut to the first location possible, searching from the left. The active cut is set the the new cut. ''' neck_width = utils.my_round(self.bit.neck) index = None cuts_save = copy.deepcopy(self.cuts) if self.cuts[0].xmin > self.bit.neck: if self.config.debug: print('add at left') index = 0 xmin = 0 xmax = self.cuts[0].xmin - neck_width wadd = 2 * self.bit.width + neck_width wdelta = self.bit.width - neck_width for i in lrange(1, len(self.cuts)): if self.cuts[i].xmin - self.cuts[i - 1].xmax + wdelta >= wadd: if self.config.debug: print('add in cut') index = i xmin = self.cuts[i - 1].xmax + neck_width xmax = xmin + self.bit.width break elif self.cuts[i].xmax - self.cuts[i].xmin >= wadd: if self.config.debug: print('add in cut') index = i + 1 xmin = self.cuts[i].xmax - self.bit.width xmax = self.cuts[i].xmax self.cuts[i].xmax = self.cuts[i].xmin + self.bit.width break if index is None and \ self.cuts[-1].xmax < self.boards[0].width - self.bit.neck: if self.config.debug: print('add at right') index = len(self.cuts) xmax = self.boards[0].width xmin = self.cuts[-1].xmax + neck_width if index is None: return 'Unable to add cut' self.undo_cuts.append(cuts_save) c = self.cuts[0:index] c.append(router.Cut(xmin, xmax)) c.extend(self.cuts[index:]) self.cuts = c self.cursor_cut = index self.active_cuts = [index] return 'Added cut'
def set_cuts(self): ''' Sets the cuts to make the joint ''' # on local variables init # we have to care about imperial values and convert them to increments before use spacing = self.params['Spacing'].v width = Decimal(math.floor(self.params['Width'].v)) if not self.bit.units.metric and width < 1.: spacing = self.bit.units.inches_to_increments(self.params['Spacing'].v) width = Decimal(math.floor(self.bit.units.inches_to_increments(self.params['Width'].v))) shift = Decimal(self.bit.midline % 2) / 2 # offset to keep cut center mm count centered = self.params['Centered'].v neck_width = width + spacing overhang = self.bit.overhang board_width = self.boards[0].width units = self.bit.units label = units.increments_to_string(spacing, True) min_interior = utils.my_round(self.dhtot + self.bit.overhang) # min_finger_width means most thin wood at the corner min_finger_width = max(1, units.abstract_to_increments(self.config.min_finger_width)) if centered or \ self.bit.angle > 0: # always symm. for dovetail # put a cut at the center of the board with half of inctrmrnt prec. xMid = Decimal(board_width // 2) - shift + (width % 2) / 2 left = Decimal(max(0, xMid - width / 2)) else: # keep corner finger and groove equality on the board edges left = (board_width % (width + neck_width)) // 2 if (left - overhang) < min_finger_width: left = 0 # Note the Width slider measures "midline" but indicates the actual cut space # show actual maximum cut with for dovetails self.labels = self.keys[:] l0 = self.transl.tr(self.labels[0]) l1 = self.transl.tr(self.labels[1]) self.labels[2] = self.transl.tr(self.labels[2]) self.labels[0] = l0 +': ' + label self.labels[1] = l1 +': ' + units.increments_to_string(width + overhang * 2, True) self.description = self.transl.tr('Equally spaced ')+' (' + self.labels[0] + \ ', ' + self.labels[1] + ')' self.cuts = [] # return value right = Decimal(min(board_width, left + width)) self.cuts.append(router.Cut(left - overhang, right + overhang)) # do left side of board i = left while left > 0: i -= neck_width left = i - width # prevent thin first cut if left < min_finger_width: left = 0 if (i - overhang) > min_finger_width and (i - left - overhang * 2) > min_interior: self.cuts.append(router.Cut(max(0, left - overhang), i + overhang)) i = left # do right side of board i = right while right < board_width: i += neck_width right = i + width # prevent thin last cut # devetail may cut off corner finger if (board_width - right) < min_finger_width: right = board_width if (board_width - i + overhang) > min_finger_width and\ (right - i - overhang * 2) > min_interior: self.cuts.append(router.Cut(i - overhang, min(board_width, right + overhang))) i = right # If we have only one cut the entire width of the board, then # the board width is too small for the bit if self.cuts[0].xmin == 0 and self.cuts[0].xmax == board_width: raise Spacing_Exception(self.transl.tr(Equally_Spaced.msg)) # sort the cuts in increasing x self.cuts = sorted(self.cuts, key=attrgetter('xmin')) if self.config.debug: print('e-s cuts:') dump_cuts(self.cuts)
def distortion_stats(T, sample, my_round_numbers=3): r""" Return the sample minimum, sample maximum, sample median, sample mean, and sample standard deviation of the maximum angular distortion, linear distortion, and area distortion functions for the map projection `T` (an projection_tools.Proj or projection_tools.Proj4 instance) of the list `sample` of longitude-latitude points chosen from the surface `T.ellipsoid`. Most likely you will want sample to comprise points sampled uniformly at random from the surface of `T.ellipsoid` (and not simply sampled uniformly at random from the rectangle (-pi, pi) x (-pi/2, pi/2)). OUTPUT: (distortions, stats), where distortions is a list of distortion() outputs for each longitude- latitude point sampled; stats is the list of lists [maximum angular distortion stats, linear distortion stats, area distortion stats], where each stats sublist is of the form [sample mean, sample standard deviation, sample minimum, sample maximum, sample median]. EXAMPLES:: >>> from projection_wrapper import Proj >>> from ellipsoids import WGS84_ELLIPSOID_RADIANS >>> E = WGS84_ELLIPSOID_RADIANS >>> f = Proj(ellipsoid=E, proj='healpix') >>> sample = [E.random_point() for i in range(100)] >>> print(distortion_stats(f, sample)[1]) # doctest: +SKIP [[0.309, 0.238, 0.001, 0.838, 0.178], [1.41, 0.375, 1.001, 2.372, 1.195], [1.178, 0.0, 1.178, 1.178, 1.178]] """ distortions = [] distortions_slice = [] k = len(distortion(T, 0, 0)) - 1 sample_sum = array([0.0 for i in range(k)]) sample_min = array([float('inf') for i in range(k)]) sample_max = array([float('-inf') for i in range(k)]) N = len(sample) for (lam, phi) in sample: d = distortion(T, lam, phi) distortions.append(d) distortions_slice.append(d[1:]) for i in range(k): if d[1 + i] < sample_min[i]: sample_min[i] = d[1 + i] if d[1 + i] > sample_max[i]: sample_max[i] = d[1 + i] sample_sum += array(d[1:]) distortions_slice = array(distortions_slice) sample_median = median(distortions_slice, axis=0) sample_mean = sample_sum/N sample_var = sum(((d - sample_mean)**2 for d in distortions_slice))/(N - 1) sample_std = sqrt(sample_var) #sample_mean_error = sample_std/sqrt(N) # Zero until i find an appropriate estimate: #sample_std_error = [0 for i in range(k)] # Compile stats. stats = [sample_mean, sample_std, sample_min, sample_max, sample_median] #errors = [sample_mean_error, sample_std_error] # Reorder to have ld stuff followed by ad stuff. stats = list(zip(*stats)) #errors = zip(*errors) ## Compile result #stats = [stats[0], errors[0], stats[1], errors[1]] # Round stats if desired. if my_round_numbers: new_stats = [] for x in stats: new_stats.append([my_round(xx, my_round_numbers) for xx in x]) stats = new_stats return distortions, stats
def set_cuts(self): """ Sets the cuts to make the joint """ board_width = self.boards[0].width m = self.params["Fingers"].v self.labels = [self.keys[0] + ":"] self.description = "Variable Spaced (" + self.keys[0] + ": {})".format(m) # c is the ideal center-cut width c = ( self.eff_width * ((m - 1.0) * self.wb - m * (m + 1.0) + self.alpha * m) / (m * m - 2.0 * m - 1.0 + self.alpha) ) # d is the ideal decrease in finger width for each finger away from center finger d = (c - self.eff_width) / (m - 1.0) # compute fingers on one side of the center and the center and store them # in increments. Keep a running total of sizes. increments = [0] * (m + 1) ivals = 0 for i in lrange(1, m + 1): increments[i] = max(self.bit.width, int(c - d * i)) ivals += 2 * increments[i] # Set the center increment. This takes up the slop in the rounding and increment # resolution. increments[0] = board_width - ivals if increments[0] < increments[1]: # The center increment is narrower than the adjacent increment, # so reset it to the adjacent increment and get rid of a finger. increments[0] = increments[1] m -= 1 if self.config.debug: print("v-s increments", increments) # Adjustments for dovetails deltaP = self.bit.width + 2 * self.dhtot - self.eff_width deltaM = utils.my_round(self.eff_width - self.bit.neck - 2 * self.dhtot) - self.bit.dovetail_correction() # put a cut at the center of the board xMid = board_width // 2 width = increments[0] + deltaP left = max(0, xMid - width // 2) right = min(board_width, left + width) self.cuts = [router.Cut(left, right)] # do the remaining cuts do_cut = False for i in lrange(1, m + 1): if do_cut: width = increments[i] + deltaP farLeft = max(0, left - width) self.cuts.append(router.Cut(farLeft, left)) farRight = min(board_width, right + width) self.cuts.append(router.Cut(right, farRight)) else: width = increments[i] - deltaM farLeft = max(0, left - width) farRight = min(board_width, right + width) left = farLeft right = farRight do_cut = not do_cut # sort the cuts in increasing x self.cuts = sorted(self.cuts, key=attrgetter("xmin")) if self.config.debug: print("v-s cuts:") dump_cuts(self.cuts)
def test_calculator(): resolver = ExpressionResolver(verbose=False) # Simple test ret = resolver.solve(expression="5 * 5^0") assert ret == "5.0" # Simple test exponential ret = resolver.solve(expression="5 * 5^10") assert ret == "48828125.0" # Simple test with priority ret = resolver.solve(expression="5 * 5 + 10") assert ret == "35.0" # Simple test with float ret = resolver.solve(expression="5.3 * 5.2 + 10.8") assert ret == "38.36" # Test with parenthesis ret = resolver.solve(expression="5 * (5 + 10)") assert ret == "75.0" # Test with multiple parenthesis ret = resolver.solve(expression="5 * (5 + (10 * 50 + 2))") assert ret == "2535.0" # Test with multiple useless parenthesis ret = resolver.solve(expression="((((5 * (5 + (10 * 50 + 2))))))") assert ret == "2535.0" # Hard test with multiple parenthesis ret = resolver.solve( expression= "5 * (5 + (10 * 50 + 24.15) * 50 * 18 *(12 + 52)) * (18 - (5 + 2))") assert ret == "1660507475.0" # Hard test with float ret = resolver.solve( expression="545875785748.34444444478 * 5.2542 + 10456.81212") assert my_round(float(ret), 2) == my_round(2868140563935.763, 2) # Implicit multiplication with open parenthesis ret = resolver.solve(expression="25(5 + 2)") assert ret == "175.0" # Implicit multiplication with closing parenthesis ret = resolver.solve(expression="(5 + 2)25") assert ret == "175.0" # Test different parenthesis ret = resolver.solve(expression="(5 + 2]25") assert ret == "175.0" # Test different parenthesis ret = resolver.solve(expression="[5 + 2]25") assert ret == "175.0" # Test different parenthesis ret = resolver.solve(expression="[5 + 2}25") assert ret == "175.0" # Test multiplying by a signed number ret = resolver.solve(expression="5 * -10 + 599") assert ret == "549.0" # Test multiplying by a signed number ret = resolver.solve(expression="5 * +10") assert ret == "50.0" # Test multiplying by a signed number in parenthesis ret = resolver.solve(expression="5 * (+10)") assert ret == "50.0" # Test multiplying by a signed number in parenthesis ret = resolver.solve(expression="(+10)10") assert ret == "100.0" # Test substract by a signed number in parenthesis ret = resolver.solve(expression="(-10)-10") assert ret == "-20.0" # Test substract by a signed number in parenthesis ret = resolver.solve(expression="(-10)(-10)") assert ret == "100.0" # Test multiplying by a signed float ret = resolver.solve(expression="5 * -10.35843958432134 + 599") assert my_round(float(ret), 2) == my_round(547.2078020783933, 2) # Test sign before first number ret = resolver.solve(expression="-42-2") assert ret == "-44.0" # Test one var with parenthesis in calculator ret = resolver.solve(expression="5 * x(5 + 10)") assert ret == "75.0*X"
def scale(self, s): '''Scales dimensions by the factor s''' self.width = my_round(self.width * s) self.width += self.width % 2 # ensure even self.depth = my_round(self.depth * s) self.reinit()
def set_cuts(self): """ Sets the cuts to make the joint """ spacing = self.params["Spacing"].v - 2 * self.dhtot width = self.params["Width"].v centered = self.params["Centered"].v board_width = self.boards[0].width units = self.bit.units label = units.increments_to_string(spacing, True) self.labels = self.keys[:] self.labels[0] += ": " + label self.labels[1] += ": " + units.increments_to_string(width, True) self.description = "Equally spaced (" + self.labels[0] + ", " + self.labels[1] + ")" self.cuts = [] # return value neck_width = width + spacing - 2 * utils.my_round(self.bit.offset) if neck_width < 1: raise Spacing_Exception( "Specified bit paramters give a zero" " or negative cut width (%d increments) at" " the surface! Please change the" " bit parameters width, depth, or angle." % neck_width ) # put a cut at the center of the board xMid = board_width // 2 if centered or self.bit.angle > 0: # always symm. for dovetail left = max(0, xMid - width // 2) else: left = max(0, (xMid // width) * width) right = min(board_width, left + width) self.cuts.append(router.Cut(left, right)) # do left side of board i = left - neck_width min_interior = utils.my_round(self.dhtot + self.bit.offset) min_finger_width = max(1, units.abstract_to_increments(self.config.min_finger_width)) while i > 0: li = max(i - width, 0) if i - li > min_finger_width and i > min_interior: self.cuts.append(router.Cut(li, i)) i = li - neck_width # do right side of board i = right + neck_width while i < board_width: ri = min(i + width, board_width) if ri - i > min_finger_width and board_width - i > min_interior: self.cuts.append(router.Cut(i, ri)) i = ri + neck_width # If we have only one cut the entire width of the board, then # the board width is too small for the bit if self.cuts[0].xmin == 0 and self.cuts[0].xmax == board_width: raise Spacing_Exception( "Unable to compute a equally-spaced" " joint for the board and bit parameters" " specified. This is likely because" " the board width is too small for the" " bit width specified." ) # sort the cuts in increasing x self.cuts = sorted(self.cuts, key=attrgetter("xmin")) if self.config.debug: print("e-s cuts:") dump_cuts(self.cuts)
def set_cuts(self): ''' Sets the cuts to make the joint ''' board_width = self.boards[0].width m = self.params['Fingers'].v self.labels = [self.keys[0] + ': %d' % m] self.description = 'Variable Spaced (' + self.labels[0] + ')' # c is the ideal center-cut width c = self.eff_width * ((m - 1.0) * self.wb - \ m * (m + 1.0) + self.alpha * m) /\ (m * m - 2.0 * m - 1.0 + self.alpha) # d is the ideal decrease in finger width for each finger away from center finger d = (c - self.eff_width) / (m - 1.0) # compute fingers on one side of the center and the center and store them # in increments. Keep a running total of sizes. increments = [0] * (m + 1) ivals = 0 for i in lrange(1, m + 1): increments[i] = max(2, int(c - d * i)) ivals += 2 * increments[i] # Set the center increment. This takes up the slop in the rounding and increment # resolution. increments[0] = board_width - ivals if increments[0] < increments[1]: # The center increment is narrower than the adjacent increment, # so reset it to the adjacent increment and get rid of a finger. increments[0] = increments[1] m -= 1 if self.config.debug: print('v-s increments', increments) # Adjustments for dovetails deltaP = self.bit.width + 2 * self.dhtot - self.eff_width deltaM = utils.my_round(self.eff_width - self.bit.neck - 2 * self.dhtot) # put a cut at the center of the board xMid = board_width // 2 width = increments[0] + deltaP left = max(0, xMid - width // 2) right = min(board_width, left + width) self.cuts = [router.Cut(left, right)] # do the remaining cuts do_cut = False for i in lrange(1, m + 1): if do_cut: width = increments[i] + deltaP farLeft = max(0, left - width) self.cuts.append(router.Cut(farLeft, left)) farRight = min(board_width, right + width) self.cuts.append(router.Cut(right, farRight)) else: width = increments[i] - deltaM farLeft = max(0, left - width) farRight = min(board_width, right + width) left = farLeft right = farRight do_cut = (not do_cut) # sort the cuts in increasing x self.cuts = sorted(self.cuts, key=attrgetter('xmin')) if self.config.debug: print('v-s cuts:') dump_cuts(self.cuts)
def resolve_npi(self, npi_list) -> str: stack = [] c = 0.0 var_is_present = True if self.var_name else False for elem in npi_list: if is_number(elem) or (var_is_present and elem in self.var_name): stack.append(elem) else: last_two_in_stack = stack[-2:] del stack[-2:] if len(last_two_in_stack) < 2: raise IndexError( "There is a problem in the npi resolver, the npi_list isn't well formated." ) # Doing var calc if there is a var if var_is_present and ( self._check_have_var(str(last_two_in_stack[0])) or self._check_have_var(str(last_two_in_stack[1])) ): # - or + operator, adding to c if elem in _SIGN: if not self._check_have_var(str(last_two_in_stack[0])): if elem == "-": c = my_round(c + float(last_two_in_stack[0])) # Inverting the sign of the var because it is the second element. result = self._multiply_a_var("-1", str(last_two_in_stack[1])) else: c = my_round(c + float(last_two_in_stack[0])) result = str(last_two_in_stack[1]) elif not self._check_have_var(str(last_two_in_stack[1])): if elem == "-": c = my_round(c - float(last_two_in_stack[1])) else: c = my_round(c + float(last_two_in_stack[1])) result = str(last_two_in_stack[0]) else: # Adding var to var result = self._add_or_substract_var_to_var( operator=elem, first_var=str(last_two_in_stack[0]), second_var=str(last_two_in_stack[1]), ) elif elem == "*": result = self._multiply_a_var( str(last_two_in_stack[0]), str(last_two_in_stack[1]) ) elif elem == "/": result = self._divide_a_var( str(last_two_in_stack[0]), str(last_two_in_stack[1]) ) elif elem == "^": result = self._power_a_var( str(last_two_in_stack[0]), str(last_two_in_stack[1]) ) else: raise NotImplementedError( "This type of operation with vars is not accepted for the moment." ) # Doing usual calc elif elem == "^": result = my_round( my_power(float(last_two_in_stack[0]), float(last_two_in_stack[1])) ) elif elem == "*": result = my_round(float(last_two_in_stack[0]) * float(last_two_in_stack[1])) elif elem == "/": if float(last_two_in_stack[1]) == 0.0: raise ValueError( "The expression lead to a division by zero : ", float(last_two_in_stack[0]), " / ", float(last_two_in_stack[1]), ) result = my_round(float(last_two_in_stack[0]) / float(last_two_in_stack[1])) elif elem == "%": if float(last_two_in_stack[1]) == 0.0: raise ValueError( "The expression lead to a modulo zero : ", float(last_two_in_stack[0]), " % ", float(last_two_in_stack[1]), ) result = my_round(float(last_two_in_stack[0]) % float(last_two_in_stack[1])) elif elem == "+": result = my_round(float(last_two_in_stack[0]) + float(last_two_in_stack[1])) elif elem == "-": result = my_round(float(last_two_in_stack[0]) - float(last_two_in_stack[1]), 6) stack.append(result) if len(stack) > 1: raise Exception( "Unexpected error when trying to resolve npi. Maybe your input format is not accepted?" ) if var_is_present: if c != 0.0: # Parse sign because could have duplicate sign with the add of the + return parse_sign(str(c) + "+" + str(stack[0])) else: return str(stack[0]) else: return str(stack[0])
def _solve_polynom_degree_two(self): try: a = get_var_multiplier(self._polynom_dict_left["a"], var_name=self.var_name) except: a = 0.0 try: b = get_var_multiplier(self._polynom_dict_left["b"], var_name=self.var_name) except: b = 0.0 try: c = float(self._polynom_dict_left["c"]) except: c = 0.0 print("a = ", a, " b = ", b, " c = ", c) if self._verbose is True else None discriminant = self._get_discriminant(a, b, c) if discriminant > 0: print("The discriminant is strictly positive.") elif discriminant == 0: print("The discriminant is exactly zero.") else: print("The discriminant is strictly negative.") print("discriminant = ", discriminant) if discriminant > 0: self.solution = [] if a == 0: raise ValueError( "The expression lead to a division by zero : ", float(str((-b + my_sqrt(discriminant)))), " / ", a, ) solution_one = str((-b + my_sqrt(discriminant)) / (2 * a)) solution_two = str((-b - my_sqrt(discriminant)) / (2 * a)) if solution_one == "-0.0": solution_one = "0.0" if solution_two == "-0.0": solution_two = "0.0" self.solution.append(str(my_round(float(solution_one), 6))) self.solution.append(str(my_round(float(solution_two), 6))) elif discriminant == 0: if a == 0: raise ValueError( "The expression lead to a division by zero : ", float(str((-b + my_sqrt(discriminant)))), " / ", a, ) self.solution = str((-b) / (2 * a)) if self.solution == "-0.0": self.solution = "0.0" else: print("There is two solutions in complex number.") self.solution = [] discriminant = -discriminant solution_one = convert_signed_number( f"{-b} / (2 * {a}) + i * {my_sqrt(discriminant)} / (2 * {a})".replace(" ", "") ) tokens = convert_to_tokens( convert_signed_number(parse_sign(solution_one), accept_var=True) ) self.solution.append( self._calculator.solve(tokens=tokens, verbose=self._force_calculator_verbose) ) solution_two = f"{-b} / (2 * {a}) - i * {my_sqrt(discriminant)} / (2 * {a})".replace( " ", "" ) tokens = convert_to_tokens( convert_signed_number(parse_sign(solution_two), accept_var=True) ) self.solution.append( self._calculator.solve(tokens=tokens, verbose=self._force_calculator_verbose) )
def main(inp, method, training_size, epoch): sample_func, data = sampling_methods[method] if data[-4:] == '.pth': data = torch.load(data) device = torch.device('cpu') batch_size = 128 budget = epoch config = { 'ndim': 250, 'sdim': 56, 'num_gnn_layers': 2, 'g_aggr': 'gsum', 'num_acc_layers': 4, 'lr': 0.00001, } t0 = time() test_dataset = fetch_data('data/test_data_20.pth') logging.info('Loaded test graphs in {} sec.'.format(round(time() - t0, 2))) t0 = time() val_dataset = fetch_data('data/validation_data_10.pth') logging.info('Loaded validation graphs model in {} sec.'.format( round(time() - t0, 2))) test_loader = DataLoader(test_dataset, batch_size=2048, shuffle=False) val_loader = DataLoader(val_dataset, batch_size=2048, shuffle=False) criterion = nn.MSELoss() for num in [training_size]: ratio = np.round(num / 100, 2) run_name = '{}{}'.format(method, num) rmse_list = list() all_loss = list() best_rmse_list = [] for step in range(5): logger.info('sampling') sampled_dataset = sample_func(ratio, data) train_loader = DataLoader(sampled_dataset, batch_size=batch_size, shuffle=True) logger.info('start run {}_{} with {}% ({} graphs) '.format( run_name, step + 1, num, len(sampled_dataset))) model = GNNpred(config['ndim'], config['sdim']).to(device) optimizer = torch.optim.Adam(model.parameters(), lr=config['lr']) best_val = np.inf best_test = np.inf for epoch in range(int(budget)): loss = 0 model.train() running_loss = torch.Tensor().to(device) for i, graph_batch in enumerate(train_loader): graph_batch = graph_batch.to(device) optimizer.zero_grad() output = model(graph_batch.edge_index, graph_batch.node_atts, graph_batch.batch.to(device)) loss = criterion(output.view(-1), graph_batch.acc) running_loss = torch.cat([running_loss, loss.view(-1)]) loss.backward() optimizer.step() loss = torch.sqrt(torch.mean(running_loss)).item() all_loss.append(loss) logger.info('epoch {}:\tloss = {}'.format( epoch, my_round(loss, 4))) val_rmse, _, val_acc = evaluate(model, val_loader, device) logger.info('epoch {}:\tval_rmse = {}'.format( epoch, my_round(val_rmse, 4))) test_rmse, test_mae, _ = evaluate(model, test_loader, device) logger.info('epoch {}:\ttest_rmse = {}'.format( epoch, my_round(test_rmse, 4))) logger.info('epoch {}:\ttest_mae = {}'.format( epoch, my_round(test_mae, 4))) if val_rmse < best_val: best_val = val_rmse best_test = test_rmse # save(model, run_name) rmse_list.append(best_val) best_rmse_list.append(best_val) logger.info('step {}:\tbest_test = {}'.format( step + 1, my_round(best_test, 4))) torch.save(rmse_list, path_results + '/{}_all_rmse.pth'.format(run_name)) logger.info('Saved all validation rmse to {}'.format(path_results)) torch.save(best_rmse_list, path_results + '/{}_best_rmse.pth'.format(run_name)) logger.info('Saved best validation rmse of each run to {}'.format( path_results)) torch.save(all_loss, path_results + '/{}_loss.pth'.format(run_name)) logger.info('Saved trainings loss to {}'.format(path_results)) torch.save(val_acc, path_saved_acc + '/{}_val_acc.pth'.format(run_name)) logger.info( 'Saved true and predicted accuracy of validation set to {}'. format(path_saved_acc)) _, _, train_acc = evaluate(model, train_loader, device) torch.save(train_acc, path_saved_acc + '/{}_train_acc.pth'.format(run_name)) logger.info( 'Saved true and predicted accuracy of training set to {}'. format(path_saved_acc)) logger.info('epoch {}:\ttest_rmse = {}'.format( epoch, my_round(test_rmse, 4))) return loss, val_rmse, test_rmse, test_mae, model.number_of_parameters()
def test_my_round(): # Test round up assert my_round(10.025, 2) == 10.03 # Test multiple round up assert my_round(19.9951, 2) == 20.00 assert my_round(10, 2) == 10 with pytest.raises(ValueError) as e: my_round(10, 200000000) == 10 assert str(e.value) == "Precision should be between 0 and 20" assert my_round(10, 20) == 10 assert my_round(10, 0) == 10 assert my_round(10.01234567891011121314555555555, 20) == 10.01234567891011121314555555555 assert my_round(10.01234567891011121314555555555, 18) == 10.01234567891011121314555555555 assert my_round(10.025, 10) == 10.025 assert my_round(10.025454555557885454242, 10) == 10.0254545556 assert my_round(10.025, 20) == 10.025 assert my_round(10.025454555557885454242, 20) == 10.025454555557885454242 assert my_round(10.0254545555578854542424444447585876545645, 20) == 10.025454555557885454242 assert my_round(0.00000000000000000000000009, 20) == 0 assert my_round(1.11111115e2, 1) == 111.1 # Big round assert my_round(99999999999999999999999999999999999999, 20) == 1e38 assert my_round(1e10, 5) == 10000000000.0 # small round assert my_round(1e-100000, 20) == 0 # Negative round assert my_round(-1.045754345454242, 6) == -1.045754 assert my_round(-0.47513146390886934, 6) == -0.475131