Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
835baf2
Simplify the XNAT data sink.
Mar 20, 2013
4782333
Make a SHA-1 digest directory name for long parameterizations.
Mar 20, 2013
c4cadb0
The ANTS 1.9 affine map is Affine.mat.
Mar 29, 2013
0617e6a
use_histogram_matching can be a Bool which applies to all transforms.…
May 21, 2013
e8eda0d
Add postfix file name input option.
May 21, 2013
0c2f849
Update the shape and slice dimension after a meta extension update.
May 21, 2013
bbdecd5
Remove unused line.
Mar 29, 2013
8113e55
Forego iterable param merge if there are no iterables.
May 21, 2013
45f66cf
Disable the ants Registration interface sigma_units vox value until i…
May 24, 2013
a6573c4
Format the smoothing-sigmas option without a unit if none is supplied.
May 24, 2013
a86e616
Set the input values.
Jun 14, 2013
63a0067
Remove unused line.
Mar 29, 2013
28df659
Remove unused kwargs Workflow parameter.
Jun 15, 2013
0001a9f
Add join feature.
Jul 24, 2013
d5fcb2d
Refactor join into JoinNode rather than a Join interface.
Jul 25, 2013
b897d8c
Clean up white space.
Jul 25, 2013
0b1d3da
Remove obsolete joinsource Node init parameter.
Jul 25, 2013
eb00354
Iterate with nodes_iter rather than nodes.
Jul 25, 2013
7976538
Support a Set join field.
Jul 25, 2013
cd30706
Support an identity join node.
Jul 26, 2013
3e3649a
The joinfield default is all input fields.
Jul 29, 2013
1382671
Support multiple join fields.
Jul 29, 2013
d620ba2
Support the unique flag.
Jul 29, 2013
c2bf451
Remove extraneous debug message.
Jul 29, 2013
cedcfac
Add new line.
Jul 30, 2013
3365581
Add itersource.
Jul 30, 2013
1bab9e1
Add itersource test.
Jul 30, 2013
385baec
The itersource iterables key is a tuple only if there is more than on…
Jul 30, 2013
306c78f
Remove spurious line.
Jul 30, 2013
f2b9305
Flush out the itersource test.
Jul 31, 2013
83d9d2e
Build the itersource iterables from the ancestor value lookup.
Jul 31, 2013
15012ff
Fix _iterable_nodes merge.
Jul 31, 2013
99b9f01
Support join on a node with an itersource.
Aug 1, 2013
6e92e9e
Add iterables synchronize.
Aug 2, 2013
a8e6e23
Clarify comment.
Aug 3, 2013
0830956
Refactor iterable standardization to account for the itersource alter…
Aug 3, 2013
088ec83
Test the alternate itersource iterables format.
Aug 3, 2013
37e01ce
Add the itersource field.
Aug 3, 2013
a9ba9c8
Support synchronize iterables tuple values.
Aug 3, 2013
766b5fc
Make the transposed synchronize iterable values a list.
Aug 4, 2013
114d026
Handle the alternate synchronize iterables format.
Aug 6, 2013
dee068d
Copy all join node fields from the override self._inputs to the base …
Aug 9, 2013
9246db6
Add a test for multiple join nodes.
Aug 9, 2013
96c9bac
The join node loop current node variable is jnode, not dest.
Aug 9, 2013
d8408f9
Use in rather than has_key for lookup.
Aug 9, 2013
80bf24e
Make joinsource a property and convert a setter node value to the nod…
Aug 14, 2013
cd340ea
Add whitespace.
Aug 16, 2013
8cd8347
Add join feature.
Jul 24, 2013
79bd1fd
Refactor join into JoinNode rather than a Join interface.
Jul 25, 2013
318a096
Clean up white space.
Jul 25, 2013
195abb1
Remove obsolete joinsource Node init parameter.
Jul 25, 2013
2a7bdda
Iterate with nodes_iter rather than nodes.
Jul 25, 2013
0a8caad
Support a Set join field.
Jul 25, 2013
ff7e157
Support an identity join node.
Jul 26, 2013
1928390
The joinfield default is all input fields.
Jul 29, 2013
49a37e9
Support multiple join fields.
Jul 29, 2013
3cdb9c1
Support the unique flag.
Jul 29, 2013
d289545
Remove extraneous debug message.
Jul 29, 2013
50b0ca6
Add new line.
Jul 30, 2013
2461482
Add itersource.
Jul 30, 2013
3d71609
Add itersource test.
Jul 30, 2013
8e8f0a9
The itersource iterables key is a tuple only if there is more than on…
Jul 30, 2013
e8ab121
Flush out the itersource test.
Jul 31, 2013
dbb091a
Build the itersource iterables from the ancestor value lookup.
Jul 31, 2013
8a90be5
Fix _iterable_nodes merge.
Jul 31, 2013
293b80f
Support join on a node with an itersource.
Aug 1, 2013
ae1a25a
Add iterables synchronize.
Aug 2, 2013
24b33d9
Clarify comment.
Aug 3, 2013
5f4a764
Refactor iterable standardization to account for the itersource alter…
Aug 3, 2013
d630887
Test the alternate itersource iterables format.
Aug 3, 2013
8ee3ea3
Add the itersource field.
Aug 3, 2013
aab06f5
Support synchronize iterables tuple values.
Aug 3, 2013
fa08d85
Make the transposed synchronize iterable values a list.
Aug 4, 2013
2a6bb8f
Handle the alternate synchronize iterables format.
Aug 6, 2013
9808609
Copy all join node fields from the override self._inputs to the base …
Aug 9, 2013
80383d0
Add a test for multiple join nodes.
Aug 9, 2013
9ece179
The join node loop current node variable is jnode, not dest.
Aug 9, 2013
c1eb0c1
Use in rather than has_key for lookup.
Aug 9, 2013
d7098af
Make joinsource a property and convert a setter node value to the nod…
Aug 14, 2013
192a7a9
Add whitespace.
Aug 16, 2013
a1c387c
Delete Nipype master merge artifact.
Sep 5, 2013
459cc3c
Add the JoinNode and itersource chapter to the index.
Sep 6, 2013
04e05d0
Add midstream itersource join tests.
Sep 6, 2013
bdfc4e4
Add JoinNode and itersource chapter to User Guide.
Sep 6, 2013
13a6bea
Improve JoinNode documentation.
Sep 6, 2013
d2106c0
Add JoinNode to pipeline init
Sep 9, 2013
c27f62d
Add JoinNode to nipype init
Sep 9, 2013
091b4a5
Flatten imports in JoinNode example.
Sep 9, 2013
8e26e7f
Fix the _add_join_item_fields doctest.
Sep 9, 2013
6d6a617
fix: tests
satra Sep 14, 2013
826cab1
sty: fixed white spaces
satra Sep 14, 2013
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor iterable standardization to account for the itersource alter…
…nate format.
  • Loading branch information
FredLoney authored and satra committed Sep 14, 2013
commit 0830956202ccdcb0438c78d543c378fc1eabdac4
123 changes: 90 additions & 33 deletions nipype/pipeline/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,24 +569,16 @@ def generate_expanded_graph(graph_in):
parameterized as (a=1,b=3), (a=1,b=4), (a=2,b=3) and (a=2,b=4).
"""
logger.debug("PE: expanding iterables")
graph_in = _remove_identity_nodes(graph_in, keep_iterables=True)
# convert list of tuples to dict fields
graph_in = _remove_nonjoin_identity_nodes(graph_in, keep_iterables=True)
# standardize the iterables as {(field, function)} dictionaries
for node in graph_in.nodes_iter():
if isinstance(node.iterables, tuple):
node.iterables = [node.iterables]
for node in graph_in.nodes_iter():
if isinstance(node.iterables, list):
node.iterables = dict(map(lambda(x): (x[0],
lambda: x[1]),
node.iterables))
if node.iterables:
_standardize_iterables(node)
allprefixes = list('abcdefghijklmnopqrstuvwxyz')

# the iterable nodes
inodes = _iterable_nodes(graph_in)
logger.debug("Detected iterable nodes %s" % inodes)
# record the iterable fields, since expansion removes them
iter_fld_dict = {inode.name: inode.iterables.keys()
for inode in inodes}
# while there is an iterable node, expand the iterable node's
# subgraphs
while inodes:
Expand All @@ -612,22 +604,25 @@ def generate_expanded_graph(graph_in):
% (src, dest))

if inode.itersource:
# the itersource is a (node name, fields) tuple
src_name, src_fields = inode.itersource
# convert a single field to a list
if isinstance(src_fields, str):
src_fields = [src_fields]
# find the unique iterable source node in the graph
iter_src = None
for node in graph_in.nodes_iter():
if (node.name == inode.itersource
and nx.has_path(graph_in, node, inode)):
iter_src = node
break
if not iter_src or not iter_fld_dict.has_key(inode.itersource):
try:
iter_src = next((node for node in graph_in.nodes_iter()
if node.name == src_name
and nx.has_path(graph_in, node, inode)))
except StopIteration:
raise ValueError("The node %s itersource %s was not found"
" among the iterable nodes %s"
% (inode, inode.itersource, iter_fld_dict.keys()))
" among the iterable predecessor nodes"
% (inode, src_name))
logger.debug("The node %s has iterable source node %s"
% (inode, iter_src))
# look up the iterables for this particular itersource descendant
# using the iterable source ancestor values as a key
iterables = {}
# the source node iterables fields
src_fields = iter_fld_dict[inode.itersource]
# the source node iterables values
src_values = [getattr(iter_src.inputs, field) for field in src_fields]
# if there is one source field, then the key is the the source value,
Expand Down Expand Up @@ -683,9 +678,12 @@ def generate_expanded_graph(graph_in):
for src_id, edge_data in old_edge_dict.iteritems():
if node._id.startswith(src_id):
expansions[src_id].append(node)
for in_id, in_nodes in expansions.iteritems():
logger.debug("The join node %s input %s was expanded"
" to %d nodes." %(jnode, in_id, len(in_nodes)))
# preserve the node iteration order by sorting on the node id
for src_nodes in expansions.itervalues():
src_nodes.sort(key=lambda node: node._id)
for in_nodes in expansions.itervalues():
in_nodes.sort(key=lambda node: node._id)

# the number of iterations.
iter_cnt = count_iterables(iterables, inode.synchronize)
Expand All @@ -700,28 +698,28 @@ def generate_expanded_graph(graph_in):
# field 'in' are qualified as ('out_file', 'in1') and
# ('out_file', 'in2'), resp. This preserves connection port
# integrity.
for old_id, src_nodes in expansions.iteritems():
for old_id, in_nodes in expansions.iteritems():
# reconnect each replication of the current join in-edge
# source
for si, src in enumerate(src_nodes):
for in_idx, in_node in enumerate(in_nodes):
olddata = old_edge_dict[old_id]
newdata = deepcopy(olddata)
connects = newdata['connect']
join_fields = [field for _, field in connects
if field in dest.joinfield]
slots = slot_dicts[si]
for ci, connect in enumerate(connects):
slots = slot_dicts[in_idx]
for con_idx, connect in enumerate(connects):
src_field, dest_field = connect
# qualify a join destination field name
if dest_field in slots:
slot_field = slots[dest_field]
connects[ci] = (src_field, slot_field)
connects[con_idx] = (src_field, slot_field)
logger.debug("Qualified the %s -> %s join field"
" %s as %s." %
(src, jnode, dest_field, slot_field))
graph_in.add_edge(src, jnode, newdata)
(in_node, jnode, dest_field, slot_field))
graph_in.add_edge(in_node, jnode, newdata)
logger.debug("Connected the join node %s subgraph to the"
" expanded join point %s" % (jnode, src))
" expanded join point %s" % (jnode, in_node))

#nx.write_dot(graph_in, '%s_post.dot' % node)
# the remaining iterable nodes
Expand Down Expand Up @@ -760,6 +758,65 @@ def _iterable_nodes(graph_in):
inodes_src = [node for node in inodes if node.itersource]
inodes_no_src.reverse()
return inodes_no_src + inodes_src

def _standardize_iterables(node):
"""Converts the given iterables to a {field: function} dictionary,
if necessary, where the function returns a list."""
# trivial case
if not node.iterables:
return
iterables = node.iterables
# The candidate iterable fields
fields = set(node.inputs.copyable_trait_names())

# Convert a tuple to a list
if isinstance(iterables, tuple):
iterables = [iterables]
# Convert a list to a dictionary
if isinstance(iterables, list):
# Synchronize iterables can be in [fields, value tuples] format
# rather than [(field, value list), (field, value list), ...]
if node.synchronize and len(iterables) == 2:
first, last = iterables
if all((isinstance(item, str) and item in fields
for item in first)):
iterables = _transpose_iterables(first, last)
# Validate the format
for item in iterables:
try:
if len(item) != 2:
raise ValueError("The %s iterables do not consist of"
" (field, values) pairs" % node.name)
except TypeError, e:
raise TypeError("The %s iterables is not iterable: %s"
% (node.name, e))
# Convert the values to functions. This is a legacy Nipype
# requirement with unknown rationale.
iter_items = map(lambda(field, value): (field, lambda: value),
iterables)
# Make the iterables dictionary
iterables = dict(iter_items)
elif not isinstance(iterables, dict):
raise ValueError("The %s iterables type is not a list or a dictionary:"
" %s" % (node.name, iterables.__class__))

# Validate the iterable fields
for field in iterables.iterkeys():
if field not in fields:
raise ValueError("The %s iterables field is unrecognized: %s"
% (node.name, field))

# Assign to the standard form
node.iterables = iterables

def _transpose_iterables(fields, values):
"""
Converts the given fields and tuple values into a list of
iterable (field: value list) pairs, suitable for setting
a node iterables property.
"""
return zip(fields, [filter(lambda(v): v != None, transpose)
for transpose in zip(*values)])

def export_graph(graph_in, base_dir=None, show=False, use_execgraph=False,
show_connectinfo=False, dotfilename='graph.dot', format='png',
Expand Down