Robochameleon  v1.0
module.m
Go to the documentation of this file.
1 classdef module < unit
2 
3  properties (Abstract)
4  nInputs;
5  nOutputs;
6  end
7 
8  properties (GetAccess=public,SetAccess=private,Hidden=false) % Set Hidden=true afterwards
9  internalUnits = {};
10  traversingOrder = [];
11  biograph_struct = struct;
12  end
13 
14  properties (GetAccess=protected,SetAccess=private,Hidden=false) % Set Hidden=true afterwards
15  destInternalUnits = {};
16  destInternalInputs = [];
17  end
18 
19  properties (GetAccess=protected,SetAccess=protected)
20  outputBuffer; % initialized to be a sink with obj.nOutputs inputs
21  end
22 
23  methods (Access=private)
24 
25  function createGraphOrdering(obj)
26  N = numel(obj.internalUnits);
27  % Traverse all internal units sequentially to discover graph structure
28  UIDs = cell(N,1);
29  for i=1:numel(obj.internalUnits)
30  UIDs{i} = obj.internalUnits{i}.ID;
31  end
32 
33  dg = logical(sparse(N,N));
34  labels = cell(N,1);
35  for i=1:N
36 % tmp = obj.internalUnits{i};
37 % for j=1:tmp.nOutputs
38 % nextNodeID = obj.internalUnits{i}.nextNodes{j}.ID;
39  for nextNode = obj.internalUnits{i}.nextNodes
40  nextNodeID = nextNode{:}.ID;
41  k = find(cellfun(@(UID)isequal(nextNodeID,UID),UIDs));
42  if numel(k)>1
43  robolog('Something is wrong. Should return just one or zero match. Is it a DAG?', 'ERR');
44  end
45  dg(i,k) = true;
46  end
47  labels{i} = obj.internalUnits{i}.label;
48  end
49  obj.biograph_struct.dg = dg;
50  obj.biograph_struct.labels = labels;
51 
52  obj.traversingOrder = graphtopoorder(sparse(dg)); % Doesn't work for one vertex
53  end
54 
55  end
56 
57 
58 
59  methods (Access=protected)
60 
61  function exportModule(obj,varargin)
62  if isempty(varargin) % Automatic export
63  vars = evalin('caller','who'); % Get variables from the caller
64  vars(strcmp(inputname(1),vars)) = []; % Remove from the export list the module itself
65 % isunit = cellfun(@(v)evalin('caller',['inherits_from(' v ',''unit'')']),vars)
66  % For some reason, the line above doesn't work and we need
67  % following 4 lines
68  isunit = false(size(vars)); % Check which variables inherit after unit
69  for i=1:numel(vars)
70  isunit(i) = evalin('caller',['inherits_from(' vars{i} ',''unit'')']);
71  end
72  if ~any(isunit) % If no units found, show a warning
73  robolog('Module does not enclose any unit. To manually export module use exportModule(obj,unit1,unit2,...).', 'WRN');
74  else % If there are units to export, call exportModule with appropriate arguments
75  evalin('caller',['exportModule(obj,' strjoin(vars(isunit)',',') ');']);
76  end
77  else % Manual export / second call of automatic export
78  if all(cellfun(@(o)inherits_from(o,'unit'),varargin))
79  obj.internalUnits = varargin;
80  end
81  createGraphOrdering(obj);
82  end
83  end
84 
85  function connectInputs(obj,destInternalUnits,destInternalInputs)
86  %make sure destination array is cell array
87  if ~iscell(destInternalUnits)
88  destInternalUnits = mat2cell(destInternalUnits(:), ones(1, numel(destInternalUnits)), 1);
89  end
90  %make sure destination inputs make sense
91  if ~isnumeric(destInternalInputs)||~isvector(destInternalInputs)
92  robolog('Destination inputs must be specified as a vector of integers.', 'ERR');
93  end
94  %check that numbers add up
95  if numel(destInternalUnits)~=obj.nInputs
96  robolog('Number of external connections must be equal to the number of inputs. %s has %d inputs; %d destination units were specified', 'ERR', obj.label, obj.nInputs, numel(destInternalUnits));
97  end
98  obj.destInternalUnits = destInternalUnits;
99  obj.destInternalInputs = destInternalInputs;
100  end
101 
102 % function connectInternalOutputs(obj,srcInternalUnits,destExternalOutputs)
103 % %TODO error checking, etc.
104 % for i=1:obj.nOutputs
105 % srcInternalUnits{i}.connectOutput(obj.outputBuffer,i,destExternalOutputs(i));
106 % end
107 % end
108  end
109 
110 
111 
112  methods (Access=public)
113 
114  function obj = module
115  % Create sink for internal output buffers
116  obj.outputBuffer = sink(obj.nOutputs);
117  end
118 
119  function view(obj)
120  module_view(obj.biograph_struct,obj.internalUnits,obj.label);
121  end
122 
123  function output = getOutput(obj)
124  output = obj.outputBuffer.inputBuffer{1};
125  end
126 
127  function keepOutput(obj)
128  obj.outputBuffer.setKeep(1);
129  end
130 
131  function varargout = traverse(obj,varargin)
132  % Rewrite internal buffers to appropriate objects
133  for i=1:obj.nInputs
134  %FIXME when there's only one obj.destInternalUnits it must
135  %be also packaged into cell array. Otherwise this line will
136  %fail with "Cell contents reference from a non-cell array
137  %object."
138  % Ensure that in a call obj.connectInputs(units,no) units
139  % is always a cell array of units.
140  try
141  writeInputBuffer(obj.destInternalUnits{i},varargin{i},obj.destInternalInputs(i));
142  catch
143  robolog('Failed to write input buffer while traversing %s. Check connections and that traverse has been called enough input signals.', 'ERR', obj.label);
144  end
145  end
146 
147  for i=obj.traversingOrder
148  traverseNode(obj.internalUnits{i});
149  end
150  [varargout{1:obj.nOutputs}] = readBuffer(obj.outputBuffer);
151  end
152  end
153 
154 end
Superclass: basic building block to hold functions.
Definition: unit.m:27
function inherits_from(in obj, in className)
Determine whether an object inherits from a specified superclass.
stores the input signal.
Definition: sink.m:12
function robolog(in msg, in varargin)
This function allows the user to print log messages in a standard way.
Superclass: collection/sequence of unit.
Definition: module.m:64