File: circle.py

package info (click to toggle)
python-bumps 1.0.3-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,200 kB
  • sloc: python: 24,517; xml: 493; ansic: 373; makefile: 211; javascript: 99; sh: 94
file content (90 lines) | stat: -rw-r--r-- 2,474 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
"""
2d array representation of a circle

References::
    None
"""

import numpy as np
from numpy import arange
from numpy import random, sin, cos, pi, inf, sqrt

random.seed(123)


def circle(coeffs, interval=0.02):
    """
    generate a 2D array representation of a circle of given coeffs
    coeffs = (x,y,r)
    """
    xc, yc, r = coeffs
    theta = arange(0, 2 * pi, interval)
    return r * cos(theta) + xc, r * sin(theta) + yc


def genpoints(coeffs, npts=20):
    """
    Generate a 2D dataset of npts enclosed in circle of given coeffs,
    where coeffs = (x,y,r).

    NOTE: if npts is None, constrain all points to circle of given radius
    """
    xo, yo, R = coeffs
    # Radial density varies as sqrt(x)
    r, theta = sqrt(random.rand(npts)), 2 * pi * (random.rand(npts))
    x, y = r * cos(theta) + xo, r * sin(theta) + yo
    return x, y


def gendensity(coeffs, density=0.1):
    xo, yo, R = coeffs
    npts = int(0.2 * pi * R**2)
    return genpoints(coeffs, npts)


from .model import Fitness


class MinimumCircle(Fitness):
    def __init__(self, data=None, limits=None, start=None):
        self.x, self.y = data
        self.dy = None
        self.limits = limits
        self.start = start

    def _residuals(self, p):
        x, y = self.x, self.y
        xc, yc, r = p
        d = sqrt((x - xc) ** 2 + (y - yc**2))
        d[d < r] = 0
        return d

    def profile(self, p):
        return circle(p)

    def residuals(self, p):
        """
        Residuals is used by Levenburg-Marquardt, so fake the
        penalty terms of the normal cost function for use here.
        """
        resid = self._residuals(p)
        # Throw r in the residual so that it is minimized, punish the circle
        # if there are too many points outside.
        d = np.concatenate((resid, self.r, sum(resid > 0)))
        return d

    def __call__(self, p):
        xc, yc, r = p
        resid = self._residuals(p)
        # Penalties are the number
        # Add additional penalties for each point outside the circle
        return sum(resid > 0) + sum(resid) + abs(r)


# prepared instances
Po = [0, 0, 1]
Plo = [-inf, -inf, 0]
Phi = [inf, inf, inf]
dense_circle = MinimumCircle(data=gendensity([3, 4, 20], density=5), limits=(Plo, Phi), start=Po)
sparse_circle = MinimumCircle(data=gendensity([3, -4, 32], density=0.5), limits=(Plo, Phi), start=Po)
minimal_circle = MinimumCircle(data=gendensity([0, 0, 10], density=5), limits=(Plo, Phi), start=Po)