diff options
author | strom <strom@vehikel.(none)> | 2010-05-02 19:04:36 (GMT) |
---|---|---|
committer | strom <strom@vehikel.(none)> | 2010-05-02 19:04:36 (GMT) |
commit | f84b965aa7b4a28786b3520671a5d0fd1881cd6d (patch) | |
tree | 79be950bc29ee8c2eb9ffb1bd0fac6723c486d89 | |
parent | 6416d002a0c99678bc38f1997a9bbc94acd7ead3 (diff) |
Added a sampler for iterated function systems.
-rw-r--r-- | activity/activity.info | 2 | ||||
-rw-r--r-- | ep_formater_html.py | 33 | ||||
-rw-r--r-- | ep_layer_letterpress.py | 55 | ||||
-rw-r--r-- | ep_page_ancestors.py | 2 | ||||
-rw-r--r-- | ep_sampler_affineifs.py | 483 | ||||
-rw-r--r-- | ep_sampler_centeredwalk.py | 5 | ||||
-rw-r--r-- | ep_sampler_randomwalk.py | 5 | ||||
-rw-r--r-- | ep_sampler_rectilineargrid.py | 5 | ||||
-rw-r--r-- | ep_sampler_squaregrid.py | 5 | ||||
-rw-r--r-- | ka_utils.py | 26 | ||||
-rw-r--r-- | model_constraintpool.py | 4 | ||||
-rw-r--r-- | model_locus.py | 2 | ||||
-rw-r--r-- | model_population.py | 3 | ||||
-rw-r--r-- | po/Kandid.pot | 2 | ||||
-rw-r--r-- | test_buildingblocks.py | 11 | ||||
-rw-r--r-- | test_model.py | 2 | ||||
-rw-r--r-- | test_status.py | 2 |
17 files changed, 581 insertions, 66 deletions
diff --git a/activity/activity.info b/activity/activity.info index 41311a4..0add1fc 100644 --- a/activity/activity.info +++ b/activity/activity.info @@ -3,6 +3,6 @@ name = Kandid service_name = net.sourceforge.kandid class = activity.KandidActivity icon = activity-kandid -activity_version = 5 +activity_version = 6 show_launcher = yes mime_types = application/x-kandid-activity; diff --git a/ep_formater_html.py b/ep_formater_html.py index e987b51..c35ff38 100644 --- a/ep_formater_html.py +++ b/ep_formater_html.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import ka_utils """Generate HTML describing the genome.""" @@ -25,8 +26,6 @@ import exon_color import exon_position import exon_direction -ICON_WIDTH = ICON_HEIGHT = 48 - class HtmlFormater(object): """Html formater inv: self._indent >= 0 @@ -94,7 +93,8 @@ class HtmlFormater(object): return u'id_' + unicode(self.id_count) def get_absolutename(self, extension, postfix=None): - """Returns absolute path appended by filename of the generated HTML page.""" + """Returns absolute path appended by filename + of the generated HTML page.""" return os.path.join(self.get_pathname(), self.get_filename(extension, postfix)) @@ -254,14 +254,15 @@ class HtmlFormater(object): pathname = self.get_absolutename('png', postfix=identification) filename = self.get_filename('png', postfix=identification) surface = exon_color.Color.make_icon(color.rgba, alpha, - ICON_WIDTH, ICON_HEIGHT) + ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT) surface.write_to_png(pathname) self.produced_files_list.append(pathname) description = color.explain(alpha) self._begin_list_item(identification) self._append_escaped(text) - self._image_item(filename, ICON_WIDTH, ICON_HEIGHT, description) + self._image_item(filename, ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT, + description) self._end_list_item() def alpha_item(self, alpha, text): @@ -275,14 +276,15 @@ class HtmlFormater(object): pathname = self.get_absolutename('png', postfix=identification) filename = self.get_filename('png', postfix=identification) surface = exon_color.Color.make_icon((1.0, 1.0, 1.0, alpha), True, - ICON_WIDTH, ICON_HEIGHT) + ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT) surface.write_to_png(pathname) self.produced_files_list.append(pathname) description = '%d%% opaque' % (100*alpha) self._begin_list_item(self._get_id()) self._append_escaped(text) - self._image_item(filename, ICON_WIDTH, ICON_HEIGHT, description) + self._image_item(filename, ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT, + description) self._end_list_item() def color_array(self, color_list, text, alpha=True): @@ -300,12 +302,13 @@ class HtmlFormater(object): pathname = self.get_absolutename('png', postfix=identification) filename = self.get_filename('png', postfix=identification) surface = color.make_icon(color.rgba, alpha, - ICON_WIDTH, ICON_HEIGHT) + ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT) surface.write_to_png(pathname) self.produced_files_list.append(pathname) description = color.explain(alpha) - self._image_item(filename, ICON_WIDTH, ICON_HEIGHT, \ - description, newline=False) + self._image_item(filename, + ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT, + description, newline=False) self._end_list_item() def position_item(self, position, text): @@ -335,10 +338,11 @@ class HtmlFormater(object): pathname = self.get_absolutename('png', postfix=identification) filename = self.get_filename('png', postfix=identification) surface = exon_position.Position.make_icon(position_list, - ICON_WIDTH, ICON_HEIGHT) + ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT) surface.write_to_png(pathname) self.produced_files_list.append(pathname) - self._image_item(filename, ICON_WIDTH, ICON_HEIGHT, description) + self._image_item(filename, ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT, + description) self._end_list_item() def direction_item(self, direction, text): @@ -368,10 +372,11 @@ class HtmlFormater(object): pathname = self.get_absolutename('png', postfix=identification) filename = self.get_filename('png', postfix=identification) surface = exon_direction.Direction.make_icon(direction_list, - ICON_WIDTH, ICON_HEIGHT) + ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT) surface.write_to_png(pathname) self.produced_files_list.append(pathname) - self._image_item(filename, ICON_WIDTH, ICON_HEIGHT, description) + self._image_item(filename, ka_utils.ICON_WIDTH, ka_utils.ICON_HEIGHT, + description) self._end_list_item() def surface_item(self, surface, text, description): diff --git a/ep_layer_letterpress.py b/ep_layer_letterpress.py index e625eaa..97dee3c 100644 --- a/ep_layer_letterpress.py +++ b/ep_layer_letterpress.py @@ -195,34 +195,35 @@ class LetterPress(model_layer.Layer): ctx.scale(1.0/width, 1.0/height) pango_ctx = pangocairo.CairoContext(ctx) points = self.sampler.get_sample_points() - fi = di = -1 - for word in self.buzzwords.wordlist: - di = (di+1) % len(points) - px = self.center.x_pos + points[di][0] - py = self.center.y_pos + points[di][1] - - try: - layout = pango_ctx.create_layout() - fi = (fi+1) % len(self.family) - desc = pango.FontDescription(self.family[fi]) - desc.set_size(int(self.size * width * 0.01 * pango.SCALE)) - desc.set_style(self.style) - desc.set_weight(self.weight) - layout.set_text(word.encode('utf-8')) - layout.set_font_description(desc) - layout.set_alignment(pango.ALIGN_CENTER) - rgba = self.textcolor.rgba - pango_ctx.set_source_rgba(rgba[0], rgba[1], rgba[2], rgba[3]) - pango_ctx.update_layout(layout) + if len(points) > 0: + fi = di = -1 + for word in self.buzzwords.wordlist: + di = (di+1) % len(points) + px = self.center.x_pos + points[di][0] + py = self.center.y_pos + points[di][1] - pixel_size = layout.get_pixel_size() - dx, dy = 0.5 * pixel_size[0], 0.9 * pixel_size[1] - pango_ctx.move_to((width * px) - dx, (height * py) - dy) - pango_ctx.show_layout(layout) - except: - ka_debug.err('failed on pango [%s] [%s]' % \ - (sys.exc_info()[0], sys.exc_info()[1])) - traceback.print_exc(file=sys.__stderr__) + try: + layout = pango_ctx.create_layout() + fi = (fi+1) % len(self.family) + desc = pango.FontDescription(self.family[fi]) + desc.set_size(int(self.size * width * 0.01 * pango.SCALE)) + desc.set_style(self.style) + desc.set_weight(self.weight) + layout.set_text(word.encode('utf-8')) + layout.set_font_description(desc) + layout.set_alignment(pango.ALIGN_CENTER) + rgba = self.textcolor.rgba + pango_ctx.set_source_rgba(rgba[0], rgba[1], rgba[2], rgba[3]) + pango_ctx.update_layout(layout) + + pixel_size = layout.get_pixel_size() + dx, dy = 0.5 * pixel_size[0], 0.9 * pixel_size[1] + pango_ctx.move_to((width * px) - dx, (height * py) - dy) + pango_ctx.show_layout(layout) + except: + ka_debug.err('failed on pango [%s] [%s]' % \ + (sys.exc_info()[0], sys.exc_info()[1])) + traceback.print_exc(file=sys.__stderr__) def explain(self, formater): formater.begin_list(_('Layer ') + self.__class__.__name__) diff --git a/ep_page_ancestors.py b/ep_page_ancestors.py index 2955db7..8935bf4 100644 --- a/ep_page_ancestors.py +++ b/ep_page_ancestors.py @@ -38,7 +38,7 @@ class AncestorsController(object): get_nth_page(_ANCESTORS_PAGE_NUMBER) self._historyview = self._widget_tree.get_widget('ancestors_drawingarea') self._history = ka_history.KandidHistory.instance() - self._protozoon_id = '' + self._protozoon_id = None def close(self): """Only a dummy.""" diff --git a/ep_sampler_affineifs.py b/ep_sampler_affineifs.py new file mode 100644 index 0000000..2707948 --- /dev/null +++ b/ep_sampler_affineifs.py @@ -0,0 +1,483 @@ +# coding: UTF-8 +# Copyright 2009, 2010 Thomas Jourdan +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import copy +import ka_utils +import model_random +import model_locus +import model_allele +import model_constraintpool +from gettext import gettext as _ +import random +import math + +NUM_TRANSFORMATION_CONSTRAINT = 'numtransformationconstraint' +SYMMETRY_CONSTRAINT = 'symmetryconstraint' +DN_CONSTRAINT = 'dnconstraint' +ORBIT_CONSTRAINT = 'orbitconstraint' +X_STAMP_SIZE_CONSTRAINT = 'xstampsizeconstraint' +Y_STAMP_SIZE_CONSTRAINT = 'ystampsizeconstraint' + + +MAX_TRANSFORMATIONS = 8 +MAX_MATCHER = 128 + + + +class AffineIfsSampler(model_allele.Allele): + """AffineIfsSampler: Affine iterated function system. + inv: self.symmetry >= 0 + inv: self.num_transformations <= MAX_TRANSFORMATIONS + inv: len(self.mta) == MAX_TRANSFORMATIONS + inv: len(self.mta) == len(self.mtf) + """ + + cdef = [{'bind' : NUM_TRANSFORMATION_CONSTRAINT, + 'name' : 'Number of transformations use in this iterated function system', + 'domain': model_constraintpool.INT_RANGE, + 'min' : 1, 'max': 8}, + {'bind' : SYMMETRY_CONSTRAINT, + 'name' : 'Symmetry', + 'domain': model_constraintpool.INT_RANGE, + 'min' : 0, 'max': 12}, + {'bind' : DN_CONSTRAINT, + 'name' : 'Dn', + 'domain': model_constraintpool.INT_RANGE, + 'min' : 0, 'max': 1}, + {'bind' : ORBIT_CONSTRAINT, + 'name' : 'Number of iterations', + 'domain': model_constraintpool.INT_RANGE, + 'min' : 1, 'max': 150}, + {'bind' : X_STAMP_SIZE_CONSTRAINT, + 'name' : 'Number of rectilinear tiles in x direction', + 'domain': model_constraintpool.FLOAT_RANGE, + 'min' : 0.01, 'max': 0.25}, + {'bind' : Y_STAMP_SIZE_CONSTRAINT, + 'name' : 'Number of rectilinear tiles in y direction', + 'domain': model_constraintpool.FLOAT_RANGE, + 'min' : 0.01, 'max': 0.25}, + ] + + def __init__(self, trunk): + """Constructor for Affine iterated function system.""" + super(AffineIfsSampler, self).__init__(trunk) + self.x_point, self.y_point = 0.0, 0.0 + self.xmin, self.ymin, self.xmax, self.ymax = -1.0, -1.0, 1.0, 1.0 + self.matcher = [0] * MAX_MATCHER + + self.random_seed = 1512 + self.orbits = 10 + self.num_transformations = 1 + self.pol_transf = [[.0, .0, .0, .0, .5, .5]] * MAX_TRANSFORMATIONS + self.mta = [0.0] * MAX_TRANSFORMATIONS + self.mtb = [0.0] * MAX_TRANSFORMATIONS + self.mtc = [0.0] * MAX_TRANSFORMATIONS + self.mtd = [0.0] * MAX_TRANSFORMATIONS + self.mte = [0.0] * MAX_TRANSFORMATIONS + self.mtf = [0.0] * MAX_TRANSFORMATIONS + + self.Dn = 0 + self.symmetry = 0 + self.tr_rand = random.Random(self.random_seed) + + self.x_stamp_size = 1 + self.y_stamp_size = 1 + + def __deepcopy__ ( self, memo ): + """Don't store transient members.""" +# x = AffineIfsSampler(self.get_trunk()) + x = self.__class__(self.get_trunk()) + memo[id(self)] = x + # deep copy members + for n, v in self.__dict__.iteritems(): + # do not copy transient members + if n not in ['x_point', 'y_point', 'xmin', 'ymin', 'xmax', 'ymax', \ + 'tr_rand', 'matcher', \ + 'mta', 'mtb', 'mtc', 'mtd', 'mte', 'mtf', ]: + setattr(x, n, copy.deepcopy(v, memo)) + return x + + def __eq__(self, other): + """Equality based persistent.""" + equal = isinstance(other, AffineIfsSampler) \ + and self.num_transformations == other.num_transformations \ + and self.random_seed == other.random_seed \ + and self.orbits == other.orbits \ + and self.symmetry == other.symmetry \ + and self.Dn == other.Dn \ + and self.x_stamp_size == other.x_stamp_size \ + and self.y_stamp_size == other.y_stamp_size + if equal: + for row, transf in enumerate(self.pol_transf): + for col, value in enumerate(transf): + equal = equal \ + and math.fabs(value-other.pol_transf[row][col]) < 0.0001 + return equal + + def randomize(self): + """Randomize tranformations. + """ + cpool = model_constraintpool.ConstraintPool.get_pool() + symmetry_constraint = cpool.get(self, SYMMETRY_CONSTRAINT) + #TODO symmetry 0, 25 Binominal + self.symmetry = model_random.randint_constrained(symmetry_constraint) + + Dn_constraint = cpool.get(self, DN_CONSTRAINT) + self.Dn = model_random.randint_constrained(Dn_constraint) + + orbit_constraint = cpool.get(self, ORBIT_CONSTRAINT) + self.orbits = model_random.randint_constrained(orbit_constraint) + + self.random_seed = random.randint(1, 65535) + + num_transformations_constraint = cpool.get(self, NUM_TRANSFORMATION_CONSTRAINT) + self.num_transformations = model_random.randint_constrained(num_transformations_constraint) + for tix in range(self.num_transformations): + #translation -2.0, 2.0 + self.pol_transf[tix][0] = model_random.uniform_constrained([-2.0, 2.0]) + self.pol_transf[tix][1] = model_random.uniform_constrained([-2.0, 2.0]) + #rotation -math.pi, math.pi + self.pol_transf[tix][2] = model_random.uniform_constrained([-math.pi, math.pi]) + self.pol_transf[tix][3] = model_random.uniform_constrained([-math.pi, math.pi]) + #scaling 0.0, 1.0 + self.pol_transf[tix][4] = model_random.uniform_constrained([-1.0, 1.0]) + self.pol_transf[tix][5] = model_random.uniform_constrained([-1.0, 1.0]) +# self._prepare_transient_members() + x_stamp_size_constraint = cpool.get(self, X_STAMP_SIZE_CONSTRAINT) + self.x_stamp_size = model_random.uniform_constrained(x_stamp_size_constraint) + y_stamp_size_constraint = cpool.get(self, Y_STAMP_SIZE_CONSTRAINT) + self.y_stamp_size = model_random.uniform_constrained(y_stamp_size_constraint) + + + def mutate(self): + """Mutate transformations.""" + cpool = model_constraintpool.ConstraintPool.get_pool() + #TODO self.pol_transf polar coordinaten mutieren + if model_random.is_mutating(): + symmetry_constraint = cpool.get(self, SYMMETRY_CONSTRAINT) + self.symmetry = model_random.jitter_discret_constrained(self.symmetry, + symmetry_constraint) + if model_random.is_mutating(): + Dn_constraint = cpool.get(self, DN_CONSTRAINT) + self.Dn = model_random.jitter_discret_constrained(self.Dn, + Dn_constraint) + + if model_random.is_mutating(): + orbit_constraint = cpool.get(self, ORBIT_CONSTRAINT) + self.orbits = model_random.jitter_discret_constrained(self.Dn, + orbit_constraint) + self.random_seed = random.randint(1, 65535) + for tix in range(self.num_transformations): + #translation -2.0, 2.0 + self.pol_transf[tix][0] = model_random.jitter_constrained(self.pol_transf[tix][0], [-2.0, 2.0]) + self.pol_transf[tix][1] = model_random.jitter_constrained(self.pol_transf[tix][1], [-2.0, 2.0]) + #rotation -math.pi, math.pi + radian = self.pol_transf[tix][2] + model_random.jitter(0.1) + self.pol_transf[tix][2] = model_random.radian_limit(radian) + radian = self.pol_transf[tix][3] + model_random.jitter(0.1) + self.pol_transf[tix][3] = model_random.radian_limit(radian) + #scaling 0.0, 1.0 + self.pol_transf[tix][4] = model_random.jitter_constrained(self.pol_transf[tix][4], [-1.0, 1.0]) + self.pol_transf[tix][5] = model_random.jitter_constrained(self.pol_transf[tix][5], [-1.0, 1.0]) +# self._prepare_transient_members() + if model_random.is_mutating(): + x_stamp_size_constraint = cpool.get(self, X_STAMP_SIZE_CONSTRAINT) + self.x_stamp_size = model_random.jitter_constrained(self.x_stamp_size, + x_stamp_size_constraint) + if model_random.is_mutating(): + y_stamp_size_constraint = cpool.get(self, Y_STAMP_SIZE_CONSTRAINT) + self.y_stamp_size = model_random.jitter_constrained(self.y_stamp_size, + y_stamp_size_constraint) + + def swap_places(self): + """Exchange x- and y-stamp_size.""" + self.x_stamp_size, self.y_stamp_size = model_random.swap_parameters(self.x_stamp_size, + self.y_stamp_size) + + def crossingover(self, other): + """ + pre: isinstance(other, AffineIfsSampler) + pre: isinstance(self, AffineIfsSampler) + # check for distinct references, needs to copy content, not references + post: __return__ is not self + post: __return__ is not other + post: model_locus.unique_check(__return__, self, other) == '' + """ + new_one = AffineIfsSampler(self.get_trunk()) + cross_sequence = model_random.crossing_sequence(7+MAX_TRANSFORMATIONS) + new_one.symmetry = self.symmetry if cross_sequence[0] else other.symmetry + new_one.Dn = self.Dn if cross_sequence[1] else other.Dn + new_one.random_seed = self.random_seed if cross_sequence[2] else other.random_seed + new_one.orbits = self.orbits if cross_sequence[3] else other.orbits + + new_one.x_stamp_size = self.x_stamp_size if cross_sequence[4] else other.x_stamp_size + new_one.y_stamp_size = self.y_stamp_size if cross_sequence[5] else other.y_stamp_size + + new_one.num_transformations = self.num_transformations \ + if cross_sequence[6] else other.num_transformations + new_one.pol_transf = [[.0, .0, .0, .0, .5, .5]] * MAX_TRANSFORMATIONS + len_self = self.num_transformations + len_other = other.num_transformations + min_rows = min([len_self, len_other]) + longest = self.pol_transf if len_self >= len_other else other.pol_transf + for row in range(new_one.num_transformations): + if row < min_rows: + if cross_sequence[7+row]: + for col in range(len(other.pol_transf[row])): + new_one.pol_transf[row][col] = other.pol_transf[row][col] + else: + for col in range(len(self.pol_transf[row])): + new_one.pol_transf[row][col] = self.pol_transf[row][col] + else: + for col in range(len(longest[row])): + new_one.pol_transf[row][col] = longest[row][col] + +# new_one._prepare_transient_members() + return new_one + + + @staticmethod + def _polar2matrix(polar): + """Converts from polar to matrix. + pre: len(polar) == 6 + """ + grad2rad = math.pi / 180.0 + # returns a, b, c, d, e, f + return \ + polar[4] * math.cos(grad2rad * polar[2]), \ + -polar[5] * math.sin(grad2rad * polar[3]), \ + polar[4] * math.sin(grad2rad * polar[2]), \ + polar[5] * math.cos(grad2rad * polar[3]), \ + polar[0], \ + polar[1] + + def _prepare_transient_members(self): + self.x_point, self.y_point = 0.5, 0.5 + self.tr_rand = random.Random(self.random_seed) + self.mta = [0.0] * MAX_TRANSFORMATIONS + self.mtb = [0.0] * MAX_TRANSFORMATIONS + self.mtc = [0.0] * MAX_TRANSFORMATIONS + self.mtd = [0.0] * MAX_TRANSFORMATIONS + self.mte = [0.0] * MAX_TRANSFORMATIONS + self.mtf = [0.0] * MAX_TRANSFORMATIONS + self.xmin, self.ymin, self.xmax, self.ymax = -1.0, -1.0, 1.0, 1.0 + self.matcher = [0] * MAX_MATCHER + + for tix in range(self.num_transformations): + matrix = AffineIfsSampler._polar2matrix(self.pol_transf[tix]) + self.mta[tix] = matrix[0] + self.mtb[tix] = matrix[1] + self.mtc[tix] = matrix[2] + self.mtd[tix] = matrix[3] + self.mte[tix] = matrix[4] + self.mtf[tix] = matrix[5] +# tnumber = 0 +# matrix = AffineIfsSampler._polar2matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.16) +# self.mta[tnumber] = matrix[0] +# self.mtb[tnumber] = matrix[1] +# self.mtc[tnumber] = matrix[2] +# self.mtd[tnumber] = matrix[3] +# self.mte[tnumber] = matrix[4] +# self.mtf[tnumber] = matrix[5] +# tnumber += 1 +# matrix = AffineIfsSampler._polar2matrix(0.0, 1.6, -2.5, -2.5, 0.85, 0.85) +# self.mta[tnumber] = matrix[0] +# self.mtb[tnumber] = matrix[1] +# self.mtc[tnumber] = matrix[2] +# self.mtd[tnumber] = matrix[3] +# self.mte[tnumber] = matrix[4] +# self.mtf[tnumber] = matrix[5] +# tnumber += 1 +# matrix = AffineIfsSampler._polar2matrix(0.0, 1.6, 49.0, 49.0, 0.3, 0.3) +# self.mta[tnumber] = matrix[0] +# self.mtb[tnumber] = matrix[1] +# self.mtc[tnumber] = matrix[2] +# self.mtd[tnumber] = matrix[3] +# self.mte[tnumber] = matrix[4] +# self.mtf[tnumber] = matrix[5] +# tnumber += 1 +# matrix = AffineIfsSampler._polar2matrix(0.0, 0.44, 120.0, -50.0, 0.3, 0.37) +# self.mta[tnumber] = matrix[0] +# self.mtb[tnumber] = matrix[1] +# self.mtc[tnumber] = matrix[2] +# self.mtd[tnumber] = matrix[3] +# self.mte[tnumber] = matrix[4] +# self.mtf[tnumber] = matrix[5] +# tnumber += 1 +# self.num_transformations = tnumber + self._prepare_matcher() + + + def _prepare_matcher(self): + """Calculate the probability a specific transformation is selected. + pre: self.num_transformations > 0 + """ + #calculate probability for each transformation + probability = [0.0] * MAX_TRANSFORMATIONS + for tnumber in xrange(self.num_transformations): + probability[tnumber] = \ + math.fabs(self.mta[tnumber] * self.mtd[tnumber] \ + - self.mtb[tnumber] * self.mtc[tnumber]) + if probability[tnumber] < 0.01: + probability[tnumber] = 0.01 + + #array of probabilities summing to 1 + probability_sum = sum(probability) + probability[0] /= probability_sum + probability[1] /= probability_sum + probability[2] /= probability_sum + probability[3] /= probability_sum + probability[4] /= probability_sum + probability[5] /= probability_sum + probability[6] /= probability_sum + probability[7] /= probability_sum + + trigger = 0.0 + mix = 0 + while mix < MAX_MATCHER: + if trigger < probability[0]: + self.matcher[mix] = 0 + elif trigger < probability[0] + probability[1]: + self.matcher[mix] = 1 + elif trigger < probability[0] + probability[1] + probability[2]: + self.matcher[mix] = 2 + elif trigger < probability[0] + probability[1] + probability[2] + probability[3]: + self.matcher[mix] = 3 + elif trigger < probability[0] + probability[1] + probability[2] + probability[3] + probability[4]: + self.matcher[mix] = 4 + elif trigger < probability[0] + probability[1] + probability[2] + probability[3] + probability[4] + probability[5]: + self.matcher[mix] = 5 + elif trigger < probability[0] + probability[1] + probability[2] + probability[3] + probability[4] + probability[5] + probability[6]: + self.matcher[mix] = 6 + else: + self.matcher[mix] = 7 + trigger += 1.0 / MAX_MATCHER + mix += 1 + + def _iterate(self): + """Calculate one iteration.""" + tnumber = self.matcher[self.tr_rand.randrange(0, MAX_MATCHER)] \ + if self.num_transformations > 1 else 0 + tnumber = tnumber % self.num_transformations + x_tmp = self.x_point * self.mta[tnumber] \ + + self.y_point * self.mtb[tnumber] + self.mte[tnumber] + y_tmp = self.x_point * self.mtc[tnumber] \ + + self.y_point * self.mtd[tnumber] + self.mtf[tnumber] + self.x_point, self.y_point = x_tmp, y_tmp + if self.symmetry > 0: + angel = 2.0 * math.pi * self.tr_rand.randint(0, self.symmetry-1) \ + / float(self.symmetry) + cosinus = math.cos(angel) + sinus = math.sin(angel) + x_tmp = cosinus * self.x_point - sinus * self.y_point + y_tmp = sinus * self.x_point + cosinus * self.y_point + self.x_point = x_tmp + self.y_point = -y_tmp if self.Dn > 0 and self.tr_rand.randrange(0, 2) == 0 \ + else y_tmp + return tnumber + + def _skip(self): + """The first values from this iteration are not valid.""" + loop = 0 + while loop < 25: + self._iterate() + loop += 1 + + def _maxima(self): + """Iterate and calculate maxima""" + self._iterate() + self.xmin = self.x_point + self.ymin = self.y_point + self.xmax = self.x_point + self.ymax = self.y_point + loop = 0 + while loop < 199: + self._iterate() + if self.x_point < self.xmin: + self.xmin = self.x_point + if self.y_point < self.ymin: + self.ymin = self.y_point + if self.x_point > self.xmax: + self.xmax = self.x_point + if self.y_point > self.ymax: + self.ymax = self.y_point + loop += 1 + + def _enumerate_points(self): + """Iterate and collect sample points""" + x_delta, y_delta = self.xmax - self.xmin, self.ymax - self.ymin + sample_points = [] + if x_delta > 0.001 and y_delta > 0.001: + loop = 0 + while loop < self.orbits: + tnumber = self._iterate() + x_rel = (self.x_point - self.xmin) / x_delta + y_rel = (self.y_point - self.ymin) / y_delta + #TODO dritter parameter sample_points.append( (x_rel-0.5, y_rel-0.5, tnumber) ) + sample_points.append( (x_rel-0.5, y_rel-0.5) ) + loop += 1 + return sample_points + + def get_sample_points(self): + """ Produces a list of sampling points. + """ +# self.tr_rand = random.Random(self.random_seed) +# self.x_point, self.y_point = 0.5, 0.5 + #transient members + self._prepare_transient_members() + self._skip() + self._maxima() + return self._enumerate_points() + + def get_sample_extent(self): + """'Size' of one sample as a fraction of 1. + """ + return self.x_stamp_size, self.y_stamp_size + + def explain(self): + """ + post: len(__return__) == 3 + """ + head = _('Affine iterated function system sampler') + details = _('iterations=%d, transformations=%d symmetry=%d, Dn=%d') + details = details % (self.orbits, self.num_transformations, + self.symmetry, self.Dn) + return ka_utils.explain_points(head + ' ' + details + ': ', + self.get_sample_points()) + + def copy(self): + """A copy constructor. + post: isinstance(__return__, AffineIfsSampler) + # check for distinct references, needs to copy content, not references + post: __return__ is not self + """ + new_one = AffineIfsSampler(self.get_trunk()) + #persistent members + new_one.random_seed = self.random_seed + new_one.orbits = self.orbits + new_one.num_transformations = self.num_transformations + new_one.pol_transf = [[.0, .0, .0, .0, .0, .0]] * MAX_TRANSFORMATIONS + for pix in range(self.num_transformations): + new_one.pol_transf[pix] = self.pol_transf[pix][:] + new_one.symmetry = self.symmetry + new_one.Dn = self.Dn + + new_one.x_stamp_size = self.x_stamp_size + new_one.y_stamp_size = self.y_stamp_size + #transient members +# new_one._prepare_transient_members() + return new_one diff --git a/ep_sampler_centeredwalk.py b/ep_sampler_centeredwalk.py index 6f48e4a..a232e50 100644 --- a/ep_sampler_centeredwalk.py +++ b/ep_sampler_centeredwalk.py @@ -88,10 +88,7 @@ class CenteredWalkSampler(ep_sampler_randomwalk.RandomWalkSampler): """ head = _('Centered random walk sampler: %d points') \ % (len(self.direction_steps)) - description = ka_utils.explain_points(head, self.get_sample_points()) - return description, \ - None, \ - None + return ka_utils.explain_points(head, self.get_sample_points()) def copy(self): """A copy constructor. diff --git a/ep_sampler_randomwalk.py b/ep_sampler_randomwalk.py index db9e2d6..8a474bb 100644 --- a/ep_sampler_randomwalk.py +++ b/ep_sampler_randomwalk.py @@ -118,10 +118,7 @@ class RandomWalkSampler(model_allele.Allele): """ head = _('Random walk sampler: %d points') \ % (len(self.direction_steps)) - description = ka_utils.explain_points(head, self.get_sample_points()) - return description, \ - None, \ - None + return ka_utils.explain_points(head, self.get_sample_points()) def copy(self): """A copy constructor. diff --git a/ep_sampler_rectilineargrid.py b/ep_sampler_rectilineargrid.py index f7b1072..f239cf7 100644 --- a/ep_sampler_rectilineargrid.py +++ b/ep_sampler_rectilineargrid.py @@ -116,10 +116,7 @@ class RectilinearGridSampler(model_allele.Allele): """ head = _('Rectilinear grid sampler: %d*x, %d*y') \ % (self.x_tiles, self.y_tiles) - description = ka_utils.explain_points(head, self.get_sample_points()) - return description, \ - None, \ - None + return ka_utils.explain_points(head, self.get_sample_points()) def copy(self): """A copy constructor. diff --git a/ep_sampler_squaregrid.py b/ep_sampler_squaregrid.py index d79574b..a4a7f82 100644 --- a/ep_sampler_squaregrid.py +++ b/ep_sampler_squaregrid.py @@ -99,10 +99,7 @@ class SquareGridSampler(model_allele.Allele): """ head = _('Squarish grid sampler: %d*%d') \ % (self.tiles, self.tiles) - description = ka_utils.explain_points(head, self.get_sample_points()) - return description, \ - None, \ - None + return ka_utils.explain_points(head, self.get_sample_points()) def copy(self): """A copy constructor. diff --git a/ka_utils.py b/ka_utils.py index 22f0a4a..df51e8d 100644 --- a/ka_utils.py +++ b/ka_utils.py @@ -14,6 +14,9 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import cairo + +ICON_WIDTH = ICON_HEIGHT = 48 def explain_points(head, points): """ @@ -24,5 +27,24 @@ def explain_points(head, points): for point in points: description += '%4.3f, %4.3f; ' % (point[0], point[1]) description += ']' - return head + ' ' + description if head is not None and len(head) \ - else description + text = head + ' ' + description if head is not None and len(head) \ + else description + + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, ICON_WIDTH, ICON_HEIGHT) + ctx = cairo.Context(surface) + ctx.scale(ICON_WIDTH, ICON_HEIGHT) + # paint background + ctx.set_operator(cairo.OPERATOR_OVER) + ctx.set_source_rgb(1.0, 1.0, 1.0) + ctx.paint() + radius = 0.1 + ctx.set_line_width(0.02) + for point in points: + # paint a cross for each position + ctx.set_source_rgb(0.0, 0.0, 0.0) + ctx.move_to(0.5+point[0]-radius, 0.5+point[1]-radius) + ctx.line_to(0.5+point[0]+radius, 0.5+point[1]+radius) + ctx.move_to(0.5+point[0]+radius, 0.5+point[1]-radius) + ctx.line_to(0.5+point[0]-radius, 0.5+point[1]+radius) + ctx.stroke() + return text, surface, head diff --git a/model_constraintpool.py b/model_constraintpool.py index 76c2542..b1b047e 100644 --- a/model_constraintpool.py +++ b/model_constraintpool.py @@ -133,6 +133,10 @@ class ConstraintPool(object): def _my_defaults(self): #TODO read from persistence, provide an constraint editor +# self.set('*', 'samplertypeconstraint', ['affineifs',]) +# self.set('*', 'layertypeconstraint', ['filledspline', ]) +# self.set('*', 'stamptypeconstraint', ['filledcyclic',]) +# self.set('*', 'layertypeconstraint', ['markovchain', ]) # self.set('*', 'samplertypeconstraint', ['randomwalk',]) # self.set('*', 'layertypeconstraint', ['referencepattern', ]) # self.set('*', 'modifiertypeconstraint', ['border', ]) diff --git a/model_locus.py b/model_locus.py index e574f2d..c55b76e 100644 --- a/model_locus.py +++ b/model_locus.py @@ -86,7 +86,7 @@ def unique_check(cpy, src1, src2): if type(cpy.__dict__[slot]) == types.ListType: # print slot, cpy.__dict__[slot] for elem in cpy.__dict__[slot]: - if type(elem) not in [types.IntType, types.StringType, types.UnicodeType]: + if type(elem) not in [types.IntType, types.FloatType, types.StringType, types.UnicodeType]: if ka_debug.contains_by_id(src1.__dict__[slot], elem): serr = 'Copy error 3 ' + str(slot) + ' ' + str(elem) \ + ': ' + str(cpy) + ', ' + str(src1) diff --git a/model_population.py b/model_population.py index 0f2e4e4..2af2a09 100644 --- a/model_population.py +++ b/model_population.py @@ -17,6 +17,7 @@ import ka_extensionpoint #import simplejson as json +import copy import pickle import zlib import sys @@ -262,7 +263,7 @@ def to_buffer(obj): # ka_debug.info('write %s to_buffer' % type(obj)) try: return MAGIC_NUMBER + _get_my_revision() \ - + zlib.compress(pickle.dumps(obj, protocol=2)) + + zlib.compress(pickle.dumps(copy.deepcopy(obj), protocol=2)) except: ka_debug.err('failed writing buffer [%s] [%s]' % \ (sys.exc_info()[0], sys.exc_info()[1])) diff --git a/po/Kandid.pot b/po/Kandid.pot index acaf308..4f18730 100644 --- a/po/Kandid.pot +++ b/po/Kandid.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-31 22:02+0200\n" +"POT-Creation-Date: 2010-04-03 22:55+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" diff --git a/test_buildingblocks.py b/test_buildingblocks.py index 39d12b4..7392ac0 100644 --- a/test_buildingblocks.py +++ b/test_buildingblocks.py @@ -26,6 +26,7 @@ import exon_position import exon_direction import exon_buzzword import test_utils +from ep_sampler_affineifs import AffineIfsSampler class TestKandidBuildingBlocks(unittest.TestCase): @@ -220,3 +221,13 @@ class TestKandidBuildingBlocks(unittest.TestCase): eql = eql and color4 == color3 self.assertFalse(eql) + def test_0ifs(self): + model_random.set_flurry(9) + ifs = AffineIfsSampler('/') + ifs.randomize() + ifs.orbits = 10 + ifs.symmetry = 5 + point_list = ifs.get_sample_points() + self.assertTrue(len(point_list) == 10) +# self.assertTrue(len(point_list[0]) == 3) + self.assertTrue(len(point_list[0]) == 2) diff --git a/test_model.py b/test_model.py index ede8f95..fa2b320 100644 --- a/test_model.py +++ b/test_model.py @@ -63,7 +63,7 @@ class TestKandidModel(unittest.TestCase): for release in range(2, ka_extensionpoint.revision_number): file_path = kandid.REFFERENCEMODEL + str(release) model = model_population.read_file(file_path) - self.assertTrue(model is not None) + self.assertTrue(model is not None, file_path) result = model.copy().dot() # Hope to reach this point without an exception for protozoon in model.protozoans: diff --git a/test_status.py b/test_status.py index bf05386..e99b492 100644 --- a/test_status.py +++ b/test_status.py @@ -34,7 +34,7 @@ class TestKandidStatus(unittest.TestCase): self.assertTrue(status.isDirty()) status.set(ka_status.TOPIC_COLLABORATION, ka_status.SUB_BUDDIES_JOINED, '2') - self.assertTrue(status.recall().find('Running: Kandid, release v5, DoB activated') >= 0) + self.assertTrue(status.recall().find('Running: Kandid, release v6, DoB activated') >= 0) self.assertFalse(status.isDirty()) def test_os_status(self): |