Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstrom <strom@vehikel.(none)>2010-05-02 19:04:36 (GMT)
committer strom <strom@vehikel.(none)>2010-05-02 19:04:36 (GMT)
commitf84b965aa7b4a28786b3520671a5d0fd1881cd6d (patch)
tree79be950bc29ee8c2eb9ffb1bd0fac6723c486d89
parent6416d002a0c99678bc38f1997a9bbc94acd7ead3 (diff)
Added a sampler for iterated function systems.
-rw-r--r--activity/activity.info2
-rw-r--r--ep_formater_html.py33
-rw-r--r--ep_layer_letterpress.py55
-rw-r--r--ep_page_ancestors.py2
-rw-r--r--ep_sampler_affineifs.py483
-rw-r--r--ep_sampler_centeredwalk.py5
-rw-r--r--ep_sampler_randomwalk.py5
-rw-r--r--ep_sampler_rectilineargrid.py5
-rw-r--r--ep_sampler_squaregrid.py5
-rw-r--r--ka_utils.py26
-rw-r--r--model_constraintpool.py4
-rw-r--r--model_locus.py2
-rw-r--r--model_population.py3
-rw-r--r--po/Kandid.pot2
-rw-r--r--test_buildingblocks.py11
-rw-r--r--test_model.py2
-rw-r--r--test_status.py2
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):