Site navigation:


Pointsets

Contents

  1. Points and Pointsets are enhanced arrays
  2. Labelling
  3. Coordinate access and manipulation
  4. Point arithmetic and comparison
  5. Implementation details
  6. An interactive exploration of Points and Pointsets
  7. Other pointset-related utility functions


1. Points and Pointsets are enhanced arrays

The Point and Pointset classes are essentially enhanced Numpy array classes. The primary goal of these two classes is to free the user from dealing with explicit array indices when manipulating scientific or numerically-computed data which are commonly most naturally referenced by names. We believe the "index free" array is a liberating substrate for users, that permits construction of sophisticated computations without the tedious book-keeping of arbitrary integer array indices. This comes at little cost to efficiency, especially as regular arrays can easily be extracted from a Pointset or reassembled into one, so that data porting to other applications is easy.

Pointsets may either be parameterized by an independent variable -- in which case they are callable with values of that variable, or they may be non-parameterized -- in which case they are not callable. In either case they can be referenced by array index, or in other ways (see below).

The display of point and pointset contents uses a numerical precision of 8 significant figures. This cannot be changed by the user, who should extract a subset of the pointset as an array in order to see the values at full precision. Of course, arithmetic comparisons using pointset values use full precision.

Attributes of Pointsets

Individual values of a Point or Pointset can be set using their 'set' method.

2. Labelling

A further feature of Points and Pointsets is their inherent point labelling system, which can be queried and manipulated much like a dictionary, as a way to organize sophisticated access to array data. For instance, this becomes especially useful when exploring the bifurcation sets of a dynamical system using PyCont.

In a Pointset, denoted w, labels are stored by index. To see which point is labelled at index i, look at w[i]. To find out which index corresponds to an independent variable value t, call w.find(t) (parameterized pointsets only). If the value of t is not in the pointset then a pair will be returned that indicates where t lies with respect to existing independent variable values in w.

To see which points in a pointset possess a given string label s, use w.bylabel(s).

Labels should be added and removed using the addlabel and removelabel methods.

Additionally, a pointset may be given a name, which resides in the attribute name.

3. Coordinate access and manipulation

The displayed order of point or pointset coordinates is alphabetical. This is the only supported ordering of coordinates, and also provides the ordering for exported arrays from these objects.

A point can be called and referenced by coordinate name or index.

A point can be removed, appended, or inserted into a pointset using the methods remove, append and insert. Note that, unlike with lists, you can append either an individual point or a pointset object. A method named extend is also provided, and has identical functionality to append.

A parameterized pointset can be called at a specific independent variable value (or set of values), with an additional argument to select coordinates in the output. A pointset can be referenced by point index (returning a point), a set of indices (returning a pointset corresponding to points at those indices), or by coordinate name (returning a pointset containing only that coordinate at all point indices). The bylabel method also allows points to be selected based on their label.

Both points and pointsets can have their values set in the same ways that both a dictionary and a list can be.

The full range of possibilities in the point and pointset interface can be seen by running the Points.py file as a script and reading the examples in the output.

Pointsets can be reversed in place using the reverse method.

4. Point arithmetic and comparison

Basic arithmetic and comparison operations can be performed on Points and Pointsets, in much the same way as can be done with arrays. The ordering and test of equality for points is defined according to the choice of norm for the points. By default, this is L2 norm, although this can be changed using the 'norm' key in the argument dictionary at initialization to be values from 1 to Inf. Comparison of both points and pointsets using the usual arithmetic operators will compare objects point-wise based on their norms.

To compare two points or pointsets, coordinate for coordinate, use the comparePointCoords function (which also accepts appropriately keyed dictionaries). The comparison can be made stricter using the optional fussy boolean argument, in which case the norm and coordinate type are also checked for equality, provided only points and pointsets are passed to the function.

Points can be compared to single values, returning a Boolean array that indicate matching coordinates (ordered). Similarly, Pointsets can be compared to Points, returning a Boolean array indicating matching positions. This functionality is much like that of Numpy arrays.

5. Implementation details

Unlabelled points and unlabelled non-parameterized pointsets can be created by calling the appropriate class constructor with a dictionary mapping coordinate name keys to numeric or array/list values.

Points and pointsets can have their values (i.e. not including the independent variable, if present) turned into a dictionary by calling the in-built function dict with the point or pointset as argument. A todict method is also implemented.

The Point class is defined to closely resemble a mapping object class such as dict (although it is not a subtype of dict). Pointset is a subclass of Point, although it acts more like a list than a dictionary. Most natural operations for dictionaries and lists apply equally to the respective subclasses.

6. An interactive exploration of Points and Pointsets

See the file /tests/test_pointsets.py for the code for the following demo.

Point exploration

>>> x = Point({'coorddict': {'x0': [1.123456789], 'x1': [-0.4],
               'x2': [4000]}, 'coordtype': float})
>>> x
x0:  1.123456789
x1:  -0.4
x2:  4000.0

>>> x.toarray()
 array([  1.12345679e+00  -4.00000000e-01   4.00000000e+03])

>>> x.dimension
3

>>> x.coordnames
['x0', 'x1', 'x2']

>>> x.coordtype


>>> x('x1')  # returns a float
-0.4

>>> x(['x1','x0'])  # returns another Point
x0:  1.123456789
x1:  -0.4

>>> x([0,1])
x0:  1.123456789
x1:  -0.4

>>> x[1] = -0.45  #Changing x entries is done by x[index] = value:
                  
                  
>>> x[['x0', 'x1']] = [4.11103, -0.56])  #The index can also be a name, a list of names, or even a dictionary

>>> y = Point({'y': 4})   # y is a 1D point (with integer type)

>>> print y
y:  4.0

>>> y(0)
4.0

>>> type(y(0))


>>> y([0])
y:  4.0

>>> y.toarray()
4.0

Pointset exploration

In the following, v is a 'singleton' pointset (only one entry)

>>> v = Pointset({'coorddict': {'x0': 0.2, 'x1': -1.2},
             'indepvardict': {'t': 0.01},
             'coordtype': float64,
             'indepvartype': float64
              })
>>> print v
Pointset  (parameterized)

>>> print v(0.01)  # a Point object
x0:  0.2
x1:  -1.2

>>> print v(0.01, 0)   # also a Point object (index 0 only = 'x0')
x0:  0.2

>>> print v(0.01, 'x0')   # alternative to using index, use the name directly
x0:  0.2

In the following, Pointset k shows a different way to specify a single-point Pointset:

>>> k = Pointset({'coordarray': array(0.1),
              'coordnames': 'k0',
              'indepvarname': 't',
              'indepvararray': array(0.0)})

>>> print k.toarray()
[ 0.1]

>>> print k['t']
[ 0.]

>>> print k(0.0)
k0:  0.1

>>> print k
Pointset  (parameterized)

In the following, u is a non-parameterized Pointset:

>>> u = Pointset({'coordarray': array([10., 20., 30., 40.])})

>>> u.toarray()
[ 10.  20.  30.  40.]

>>> isparameterized(u)
False

>>> print u
Pointset  (non-parameterized)

In the following, w shows alternative declaration syntax, and other forms of calling:

>>> wp = Pointset({'coordarray': array([[4.456, 2.34634, 7.3431, 5.443],
                              [-10.0336, -5.2235, -3.23221, -0.01],
                              [3e5, 3.1e5, 3.3e5, 2.8e5]], float64),
              'coordnames': ['x0', 'x1', 'x2'],
              'indepvarname': 't',
              'indepvararray': array([0.0, 1.0, 2.0, 3.0], float64)})

>>> wp.dimension
3

>>> print wp(0.0)
x0:  4.456
x1:  -10.0336
x2:  300000.0

>>> type(wp(0.0))


>>> print wp(1.0)(0)
2.34634

>>> print wp(2.0, 'x1')
x1:  -3.23221

>>> print wp(2.0, ['x2', 'x1'])
x1:  -3.23221
x2:  330000.0

>>> type(wp(2.0, ['x1', 'x2']))


>>> print wp[['x1','x0']]
Pointset  (parameterized)

>>> wp.info(1)
Pointset  (parameterized)
Independent variable:
t:  [ 0.  1.  2.  3.]
Coordinates:
x0:  [ 4.456    2.34634  7.3431   5.443  ]
x1:  [ -1.00336000e+01  -5.22350000e+00  -3.23221000e+00  -1.00000000e-02]
x2:  [ 300000.  310000.  330000.  280000.]
Labels by index: Empty

>>> wp(1.0).info(1)
x0:  2.34634
x1:  -5.2235
x2:  310000.0

>>> wp['t']
[ 0.  1.  2.  3.]

>>> # Call several 't' values at once (explicit values only -- no ellipses):
>>> wp([1., 2.])
Pointset  (parameterized)

>>> # Extract a coordinate (only by name) as a regular array:
>>> w_x0 = wp['x0']
>>> print w_x0
[ 4.456    2.34634  7.3431   5.443  ]

>>> # Extract a point of w as a regular array:
>>> w_at_1 = wp(1.).toarray()
>>> print w_at_1
[  2.34634000e+00  -5.22350000e+00   3.10000000e+05]

>>> # Many forms to access individual values or sub-arrays:
>>> wp(1., 'x1')
x1:  -5.2235

>>> wp(1.)('x1')
-5.2235

>>> wp(1., 1))
x1:  -5.2235

>>> wp([1.,3.], 1)
Pointset  (parameterized)

>>> wp([1.,3.])('x1')
[-5.2235 -0.01  ]

>>> wp(1.)([0,1])
x0:  2.34634
x1:  -5.2235

>>> wp([1.])(1., [0,1])
x0:  2.34634
x1:  -5.2235

>>> # ... because wp([1.]) is a Pointset and wp(1.) is a Point
    #This is why wp(1.).toarray() shows a different array shape to wp([1.]).toarray():
    
>>> wp(1.).toarray().shape
(3,)

>>> wp([1.]).toarray().shape
(3, 1)

>>> # Change a point in w using wp[indepvar_value] = point:
    # Old value at t=1.0:
>>> wp(1.0)
x0:  2.34634
x1:  -5.2235
x2:  310000.0

>>> wp[1] = x
>>> # w has now been updated for the meshpoint at t=1.0  =>
    # New value at t=1.0:
>>> wp(1.0)
x0:  4.11103
x1:  -0.56
x2:  4000.0

>>> # We can test equality between arrays, as expected:
>>> w_at_1 != wp(1.).toarray()
[ True  True  True]

>>> # We can also compare with a Pointset object:
>>> wp(1.) != w_at_1
[ True  True  True]

>>> # But we can't put an array on the left-hand side if a Point or Pointset is on the right.

>>> # To demonstrate appending a Point and Pointset to another Pointset:
>>> vw.labels
1: {c: {}}

>>> wp.append(vw)

>>> wp.labels
5: {c: {}}

>>> wp.toarray()
[[  4.45600000e+00   4.11103000e+00   7.34310000e+00   5.44300000e+00
    1.00000000e-01   1.50000000e-01   2.00000000e+00]
 [ -1.00336000e+01  -5.60000000e-01  -3.23221000e+00  -1.00000000e-02
    1.00000000e+02   1.02000000e+02  -3.00000000e+02]
 [  3.00000000e+05   4.00000000e+03   3.30000000e+05   2.80000000e+05
    2.00000000e-01   1.00000000e-01  -9.99700000e-01]]

>>> wp(4.5)
x0:  0.1
x1:  100.0
x2:  0.2

>>> wp[[3,6]]
Pointset  (parameterized)

>>> wp[3:5]
Pointset  (parameterized)

>>> wp[2:]
Pointset  (parameterized)

>>> wp[wp.findIndex(4.5)]
x0:  0.1
x1:  100.0
x2:  0.2

>>> wp.labels
5: {c: {}}

>>> # Labels test:
>>> wp.labels[3]
{'a': {'bif': 'SN'}}

>>> wp_part.labels
0: {a: {keys=bif}}

>>> # wp_ins object created to insert into wp:

>>> wp.insert(wp_ins) # returns a new Pointset
Pointset  (parameterized)

>>> # To demonstrate building a Pointset from a list of Point objects:

>>> pointlist = []
>>> for t in wp['t']:
      pointlist.append(wp(t))

>>> w_reconstructed = pointsToPointset(pointlist, 't', wp['t'])

>>> # And to demonstrate that this yields an identical object:
>>> w_reconstructed == w
[ True  True  True  True  True  True  True  True  True  True  True]

>>> # (ensure that any independent variable values to append are well-ordered)

>>> # Test of non-parameterized use of pointsToPointset:
    # (Adding two additional labels to wnp)

>>> wnp[:]   # can use index slicing, etc. as expected
Pointset  (non-parameterized)

>>> # Can iterate over points and pointsets:
>>> for p in wnp.bylabel('a'):
      print p

x0:  4.456
x1:  -10.0336
x2:  300000.0
Labels: a ({'bif': 'SN'})
Labels: b ({})
x0:  7.3431
x1:  -3.23221
x2:  330000.0
Labels: a ({'bif': 'H'})

Other pointset-related utility functions