def terms_from_trace(tr):
    'Helper function to extract elbo components from execution traces.'
    terms = {'log_factors': [], 'log_measures': [], 'scale': to_funsor(1.0), 'plate_vars': frozenset(), 'measure_vars': frozenset(), 'plate_to_step': dict()}
    for (name, node) in tr.nodes.items():
        if (node['type'] == 'markov_chain'):
            terms['plate_to_step'][node['name']] = node['value']
            for step in node['value']:
                terms['measure_vars'] |= frozenset({var for var in step[1:(- 1)] if (tr.nodes[var]['funsor'].get('log_measure', None) is not None)})
        if ((node['type'] != 'sample') or (type(node['fn']).__name__ == '_Subsample') or node['infer'].get('_do_not_score', False)):
            continue
        terms['plate_vars'] |= frozenset((f.name for f in node['cond_indep_stack'] if f.vectorized))
        if (node['funsor'].get('log_measure', None) is not None):
            terms['log_measures'].append(node['funsor']['log_measure'])
            terms['measure_vars'] |= ((frozenset(node['funsor']['value'].inputs) | {name}) - terms['plate_vars'])
        if (node.get('replay_active', False) and (set(node['funsor']['log_prob'].inputs) & terms['measure_vars']) and (float(to_data(node['funsor']['scale'])) != 1.0)):
            terms['scale'] = node['funsor']['scale']
        else:
            node['funsor']['log_prob'] = (node['funsor']['log_prob'] * node['funsor']['scale'])
        if (node['is_observed'] or (not node.get('replay_skipped', False))):
            terms['log_factors'].append(node['funsor']['log_prob'])
    terms['plate_to_step'].update({plate: terms['plate_to_step'].get(plate, {}) for plate in terms['plate_vars']})
    return terms
Helper function to extract elbo components from execution traces.
def terms_from_trace(tr):
    
    terms = {'log_factors': [], 'log_measures': [], 'scale': to_funsor(1.0), 'plate_vars': frozenset(), 'measure_vars': frozenset(), 'plate_to_step': dict()}
    for (name, node) in tr.nodes.items():
        if (node['type'] == 'markov_chain'):
            terms['plate_to_step'][node['name']] = node['value']
            for step in node['value']:
                terms['measure_vars'] |= frozenset({var for var in step[1:(- 1)] if (tr.nodes[var]['funsor'].get('log_measure', None) is not None)})
        if ((node['type'] != 'sample') or (type(node['fn']).__name__ == '_Subsample') or node['infer'].get('_do_not_score', False)):
            continue
        terms['plate_vars'] |= frozenset((f.name for f in node['cond_indep_stack'] if f.vectorized))
        if (node['funsor'].get('log_measure', None) is not None):
            terms['log_measures'].append(node['funsor']['log_measure'])
            terms['measure_vars'] |= ((frozenset(node['funsor']['value'].inputs) | {name}) - terms['plate_vars'])
        if (node.get('replay_active', False) and (set(node['funsor']['log_prob'].inputs) & terms['measure_vars']) and (float(to_data(node['funsor']['scale'])) != 1.0)):
            terms['scale'] = node['funsor']['scale']
        else:
            node['funsor']['log_prob'] = (node['funsor']['log_prob'] * node['funsor']['scale'])
        if (node['is_observed'] or (not node.get('replay_skipped', False))):
            terms['log_factors'].append(node['funsor']['log_prob'])
    terms['plate_to_step'].update({plate: terms['plate_to_step'].get(plate, {}) for plate in terms['plate_vars']})
    return terms