Skip to main content
Glama
ProbabilisticReasoningEngine.ts24.2 kB
/** * Probabilistic Reasoning Engine with Bayesian belief updating and uncertainty quantification */ import { BeliefEdge, BeliefNetwork, BeliefNode, BranchPoint, ConditionalProbability, Evidence, EvidenceIntegration, Hypothesis, ProbabilisticReasoningEngine as IProbabilisticReasoningEngine, ProbabilisticReasoningResult, ReasoningChain, ReasoningStep, UncertaintyAssessment, UncertaintyPropagation, UncertaintySource, } from "../interfaces/probabilistic-reasoning.js"; import { Context } from "../types/core.js"; interface PropagationPathStep { from_node: string; to_node: string; uncertainty_transfer: number; amplification_factor: number; method: string; } export class ProbabilisticReasoningEngine implements IProbabilisticReasoningEngine { async processWithUncertainty( input: string, context?: Context ): Promise<ProbabilisticReasoningResult> { const startTime = Date.now(); try { // Step 1: Parse input and extract key concepts const concepts = this.extractConcepts(input); // Step 2: Generate initial hypotheses const hypotheses = this.generateHypotheses(input, concepts); // Step 3: Collect and evaluate evidence const evidence = this.collectEvidence(input, concepts, context); // Step 4: Build belief network const beliefNetwork = this.buildBeliefNetwork(hypotheses, evidence); // Step 5: Perform Bayesian updating const updatedNetwork = await this.updateBeliefs( evidence[0], beliefNetwork ); // Step 6: Generate reasoning chain const reasoningChain = this.buildReasoningChain( hypotheses, evidence, updatedNetwork ); // Step 7: Quantify uncertainty const uncertaintyAssessment = this.quantifyUncertainty(reasoningChain); // Step 8: Integrate evidence const evidenceIntegration = this.integrateEvidence(evidence); // Step 9: Select best hypothesis and generate conclusion const bestHypothesis = this.selectBestHypothesis( hypotheses, updatedNetwork ); const conclusion = this.generateConclusion( bestHypothesis, evidenceIntegration ); const processingTime = Date.now() - startTime; return { conclusion, confidence: bestHypothesis.confidence, uncertainty_assessment: uncertaintyAssessment, belief_network: updatedNetwork, evidence_integration: evidenceIntegration, alternative_hypotheses: hypotheses.filter( (h) => h.id !== bestHypothesis.id ), reasoning_chain: reasoningChain, processing_time_ms: processingTime, }; } catch (error) { // Fallback response with high uncertainty return { conclusion: `Unable to process with high confidence due to: ${ error instanceof Error ? error.message : "Unknown error" }`, confidence: 0.1, uncertainty_assessment: { epistemic_uncertainty: 0.9, aleatoric_uncertainty: 0.5, combined_uncertainty: 0.95, confidence_interval: [0.05, 0.15], uncertainty_sources: [ { type: "model_limitations", description: "Processing error occurred", impact: 0.9, mitigation_suggestions: [ "Retry with simpler input", "Check input format", ], }, ], reliability_assessment: 0.1, }, belief_network: this.createEmptyBeliefNetwork(), evidence_integration: this.createEmptyEvidenceIntegration(), alternative_hypotheses: [], reasoning_chain: { steps: [], logical_structure: "", confidence_propagation: [], uncertainty_propagation: [], branch_points: [], }, processing_time_ms: Date.now() - startTime, }; } } async updateBeliefs( evidence: Evidence, priorBeliefs: BeliefNetwork ): Promise<BeliefNetwork> { const updatedNetwork: BeliefNetwork = { nodes: new Map(priorBeliefs.nodes), edges: new Map(priorBeliefs.edges), prior_probabilities: new Map(priorBeliefs.prior_probabilities), conditional_probabilities: new Map( priorBeliefs.conditional_probabilities ), evidence_nodes: [...priorBeliefs.evidence_nodes], }; // Apply Bayesian updating to relevant nodes for (const [, node] of updatedNetwork.nodes) { if (this.isRelevantToEvidence(node, evidence)) { const prior = node.probability; const likelihood = this.calculateLikelihood(evidence, node); const marginalLikelihood = this.calculateMarginalLikelihood( evidence, updatedNetwork ); // Bayes' theorem: P(H|E) = P(E|H) * P(H) / P(E) const posterior = (likelihood * prior) / marginalLikelihood; node.probability = Math.max(0.01, Math.min(0.99, posterior)); node.evidence_support.push(evidence); // Update uncertainty based on evidence quality node.uncertainty = this.updateUncertainty( node.uncertainty, evidence.reliability ); } } return updatedNetwork; } quantifyUncertainty(reasoning: ReasoningChain): UncertaintyAssessment { const epistemicUncertainty = this.calculateEpistemicUncertainty(reasoning); const aleatoricUncertainty = this.calculateAleatoricUncertainty(reasoning); const combinedUncertainty = this.combineUncertainties( epistemicUncertainty, aleatoricUncertainty ); const uncertaintySources = this.identifyUncertaintySources(reasoning); const reliabilityAssessment = this.assessReliability(reasoning); const avgConfidence = reasoning.confidence_propagation.reduce((a, b) => a + b, 0) / reasoning.confidence_propagation.length; const confidenceInterval: [number, number] = [ Math.max(0, avgConfidence - combinedUncertainty), Math.min(1, avgConfidence + combinedUncertainty), ]; return { epistemic_uncertainty: epistemicUncertainty, aleatoric_uncertainty: aleatoricUncertainty, combined_uncertainty: combinedUncertainty, confidence_interval: confidenceInterval, uncertainty_sources: uncertaintySources, reliability_assessment: reliabilityAssessment, }; } propagateUncertainty( beliefs: BeliefNetwork, evidence: Evidence[] ): UncertaintyPropagation { const initialUncertainty = new Map<string, number>(); const finalUncertainty = new Map<string, number>(); // Initialize uncertainty values for (const [nodeId, node] of beliefs.nodes) { initialUncertainty.set(nodeId, node.uncertainty); } // Propagate uncertainty through the network const propagationPath = this.calculatePropagationPath(beliefs, evidence); // Update final uncertainty values for (const [nodeId, node] of beliefs.nodes) { finalUncertainty.set(nodeId, node.uncertainty); } const uncertaintyAmplification = this.calculateUncertaintyAmplification( initialUncertainty, finalUncertainty ); const criticalNodes = this.identifyCriticalNodes(beliefs, propagationPath); return { initial_uncertainty: initialUncertainty, final_uncertainty: finalUncertainty, propagation_path: propagationPath, uncertainty_amplification: uncertaintyAmplification, critical_nodes: criticalNodes, }; } // Private helper methods private extractConcepts(input: string): string[] { // Simple concept extraction - in a real implementation, this would use NLP const words = input.toLowerCase().split(/\s+/); const stopWords = new Set([ "the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with", "by", ]); return words.filter((word) => word.length > 3 && !stopWords.has(word)); } private generateHypotheses(input: string, concepts: string[]): Hypothesis[] { const hypotheses: Hypothesis[] = []; // Generate primary hypothesis hypotheses.push({ id: "h1", description: `Primary interpretation: ${input}`, probability: 0.6, evidence_support: [], alternative_explanations: [], testable_predictions: [ `If true, we should observe evidence related to: ${concepts.join( ", " )}`, ], confidence: 0.7, }); // Generate alternative hypotheses hypotheses.push({ id: "h2", description: `Alternative interpretation with different emphasis`, probability: 0.3, evidence_support: [], alternative_explanations: [ "Different causal relationship", "Different context interpretation", ], testable_predictions: ["Alternative evidence patterns should emerge"], confidence: 0.5, }); hypotheses.push({ id: "h3", description: `Null hypothesis: No significant pattern`, probability: 0.1, evidence_support: [], alternative_explanations: [ "Random occurrence", "Insufficient information", ], testable_predictions: ["No consistent evidence patterns"], confidence: 0.3, }); return hypotheses; } private collectEvidence( input: string, concepts: string[], context?: Context ): Evidence[] { const evidence: Evidence[] = []; // Generate evidence based on input analysis evidence.push({ id: "e1", content: `Direct textual evidence from input: "${input}"`, type: "observational", reliability: 0.8, relevance: 0.9, timestamp: Date.now(), source: "input_analysis", weight: 1.0, }); // Generate contextual evidence if available if (context) { evidence.push({ id: "e2", content: `Contextual information: domain=${ context.domain ?? "unknown" }`, type: "testimonial", reliability: 0.6, relevance: 0.7, timestamp: Date.now(), source: "context", weight: 0.7, }); } // Generate concept-based evidence if (concepts.length > 0) { evidence.push({ id: "e3", content: `Conceptual analysis reveals key terms: ${concepts.join( ", " )}`, type: "logical", reliability: 0.7, relevance: 0.8, timestamp: Date.now(), source: "concept_extraction", weight: 0.8, }); } return evidence; } private buildBeliefNetwork( hypotheses: Hypothesis[], evidence: Evidence[] ): BeliefNetwork { const nodes = new Map<string, BeliefNode>(); const edges = new Map<string, BeliefEdge>(); const priorProbabilities = new Map<string, number>(); const conditionalProbabilities = new Map<string, ConditionalProbability>(); const evidenceNodes: string[] = []; // Add hypothesis nodes for (const hypothesis of hypotheses) { nodes.set(hypothesis.id, { id: hypothesis.id, name: hypothesis.description, type: "hypothesis", probability: hypothesis.probability, uncertainty: 1 - hypothesis.confidence, dependencies: [], evidence_support: hypothesis.evidence_support, }); priorProbabilities.set(hypothesis.id, hypothesis.probability); } // Add evidence nodes for (const evidenceItem of evidence) { nodes.set(evidenceItem.id, { id: evidenceItem.id, name: evidenceItem.content, type: "evidence", probability: evidenceItem.reliability, uncertainty: 1 - evidenceItem.reliability, dependencies: [], evidence_support: [evidenceItem], }); evidenceNodes.push(evidenceItem.id); } // Create edges between evidence and hypotheses for (const evidenceItem of evidence) { for (const hypothesis of hypotheses) { const relevanceScore = this.calculateRelevance( evidenceItem, hypothesis ); if (relevanceScore > 0.3) { const edgeId = `${evidenceItem.id}->${hypothesis.id}`; edges.set(edgeId, { from: evidenceItem.id, to: hypothesis.id, strength: relevanceScore, type: "evidential", confidence: evidenceItem.reliability * hypothesis.confidence, }); } } } return { nodes, edges, prior_probabilities: priorProbabilities, conditional_probabilities: conditionalProbabilities, evidence_nodes: evidenceNodes, }; } private buildReasoningChain( hypotheses: Hypothesis[], evidence: Evidence[], _network: BeliefNetwork ): ReasoningChain { const steps: ReasoningStep[] = []; const confidencePropagation: number[] = []; const uncertaintyPropagation: number[] = []; const branchPoints: BranchPoint[] = []; // Add premise steps for evidence for (const evidenceItem of evidence) { steps.push({ id: `step_${evidenceItem.id}`, type: "premise", content: evidenceItem.content, confidence: evidenceItem.reliability, uncertainty: 1 - evidenceItem.reliability, evidence_basis: [evidenceItem], logical_form: "premise", alternatives: [], }); confidencePropagation.push(evidenceItem.reliability); uncertaintyPropagation.push(1 - evidenceItem.reliability); } // Add inference steps const bestHypothesis = hypotheses.reduce((best, current) => current.probability > best.probability ? current : best ); steps.push({ id: "inference_step", type: "inference", content: `Based on the evidence, the most likely explanation is: ${bestHypothesis.description}`, confidence: bestHypothesis.confidence, uncertainty: 1 - bestHypothesis.confidence, evidence_basis: evidence, logical_form: "abductive_inference", alternatives: hypotheses .filter((h) => h.id !== bestHypothesis.id) .map((h) => h.description), }); confidencePropagation.push(bestHypothesis.confidence); uncertaintyPropagation.push(1 - bestHypothesis.confidence); // Add conclusion step steps.push({ id: "conclusion_step", type: "conclusion", content: `Therefore, ${bestHypothesis.description}`, confidence: bestHypothesis.probability, uncertainty: 1 - bestHypothesis.probability, evidence_basis: evidence, logical_form: "conclusion", alternatives: [], }); confidencePropagation.push(bestHypothesis.probability); uncertaintyPropagation.push(1 - bestHypothesis.probability); // Add branch point for hypothesis selection if (hypotheses.length > 1) { branchPoints.push({ step_id: "inference_step", alternatives: hypotheses.map((h) => ({ description: h.description, probability: h.probability, consequences: h.testable_predictions, evidence_requirements: [`Evidence supporting: ${h.description}`], })), selection_rationale: "Selected hypothesis with highest posterior probability", confidence_impact: bestHypothesis.confidence - 0.5, }); } return { steps, logical_structure: "premise -> inference -> conclusion", confidence_propagation: confidencePropagation, uncertainty_propagation: uncertaintyPropagation, branch_points: branchPoints, }; } private selectBestHypothesis( hypotheses: Hypothesis[], network: BeliefNetwork ): Hypothesis { return hypotheses.reduce((best, current) => { const currentNode = network.nodes.get(current.id); const bestNode = network.nodes.get(best.id); if (!currentNode || !bestNode) return best; return currentNode.probability > bestNode.probability ? current : best; }); } private generateConclusion( hypothesis: Hypothesis, evidenceIntegration: EvidenceIntegration ): string { const confidenceLevel = hypothesis.confidence > 0.8 ? "high" : hypothesis.confidence > 0.6 ? "moderate" : "low"; return ( `With ${confidenceLevel} confidence (${( hypothesis.confidence * 100 ).toFixed(1)}%), ` + `the analysis suggests: ${hypothesis.description}. ` + `This conclusion is based on ${evidenceIntegration.total_evidence_count} pieces of evidence ` + `with an overall quality score of ${( evidenceIntegration.evidence_quality_score * 100 ).toFixed(1)}%.` ); } private integrateEvidence(evidence: Evidence[]): EvidenceIntegration { const totalCount = evidence.length; const qualityScore = evidence.reduce((sum, e) => sum + e.reliability, 0) / totalCount; const conflictingEvidence = evidence.filter((e) => e.reliability < 0.5); const supportingEvidence = evidence.filter((e) => e.reliability >= 0.5); const reliabilityWeightedScore = evidence.reduce((sum, e) => sum + e.reliability * e.weight, 0) / evidence.reduce((sum, e) => sum + e.weight, 0); return { total_evidence_count: totalCount, evidence_quality_score: qualityScore, conflicting_evidence: conflictingEvidence, supporting_evidence: supportingEvidence, evidence_synthesis: `Integrated ${totalCount} pieces of evidence with average quality ${( qualityScore * 100 ).toFixed(1)}%`, reliability_weighted_score: reliabilityWeightedScore, }; } // Uncertainty calculation methods private calculateEpistemicUncertainty(reasoning: ReasoningChain): number { // Epistemic uncertainty comes from lack of knowledge const knowledgeGaps = reasoning.steps.filter( (step) => step.type === "assumption" ).length; const totalSteps = reasoning.steps.length; return Math.min(0.9, knowledgeGaps / totalSteps + 0.1); } private calculateAleatoricUncertainty(reasoning: ReasoningChain): number { // Aleatoric uncertainty comes from inherent randomness const avgUncertainty = reasoning.uncertainty_propagation.reduce((a, b) => a + b, 0) / reasoning.uncertainty_propagation.length; return Math.min(0.9, avgUncertainty); } private combineUncertainties(epistemic: number, aleatoric: number): number { // Combine uncertainties using quadrature sum return Math.sqrt(epistemic * epistemic + aleatoric * aleatoric); } private identifyUncertaintySources( reasoning: ReasoningChain ): UncertaintySource[] { const sources: UncertaintySource[] = []; // Check for data quality issues const lowConfidenceSteps = reasoning.steps.filter( (step) => step.confidence < 0.6 ); if (lowConfidenceSteps.length > 0) { sources.push({ type: "data_quality", description: `${lowConfidenceSteps.length} reasoning steps have low confidence`, impact: lowConfidenceSteps.length / reasoning.steps.length, mitigation_suggestions: [ "Gather additional evidence", "Verify low-confidence claims", ], }); } // Check for incomplete information const assumptionSteps = reasoning.steps.filter( (step) => step.type === "assumption" ); if (assumptionSteps.length > 0) { sources.push({ type: "incomplete_information", description: `${assumptionSteps.length} assumptions made due to missing information`, impact: assumptionSteps.length / reasoning.steps.length, mitigation_suggestions: [ "Research missing information", "Validate assumptions", ], }); } return sources; } private assessReliability(reasoning: ReasoningChain): number { const avgConfidence = reasoning.confidence_propagation.reduce((a, b) => a + b, 0) / reasoning.confidence_propagation.length; const consistencyScore = this.calculateConsistency(reasoning); return (avgConfidence + consistencyScore) / 2; } private calculateConsistency(reasoning: ReasoningChain): number { // Simple consistency check based on confidence variance const confidences = reasoning.confidence_propagation; const mean = confidences.reduce((a, b) => a + b, 0) / confidences.length; const variance = confidences.reduce((sum, conf) => sum + Math.pow(conf - mean, 2), 0) / confidences.length; return Math.max(0, 1 - variance); // Lower variance = higher consistency } // Helper methods for Bayesian updating private isRelevantToEvidence(node: BeliefNode, evidence: Evidence): boolean { return node.type === "hypothesis" && evidence.relevance > 0.3; } private calculateLikelihood(evidence: Evidence, _node: BeliefNode): number { // Simplified likelihood calculation based on evidence relevance and reliability return evidence.relevance * evidence.reliability; } private calculateMarginalLikelihood( evidence: Evidence, network: BeliefNetwork ): number { // Simplified marginal likelihood calculation let marginal = 0; for (const [_, node] of network.nodes) { if (node.type === "hypothesis") { marginal += this.calculateLikelihood(evidence, node) * node.probability; } } return Math.max(0.01, marginal); // Avoid division by zero } private updateUncertainty( currentUncertainty: number, evidenceReliability: number ): number { // Evidence reduces uncertainty proportionally to its reliability const reductionFactor = evidenceReliability * 0.5; return Math.max(0.01, currentUncertainty * (1 - reductionFactor)); } private calculateRelevance( evidence: Evidence, hypothesis: Hypothesis ): number { // Simple relevance calculation based on content overlap const evidenceWords = evidence.content.toLowerCase().split(/\s+/); const hypothesisWords = hypothesis.description.toLowerCase().split(/\s+/); const overlap = evidenceWords.filter((word) => hypothesisWords.includes(word) ).length; return Math.min( 1, overlap / Math.min(evidenceWords.length, hypothesisWords.length) ); } private calculatePropagationPath( _network: BeliefNetwork, evidence: Evidence[] ): PropagationPathStep[] { // Simplified propagation path calculation return evidence.map((e) => ({ from_node: e.id, to_node: "hypothesis_nodes", uncertainty_transfer: 1 - e.reliability, amplification_factor: 1.0, method: "bayesian_update", })); } private calculateUncertaintyAmplification( initial: Map<string, number>, final: Map<string, number> ): number { let totalAmplification = 0; let count = 0; for (const [nodeId, initialUncertainty] of initial) { const finalUncertainty = final.get(nodeId) ?? initialUncertainty; totalAmplification += finalUncertainty / initialUncertainty; count++; } return count > 0 ? totalAmplification / count : 1.0; } private identifyCriticalNodes( network: BeliefNetwork, _propagationPath: PropagationPathStep[] ): string[] { // Identify nodes with high impact on uncertainty propagation const criticalNodes: string[] = []; for (const [nodeId, node] of network.nodes) { if (node.uncertainty > 0.7 && node.type === "hypothesis") { criticalNodes.push(nodeId); } } return criticalNodes; } private createEmptyBeliefNetwork(): BeliefNetwork { return { nodes: new Map(), edges: new Map(), prior_probabilities: new Map(), conditional_probabilities: new Map(), evidence_nodes: [], }; } private createEmptyEvidenceIntegration(): EvidenceIntegration { return { total_evidence_count: 0, evidence_quality_score: 0, conflicting_evidence: [], supporting_evidence: [], evidence_synthesis: "No evidence available", reliability_weighted_score: 0, }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/keyurgolani/ThoughtMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server