ReasonMachine: Status and Gating
The ReasonMachine (RM, src/ADSIDAC/ReasonMachine/) is the knowledge-based reasoning model of the Decision Maker. Its reasoning cycle does not run in the current engine. This page states what of the RM still executes, how the --enable-rm-cycle flag gates the rest, and what has to be dealt with before the cycle is called again.
Status
The cycle entry point ReasonMachine::OneStepOfReasonMachine() has no caller. What still executes:
| Surface | Where | Why it matters |
|---|---|---|
| Construction and knowledge-base load at start-up | Operator::initiationForSimulation calls InitiationOfReasonMachineFromInputFile(), for the Decision Maker only | RandomlyGenerateKnowledgeBug() draws one rand() value per knowledge unit from the global random stream that all later stochastic sampling uses. Removing or reordering this call changes the sampled values of a run |
WhetherItIsNormalOperating() | called from the Decision Maker cycle (OperatorDM.cpp) | It reads a list that only the reasoning cycle fills, so its result is constant |
AddDeltaToCognitiveLoad() | called when an operator actively fetches information (Operator.cpp) | The accumulated value has no reader: the call that would pass it to the human-failure-event network (hfe_bbn.setCognitiveTaskLoad) is commented out |
Start-up also writes RMI.txt, AuxInfo.txt and Semantic_Base.txt into the working directory.
The gate
The runtime flag g_sim.config.rm_cycle_enabled (command line --enable-rm-cycle, default off) gates the copy and serialization machinery and leaves the live RM untouched.
With the flag off:
Operator::copyOperatorToRestartInfodoes not clone the RM into the restart snapshot, so the snapshot'sm_RMis null.Operator::serializewrites ahas_rmflag followed by the RM data only whenm_RMis not null. A snapshot without an RM therefore adds no RM data to MPI transfers and checkpoints. An archive that does contain RM data still loads.- On restore (
copyOperatorFromRestartInfoand the MPI restore path) the live RM persists across sequences, andReasonMachine::ClearTBIListsForRestart()resets the input queues of the cycle. - The five
m_tbi_*_listproducers inOperatorDM::infoChunkingdo not push. Those lists are consumed only by the reasoning cycle.
With the flag on, the snapshot holds a clone of the RM (CopyReasonMachineFromAnotherRM() followed by BuildTheConnectionsWithinRM()) at every branch point, a restore replaces the live RM by a clone of the snapshot's, the RM data travels in every transfer and checkpoint, and the m_tbi_*_list producers push. The cycle itself still does not run, because nothing calls OneStepOfReasonMachine().
Never gated: the start-up construction (and with it the rand() draws; the only rand() call in ReasonMachine.cpp is in RandomlyGenerateKnowledgeBug()), WhetherItIsNormalOperating() and AddDeltaToCognitiveLoad().
Before calling the cycle again
The following are properties of the dormant code. They have no effect while the cycle does not run.
- Archive round trip of dynamic state.
RMSerialization.hserializes string ids and skips raw pointers. It also skipsm_other_evidence_list, the investigator case lists and several pointer members, with the expectation that execution rebuilds them. Confirm that for every skipped member before relying on MPI transfers or checkpoints with the cycle enabled, and include them_position_tbi_*_listvectors. ReasonMachine::FindRecentStatementBySentence()never advances its iterator and readsstate_ptbefore assigning it. It does not terminate when the statement list is not empty.SentenceUnit, sentence type 5. In the activation-ratioswitch,case 5has itsbreakbefore the statement that does the work, so the attribute's activation ratio is never applied.- Model-specific debug residue inside the cycle.
ReasonMachine.cppcontains a statement conditioned ontimesno >= 1809, a block conditioned on848 < timesno < 850, and checks against literal ids ("statement_2472", and"Investigator_278"inSymptomInvestigator.cppandEventSchemaBase.cpp). They belong to one plant model and one debugging session and have to be removed for any other model. OperatorCT::OperatorCT()dereferencesm_RM, which is null untilinitiationForSimulationcreates it.
Design guidance for enabling it
- Split static from dynamic state. Most of what
CopyReasonMachineFromAnotherRM()copies (concepts, sentences, knowledge elements, nodes and units, mental-representation templates, the instantiation base) does not change after start-up. Hold it behind ashared_ptr<const ...>shared by the live RM and every snapshot, and copy and serialize only the dynamic part (activations, statements, investigators, histories). - Index the lookups. The
Find*ByID(std::string)functions are linear scans with by-value string parameters. They dominateBuildTheConnectionsWithinRM()and sit on the per-tick path once the cycle runs. Useconst std::string&andunordered_map<string, T*>indexes maintained on insertion. - Keep diagnostics out of snapshots. The history vectors (performance shaping factors, loads,
m_data_array, token histories) grow with every cycle step and would be cloned and shipped at every branch point. Write them out per sequence, asKeyParameterHistorydoes, or bound them. - Buffer the cycle's output.
PrintMessage()andWriteAuxInfo()open, append to and closeRMI.txtandAuxInfo.txtfor every message. Buffer in memory and flush per sequence, and write underOutput/and not into the working directory. - Use a deque or a cursor for the
m_tbi_*queues. The cycle erases from the front of growing vectors. - Expect different trees. The cycle generates goals (
MaintainGlobalSafetyMargin, throughWhetherItIsNormalOperating()), so the reference tree sizes change when it runs. Plan a new set of reference counts. - Mind the random stream. Any change to the start-up knowledge-base load that adds or removes
rand()draws shifts the global stream. A seeded generator with deterministic reseeding per sequence is best introduced together with the new reference counts, since both change sampled values.