<commit_before>### Fragment Traversal with Parameters
## updated Mon 06-16 11:22:24 -0700

Traverse(ScenarioID)
{
  // The top-level entry for fragment traversal.
  // first things first: don't re-compute if there is cached data

  if ~isempty( SELECT * FROM NodeCache WHERE FragmentID = @FragmentID AND
  ScenarioID = @ScenarioID AND NodeWeight ~=0 ) 
    return // do not re-compute 

  myflows = this.flows; // (I have no idea what language I'm writing)
    
  // Add on FlowFlowPropertyID
  fpflows = lookupFlowProperty ( myflows )

  myflows = applyParam ( myflows, ScenarioID, DependencyParam,
  	    	         FragmentFlowID, Quantity );
  
  myflows = applyParam ( myflows, ScenarioID, FlowPropertyParam,
  	    	       	 FlowFlowPropertyID, meanValue );

  float activity = 1;
  
  Ref_Flow = this.ReferenceFragmentFlowID; //

  // traverse the tree recursively, writing cache values as you go
  node_recurse(fpflows, ScenarioID, Ref_Flow, activity);
  // DONE.
}


fp_flows=lookupFlowProperty(flows)
{
  // This function returns an augmented flows table that includes
  // a field containing the FlowFlowProperty record that
  // matches both FlowID and FlowPropertyID in each flows record. Adds
  // FlowFlowPropertyID and meanValue fields.

  // first, determine the correct FlowFlowPropertyID
  fp_flows = SELECT flows.*,
  	     ffp.FlowFlowPropertyID,
  	     ffp.meanValue
	     FROM flows INNER JOIN FlowFlowProperty ffp
  	     ON flows.FlowID = ffp.FlowID
	     WHERE flows.FlowPropertyID = ffp.FlowPropertyID

  return fp_flows;
}

/* ***************************************************************
e=applyDependencyParam(flows,ScenarioID)
{
  // This function returns modified flows table that contains
  // scenario-specific parameterization for dependency relationships

  ParamList params = ScenarioParam.* WHERE ScenarioID = @ScenarioID
  dep_params = INNER JOIN params->Param->DependencyParam // types 1, 2, 3
  
  // generate scenario-specific edge table.  The idea is that we use the
  // edge weights specified in the default FragmentEdge table, unless they
  // have been overridden by scenario params
  e = SELECT flows.*,
      dep_params.Value AS ParamValue,
      FROM flows 
      LEFT OUTER JOIN dep_params ON FragmentFlowID
        
  // take the param values as defaults:
  UPDATE e.Quantity with e.ParamValue where e.ParamValue is not null;

  DROP field ParamValue; // so e has the same fields as flows

  return e;
}
****************************************************************** */

e=applyParam(flows,ScenarioID,ParamTable,LookupField,ReplaceField)
{ 
  // This function returns modified flows table that contains
  // scenario-specific parameterization for all relationships
  //
  // generic param override: on input table flows, find params belonging 
  // to the named ParamTable; join on LookupField; replace ReplaceField
  // with ParamTable.Value
  //
  // ParamTable is one of:
  //  - DependencyParam
  //  - FlowPropertyParam
  //  - CompositionParam
  //  - ProcessDissipationParam
  //  - NodeDissipationParam
  //  - ProcessEmissionParam
  //  - NodeEmissionParam
  //  - CharacterizationParam

  ParamList params = ScenarioParam.* WHERE ScenarioID = @ScenarioID
  my_params = INNER JOIN params->Param->@ParamTable

  // then attach the param values (if there are any) to flows
  e = SELECT flows.*,
      	     fp_params.Value AS ParamValue,
      	     FROM flows 
      	     LEFT OUTER JOIN fp_params 
	     ON flows.@LookupField = fp_params.@LookupField

  // take the param values as defaults:
  UPDATE e.@ReplaceField with e.ParamValue 
  	 where e.ParamValue is not null;

  DROP field ParamValue; 

  return e;
}

e=applyNodeParam(flows,ScenarioID,FragmentFlowID,ParamTable,LookupField,ReplaceField) 
{ 
  // this is just like applyParam, but has scope limited to a single node

  ParamList params = ScenarioParam.* WHERE ScenarioID = @ScenarioID
  my_params = INNER JOIN params->Param->@ParamTable
  	      WHERE @ParamTable.FragmentFlowID = @FragmentFlowID

  // then attach the param values (if there are any) to flows
  e = SELECT flows.*,
      	     fp_params.Value AS ParamValue,
      	     FROM flows 
      	     LEFT OUTER JOIN fp_params 
	     ON flows.@LookupField = fp_params.@LookupField

  // take the param values as defaults:
  UPDATE e.@ReplaceField with e.ParamValue 
  	 where e.ParamValue is not null;

  DROP field ParamValue; 

  return e;
}




Fragment.node_recurse(flows, ScenarioID, current_flow, activity)
{
  the_flow = SELECT * FROM flows WHERE FragmentFlowID = current_flow

  // "enter" the node -- handle reference property conversion
  // (params of type 4 have effect here)
  node_weight = the_flow.Quantity;
  node_conv = the_flow.MeanValue;

  activity = activity * node_weight * node_conv; % node activity level unit conversion

  SetNodeCache( current_flow, ScenarioID, activity )
  
  // now descend into node's children
  switch the_flow.NodeType
    case 'Process'
    {
      // dependencies are encoded in the edge table
      dependencies = SELECT * FROM flows WHERE ParentFragmentFlowID = current_flow
      for i in dependencies
      { 
        node_recurse(flows, ScenarioID, i.FragmentFlowID, activity )
      }
    }
    case 'Fragment'
    { 
      // dependencies are inputs and outputs from subfragment
      the_node = SELECT * FROM the_flow INNER JOIN FragmentNodeFragment fnf
      	       	 ON the_flow.FragmentNodeID = fnf.FragmentNodeID
      
      // flows in current fragment that depend on this node
      dependencies = SELECT * FROM flows
      		     WHERE flows.ParentFragmentFlowID = current_flow;

      F = new Fragment(the_node.SubFragmentID);

      // traverse the subfragment
      F.Traverse(ScenarioID);

      // need to set current fragment quantities based on subfragment 
      // inputs and outputs
      F.map_dependencies(dependencies); // updates dependencies.Quantity

      /*
      // IOFlows is a list of edges.  For every edge that has a
      // corresponding entry in our local edge table, follow it.  
      IOFlows = F.InputOutput(ScenarioID)
      dependencies = MatchDependencies(flows,IOFlows); 
      */


      for i in dependencies
      { 
        node_recurse(flows, ScenarioID, i.ParentFragmentFlowID, activity )
      }

    }
    case Background
      // nothing to do -- background fragments have already been traversed

    case InputOutput
      // nothing to do -- cache value specifies input/output quantity

  end // switch NodeType
}

Fragment.map_dependencies( dep )
{
  // match local input-output flows to remote dependencies
  // flows = this fragment
  // dependencies = remote fragment

  my_IO = SELECT FlowID, 
  	         DirectionID, 
		 sum( Quantity ) AS IOsum
	  FROM flows
	  WHERE flows.NodeType = 'InputOutput'
	  GROUP BY FlowID, DirectionID;

  dep = CompDir( dep ); // create a new field CompDirID which reverses the
      		     	// sense of DirectionID: 
      		     	// 'Input' becomes 'Output' and vice versa<commit_msg>Important fix to node recursion code<commit_after>### Fragment Traversal with Parameters
## updated Mon 06-16 11:22:24 -0700

Traverse(ScenarioID)
{
  // The top-level entry for fragment traversal.
  // first things first: don't re-compute if there is cached data

  if ~isempty( SELECT * FROM NodeCache WHERE FragmentID = @FragmentID AND
  ScenarioID = @ScenarioID AND NodeWeight ~=0 ) 
    return // do not re-compute 

  myflows = this.flows; // (I have no idea what language I'm writing)
    
  // Add on FlowFlowPropertyID
  fpflows = lookupFlowProperty ( myflows )

  myflows = applyParam ( myflows, ScenarioID, DependencyParam,
  	    	         FragmentFlowID, Quantity );
  
  myflows = applyParam ( myflows, ScenarioID, FlowPropertyParam,
  	    	       	 FlowFlowPropertyID, meanValue );

  float activity = 1;
  
  Ref_Flow = this.ReferenceFragmentFlowID; //

  // traverse the tree recursively, writing cache values as you go
  node_recurse(fpflows, ScenarioID, Ref_Flow, activity);
  // DONE.
}


fp_flows=lookupFlowProperty(flows)
{
  // This function returns an augmented flows table that includes
  // a field containing the FlowFlowProperty record that
  // matches both FlowID and FlowPropertyID in each flows record. Adds
  // FlowFlowPropertyID and meanValue fields.

  // first, determine the correct FlowFlowPropertyID
  fp_flows = SELECT flows.*,
  	     ffp.FlowFlowPropertyID,
  	     ffp.meanValue
	     FROM flows INNER JOIN FlowFlowProperty ffp
  	     ON flows.FlowID = ffp.FlowID
	     WHERE flows.FlowPropertyID = ffp.FlowPropertyID

  return fp_flows;
}

/* ***************************************************************
e=applyDependencyParam(flows,ScenarioID)
{
  // This function returns modified flows table that contains
  // scenario-specific parameterization for dependency relationships

  ParamList params = ScenarioParam.* WHERE ScenarioID = @ScenarioID
  dep_params = INNER JOIN params->Param->DependencyParam // types 1, 2, 3
  
  // generate scenario-specific edge table.  The idea is that we use the
  // edge weights specified in the default FragmentEdge table, unless they
  // have been overridden by scenario params
  e = SELECT flows.*,
      dep_params.Value AS ParamValue,
      FROM flows 
      LEFT OUTER JOIN dep_params ON FragmentFlowID
        
  // take the param values as defaults:
  UPDATE e.Quantity with e.ParamValue where e.ParamValue is not null;

  DROP field ParamValue; // so e has the same fields as flows

  return e;
}
****************************************************************** */

e=applyParam(flows,ScenarioID,ParamTable,LookupField,ReplaceField)
{ 
  // This function returns modified flows table that contains
  // scenario-specific parameterization for all relationships
  //
  // generic param override: on input table flows, find params belonging 
  // to the named ParamTable; join on LookupField; replace ReplaceField
  // with ParamTable.Value
  //
  // ParamTable is one of:
  //  - DependencyParam
  //  - FlowPropertyParam
  //  - CompositionParam
  //  - ProcessDissipationParam
  //  - NodeDissipationParam
  //  - ProcessEmissionParam
  //  - NodeEmissionParam
  //  - CharacterizationParam

  ParamList params = ScenarioParam.* WHERE ScenarioID = @ScenarioID
  my_params = INNER JOIN params->Param->@ParamTable

  // then attach the param values (if there are any) to flows
  e = SELECT flows.*,
      	     fp_params.Value AS ParamValue,
      	     FROM flows 
      	     LEFT OUTER JOIN fp_params 
	     ON flows.@LookupField = fp_params.@LookupField

  // take the param values as defaults:
  UPDATE e.@ReplaceField with e.ParamValue 
  	 where e.ParamValue is not null;

  DROP field ParamValue; 

  return e;
}

e=applyNodeParam(flows,ScenarioID,FragmentFlowID,ParamTable,LookupField,ReplaceField) 
{ 
  // this is just like applyParam, but has scope limited to a single node

  ParamList params = ScenarioParam.* WHERE ScenarioID = @ScenarioID
  my_params = INNER JOIN params->Param->@ParamTable
  	      WHERE @ParamTable.FragmentFlowID = @FragmentFlowID

  // then attach the param values (if there are any) to flows
  e = SELECT flows.*,
      	     fp_params.Value AS ParamValue,
      	     FROM flows 
      	     LEFT OUTER JOIN fp_params 
	     ON flows.@LookupField = fp_params.@LookupField

  // take the param values as defaults:
  UPDATE e.@ReplaceField with e.ParamValue 
  	 where e.ParamValue is not null;

  DROP field ParamValue; 

  return e;
}




Fragment.node_recurse(flows, ScenarioID, current_flow, activity)
{
  the_flow = SELECT * FROM flows WHERE FragmentFlowID = current_flow

  // "enter" the node -- handle reference property conversion
  // (params of type 4 have effect here)
  node_weight = the_flow.Quantity;
  node_conv = the_flow.MeanValue;

  activity = activity * node_weight * node_conv; % node activity level unit conversion

  SetNodeCache( current_flow, ScenarioID, activity )
  
  // now descend into node's children
  switch the_flow.NodeType
    case 'Process'
    {
      // dependencies are encoded in the edge table
      dependencies = SELECT * FROM flows WHERE ParentFragmentFlowID = current_flow
      for i in dependencies
      { 
        node_recurse(flows, ScenarioID, i.FragmentFlowID, activity )
      }
    }
    case 'Fragment'
    { 
      // dependencies are inputs and outputs from subfragment
      the_node = SELECT * FROM the_flow INNER JOIN FragmentNodeFragment fnf
      	       	 ON the_flow.FragmentNodeID = fnf.FragmentNodeID
      
      // flows in current fragment that depend on this node
      dependencies = SELECT * FROM flows
      		     WHERE flows.ParentFragmentFlowID = current_flow;

      F = new Fragment(the_node.SubFragmentID);

      // traverse the subfragment
      F.Traverse(ScenarioID);

      // need to set current fragment quantities based on subfragment 
      // inputs and outputs
      F.map_dependencies(dependencies); // updates dependencies.Quantity

      /*
      // IOFlows is a list of edges.  For every edge that has a
      // corresponding entry in our local edge table, follow it.  
      IOFlows = F.InputOutput(ScenarioID)
      dependencies = MatchDependencies(flows,IOFlows); 
      */

      // there's an outer join in here somewhere
      UPDATE flows.Quantity with dependencies.Quantity 
         WHERE flows.FragmentFlowID = dependencies.FragmentFlowID

      for i in dependencies
      { 
        node_recurse(flows, ScenarioID, i.FragmentFlowID, activity )
      }

    }
    case Background
      // nothing to do -- background fragments have already been traversed

    case InputOutput
      // nothing to do -- cache value specifies input/output quantity

  end // switch NodeType
}

Fragment.map_dependencies( dep )
{
  // match local input-output flows to remote dependencies
  // flows = this fragment
  // dependencies = remote fragment

  my_IO = SELECT FlowID, 
  	         DirectionID, 
		 sum( Quantity ) AS IOsum
	  FROM flows
	  WHERE flows.NodeType = 'InputOutput'
	  GROUP BY FlowID, DirectionID;

  dep = CompDir( dep ); // create a new field CompDirID which reverses the
      		     	// sense of DirectionID: 
      		     	// 'Input' becomes 'Output' and vice versa
{'fraction_non_alphanumeric': 0.08792134831460674, 'fraction_numerical': 0.0028089887640449437, 'mean_word_length': 2.903782894736842, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6263379', 'n_tokens_mistral': 4206, 'n_tokens_neox': 3912, 'n_words': 1344}