def add_inputs(self, es):
for e in es:<EOL><INDENT>ensure_freshness(e)<EOL><DEDENT>for (fb,bb) in self.builder_layers[:-<NUM_LIT:1>]:<EOL><INDENT>fs = fb.initial_state().transduce(es)<EOL>bs = bb.initial_state().transduce(reversed(es))<EOL>es = [concatenate([f,b]) for f,b in zip(fs, reversed(bs))]<EOL><DEDENT>(fb,bb) = self.builder_layers[-<NUM_LIT:1>]<EOL>fs = fb.initial_state().add_inputs(es)<EOL>bs = bb.initial_state().add_inputs(reversed(es))<EOL>return [(f,b) for f,b in zip(fs, reversed(bs))]<EOL>
returns the list of state pairs (stateF, stateB) obtained by adding 
inputs to both forward (stateF) and backward (stateB) RNNs.  

@param es: a list of Expression

see also transduce(xs)

.transduce(xs) is different from .add_inputs(xs) in the following way:

    .add_inputs(xs) returns a list of RNNState pairs. RNNState objects can be
     queried in various ways. In particular, they allow access to the previous
     state, as well as to the state-vectors (h() and s() )

    .transduce(xs) returns a list of Expression. These are just the output
     expressions. For many cases, this suffices. 
     transduce is much more memory efficient than add_inputs.