pulsatrix
Loading...
Searching...
No Matches
pulsatrix::ToyKnowledgeBase Class Reference

A small, hand-traceable knowledge base: two neural predicates A(x)/B(x) (each a sigmoid-squashed LinearModule(1,1), producing a fuzzy truth degree in (0,1)), one logical rule A(x) -> not(B(x)), expressed via De Morgan (not(A(x)) or not(B(x)), Product t-conorm/t-negation) using only NegationModule/DisjunctionModule (Mission 0) – no dedicated Implication Module – aggregated across synthetic groundings into one scalar via SatisfactionLoss (Mission 1). More...

#include <neuro_symbolic_toy_kb.hpp>

Public Member Functions

 ToyKnowledgeBase (DeviceBackend *backend, float p=2.0f)
 Constructs the toy KB with fixed, small, sign-varied initial predicate weights (mission file Stage 3's own hand-picked values: W_A=0.6, b_A=0.0, W_B=-0.4, b_B=0.0), mirroring XorNetwork's documented non-zero-init rationale.
 
float forward (const Tensor &x)
 Runs the full forward pass: A(x)/B(x) (Linear+sigmoid) -> not(A)/not(B) (NegationModule) -> rule = not(A) or not(B) (DisjunctionModule, Product) -> loss = 1 - agg_p(rule) (SatisfactionLoss). Caches every intermediate backward() needs.
 
void backward ()
 Backpropagates the loss through SatisfactionLoss -> DisjunctionModule -> NegationModule(x2) -> sigmoid(x2) -> LinearModule(x2), accumulating each predicate's weight/bias gradient (LinearModule::accumulate() convention).
 
float train_step (const Tensor &x, SGDOptimizer &optimizer)
 One SGD step: zero_grad both predicates, forward(), backward(), optimizer step on both predicates.
 
const Tensor & last_a () const
 Cached predicate A output from the most recent forward(), shape (N, 1).
 
const Tensor & last_b () const
 Cached predicate B output from the most recent forward(), shape (N, 1).
 
const Tensor & last_rule () const
 Cached rule truth degrees from the most recent forward(), shape (N,).
 
LinearModule & predicate_a ()
 Predicate A's own LinearModule – test/inspection accessor.
 
LinearModule & predicate_b ()
 Predicate B's own LinearModule – test/inspection accessor.
 
NegationModule & negation_a ()
 Predicate A's own NegationModule (not(A)) – test/inspection accessor, added for Phase 2 Mission 0's end-to-end conservation test (needs to chain propagate_relevance across the actual composed pipeline, not a reimplementation of it).
 
NegationModule & negation_b ()
 Predicate B's own NegationModule (not(B)) – test/inspection accessor, same rationale as negation_a().
 
DisjunctionModule & disjunction ()
 The rule's own DisjunctionModule (not(A) or not(B), Product) – test/inspection accessor, same rationale as negation_a().
 

Detailed Description

A small, hand-traceable knowledge base: two neural predicates A(x)/B(x) (each a sigmoid-squashed LinearModule(1,1), producing a fuzzy truth degree in (0,1)), one logical rule A(x) -> not(B(x)), expressed via De Morgan (not(A(x)) or not(B(x)), Product t-conorm/t-negation) using only NegationModule/DisjunctionModule (Mission 0) – no dedicated Implication Module – aggregated across synthetic groundings into one scalar via SatisfactionLoss (Mission 1).

Note
Not a Module subclass – directly analogous to XorNetwork's own classification (mission_training_loop.md): a composing class that owns and chains real Modules/SatisfactionLoss but is not itself relevance-bearing in the propagate_relevance sense. See mission_2_toy_kb_training_demo.md's Stage 3 "Interface/class design" note.
De Morgan is exact, not approximate, for this rule under the Product family: A -> not(B) == not(A) or not(B) is the ordinary propositional-logic identity (P -> Q == not(P) or Q, here Q = not(B)); with Product t-conorm/t-norm, the composed rule's truth degree collapses algebraically to the closed form rule_i = 1 - a_i*b_i (disjunction_Product(not_a, not_b) = not_a+not_b-not_a*not_b = 1-a*b after substituting not_a=1-a, not_b=1-b) – verified as a dedicated test comparing the composed Negation->Negation->Disjunction pipeline against this closed form elementwise, not merely asserted. See mission file Stage 3, Decision 1.
Sigmoid squashing is file-local glue, not a new library Module – pulsatrix has no standalone Sigmoid Module (checked); adding one for a single toy demo would be scope creep the mission file explicitly cautions against (by direct extension of its Implication-Module caution). sigmoid/sigmoid_backward are small anonymous-namespace free functions in neuro_symbolic_toy_kb.cpp, the same "small, per-file helper" convention ConjunctionModule/DisjunctionModule's own split_operands/combine_operands already established (mission_0's Stage 3).
No direct (label) supervision on A/B – the only training signal is the rule's own satisfaction loss, per the phase gate's literal "trainable end-to-end... on the toy knowledge base" wording. The honest degenerate optimum (push a_i*b_i toward 0 per grounding) is exactly what "satisfaction increases over epochs" is expected to show – not disguised as a more semantically rich result than it is.

Constructor & Destructor Documentation

◆ ToyKnowledgeBase()

pulsatrix::ToyKnowledgeBase::ToyKnowledgeBase ( DeviceBackend *  backend,
float  p = 2.0f 
)
explicit

Constructs the toy KB with fixed, small, sign-varied initial predicate weights (mission file Stage 3's own hand-picked values: W_A=0.6, b_A=0.0, W_B=-0.4, b_B=0.0), mirroring XorNetwork's documented non-zero-init rationale.

Parameters
backendBackend to compute through. Not owned; must outlive this object.
pAggregator exponent, forwarded to the owned SatisfactionLoss. Defaults to 2.0 (RMS), matching SatisfactionLoss's own default.

Member Function Documentation

◆ backward()

void pulsatrix::ToyKnowledgeBase::backward ( )

Backpropagates the loss through SatisfactionLoss -> DisjunctionModule -> NegationModule(x2) -> sigmoid(x2) -> LinearModule(x2), accumulating each predicate's weight/bias gradient (LinearModule::accumulate() convention).

Exceptions
std::logic_errorif called before forward().

◆ disjunction()

DisjunctionModule & pulsatrix::ToyKnowledgeBase::disjunction ( )
inline

The rule's own DisjunctionModule (not(A) or not(B), Product) – test/inspection accessor, same rationale as negation_a().

◆ forward()

float pulsatrix::ToyKnowledgeBase::forward ( const Tensor &  x)

Runs the full forward pass: A(x)/B(x) (Linear+sigmoid) -> not(A)/not(B) (NegationModule) -> rule = not(A) or not(B) (DisjunctionModule, Product) -> loss = 1 - agg_p(rule) (SatisfactionLoss). Caches every intermediate backward() needs.

Parameters
xShape (N, 1) – N synthetic groundings' shared feature value.
Returns
The scalar satisfaction loss (to minimize via gradient descent).
Exceptions
std::invalid_argumentif x is not rank 2 with a trailing dimension of 1, or if N == 0 – external boundary, this class's own documented shape contract (not delegated silently to whichever downstream module would happen to reject it first).

◆ last_a()

const Tensor & pulsatrix::ToyKnowledgeBase::last_a ( ) const
inline

Cached predicate A output from the most recent forward(), shape (N, 1).

◆ last_b()

const Tensor & pulsatrix::ToyKnowledgeBase::last_b ( ) const
inline

Cached predicate B output from the most recent forward(), shape (N, 1).

◆ last_rule()

const Tensor & pulsatrix::ToyKnowledgeBase::last_rule ( ) const
inline

Cached rule truth degrees from the most recent forward(), shape (N,).

◆ negation_a()

NegationModule & pulsatrix::ToyKnowledgeBase::negation_a ( )
inline

Predicate A's own NegationModule (not(A)) – test/inspection accessor, added for Phase 2 Mission 0's end-to-end conservation test (needs to chain propagate_relevance across the actual composed pipeline, not a reimplementation of it).

◆ negation_b()

NegationModule & pulsatrix::ToyKnowledgeBase::negation_b ( )
inline

Predicate B's own NegationModule (not(B)) – test/inspection accessor, same rationale as negation_a().

◆ predicate_a()

LinearModule & pulsatrix::ToyKnowledgeBase::predicate_a ( )
inline

Predicate A's own LinearModule – test/inspection accessor.

◆ predicate_b()

LinearModule & pulsatrix::ToyKnowledgeBase::predicate_b ( )
inline

Predicate B's own LinearModule – test/inspection accessor.

◆ train_step()

float pulsatrix::ToyKnowledgeBase::train_step ( const Tensor &  x,
SGDOptimizer &  optimizer 
)

One SGD step: zero_grad both predicates, forward(), backward(), optimizer step on both predicates.

Parameters
xShape (N, 1), as forward()'s own parameter.
optimizerOptimizer applied to both predicate LinearModules.
Returns
The loss value for this step, before the update (matches XorNetwork::train_step's own "before the update" convention).

The documentation for this class was generated from the following file: