At the core of the array family is the flex submodule, which includes most of the array types, including:
To use flex arrays, the module needs to be imported from the CCTBX:
from scitbx.array_family import flex
For example, to create an integer flex array, use flex.int().
>>> int_array = flex.int([3,1,2,6])
As the array is an object, simply calling the variable will only print the type.
>>>int_array
<scitbx_array_family_flex_ext.int object at 0x107476ba8>>
Instead, convert the array to a list or a tuple.
>>> int_array = flex.int([3,1,2,6])
>>> list(int_array)
[3, 1, 2, 6]
>>> tuple(int_array)
(3, 1, 2, 6)
As in python lists, append
and extend
allows adding content to the array.
>>> int_array = flex.int([3,1,2,6])
>>> int_array.append(5)
>>> list(int_array)
[3, 1, 2, 6, 5]
>>> int_array.extend(flex.int([12,10]))
>>> list(int_array)
[3, 1, 2, 6, 5, 12, 10]
int_array = flex.int([3,1,2,6])
>>> len(int_array)
4
>>> int_array.size()
4
Delete the element at index 3
>>> int_array = flex.int([3,1,2,6,8,2,6,3,4])
>>> del int_array[3]
>>> list(int_array)
[3, 1, 2, 8, 2, 6, 3, 4]
Slice the array (continuing the example above) from element at index 2 (included) to index 5 (excluded).
>>> list(int_array[2:5])
[2, 8, 2]
Mathematical operations like additions, subtraction, division and multiplication can be performed on an array.
>>> a=flex.int([1,2,3])
>>> b=flex.int([2,3,1])
>>> tuple(a+b)
(3, 5, 4)
>>> tuple(a-b)
(-1, -1, 2)
>>> tuple(a*b)
(2, 6, 3)
Note that division on integers follows rules for C++, where the result will always be rounded down.
>>> a=flex.int([1,2,3])
>>> b=flex.int([2,3,1])
>>> tuple(a/b)
(0, 0, 3)
The result above is different than integer division in python:
>>> 1/2
0.5
Dividing the elements one by one can therefore lead to different results than applying the operation to the array:
>>> a=flex.int([1,2,3])
>>> b=flex.int([2,3,1])
>>> tuple(a/b)
(0, 0, 3)
>>> for i,ai in enumerate(a):
>>> print(ai/b[i])
0.5
0.666666666667
3.0
Some operations won't work on certain array types. For example one cannot take the square root of integers:
>>> a=flex.int([1,2,3])
>>> tuple(flex.sqrt(a))
Traceback (most recent call last):
File "", line 1, in
Boost.Python.ArgumentError: Python argument types in
scitbx_array_family_flex_ext.sqrt(int)
did not match C++ signature:
sqrt(scitbx::af::versa > >)
sqrt(scitbx::af::versa > >)
When such an error occurs ("types in ... did not match C++ signature"), it is a hint that the input type is not compatible.
The square root can for example be applied on an array of type double. The array can be either created as type double or an array can be converted to type double using the method as_double()
.
>>> a = flex.double([4,4,4])
>>> list(flex.sqrt(a))
[2.0, 2.0, 2.0]
>>> a=flex.int([4,4,4])
>>> list(flex.sqrt(a.as_double()))
[2.0, 2.0, 2.0]
Flex arrays have methods to get quick access of some element properties:
>>> a=flex.int([1,2,3])
>>> a.all_eq(2)
False
>>> b=flex.int([2,2,2,2])
>>> b.all_eq(2)
True
>>> a=flex.double([1.5, 3.6, 7.4, 3, 5])
>>> list(a)
[1.5, 3.6, 7.4, 3.0, 5.0]
>>> a.all_ge(1.5)
True
>>> a.all_gt(1.5)
False
>>> a=flex.int([1,3,5,7,9])
>>> list(a)
[1, 3, 5, 7, 9]
>>> a.all_le(9)
True
>>> a.all_lt(9)
False
>>> a=flex.int([1,2,3])
>>> a.all_ne(4)
True
>>> a.all_ne(3)
False
The data in a flex array is stored in a contiguous one-dimensional sequence of memory. Multidimensional flex arrays up to 10 dimensions are supported. An accessor (of type flex.grid) specifies how the underlying one-dimensional data array should be interpreted as a multidimensional array.
Creating the accessor (grid
) for a 1d array:
>>> a = flex.double(range(9))
>>> list(a)
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
>>> grid = a.accessor()
>>> grid.nd() # the number of dimensions
1
>>> grid.all()
(9,)
Create a multidimensional array using the reshape()
method.
>>> a = flex.double(range(9))
>>> a.reshape(flex.grid(3,3))
>>> a.nd()
2
>>> a.all()
(3, 3)
Note that the reshape()
method only works if the dimensions are consistent.
>>> a = flex.double(range(9))
>>> a.reshape(flex.grid(3,2))
Traceback (most recent call last):
File "", line 1, in
RuntimeError: scitbx Internal Error: .../phenix_svn/modules/cctbx_project/scitbx/array_family/boost_python/flex_wrapper.h(449):
SCITBX_ASSERT(grid.size_1d() == a.size()) failure.
Multidimensional flex arrays are stored in row-major order (the consecutive elements of a row reside next to each other) and elements can be accessed using the Python square bracket notation:
>>> c = flex.int(range(6))
>>> list(c)
[0, 1, 2, 3, 4, 5]
>>> c.nd()
1
>>> c.reshape(flex.grid(2,3))
>>> list(c)
[0, 1, 2, 3, 4, 5]
>>> c.nd()
2
>>> for i in range(c.all()[0]):
... for j in range(c.all()[1]):
... print(c[i,j]),
... print
...
0 1 2
3 4 5
Note that for the initial and the reshaped array, list(c)
will print a one dimensional list in each case.
It is also worth noting that vec2_double
and vec3_double
are one dimensional arrays:
>>> c = flex.double([(1.5,2,3), (4,5,6)])
>>> c.nd()
2
>>> d = flex.vec3_double([(1.5,2,3), (4,5,6)])
>>> d.nd()
1
The flex module has several methods to convert the type of an array.
>>> a=flex.int([1,2,3])
>>> b=flex.int([2,3,1])