diff --git a/CMakeLists.txt b/CMakeLists.txt index f3d1d478..98d49d5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,9 @@ INCLUDE(TorchExports) # Torch libraries ADD_SUBDIRECTORY(lib) +# OpenCog Multi-Dimensional Tensor Inference Engine +ADD_SUBDIRECTORY(opencog) + CONFIGURE_FILE(paths.lua.in "${CMAKE_CURRENT_BINARY_DIR}/paths.lua") INCLUDE_DIRECTORIES(BEFORE "${LUA_INCDIR}") diff --git a/README.md b/README.md index 9495540c..d55c2c5b 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,26 @@ Torch7 community support can be found at the following locations. As of 2019, th # Torch Package Reference Manual # -__Torch__ is the main package in [Torch7](http://torch.ch) where data -structures for multi-dimensional tensors and mathematical operations -over these are defined. Additionally, it provides many utilities for -accessing files, serializing objects of arbitrary types and other -useful utilities. +__TorCog__ is an enhanced version of [Torch7](http://torch.ch) that implements +**OpenCog as a Multi-Dimensional Tensor Inference Engine**. It provides the +original Torch tensor library enhanced with a complete OpenCog cognitive +architecture using tensors for knowledge representation, inference, and +attention allocation. -## Torch Packages ## +## TorCog Packages ## + +### OpenCog Multi-Dimensional Tensor Inference Engine + + * **[OpenCog Tensor Engine](opencog/README.md)** - Complete OpenCog cognitive architecture implementation using multi-dimensional tensors + * [Tensor-based Atoms](opencog/atoms/) - Knowledge representation with high-dimensional embeddings + * [Inference Engine](opencog/inference/) - Rule-based reasoning with neural components + * [Attention Allocation](opencog/attention/) - Neural attention mechanism with tensor dynamics + * Pattern matching and similarity using tensor operations + * Probabilistic reasoning with uncertainty propagation + * Hebbian learning and neural adaptation + +### Original Torch Components * Tensor Library * [Tensor](doc/tensor.md) defines the _all powerful_ tensor object that provides multi-dimensional numerical arrays with type templating. diff --git a/opencog/CMakeLists.txt b/opencog/CMakeLists.txt new file mode 100644 index 00000000..5072c44a --- /dev/null +++ b/opencog/CMakeLists.txt @@ -0,0 +1,72 @@ +# OpenCog Multi-Dimensional Tensor Inference Engine +CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR) + +SET(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake" + "${CMAKE_MODULE_PATH}") + +# Source files for OpenCog components +SET(OPENCOG_ATOMS_SRC + atoms/opencog_atoms.c +) + +SET(OPENCOG_INFERENCE_SRC + inference/inference_engine.c +) + +SET(OPENCOG_ATTENTION_SRC + attention/attention_allocation.c +) + +SET(OPENCOG_CORE_SRC + opencog.c +) + +SET(OPENCOG_TEST_SRC + test_opencog.c +) + +# Tensor wrapper source +SET(OPENCOG_TENSOR_SRC + tensor_wrapper.c +) + +# All OpenCog sources +SET(OPENCOG_ALL_SRC + ${OPENCOG_TENSOR_SRC} + ${OPENCOG_ATOMS_SRC} + ${OPENCOG_INFERENCE_SRC} + ${OPENCOG_ATTENTION_SRC} + ${OPENCOG_CORE_SRC} +) + +# Include directories +# Include current directory for tensor wrapper +INCLUDE_DIRECTORIES(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}") + +# Create OpenCog library +ADD_LIBRARY(opencog SHARED ${OPENCOG_ALL_SRC}) + +# Link with math library (no longer need TH) +# TARGET_LINK_LIBRARIES(opencog TH) + +# Math library for mathematical functions +TARGET_LINK_LIBRARIES(opencog m) + +# Create test executable +ADD_EXECUTABLE(test_opencog ${OPENCOG_TEST_SRC}) +TARGET_LINK_LIBRARIES(test_opencog opencog m) + +# Create demo executable +ADD_EXECUTABLE(example_opencog_demo example_opencog_demo.c) +TARGET_LINK_LIBRARIES(example_opencog_demo opencog m) + +# Install OpenCog library and headers +INSTALL(TARGETS opencog DESTINATION lib) +INSTALL(FILES opencog.h DESTINATION include/opencog) +INSTALL(FILES atoms/opencog_atoms.h DESTINATION include/opencog/atoms) +INSTALL(FILES inference/inference_engine.h DESTINATION include/opencog/inference) +INSTALL(FILES attention/attention_allocation.h DESTINATION include/opencog/attention) + +# Install test and demo executables +INSTALL(TARGETS test_opencog example_opencog_demo DESTINATION bin) \ No newline at end of file diff --git a/opencog/README.md b/opencog/README.md new file mode 100644 index 00000000..056ce886 --- /dev/null +++ b/opencog/README.md @@ -0,0 +1,265 @@ +# OpenCog Multi-Dimensional Tensor Inference Engine + +This directory contains the implementation of OpenCog as a multi-dimensional tensor inference engine, built on top of the Torch tensor library. This implementation provides a tensor-based cognitive architecture that combines symbolic reasoning with neural computation. + +## Overview + +The OpenCog Tensor Inference Engine implements the core components of the OpenCog cognitive architecture using multi-dimensional tensors for efficient computation: + +- **Tensor-based Atoms**: All knowledge is represented as atoms with high-dimensional tensor embeddings +- **Truth Value Computations**: Probabilistic truth values computed using tensor operations +- **Attention Allocation**: Neural attention mechanism with tensor-based dynamics +- **Pattern Matching**: Efficient pattern matching using tensor similarity computations +- **Inference Engine**: Rule-based reasoning with neural network components +- **Learning System**: Hebbian learning and neural adaptation using tensor updates + +## Architecture + +### Core Components + +1. **Atoms and AtomSpace** (`atoms/`) + - `OCAtom`: Basic knowledge representation with tensor embeddings + - `OCTruthValue`: Probabilistic truth values using tensors + - `OCAtomSpace`: Container for all atoms with relationship matrices + +2. **Inference Engine** (`inference/`) + - `OCInferenceEngine`: Main reasoning engine + - `OCInferenceRule`: Configurable inference rules + - `OCPattern`: Pattern matching system + - Built-in rules: deduction, induction, abduction, revision + +3. **Attention Allocation** (`attention/`) + - `OCAttentionBank`: Central attention management system + - `OCAttentionAgent`: Specialized attention processing agents + - Attention dynamics: spreading, decay, competition, novelty detection + +4. **Main API** (`opencog.h/c`) + - High-level interface for the complete system + - Configuration management + - Statistics and monitoring + - Error handling + +### Key Features + +#### Tensor-Based Representation +- Each atom has a high-dimensional embedding vector (default: 128 dimensions) +- Truth values are represented as tensors enabling batch operations +- Attention values (STI, LTI, VLTI) stored as tensor components +- Relationship matrices for efficient graph operations + +#### Neural-Symbolic Integration +- Symbolic atoms with neural embeddings +- Truth value propagation using tensor mathematics +- Neural attention mechanisms +- Hebbian learning for association strengthening +- Backpropagation for embedding optimization + +#### Attention Allocation System +- Short-Term Importance (STI) for working memory +- Long-Term Importance (LTI) for episodic memory +- Very Long-Term Importance (VLTI) for semantic memory +- Attention spreading through atom connections +- Economic model with rent collection and resource allocation + +#### Inference Capabilities +- Forward chaining inference +- Backward chaining (goal-directed reasoning) +- Pattern matching with tensor similarity +- Probabilistic reasoning with uncertainty propagation +- Temporal reasoning support + +## Usage Examples + +### Basic System Setup + +```c +#include "opencog/opencog.h" + +// Create OpenCog system with default configuration +OpenCog *opencog = OpenCog_new(NULL); + +// Add some knowledge +OCAtom *cat = OpenCog_addConcept(opencog, "cat", 0.9f, 0.8f); +OCAtom *animal = OpenCog_addConcept(opencog, "animal", 0.95f, 0.9f); + +// Create relationship +OpenCog_associateAtoms(opencog, cat, animal, 0.85f); + +// Run inference +OpenCog_forwardChain(opencog, 10); + +// Clean up +OpenCog_free(opencog); +``` + +### Attention and Learning + +```c +// Enable attention and learning +OCConfig *config = OpenCog_getDefaultConfig(); +config->enable_attention = 1; +config->enable_hebbian_learning = 1; + +OpenCog *opencog = OpenCog_new(config); + +// Add concepts +OCAtom *red = OpenCog_addConcept(opencog, "red", 0.8f, 0.7f); +OCAtom *apple = OpenCog_addConcept(opencog, "apple", 0.9f, 0.8f); + +// Boost attention to activate learning +OpenCog_boostAttention(opencog, red, 20.0f); +OpenCog_boostAttention(opencog, apple, 15.0f); + +// Run attention cycles +for (int i = 0; i < 10; i++) { + OpenCog_stepAttention(opencog); +} + +// Check attentional focus +int focus_count; +OCAtom **focus = OpenCog_getAttentionalFocus(opencog, &focus_count); +``` + +### Pattern Matching and Similarity + +```c +// Create atoms +OCAtom *dog = OpenCog_addConcept(opencog, "dog", 0.85f, 0.75f); +OCAtom *wolf = OpenCog_addConcept(opencog, "wolf", 0.8f, 0.7f); + +// Compute similarity using tensor embeddings +float similarity = OpenCog_similarity(opencog, dog, wolf); +printf("Similarity between dog and wolf: %.3f\n", similarity); + +// Find similar atoms +int similar_count; +OCAtom **similar = OpenCog_findSimilarAtoms(opencog, dog, 0.5f, &similar_count); +``` + +## Building + +The OpenCog tensor engine is built as part of the main TorCog project: + +```bash +mkdir build +cd build +cmake .. +make opencog +``` + +To run tests: +```bash +./opencog/test_opencog +``` + +## Configuration + +The system can be configured using `OCConfig`: + +```c +OCConfig *config = OpenCog_getDefaultConfig(); + +// Adjust system limits +config->max_atoms = 50000; +config->max_inference_steps = 200; +config->embedding_dimensions = 256; + +// Control components +config->enable_attention = 1; +config->enable_forgetting = 1; +config->enable_hebbian_learning = 1; + +// Learning parameters +config->learning_rate = 0.05f; +config->confidence_threshold = 0.6f; +config->attention_threshold = 0.2f; + +OpenCog *opencog = OpenCog_new(config); +``` + +## Performance Considerations + +### Memory Usage +- Each atom requires ~1KB base memory + embedding size +- Default embedding: 128 dimensions × 4 bytes = 512 bytes per atom +- Attention matrices: O(N²) where N is max_atoms +- Inference matrices: O(N²) space for relationship storage + +### Computational Complexity +- Atom similarity: O(D) where D is embedding dimension +- Attention spreading: O(N×E) where E is average edges per atom +- Forward chaining: O(R×N²) where R is number of rules +- Pattern matching: O(N×D) for tensor-based matching + +### Optimization Tips +- Use smaller embedding dimensions for memory-constrained environments +- Limit max_atoms based on available RAM +- Adjust attention_threshold to control focus size +- Use sparse tensors for large, mostly-zero relationship matrices + +## Advanced Features + +### Custom Inference Rules +```c +OCInferenceRule *custom_rule = OCInferenceRule_new(OC_DEDUCTION_RULE, "my_rule"); +// Set custom truth value function +custom_rule->tv_function = my_custom_tv_function; +OCInferenceEngine_addRule(opencog->inference, custom_rule); +``` + +### Neural Training +```c +// Train atom embeddings +THTensor *target_embedding = THTensor_(newWithSize1d)(128); +// ... set target values ... +OpenCog_trainEmbedding(opencog, atom, target_embedding); + +// Train attention networks +OpenCog_trainNeuralComponent(opencog, "attention_network", inputs, targets); +``` + +### Monitoring and Analysis +```c +// Get system statistics +char stats[1000]; +OpenCog_getStats(opencog, stats, sizeof(stats)); + +// Export embeddings for analysis +THTensor *embeddings = OpenCog_getAtomEmbeddings(opencog); + +// Get attention distribution +THTensor *attention_dist = OCAttentionBank_getAttentionDistribution(opencog->attention); +``` + +## Integration with Other Systems + +The OpenCog tensor engine can be integrated with: + +- **Neural Networks**: Export embeddings for deep learning models +- **Symbolic Reasoners**: Import/export logical statements +- **Databases**: Serialize atomspace to persistent storage +- **Robotics**: Real-time sensor integration and motor control +- **NLP Systems**: Language understanding and generation + +## Future Extensions + +Planned enhancements include: + +- GPU acceleration using CUDA tensors +- Distributed atomspace across multiple nodes +- Quantum-inspired tensor operations +- Evolutionary optimization of inference rules +- Integration with large language models +- Real-time streaming data processing + +## References + +- OpenCog Framework: https://opencog.org/ +- Torch Tensor Library: https://github.com/torch/torch7 +- "The OpenCog Cognitive Architecture" by Ben Goertzel +- "Probabilistic Logic Networks" by Ben Goertzel et al. +- "Attention Allocation in OpenCog" by Nil Geisweiller + +## License + +This implementation is released under the same license as the parent TorCog project. \ No newline at end of file diff --git a/opencog/atoms/opencog_atoms.c b/opencog/atoms/opencog_atoms.c new file mode 100644 index 00000000..4e8088c4 --- /dev/null +++ b/opencog/atoms/opencog_atoms.c @@ -0,0 +1,358 @@ +#include "opencog_atoms.h" +#include +#include +#include + +/* Default embedding dimension for atoms */ +#ifndef OC_DEFAULT_EMBEDDING_DIM +#define OC_DEFAULT_EMBEDDING_DIM 128 +#endif +#ifndef OC_DEFAULT_ATTENTION_DIM +#define OC_DEFAULT_ATTENTION_DIM 3 // STI, LTI, VLTI +#endif + +/* Atom Creation and Management */ +OCAtom* OCAtom_new(OCAtomType type, const char *name) { + OCAtom *atom = (OCAtom*)malloc(sizeof(OCAtom)); + if (!atom) return NULL; + + atom->type = type; + atom->name = name ? strdup(name) : NULL; + + // Create default embedding tensor + atom->embedding = OCTensor_newWithSize1d(OC_DEFAULT_EMBEDDING_DIM); + OCTensor_zero(atom->embedding); + + // Create attention tensor (STI, LTI, VLTI) + atom->attention = OCTensor_newWithSize1d(OC_DEFAULT_ATTENTION_DIM); + OCTensor_zero(atom->attention); + + atom->tv = NULL; + atom->incoming = NULL; + atom->outgoing = NULL; + atom->incoming_count = 0; + atom->outgoing_count = 0; + atom->atom_id = 0; + atom->refcount = 1; + + return atom; +} + +OCAtom* OCAtom_newWithEmbedding(OCAtomType type, const char *name, OCTensor *embedding) { + OCAtom *atom = OCAtom_new(type, name); + if (!atom) return NULL; + + if (embedding) { + OCTensor_free(atom->embedding); + atom->embedding = OCTensor_newWithTensor(embedding); + } + + return atom; +} + +void OCAtom_retain(OCAtom *atom) { + if (atom) { + atom->refcount++; + } +} + +void OCAtom_free(OCAtom *atom) { + if (!atom) return; + + atom->refcount--; + if (atom->refcount > 0) return; + + if (atom->name) free(atom->name); + if (atom->embedding) OCTensor_free(atom->embedding); + if (atom->attention) OCTensor_free(atom->attention); + if (atom->tv) OCTruthValue_free(atom->tv); + + if (atom->incoming) free(atom->incoming); + if (atom->outgoing) free(atom->outgoing); + + free(atom); +} + +void OCAtom_setTruthValue(OCAtom *atom, OCTruthValue *tv) { + if (!atom) return; + + if (atom->tv) OCTruthValue_free(atom->tv); + atom->tv = tv; +} + +void OCAtom_addIncoming(OCAtom *atom, OCAtom *incoming) { + if (!atom || !incoming) return; + + atom->incoming = (OCAtom**)realloc(atom->incoming, + sizeof(OCAtom*) * (atom->incoming_count + 1)); + atom->incoming[atom->incoming_count] = incoming; + atom->incoming_count++; + OCAtom_retain(incoming); +} + +void OCAtom_addOutgoing(OCAtom *atom, OCAtom *outgoing) { + if (!atom || !outgoing) return; + + atom->outgoing = (OCAtom**)realloc(atom->outgoing, + sizeof(OCAtom*) * (atom->outgoing_count + 1)); + atom->outgoing[atom->outgoing_count] = outgoing; + atom->outgoing_count++; + OCAtom_retain(outgoing); +} + +/* Truth Value Operations */ +OCTruthValue* OCTruthValue_new(float strength, float confidence) { + OCTruthValue *tv = (OCTruthValue*)malloc(sizeof(OCTruthValue)); + if (!tv) return NULL; + + tv->strength = OCTensor_newWithSize1d(1); + tv->confidence = OCTensor_newWithSize1d(1); + tv->frequency = OCTensor_newWithSize1d(1); + tv->probability = OCTensor_newWithSize1d(1); + + OCTensor_set1d(tv->strength, 0, strength); + OCTensor_set1d(tv->confidence, 0, confidence); + OCTensor_set1d(tv->frequency, 0, strength); // Default frequency = strength + OCTensor_set1d(tv->probability, 0, strength); // Default probability = strength + + return tv; +} + +OCTruthValue* OCTruthValue_newFromTensor(OCTensor *strength, OCTensor *confidence) { + OCTruthValue *tv = (OCTruthValue*)malloc(sizeof(OCTruthValue)); + if (!tv) return NULL; + + tv->strength = OCTensor_newWithTensor(strength); + tv->confidence = OCTensor_newWithTensor(confidence); + tv->frequency = OCTensor_newWithTensor(strength); // Default frequency = strength + tv->probability = OCTensor_newWithTensor(strength); // Default probability = strength + + return tv; +} + +void OCTruthValue_free(OCTruthValue *tv) { + if (!tv) return; + + if (tv->strength) OCTensor_free(tv->strength); + if (tv->confidence) OCTensor_free(tv->confidence); + if (tv->frequency) OCTensor_free(tv->frequency); + if (tv->probability) OCTensor_free(tv->probability); + + free(tv); +} + +/* Truth Value Revision Formula: Combines two truth values */ +OCTruthValue* OCTruthValue_revision(OCTruthValue *tv1, OCTruthValue *tv2) { + if (!tv1 || !tv2) return NULL; + + OCTruthValue *result = (OCTruthValue*)malloc(sizeof(OCTruthValue)); + if (!result) return NULL; + + // Initialize result tensors + result->strength = OCTensor_newWithSize1d(1); + result->confidence = OCTensor_newWithSize1d(1); + result->frequency = OCTensor_newWithSize1d(1); + result->probability = OCTensor_newWithSize1d(1); + + // Temporary tensors for computation + OCTensor *temp1 = OCTensor_newWithSize1d(1); + OCTensor *temp2 = OCTensor_newWithSize1d(1); + OCTensor *temp3 = OCTensor_newWithSize1d(1); + + // Get values + float s1 = OCTensor_get1d(tv1->strength, 0); + float c1 = OCTensor_get1d(tv1->confidence, 0); + float s2 = OCTensor_get1d(tv2->strength, 0); + float c2 = OCTensor_get1d(tv2->confidence, 0); + + // Revision formula: s_rev = (s1*c1 + s2*c2) / (c1 + c2) + float c_sum = c1 + c2; + float s_rev = (c_sum > 0) ? (s1 * c1 + s2 * c2) / c_sum : 0.5; + float c_rev = c_sum; + + OCTensor_set1d(result->strength, 0, s_rev); + OCTensor_set1d(result->confidence, 0, c_rev); + OCTensor_set1d(result->frequency, 0, s_rev); + OCTensor_set1d(result->probability, 0, s_rev); + + OCTensor_free(temp1); + OCTensor_free(temp2); + OCTensor_free(temp3); + + return result; +} + +/* Truth Value Merge: Simple averaging */ +OCTruthValue* OCTruthValue_merge(OCTruthValue *tv1, OCTruthValue *tv2) { + if (!tv1 || !tv2) return NULL; + + OCTruthValue *result = (OCTruthValue*)malloc(sizeof(OCTruthValue)); + if (!result) return NULL; + + result->strength = OCTensor_newWithTensor(tv1->strength); + result->confidence = OCTensor_newWithTensor(tv1->confidence); + result->frequency = OCTensor_newWithTensor(tv1->frequency); + result->probability = OCTensor_newWithTensor(tv1->probability); + + // Average the values + OCTensor_cadd(result->strength, result->strength, 1.0, tv2->strength); + OCTensor_mul(result->strength, result->strength, 0.5); + + OCTensor_cadd(result->confidence, result->confidence, 1.0, tv2->confidence); + OCTensor_mul(result->confidence, result->confidence, 0.5); + + OCTensor_cadd(result->frequency, result->frequency, 1.0, tv2->frequency); + OCTensor_mul(result->frequency, result->frequency, 0.5); + + OCTensor_cadd(result->probability, result->probability, 1.0, tv2->probability); + OCTensor_mul(result->probability, result->probability, 0.5); + + return result; +} + +/* AtomSpace Operations */ +OCAtomSpace* OCAtomSpace_new(long max_atoms) { + OCAtomSpace *atomspace = (OCAtomSpace*)malloc(sizeof(OCAtomSpace)); + if (!atomspace) return NULL; + + atomspace->atoms = (OCAtom**)calloc(max_atoms, sizeof(OCAtom*)); + if (!atomspace->atoms) { + free(atomspace); + return NULL; + } + + // Create atom relationship matrix (max_atoms x max_atoms) + atomspace->atom_matrix = OCTensor_newWithSize2d(max_atoms, max_atoms); + OCTensor_zero(atomspace->atom_matrix); + + // Create attention allocation matrix + atomspace->attention_matrix = OCTensor_newWithSize2d(max_atoms, OC_DEFAULT_ATTENTION_DIM); + OCTensor_zero(atomspace->attention_matrix); + + atomspace->atom_count = 0; + atomspace->max_atoms = max_atoms; + atomspace->next_atom_id = 1; + + return atomspace; +} + +void OCAtomSpace_free(OCAtomSpace *atomspace) { + if (!atomspace) return; + + // Free all atoms + for (long i = 0; i < atomspace->atom_count; i++) { + if (atomspace->atoms[i]) { + OCAtom_free(atomspace->atoms[i]); + } + } + + free(atomspace->atoms); + OCTensor_free(atomspace->atom_matrix); + OCTensor_free(atomspace->attention_matrix); + free(atomspace); +} + +long OCAtomSpace_addAtom(OCAtomSpace *atomspace, OCAtom *atom) { + if (!atomspace || !atom || atomspace->atom_count >= atomspace->max_atoms) { + return -1; + } + + atom->atom_id = atomspace->next_atom_id++; + atomspace->atoms[atomspace->atom_count] = atom; + OCAtom_retain(atom); + + // Update attention matrix with atom's attention values + for (int i = 0; i < OC_DEFAULT_ATTENTION_DIM; i++) { + float att_val = OCTensor_get1d(atom->attention, i); + OCTensor_set2d(atomspace->attention_matrix, atomspace->atom_count, i, att_val); + } + + atomspace->atom_count++; + return atom->atom_id; +} + +OCAtom* OCAtomSpace_getAtom(OCAtomSpace *atomspace, long atom_id) { + if (!atomspace) return NULL; + + for (long i = 0; i < atomspace->atom_count; i++) { + if (atomspace->atoms[i] && atomspace->atoms[i]->atom_id == atom_id) { + return atomspace->atoms[i]; + } + } + return NULL; +} + +void OCAtomSpace_removeAtom(OCAtomSpace *atomspace, long atom_id) { + if (!atomspace) return; + + for (long i = 0; i < atomspace->atom_count; i++) { + if (atomspace->atoms[i] && atomspace->atoms[i]->atom_id == atom_id) { + OCAtom_free(atomspace->atoms[i]); + atomspace->atoms[i] = NULL; + break; + } + } +} + +OCTensor* OCAtomSpace_getAtomMatrix(OCAtomSpace *atomspace) { + if (!atomspace) return NULL; + return atomspace->atom_matrix; +} + +/* Pattern Matching and Inference */ +OCTensor* OCAtom_computeSimilarity(OCAtom *atom1, OCAtom *atom2) { + if (!atom1 || !atom2 || !atom1->embedding || !atom2->embedding) return NULL; + + // Compute cosine similarity using dot product + OCTensor *result = OCTensor_newWithSize1d(1); + + // Dot product of embeddings + float dot_product = OCTensor_dot(atom1->embedding, atom2->embedding); + + // Compute norms + OCTensor *norm1_tensor = OCTensor_newWithSize1d(1); + OCTensor *norm2_tensor = OCTensor_newWithSize1d(1); + + OCTensor_norm(norm1_tensor, atom1->embedding, 2, 0, 0); // L2 norm + OCTensor_norm(norm2_tensor, atom2->embedding, 2, 0, 0); + + float norm1 = OCTensor_get1d(norm1_tensor, 0); + float norm2 = OCTensor_get1d(norm2_tensor, 0); + + float similarity = (norm1 > 0 && norm2 > 0) ? dot_product / (norm1 * norm2) : 0.0; + OCTensor_set1d(result, 0, similarity); + + OCTensor_free(norm1_tensor); + OCTensor_free(norm2_tensor); + + return result; +} + +OCTensor* OCAtom_tensorProduct(OCAtom *atom1, OCAtom *atom2) { + if (!atom1 || !atom2 || !atom1->embedding || !atom2->embedding) return NULL; + + // Create tensor product (outer product) of embeddings + long dim1 = OCTensor_size(atom1->embedding, 0); + long dim2 = OCTensor_size(atom2->embedding, 0); + + OCTensor *result = OCTensor_newWithSize2d(dim1, dim2); + + for (long i = 0; i < dim1; i++) { + for (long j = 0; j < dim2; j++) { + float val1 = OCTensor_get1d(atom1->embedding, i); + float val2 = OCTensor_get1d(atom2->embedding, j); + OCTensor_set2d(result, i, j, val1 * val2); + } + } + + return result; +} + +void OCAtom_updateAttention(OCAtom *atom, OCTensor *sti_update) { + if (!atom || !atom->attention || !sti_update) return; + + // Update Short Term Importance (STI) + float current_sti = OCTensor_get1d(atom->attention, 0); + float update_val = OCTensor_get1d(sti_update, 0); + OCTensor_set1d(atom->attention, 0, current_sti + update_val); +} \ No newline at end of file diff --git a/opencog/atoms/opencog_atoms.h b/opencog/atoms/opencog_atoms.h new file mode 100644 index 00000000..db796cb3 --- /dev/null +++ b/opencog/atoms/opencog_atoms.h @@ -0,0 +1,92 @@ +#ifndef OPENCOG_ATOMS_H +#define OPENCOG_ATOMS_H + +#include "../tensor_wrapper.h" + +// Forward declarations +typedef struct OCAtom OCAtom; +typedef struct OCAtomSpace OCAtomSpace; +typedef struct OCTruthValue OCTruthValue; + +/* OpenCog Atom Types */ +typedef enum { + OC_NODE = 1, + OC_LINK, + OC_CONCEPT_NODE, + OC_PREDICATE_NODE, + OC_VARIABLE_NODE, + OC_LIST_LINK, + OC_AND_LINK, + OC_OR_LINK, + OC_NOT_LINK, + OC_IMPLICATION_LINK, + OC_EVALUATION_LINK, + OC_EXECUTION_LINK, + OC_PATTERN_LINK, + OC_BIND_LINK, + OC_LAMBDA_LINK +} OCAtomType; + +/* OpenCog Truth Value Structure using Tensors */ +typedef struct OCTruthValue { + OCTensor *strength; // Tensor representing confidence/strength + OCTensor *confidence; // Tensor representing confidence/count + OCTensor *frequency; // Tensor for frequency-based truth values + OCTensor *probability; // Tensor for probabilistic reasoning +} OCTruthValue; + +/* OpenCog Atom Structure with Tensor-based Representation */ +typedef struct OCAtom { + OCAtomType type; + char *name; // Atom name/label + OCTensor *embedding; // High-dimensional tensor representation + OCTensor *attention; // Attention values (STI, LTI, VLTI) + OCTruthValue *tv; // Truth value with tensor components + OCAtom **incoming; // Incoming links + OCAtom **outgoing; // Outgoing links + int incoming_count; + int outgoing_count; + long atom_id; // Unique identifier + int refcount; +} OCAtom; + +/* OpenCog AtomSpace - Container for all atoms */ +typedef struct OCAtomSpace { + OCAtom **atoms; // Array of all atoms + OCTensor *atom_matrix; // Matrix representation of atom relationships + OCTensor *attention_matrix; // Global attention allocation matrix + long atom_count; + long max_atoms; + long next_atom_id; +} OCAtomSpace; + +/* Atom Creation and Management */ +OCAtom* OCAtom_new(OCAtomType type, const char *name); +OCAtom* OCAtom_newWithEmbedding(OCAtomType type, const char *name, OCTensor *embedding); +void OCAtom_retain(OCAtom *atom); +void OCAtom_free(OCAtom *atom); +void OCAtom_setTruthValue(OCAtom *atom, OCTruthValue *tv); +void OCAtom_addIncoming(OCAtom *atom, OCAtom *incoming); +void OCAtom_addOutgoing(OCAtom *atom, OCAtom *outgoing); + +/* Truth Value Operations */ +OCTruthValue* OCTruthValue_new(float strength, float confidence); +OCTruthValue* OCTruthValue_newFromTensor(OCTensor *strength, OCTensor *confidence); +void OCTruthValue_free(OCTruthValue *tv); +OCTruthValue* OCTruthValue_merge(OCTruthValue *tv1, OCTruthValue *tv2); +OCTruthValue* OCTruthValue_revision(OCTruthValue *tv1, OCTruthValue *tv2); + +/* AtomSpace Operations */ +OCAtomSpace* OCAtomSpace_new(long max_atoms); +void OCAtomSpace_free(OCAtomSpace *atomspace); +long OCAtomSpace_addAtom(OCAtomSpace *atomspace, OCAtom *atom); +OCAtom* OCAtomSpace_getAtom(OCAtomSpace *atomspace, long atom_id); +void OCAtomSpace_removeAtom(OCAtomSpace *atomspace, long atom_id); +OCTensor* OCAtomSpace_getAtomMatrix(OCAtomSpace *atomspace); + +/* Pattern Matching and Inference */ +OCTensor* OCAtom_computeSimilarity(OCAtom *atom1, OCAtom *atom2); +OCTensor* OCAtom_tensorProduct(OCAtom *atom1, OCAtom *atom2); +void OCAtom_updateAttention(OCAtom *atom, OCTensor *sti_update); + +#endif \ No newline at end of file diff --git a/opencog/attention/attention_allocation.c b/opencog/attention/attention_allocation.c new file mode 100644 index 00000000..ca7b5afe --- /dev/null +++ b/opencog/attention/attention_allocation.c @@ -0,0 +1,522 @@ +#include "attention_allocation.h" +#include +#include +#include +#include + +#ifndef OC_DEFAULT_MAX_STI +#define OC_DEFAULT_MAX_STI 100.0f +#endif +#ifndef OC_DEFAULT_MIN_STI +#define OC_DEFAULT_MIN_STI -100.0f +#endif +#ifndef OC_DEFAULT_STI_DECAY +#define OC_DEFAULT_STI_DECAY 0.01f +#endif +#ifndef OC_DEFAULT_LTI_DECAY +#define OC_DEFAULT_LTI_DECAY 0.001f +#endif +#ifndef OC_DEFAULT_SPREAD_RATE +#define OC_DEFAULT_SPREAD_RATE 0.1f +#endif +#ifndef OC_DEFAULT_HEBBIAN_RATE +#define OC_DEFAULT_HEBBIAN_RATE 0.05f +#endif +#ifndef OC_DEFAULT_RENT_RATE +#define OC_DEFAULT_RENT_RATE 0.02f +#endif +#ifndef OC_DEFAULT_NOVELTY_BONUS +#define OC_DEFAULT_NOVELTY_BONUS 10.0f +#endif +#ifndef OC_DEFAULT_FOCUS_SIZE +#define OC_DEFAULT_FOCUS_SIZE 20 +#endif +#ifndef OC_DEFAULT_EMBEDDING_DIM +#define OC_DEFAULT_EMBEDDING_DIM 128 +#endif +#ifndef OC_DEFAULT_ATTENTION_DIM +#define OC_DEFAULT_ATTENTION_DIM 3 +#endif + +/* Attention Bank Operations */ +OCAttentionBank* OCAttentionBank_new(OCAtomSpace *atomspace) { + OCAttentionBank *bank = (OCAttentionBank*)malloc(sizeof(OCAttentionBank)); + if (!bank) return NULL; + + bank->atomspace = atomspace; + bank->max_agents = 50; + bank->agents = (OCAttentionAgent**)calloc(bank->max_agents, sizeof(OCAttentionAgent*)); + bank->agent_count = 0; + + long max_atoms = atomspace ? atomspace->max_atoms : 1000; + + // Initialize attention matrices + bank->attention_matrix = OCTensor_newWithSize2d(max_atoms, OC_DEFAULT_ATTENTION_DIM); + bank->activity_matrix = OCTensor_newWithSize2d(max_atoms, max_atoms); + bank->importance_vector = OCTensor_newWithSize1d(max_atoms); + bank->focus_mask = OCTensor_newWithSize1d(max_atoms); + bank->attention_history = OCTensor_newWithSize2d(max_atoms, 100); // 100 time steps + + OCTensor_zero(bank->attention_matrix); + OCTensor_zero(bank->activity_matrix); + OCTensor_zero(bank->importance_vector); + OCTensor_zero(bank->focus_mask); + OCTensor_zero(bank->attention_history); + + // Neural networks for learned attention + bank->attention_network = OCTensor_newWithSize3d(OC_DEFAULT_EMBEDDING_DIM, 64, max_atoms); + bank->value_network = OCTensor_newWithSize2d(OC_DEFAULT_EMBEDDING_DIM, 1); + + OCTensor_rand(bank->attention_network, NULL, NULL); + OCTensor_rand(bank->value_network, NULL, NULL); + + // Initialize global parameters + bank->global_params.max_sti = OC_DEFAULT_MAX_STI; + bank->global_params.min_sti = OC_DEFAULT_MIN_STI; + bank->global_params.sti_decay_rate = OC_DEFAULT_STI_DECAY; + bank->global_params.lti_decay_rate = OC_DEFAULT_LTI_DECAY; + bank->global_params.attention_spread_rate = OC_DEFAULT_SPREAD_RATE; + bank->global_params.hebbian_learning_rate = OC_DEFAULT_HEBBIAN_RATE; + bank->global_params.rent_rate = OC_DEFAULT_RENT_RATE; + bank->global_params.novelty_bonus = OC_DEFAULT_NOVELTY_BONUS; + bank->global_params.attention_focus_size = OC_DEFAULT_FOCUS_SIZE; + + bank->total_attention = 0; + bank->attention_cycles = 0; + + return bank; +} + +void OCAttentionBank_free(OCAttentionBank *bank) { + if (!bank) return; + + // Free all agents + for (int i = 0; i < bank->agent_count; i++) { + if (bank->agents[i]) { + OCAttentionAgent_free(bank->agents[i]); + } + } + free(bank->agents); + + OCTensor_free(bank->attention_matrix); + OCTensor_free(bank->activity_matrix); + OCTensor_free(bank->importance_vector); + OCTensor_free(bank->focus_mask); + OCTensor_free(bank->attention_history); + OCTensor_free(bank->attention_network); + OCTensor_free(bank->value_network); + + free(bank); +} + +void OCAttentionBank_addAgent(OCAttentionBank *bank, OCAttentionAgent *agent) { + if (!bank || !agent || bank->agent_count >= bank->max_agents) return; + + bank->agents[bank->agent_count] = agent; + bank->agent_count++; +} + +void OCAttentionBank_cycle(OCAttentionBank *bank) { + if (!bank || !bank->atomspace) return; + + // Run all active attention agents + for (int i = 0; i < bank->agent_count; i++) { + OCAttentionAgent *agent = bank->agents[i]; + if (agent && agent->active && agent->process) { + // Check if agent should run based on frequency + if (bank->attention_cycles % (int)(1.0f / agent->frequency) == 0) { + agent->process(agent, bank->atomspace); + agent->cycle_count++; + } + } + } + + // Update global attention dynamics + OCAttentionBank_spreadAttention(bank); + OCAttentionBank_updateImportance(bank); + OCAttentionBank_collectRent(bank); + OCAttentionBank_updateFocus(bank); + + bank->attention_cycles++; +} + +/* Attention Agent Creation and Management */ +OCAttentionAgent* OCAttentionAgent_new(OCAttentionAgentType type, const char *name) { + OCAttentionAgent *agent = (OCAttentionAgent*)malloc(sizeof(OCAttentionAgent)); + if (!agent) return NULL; + + agent->type = type; + agent->name = name ? strdup(name) : NULL; + + // Initialize agent weights + agent->agent_weights = OCTensor_newWithSize2d(OC_DEFAULT_EMBEDDING_DIM, OC_DEFAULT_EMBEDDING_DIM); + agent->activation_history = OCTensor_newWithSize1d(1000); // Store 1000 activations + + OCTensor_rand(agent->agent_weights, NULL, NULL); + OCTensor_zero(agent->activation_history); + + // Set default parameters + agent->params.max_sti = OC_DEFAULT_MAX_STI; + agent->params.min_sti = OC_DEFAULT_MIN_STI; + agent->params.sti_decay_rate = OC_DEFAULT_STI_DECAY; + agent->params.lti_decay_rate = OC_DEFAULT_LTI_DECAY; + agent->params.attention_spread_rate = OC_DEFAULT_SPREAD_RATE; + agent->params.hebbian_learning_rate = OC_DEFAULT_HEBBIAN_RATE; + agent->params.rent_rate = OC_DEFAULT_RENT_RATE; + agent->params.novelty_bonus = OC_DEFAULT_NOVELTY_BONUS; + agent->params.attention_focus_size = OC_DEFAULT_FOCUS_SIZE; + + // Set process function based on type + switch (type) { + case OC_HEBBIAN_AGENT: + agent->process = OCAgent_hebbian; + break; + case OC_IMPORTANCE_UPDATING_AGENT: + agent->process = OCAgent_importanceUpdating; + break; + case OC_FORGETTING_AGENT: + agent->process = OCAgent_forgetting; + break; + case OC_SPREADING_AGENT: + agent->process = OCAgent_spreading; + break; + case OC_RENT_COLLECTION_AGENT: + agent->process = OCAgent_rentCollection; + break; + case OC_NOVELTY_AGENT: + agent->process = OCAgent_novelty; + break; + default: + agent->process = NULL; + break; + } + + agent->active = 1; + agent->frequency = 1.0f; // 1 Hz by default + agent->cycle_count = 0; + + return agent; +} + +void OCAttentionAgent_free(OCAttentionAgent *agent) { + if (!agent) return; + + if (agent->name) free(agent->name); + if (agent->agent_weights) OCTensor_free(agent->agent_weights); + if (agent->activation_history) OCTensor_free(agent->activation_history); + + free(agent); +} + +/* Attention Value Operations */ +void OCAtom_setSTI(OCAtom *atom, float sti) { + if (!atom || !atom->attention) return; + OCTensor_set1d(atom->attention, OC_STI, sti); +} + +void OCAtom_setLTI(OCAtom *atom, float lti) { + if (!atom || !atom->attention) return; + OCTensor_set1d(atom->attention, OC_LTI, lti); +} + +void OCAtom_setVLTI(OCAtom *atom, float vlti) { + if (!atom || !atom->attention) return; + OCTensor_set1d(atom->attention, OC_VLTI, vlti); +} + +float OCAtom_getSTI(OCAtom *atom) { + if (!atom || !atom->attention) return 0.0f; + return OCTensor_get1d(atom->attention, OC_STI); +} + +float OCAtom_getLTI(OCAtom *atom) { + if (!atom || !atom->attention) return 0.0f; + return OCTensor_get1d(atom->attention, OC_LTI); +} + +float OCAtom_getVLTI(OCAtom *atom) { + if (!atom || !atom->attention) return 0.0f; + return OCTensor_get1d(atom->attention, OC_VLTI); +} + +void OCAtom_updateAttentionValue(OCAtom *atom, OCAttentionType type, float delta) { + if (!atom || !atom->attention) return; + + float current_val = OCTensor_get1d(atom->attention, type); + OCTensor_set1d(atom->attention, type, current_val + delta); +} + +/* Attention Spreading and Dynamics */ +void OCAttentionBank_spreadAttention(OCAttentionBank *bank) { + if (!bank || !bank->atomspace) return; + + OCTensor *spread_matrix = OCTensor_newWithSize2d(bank->atomspace->max_atoms, + bank->atomspace->max_atoms); + OCTensor_zero(spread_matrix); + + // Compute attention spreading through atom connections + for (long i = 0; i < bank->atomspace->atom_count; i++) { + OCAtom *atom = bank->atomspace->atoms[i]; + if (!atom) continue; + + float sti = OCAtom_getSTI(atom); + + // Spread attention to connected atoms + for (int j = 0; j < atom->outgoing_count; j++) { + OCAtom *target = atom->outgoing[j]; + if (target) { + // Find target atom index + for (long k = 0; k < bank->atomspace->atom_count; k++) { + if (bank->atomspace->atoms[k] == target) { + float spread_amount = sti * bank->global_params.attention_spread_rate; + OCTensor_set2d(spread_matrix, i, k, spread_amount); + break; + } + } + } + } + } + + // Apply spreading updates + for (long i = 0; i < bank->atomspace->atom_count; i++) { + OCAtom *atom = bank->atomspace->atoms[i]; + if (!atom) continue; + + float total_incoming = 0.0f; + for (long j = 0; j < bank->atomspace->atom_count; j++) { + total_incoming += OCTensor_get2d(spread_matrix, j, i); + } + + if (total_incoming > 0) { + OCAtom_updateAttentionValue(atom, OC_STI, total_incoming); + } + } + + OCTensor_free(spread_matrix); +} + +void OCAttentionBank_updateImportance(OCAttentionBank *bank) { + if (!bank || !bank->atomspace) return; + + // Update importance vector with current STI values + for (long i = 0; i < bank->atomspace->atom_count; i++) { + OCAtom *atom = bank->atomspace->atoms[i]; + if (atom) { + float sti = OCAtom_getSTI(atom); + OCTensor_set1d(bank->importance_vector, i, sti); + } + } +} + +void OCAttentionBank_collectRent(OCAttentionBank *bank) { + if (!bank || !bank->atomspace) return; + + // Collect rent (decay attention) from all atoms + for (long i = 0; i < bank->atomspace->atom_count; i++) { + OCAtom *atom = bank->atomspace->atoms[i]; + if (!atom) continue; + + float sti = OCAtom_getSTI(atom); + float lti = OCAtom_getLTI(atom); + + // Apply decay + float sti_decay = sti * bank->global_params.sti_decay_rate; + float lti_decay = lti * bank->global_params.lti_decay_rate; + + OCAtom_setSTI(atom, sti - sti_decay); + OCAtom_setLTI(atom, lti - lti_decay); + + // Ensure values stay within bounds + if (OCAtom_getSTI(atom) < bank->global_params.min_sti) { + OCAtom_setSTI(atom, bank->global_params.min_sti); + } + if (OCAtom_getSTI(atom) > bank->global_params.max_sti) { + OCAtom_setSTI(atom, bank->global_params.max_sti); + } + } +} + +void OCAttentionBank_updateFocus(OCAttentionBank *bank) { + if (!bank || !bank->atomspace) return; + + // Clear current focus + OCTensor_zero(bank->focus_mask); + + // Find atoms with highest STI values for focus + OCTensor *sti_values = OCTensor_newWithSize1d(bank->atomspace->atom_count); + OCTensor *indices = OCTensor_newWithSize1d(bank->atomspace->atom_count); + + for (long i = 0; i < bank->atomspace->atom_count; i++) { + OCAtom *atom = bank->atomspace->atoms[i]; + float sti = atom ? OCAtom_getSTI(atom) : 0.0f; + OCTensor_set1d(sti_values, i, sti); + OCTensor_set1d(indices, i, (float)i); + } + + // Sort by STI (simplified - just mark top atoms) + int focus_count = 0; + for (long i = 0; i < bank->atomspace->atom_count && focus_count < bank->global_params.attention_focus_size; i++) { + OCAtom *atom = bank->atomspace->atoms[i]; + if (atom && OCAtom_getSTI(atom) > 0) { + OCTensor_set1d(bank->focus_mask, i, 1.0f); + focus_count++; + } + } + + OCTensor_free(sti_values); + OCTensor_free(indices); +} + +/* Built-in Attention Agents */ +void OCAgent_hebbian(OCAttentionAgent *agent, OCAtomSpace *atomspace) { + if (!agent || !atomspace) return; + + // Strengthen connections between co-active atoms + for (long i = 0; i < atomspace->atom_count; i++) { + OCAtom *atom1 = atomspace->atoms[i]; + if (!atom1 || OCAtom_getSTI(atom1) <= 0) continue; + + for (long j = i + 1; j < atomspace->atom_count; j++) { + OCAtom *atom2 = atomspace->atoms[j]; + if (!atom2 || OCAtom_getSTI(atom2) <= 0) continue; + + // If both atoms have positive STI, strengthen their connection + float sti1 = OCAtom_getSTI(atom1); + float sti2 = OCAtom_getSTI(atom2); + + float hebbian_strength = sti1 * sti2 * agent->params.hebbian_learning_rate; + + // Update embeddings to be more similar (simplified hebbian learning) + if (atom1->embedding && atom2->embedding) { + OCTensor *diff = OCTensor_newWithTensor(atom1->embedding); + OCTensor_csub(diff, diff, 1.0, atom2->embedding); + OCTensor_mul(diff, diff, hebbian_strength); + + OCTensor_csub(atom1->embedding, atom1->embedding, 0.5, diff); + OCTensor_cadd(atom2->embedding, atom2->embedding, 0.5, diff); + + OCTensor_free(diff); + } + } + } +} + +void OCAgent_importanceUpdating(OCAttentionAgent *agent, OCAtomSpace *atomspace) { + if (!agent || !atomspace) return; + + // Update importance based on usage and connections + for (long i = 0; i < atomspace->atom_count; i++) { + OCAtom *atom = atomspace->atoms[i]; + if (!atom) continue; + + // Increase importance for atoms with many connections + float connection_bonus = (atom->incoming_count + atom->outgoing_count) * 0.1f; + + // Increase importance for atoms with high truth value confidence + float tv_bonus = 0.0f; + if (atom->tv && atom->tv->confidence) { + tv_bonus = OCTensor_get1d(atom->tv->confidence, 0) * 5.0f; + } + + float total_bonus = connection_bonus + tv_bonus; + OCAtom_updateAttentionValue(atom, OC_STI, total_bonus); + } +} + +void OCAgent_forgetting(OCAttentionAgent *agent, OCAtomSpace *atomspace) { + if (!agent || !atomspace) return; + + // Apply stronger forgetting to atoms with very low attention + for (long i = 0; i < atomspace->atom_count; i++) { + OCAtom *atom = atomspace->atoms[i]; + if (!atom) continue; + + float sti = OCAtom_getSTI(atom); + + // Apply exponential decay for very low attention atoms + if (sti < agent->params.min_sti * 0.5f) { + float decay_factor = 1.0f + agent->params.sti_decay_rate * 2.0f; + OCAtom_setSTI(atom, sti / decay_factor); + } + } +} + +void OCAgent_spreading(OCAttentionAgent *agent, OCAtomSpace *atomspace) { + if (!agent || !atomspace) return; + + // This is handled by OCAttentionBank_spreadAttention + // Agent-specific spreading could be implemented here +} + +void OCAgent_rentCollection(OCAttentionAgent *agent, OCAtomSpace *atomspace) { + if (!agent || !atomspace) return; + + // This is handled by OCAttentionBank_collectRent + // Agent-specific rent collection could be implemented here +} + +void OCAgent_novelty(OCAttentionAgent *agent, OCAtomSpace *atomspace) { + if (!agent || !atomspace) return; + + // Detect and reward novel patterns + for (long i = 0; i < atomspace->atom_count; i++) { + OCAtom *atom = atomspace->atoms[i]; + if (!atom || !atom->embedding) continue; + + // Simple novelty detection: compare with all other atoms + float min_similarity = 1.0f; + + for (long j = 0; j < atomspace->atom_count; j++) { + if (i == j) continue; + + OCAtom *other = atomspace->atoms[j]; + if (!other || !other->embedding) continue; + + // Compute similarity + float similarity = OCTensor_dot(atom->embedding, other->embedding); + if (similarity < min_similarity) { + min_similarity = similarity; + } + } + + // Reward novelty (low similarity means high novelty) + float novelty_score = 1.0f - min_similarity; + if (novelty_score > 0.5f) { + float novelty_bonus = novelty_score * agent->params.novelty_bonus; + OCAtom_updateAttentionValue(atom, OC_STI, novelty_bonus); + } + } +} + +float OCAttentionBank_computeNovelty(OCAttentionBank *bank, OCAtom *atom) { + if (!bank || !atom || !atom->embedding) return 0.0f; + + float total_similarity = 0.0f; + int comparison_count = 0; + + for (long i = 0; i < bank->atomspace->atom_count; i++) { + OCAtom *other = bank->atomspace->atoms[i]; + if (other == atom || !other || !other->embedding) continue; + + float similarity = OCTensor_dot(atom->embedding, other->embedding); + total_similarity += similarity; + comparison_count++; + } + + float avg_similarity = (comparison_count > 0) ? total_similarity / comparison_count : 0.0f; + return 1.0f - avg_similarity; // Novelty is inverse of average similarity +} + +OCTensor* OCAttentionBank_getAttentionDistribution(OCAttentionBank *bank) { + if (!bank || !bank->atomspace) return NULL; + + OCTensor *distribution = OCTensor_newWithSize1d(bank->atomspace->atom_count); + + for (long i = 0; i < bank->atomspace->atom_count; i++) { + OCAtom *atom = bank->atomspace->atoms[i]; + float sti = atom ? OCAtom_getSTI(atom) : 0.0f; + OCTensor_set1d(distribution, i, sti); + } + + return distribution; +} \ No newline at end of file diff --git a/opencog/attention/attention_allocation.h b/opencog/attention/attention_allocation.h new file mode 100644 index 00000000..95a0e7b0 --- /dev/null +++ b/opencog/attention/attention_allocation.h @@ -0,0 +1,146 @@ +#ifndef OPENCOG_ATTENTION_ALLOCATION_H +#define OPENCOG_ATTENTION_ALLOCATION_H + +#include "../atoms/opencog_atoms.h" + +/* Forward declarations */ +typedef struct OCAttentionBank OCAttentionBank; +typedef struct OCAttentionAgent OCAttentionAgent; +typedef struct OCAttentionParams OCAttentionParams; + +/* Attention Value Types */ +typedef enum { + OC_STI = 0, // Short Term Importance + OC_LTI = 1, // Long Term Importance + OC_VLTI = 2 // Very Long Term Importance +} OCAttentionType; + +/* Attention Agent Types */ +typedef enum { + OC_HEBBIAN_AGENT, // Strengthens frequently co-activated atoms + OC_IMPORTANCE_UPDATING_AGENT, // Updates STI based on activity + OC_FORGETTING_AGENT, // Decreases attention over time + OC_SPREADING_AGENT, // Spreads attention through links + OC_RENT_COLLECTION_AGENT, // Collects rent from atoms + OC_NOVELTY_AGENT // Detects and rewards novel patterns +} OCAttentionAgentType; + +/* Attention Parameters */ +typedef struct OCAttentionParams { + float max_sti; // Maximum short-term importance + float min_sti; // Minimum short-term importance + float sti_decay_rate; // Rate of STI decay over time + float lti_decay_rate; // Rate of LTI decay over time + float attention_spread_rate; // Rate of attention spreading + float hebbian_learning_rate; // Hebbian learning rate + float rent_rate; // Attention rent collection rate + float novelty_bonus; // Bonus for novel patterns + int attention_focus_size; // Size of attentional focus +} OCAttentionParams; + +/* Attention Agent */ +typedef struct OCAttentionAgent { + OCAttentionAgentType type; + char *name; + OCTensor *agent_weights; // Neural weights for attention computation + OCTensor *activation_history; // History of agent activations + OCAttentionParams params; // Agent-specific parameters + + // Agent function pointer + void (*process)(struct OCAttentionAgent *agent, OCAtomSpace *atomspace); + + int active; // Whether agent is currently active + float frequency; // How often agent runs (cycles per second) + int cycle_count; // Number of cycles agent has run +} OCAttentionAgent; + +/* Attention Bank - Central attention allocation system */ +typedef struct OCAttentionBank { + OCAtomSpace *atomspace; + OCAttentionAgent **agents; // Array of attention agents + int agent_count; + int max_agents; + + OCTensor *attention_matrix; // Global attention allocation matrix + OCTensor *activity_matrix; // Atom co-activation matrix + OCTensor *importance_vector; // Current importance values + OCTensor *focus_mask; // Mask for attentional focus + + OCAttentionParams global_params; // Global attention parameters + + // Statistics and monitoring + OCTensor *attention_history; // History of attention allocations + long total_attention; // Total attention in the system + long attention_cycles; // Number of attention cycles run + + // Neural components for learned attention + OCTensor *attention_network; // Neural network for attention prediction + OCTensor *value_network; // Value network for importance estimation +} OCAttentionBank; + +/* Attention Bank Operations */ +OCAttentionBank* OCAttentionBank_new(OCAtomSpace *atomspace); +void OCAttentionBank_free(OCAttentionBank *bank); +void OCAttentionBank_addAgent(OCAttentionBank *bank, OCAttentionAgent *agent); +void OCAttentionBank_removeAgent(OCAttentionBank *bank, const char *agent_name); +void OCAttentionBank_cycle(OCAttentionBank *bank); + +/* Attention Agent Creation and Management */ +OCAttentionAgent* OCAttentionAgent_new(OCAttentionAgentType type, const char *name); +void OCAttentionAgent_free(OCAttentionAgent *agent); +void OCAttentionAgent_setParameters(OCAttentionAgent *agent, OCAttentionParams *params); +void OCAttentionAgent_activate(OCAttentionAgent *agent, OCAtomSpace *atomspace); + +/* Attention Value Operations */ +void OCAtom_setSTI(OCAtom *atom, float sti); +void OCAtom_setLTI(OCAtom *atom, float lti); +void OCAtom_setVLTI(OCAtom *atom, float vlti); +float OCAtom_getSTI(OCAtom *atom); +float OCAtom_getLTI(OCAtom *atom); +float OCAtom_getVLTI(OCAtom *atom); +void OCAtom_updateAttentionValue(OCAtom *atom, OCAttentionType type, float delta); + +/* Attention Spreading and Dynamics */ +void OCAttentionBank_spreadAttention(OCAttentionBank *bank); +void OCAttentionBank_updateImportance(OCAttentionBank *bank); +void OCAttentionBank_collectRent(OCAttentionBank *bank); +void OCAttentionBank_updateFocus(OCAttentionBank *bank); + +/* Hebbian Learning */ +void OCAttentionBank_hebbianUpdate(OCAttentionBank *bank, OCAtom **co_active_atoms, int count); +OCTensor* OCAttentionBank_computeCoActivation(OCAttentionBank *bank, OCAtom *atom1, OCAtom *atom2); + +/* Novelty Detection */ +float OCAttentionBank_computeNovelty(OCAttentionBank *bank, OCAtom *atom); +void OCAttentionBank_rewardNovelty(OCAttentionBank *bank, OCAtom *atom, float novelty_score); + +/* Built-in Attention Agents */ +void OCAgent_hebbian(OCAttentionAgent *agent, OCAtomSpace *atomspace); +void OCAgent_importanceUpdating(OCAttentionAgent *agent, OCAtomSpace *atomspace); +void OCAgent_forgetting(OCAttentionAgent *agent, OCAtomSpace *atomspace); +void OCAgent_spreading(OCAttentionAgent *agent, OCAtomSpace *atomspace); +void OCAgent_rentCollection(OCAttentionAgent *agent, OCAtomSpace *atomspace); +void OCAgent_novelty(OCAttentionAgent *agent, OCAtomSpace *atomspace); + +/* Attention Allocation Algorithms */ +OCTensor* OCAttention_computeCompetition(OCTensor *importance_vector, float competition_strength); +OCTensor* OCAttention_computeFocus(OCTensor *attention_values, int focus_size); +OCTensor* OCAttention_computeSpread(OCTensor *source_attention, OCTensor *connectivity_matrix); + +/* Economic Attention Model */ +void OCAttentionBank_marketUpdate(OCAttentionBank *bank); +float OCAttentionBank_computeUtility(OCAttentionBank *bank, OCAtom *atom); +void OCAttentionBank_allocateResources(OCAttentionBank *bank); + +/* Neural Attention Learning */ +void OCAttentionBank_trainAttentionNetwork(OCAttentionBank *bank, + OCTensor *input_features, + OCTensor *target_attention); +OCTensor* OCAttentionBank_predictAttention(OCAttentionBank *bank, OCTensor *atom_features); + +/* Attention Statistics and Analysis */ +OCTensor* OCAttentionBank_getAttentionDistribution(OCAttentionBank *bank); +float OCAttentionBank_getAttentionEntropy(OCAttentionBank *bank); +OCTensor* OCAttentionBank_getTopAttention(OCAttentionBank *bank, int top_k); + +#endif \ No newline at end of file diff --git a/opencog/example_opencog_demo.c b/opencog/example_opencog_demo.c new file mode 100644 index 00000000..db9ac5e6 --- /dev/null +++ b/opencog/example_opencog_demo.c @@ -0,0 +1,293 @@ +/* + * OpenCog Multi-Dimensional Tensor Inference Engine Demo + * + * This example demonstrates the key features of the OpenCog tensor-based + * cognitive architecture including knowledge representation, inference, + * attention allocation, and learning. + */ + +#include "opencog.h" +#include +#include + +void print_separator(const char *title) { + printf("\n" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" + "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "\n"); + printf("%s\n", title); + printf("=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" + "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "=" "\n"); +} + +void demo_basic_knowledge() { + print_separator("Demo 1: Basic Knowledge Representation"); + + // Create OpenCog system + printf("Creating OpenCog system...\n"); + OpenCog *opencog = OpenCog_new(NULL); + + // Add basic concepts + printf("\nAdding basic concepts:\n"); + OCAtom *socrates = OpenCog_addConcept(opencog, "Socrates", 0.95f, 0.9f); + OCAtom *plato = OpenCog_addConcept(opencog, "Plato", 0.93f, 0.88f); + OCAtom *human = OpenCog_addConcept(opencog, "human", 0.98f, 0.95f); + OCAtom *philosopher = OpenCog_addConcept(opencog, "philosopher", 0.92f, 0.85f); + OCAtom *mortal = OpenCog_addConcept(opencog, "mortal", 0.99f, 0.98f); + + printf("- %s (strength=%.2f, confidence=%.2f)\n", socrates->name, + OCTensor_get1d(socrates->tv->strength, 0), + OCTensor_get1d(socrates->tv->confidence, 0)); + printf("- %s (strength=%.2f, confidence=%.2f)\n", plato->name, + OCTensor_get1d(plato->tv->strength, 0), + OCTensor_get1d(plato->tv->confidence, 0)); + + // Create relationships + printf("\nCreating relationships:\n"); + OpenCog_associateAtoms(opencog, socrates, human, 0.9f); + OpenCog_associateAtoms(opencog, socrates, philosopher, 0.95f); + OpenCog_associateAtoms(opencog, plato, human, 0.88f); + OpenCog_associateAtoms(opencog, plato, philosopher, 0.92f); + OpenCog_associateAtoms(opencog, human, mortal, 0.98f); + + printf("- Socrates is human (strength=0.90)\n"); + printf("- Socrates is philosopher (strength=0.95)\n"); + printf("- Plato is human (strength=0.88)\n"); + printf("- Plato is philosopher (strength=0.92)\n"); + printf("- Humans are mortal (strength=0.98)\n"); + + // Display current knowledge base + printf("\nCurrent AtomSpace:\n"); + printf("Total atoms: %ld\n", opencog->atomspace->atom_count); + + OpenCog_free(opencog); +} + +void demo_attention_system() { + print_separator("Demo 2: Attention Allocation System"); + + // Create system with attention enabled + OCConfig *config = OpenCog_getDefaultConfig(); + config->enable_attention = 1; + config->enable_hebbian_learning = 1; + config->attention_threshold = 5.0f; + + OpenCog *opencog = OpenCog_new(config); + free(config); + + printf("Created OpenCog system with attention enabled\n"); + + // Add concepts + OCAtom *red = OpenCog_addConcept(opencog, "red", 0.8f, 0.7f); + OCAtom *apple = OpenCog_addConcept(opencog, "apple", 0.9f, 0.8f); + OCAtom *fire = OpenCog_addConcept(opencog, "fire", 0.85f, 0.75f); + OCAtom *color = OpenCog_addConcept(opencog, "color", 0.95f, 0.9f); + + printf("\nInitial attention values:\n"); + printf("- red: STI=%.2f\n", OCAtom_getSTI(red)); + printf("- apple: STI=%.2f\n", OCAtom_getSTI(apple)); + printf("- fire: STI=%.2f\n", OCAtom_getSTI(fire)); + printf("- color: STI=%.2f\n", OCAtom_getSTI(color)); + + // Create associations + OpenCog_associateAtoms(opencog, red, apple, 0.8f); + OpenCog_associateAtoms(opencog, red, fire, 0.7f); + OpenCog_associateAtoms(opencog, red, color, 0.9f); + + // Boost attention to activate learning + printf("\nBoosting attention to 'red' and 'apple'...\n"); + OpenCog_boostAttention(opencog, red, 25.0f); + OpenCog_boostAttention(opencog, apple, 20.0f); + + printf("After attention boost:\n"); + printf("- red: STI=%.2f\n", OCAtom_getSTI(red)); + printf("- apple: STI=%.2f\n", OCAtom_getSTI(apple)); + + // Run attention cycles + printf("\nRunning attention cycles...\n"); + for (int i = 0; i < 5; i++) { + OpenCog_stepAttention(opencog); + printf("Cycle %d: red STI=%.2f, apple STI=%.2f, fire STI=%.2f\n", + i+1, OCAtom_getSTI(red), OCAtom_getSTI(apple), OCAtom_getSTI(fire)); + } + + // Show attentional focus + int focus_count; + OCAtom **focus_atoms = OpenCog_getAttentionalFocus(opencog, &focus_count); + printf("\nAttentional focus (%d atoms):\n", focus_count); + for (int i = 0; i < focus_count; i++) { + printf("- %s (STI=%.2f)\n", focus_atoms[i]->name, OCAtom_getSTI(focus_atoms[i])); + } + + if (focus_atoms) free(focus_atoms); + OpenCog_free(opencog); +} + +void demo_similarity_inference() { + print_separator("Demo 3: Similarity and Inference"); + + OpenCog *opencog = OpenCog_new(NULL); + + // Create animal concepts + OCAtom *cat = OpenCog_addConcept(opencog, "cat", 0.9f, 0.8f); + OCAtom *dog = OpenCog_addConcept(opencog, "dog", 0.88f, 0.82f); + OCAtom *wolf = OpenCog_addConcept(opencog, "wolf", 0.85f, 0.75f); + OCAtom *tiger = OpenCog_addConcept(opencog, "tiger", 0.87f, 0.78f); + OCAtom *tree = OpenCog_addConcept(opencog, "tree", 0.8f, 0.7f); + + printf("Testing similarity computation...\n"); + + // Modify embeddings to create meaningful similarities + if (cat->embedding && dog->embedding && wolf->embedding) { + // Make cat and dog more similar (both pets) + for (int i = 0; i < 20; i++) { + float pet_feature = 0.7f + i * 0.01f; + OCTensor_set1d(cat->embedding, i, pet_feature + 0.1f); + OCTensor_set1d(dog->embedding, i, pet_feature); + } + + // Make dog and wolf similar (both canines) + for (int i = 20; i < 40; i++) { + float canine_feature = 0.6f + i * 0.005f; + OCTensor_set1d(dog->embedding, i, canine_feature); + OCTensor_set1d(wolf->embedding, i, canine_feature + 0.05f); + } + + // Make cat and tiger similar (both felines) + for (int i = 40; i < 60; i++) { + float feline_feature = 0.8f + i * 0.003f; + OCTensor_set1d(cat->embedding, i, feline_feature); + OCTensor_set1d(tiger->embedding, i, feline_feature - 0.02f); + } + + // Make tree very different + for (int i = 0; i < 60; i++) { + OCTensor_set1d(tree->embedding, i, -0.5f + i * 0.01f); + } + } + + // Compute and display similarities + printf("\nSimilarity matrix:\n"); + OCAtom *animals[] = {cat, dog, wolf, tiger, tree}; + const char *names[] = {"cat", "dog", "wolf", "tiger", "tree"}; + int n_animals = 5; + + printf(" "); + for (int j = 0; j < n_animals; j++) { + printf("%8s", names[j]); + } + printf("\n"); + + for (int i = 0; i < n_animals; i++) { + printf("%8s", names[i]); + for (int j = 0; j < n_animals; j++) { + if (i == j) { + printf("%8.3f", 1.0f); + } else { + float sim = OpenCog_similarity(opencog, animals[i], animals[j]); + printf("%8.3f", sim); + } + } + printf("\n"); + } + + // Run inference + printf("\nRunning inference on animal knowledge...\n"); + long initial_atoms = opencog->atomspace->atom_count; + + OpenCog_forwardChain(opencog, 3); + + long final_atoms = opencog->atomspace->atom_count; + printf("Atoms before inference: %ld\n", initial_atoms); + printf("Atoms after inference: %ld\n", final_atoms); + printf("New atoms inferred: %ld\n", final_atoms - initial_atoms); + + OpenCog_free(opencog); +} + +void demo_system_monitoring() { + print_separator("Demo 4: System Monitoring and Statistics"); + + OCConfig *config = OpenCog_getDefaultConfig(); + config->enable_attention = 1; + + OpenCog *opencog = OpenCog_new(config); + free(config); + + // Build a small knowledge base + printf("Building knowledge base...\n"); + OCAtom *concepts[10]; + const char *concept_names[] = { + "cat", "dog", "animal", "pet", "mammal", + "red", "blue", "color", "apple", "fruit" + }; + + for (int i = 0; i < 10; i++) { + float strength = 0.8f + (i * 0.02f); + float confidence = 0.7f + (i * 0.02f); + concepts[i] = OpenCog_addConcept(opencog, concept_names[i], strength, confidence); + } + + // Create some associations + OpenCog_associateAtoms(opencog, concepts[0], concepts[2], 0.9f); // cat -> animal + OpenCog_associateAtoms(opencog, concepts[1], concepts[2], 0.85f); // dog -> animal + OpenCog_associateAtoms(opencog, concepts[0], concepts[3], 0.8f); // cat -> pet + OpenCog_associateAtoms(opencog, concepts[1], concepts[3], 0.9f); // dog -> pet + OpenCog_associateAtoms(opencog, concepts[8], concepts[9], 0.95f); // apple -> fruit + OpenCog_associateAtoms(opencog, concepts[8], concepts[5], 0.7f); // apple -> red + + // Run some operations + OpenCog_forwardChain(opencog, 2); + + for (int i = 0; i < 3; i++) { + OpenCog_stepAttention(opencog); + } + + // Display system statistics + printf("\nSystem Statistics:\n"); + char stats_buffer[1000]; + OpenCog_getStats(opencog, stats_buffer, sizeof(stats_buffer)); + printf("%s\n", stats_buffer); + + // Show version information + printf("OpenCog Version: %s\n", OpenCog_getVersion()); + + // Display embedding matrix info + OCTensor *embeddings = OpenCog_getAtomEmbeddings(opencog); + if (embeddings) { + printf("Embedding matrix size: %ldx%ld\n", + OCTensor_size(embeddings, 0), + OCTensor_size(embeddings, 1)); + OCTensor_free(embeddings); + } + + OpenCog_free(opencog); +} + +int main() { + printf("OpenCog Multi-Dimensional Tensor Inference Engine\n"); + printf("Demonstration Program\n\n"); + printf("This demo showcases the key features of the OpenCog tensor-based\n"); + printf("cognitive architecture including knowledge representation, attention\n"); + printf("allocation, similarity computation, and inference capabilities.\n"); + + // Run demonstrations + demo_basic_knowledge(); + demo_attention_system(); + demo_similarity_inference(); + demo_system_monitoring(); + + print_separator("Demo Complete"); + printf("OpenCog tensor inference engine demonstration finished successfully!\n\n"); + printf("Key features demonstrated:\n"); + printf("✓ Knowledge representation with tensor embeddings\n"); + printf("✓ Truth value computations using tensors\n"); + printf("✓ Attention allocation with neural dynamics\n"); + printf("✓ Similarity computation using tensor operations\n"); + printf("✓ Forward chaining inference\n"); + printf("✓ Hebbian learning and association strengthening\n"); + printf("✓ System monitoring and statistics\n\n"); + printf("The OpenCog tensor inference engine provides a powerful foundation\n"); + printf("for building intelligent systems that combine symbolic reasoning\n"); + printf("with neural computation using multi-dimensional tensors.\n"); + + return 0; +} \ No newline at end of file diff --git a/opencog/inference/inference_engine.c b/opencog/inference/inference_engine.c new file mode 100644 index 00000000..379cbae4 --- /dev/null +++ b/opencog/inference/inference_engine.c @@ -0,0 +1,493 @@ +#include "inference_engine.h" +#include +#include +#include +#include + +#ifndef OC_MAX_INFERENCE_STEPS +#define OC_MAX_INFERENCE_STEPS 100 +#endif +#ifndef OC_DEFAULT_LEARNING_RATE +#define OC_DEFAULT_LEARNING_RATE 0.01 +#endif +#ifndef OC_DEFAULT_CONFIDENCE_THRESHOLD +#define OC_DEFAULT_CONFIDENCE_THRESHOLD 0.5 +#endif +#ifndef OC_DEFAULT_EMBEDDING_DIM +#define OC_DEFAULT_EMBEDDING_DIM 128 +#endif + +/* Inference Engine Operations */ +OCInferenceEngine* OCInferenceEngine_new(OCAtomSpace *atomspace) { + OCInferenceEngine *engine = (OCInferenceEngine*)malloc(sizeof(OCInferenceEngine)); + if (!engine) return NULL; + + engine->atomspace = atomspace; + engine->max_rules = 100; + engine->rules = (OCInferenceRule**)calloc(engine->max_rules, sizeof(OCInferenceRule*)); + engine->rule_count = 0; + + // Initialize inference matrix (atoms x atoms) + long max_atoms = atomspace ? atomspace->max_atoms : 1000; + engine->inference_matrix = OCTensor_newWithSize2d(max_atoms, max_atoms); + OCTensor_zero(engine->inference_matrix); + + // Rule activation tensor + engine->rule_activations = OCTensor_newWithSize1d(engine->max_rules); + OCTensor_zero(engine->rule_activations); + + // Neural network components + engine->embedding_weights = OCTensor_newWithSize2d(OC_DEFAULT_EMBEDDING_DIM, OC_DEFAULT_EMBEDDING_DIM); + engine->attention_weights = OCTensor_newWithSize2d(OC_DEFAULT_ATTENTION_DIM, OC_DEFAULT_ATTENTION_DIM); + engine->inference_weights = OCTensor_newWithSize2d(max_atoms, max_atoms); + + // Initialize weights randomly (simplified initialization) + OCTensor_rand(engine->embedding_weights, NULL, NULL); + OCTensor_rand(engine->attention_weights, NULL, NULL); + OCTensor_rand(engine->inference_weights, NULL, NULL); + + // Scale weights to [-0.1, 0.1] + OCTensor_mul(engine->embedding_weights, engine->embedding_weights, 0.2); + OCTensor_sub(engine->embedding_weights, engine->embedding_weights, 0.1); + + engine->learning_rate = OC_DEFAULT_LEARNING_RATE; + engine->max_inference_steps = OC_MAX_INFERENCE_STEPS; + engine->confidence_threshold = OC_DEFAULT_CONFIDENCE_THRESHOLD; + + return engine; +} + +void OCInferenceEngine_free(OCInferenceEngine *engine) { + if (!engine) return; + + // Free all rules + for (int i = 0; i < engine->rule_count; i++) { + if (engine->rules[i]) { + OCInferenceRule_free(engine->rules[i]); + } + } + free(engine->rules); + + OCTensor_free(engine->inference_matrix); + OCTensor_free(engine->rule_activations); + OCTensor_free(engine->embedding_weights); + OCTensor_free(engine->attention_weights); + OCTensor_free(engine->inference_weights); + + free(engine); +} + +void OCInferenceEngine_addRule(OCInferenceEngine *engine, OCInferenceRule *rule) { + if (!engine || !rule || engine->rule_count >= engine->max_rules) return; + + engine->rules[engine->rule_count] = rule; + engine->rule_count++; +} + +void OCInferenceEngine_removeRule(OCInferenceEngine *engine, const char *rule_name) { + if (!engine || !rule_name) return; + + for (int i = 0; i < engine->rule_count; i++) { + if (engine->rules[i] && engine->rules[i]->name && + strcmp(engine->rules[i]->name, rule_name) == 0) { + OCInferenceRule_free(engine->rules[i]); + + // Shift remaining rules + for (int j = i; j < engine->rule_count - 1; j++) { + engine->rules[j] = engine->rules[j + 1]; + } + engine->rule_count--; + break; + } + } +} + +/* Pattern Matching */ +OCPattern* OCPattern_new(OCAtom **pattern_atoms, int count) { + OCPattern *pattern = (OCPattern*)malloc(sizeof(OCPattern)); + if (!pattern) return NULL; + + pattern->pattern_atoms = (OCAtom**)malloc(sizeof(OCAtom*) * count); + pattern->pattern_count = count; + + // Copy pattern atoms + for (int i = 0; i < count; i++) { + pattern->pattern_atoms[i] = pattern_atoms[i]; + OCAtom_retain(pattern_atoms[i]); + } + + // Create pattern tensor (average of all atom embeddings) + pattern->pattern_tensor = OCTensor_newWithSize1d(OC_DEFAULT_EMBEDDING_DIM); + OCTensor_zero(pattern->pattern_tensor); + + for (int i = 0; i < count; i++) { + if (pattern_atoms[i]->embedding) { + OCTensor_cadd(pattern->pattern_tensor, pattern->pattern_tensor, + 1.0 / count, pattern_atoms[i]->embedding); + } + } + + pattern->required_types = NULL; + pattern->type_count = 0; + + return pattern; +} + +void OCPattern_free(OCPattern *pattern) { + if (!pattern) return; + + for (int i = 0; i < pattern->pattern_count; i++) { + OCAtom_free(pattern->pattern_atoms[i]); + } + free(pattern->pattern_atoms); + + if (pattern->pattern_tensor) OCTensor_free(pattern->pattern_tensor); + if (pattern->required_types) free(pattern->required_types); + + free(pattern); +} + +OCTensor* OCPattern_match(OCPattern *pattern, OCAtomSpace *atomspace) { + if (!pattern || !atomspace) return NULL; + + // Create similarity tensor for all atoms in atomspace + OCTensor *similarity_scores = OCTensor_newWithSize1d(atomspace->atom_count); + OCTensor_zero(similarity_scores); + + for (long i = 0; i < atomspace->atom_count; i++) { + OCAtom *atom = atomspace->atoms[i]; + if (atom && atom->embedding) { + // Compute similarity with pattern + float similarity = OCTensor_dot(pattern->pattern_tensor, atom->embedding); + OCTensor_set1d(similarity_scores, i, similarity); + } + } + + return similarity_scores; +} + +/* Query Processing */ +OCQuery* OCQuery_new(OCPattern *pattern, OCAtom **variables, int var_count) { + OCQuery *query = (OCQuery*)malloc(sizeof(OCQuery)); + if (!query) return NULL; + + query->pattern = pattern; + query->variables = (OCAtom**)malloc(sizeof(OCAtom*) * var_count); + query->variable_count = var_count; + + for (int i = 0; i < var_count; i++) { + query->variables[i] = variables[i]; + OCAtom_retain(variables[i]); + } + + query->constraint_tensor = OCTensor_newWithSize1d(var_count); + OCTensor_ones(query->constraint_tensor, NULL); + + query->min_confidence = OC_DEFAULT_CONFIDENCE_THRESHOLD; + + return query; +} + +void OCQuery_free(OCQuery *query) { + if (!query) return; + + for (int i = 0; i < query->variable_count; i++) { + OCAtom_free(query->variables[i]); + } + free(query->variables); + + if (query->constraint_tensor) OCTensor_free(query->constraint_tensor); + + free(query); +} + +/* Inference Rule Creation */ +OCInferenceRule* OCInferenceRule_new(OCInferenceRuleType type, const char *name) { + OCInferenceRule *rule = (OCInferenceRule*)malloc(sizeof(OCInferenceRule)); + if (!rule) return NULL; + + rule->type = type; + rule->name = name ? strdup(name) : NULL; + rule->premise_pattern = NULL; + rule->conclusion_pattern = NULL; + + // Create rule weights tensor + rule->rule_weights = OCTensor_newWithSize2d(OC_DEFAULT_EMBEDDING_DIM, OC_DEFAULT_EMBEDDING_DIM); + OCTensor_rand(rule->rule_weights, NULL, NULL); + + // Set default functions based on rule type + switch (type) { + case OC_DEDUCTION_RULE: + rule->tv_function = OCInferenceRule_deduction; + break; + case OC_INDUCTION_RULE: + rule->tv_function = OCInferenceRule_induction; + break; + case OC_ABDUCTION_RULE: + rule->tv_function = OCInferenceRule_abduction; + break; + case OC_REVISION_RULE: + rule->tv_function = OCInferenceRule_revision; + break; + default: + rule->tv_function = NULL; + break; + } + + rule->rule_function = NULL; + + return rule; +} + +void OCInferenceRule_free(OCInferenceRule *rule) { + if (!rule) return; + + if (rule->name) free(rule->name); + if (rule->premise_pattern) OCPattern_free(rule->premise_pattern); + if (rule->conclusion_pattern) OCPattern_free(rule->conclusion_pattern); + if (rule->rule_weights) OCTensor_free(rule->rule_weights); + + free(rule); +} + +/* Built-in Inference Rules */ +OCTruthValue* OCInferenceRule_deduction(OCTruthValue **premise_tvs, int count) { + if (!premise_tvs || count < 2) return NULL; + + // Deduction: If A->B and A, then B + // TV(B) = TV(A->B) * TV(A) + OCTruthValue *result = OCTruthValue_new(1.0, 0.0); + + float s1 = OCTensor_get1d(premise_tvs[0]->strength, 0); + float c1 = OCTensor_get1d(premise_tvs[0]->confidence, 0); + float s2 = OCTensor_get1d(premise_tvs[1]->strength, 0); + float c2 = OCTensor_get1d(premise_tvs[1]->confidence, 0); + + float result_strength = s1 * s2; + float result_confidence = c1 * c2; + + OCTensor_set1d(result->strength, 0, result_strength); + OCTensor_set1d(result->confidence, 0, result_confidence); + + return result; +} + +OCTruthValue* OCInferenceRule_induction(OCTruthValue **premise_tvs, int count) { + if (!premise_tvs || count < 1) return NULL; + + // Simple induction: generalize from specific instances + OCTruthValue *result = OCTruthValue_new(0.0, 0.0); + + float avg_strength = 0.0; + float avg_confidence = 0.0; + + for (int i = 0; i < count; i++) { + avg_strength += OCTensor_get1d(premise_tvs[i]->strength, 0); + avg_confidence += OCTensor_get1d(premise_tvs[i]->confidence, 0); + } + + avg_strength /= count; + avg_confidence /= count; + + // Reduce confidence for generalization + avg_confidence *= 0.8; + + OCTensor_set1d(result->strength, 0, avg_strength); + OCTensor_set1d(result->confidence, 0, avg_confidence); + + return result; +} + +OCTruthValue* OCInferenceRule_abduction(OCTruthValue **premise_tvs, int count) { + if (!premise_tvs || count < 2) return NULL; + + // Abduction: If A->B and B, then A (with reduced confidence) + OCTruthValue *result = OCTruthValue_new(1.0, 0.0); + + float s1 = OCTensor_get1d(premise_tvs[0]->strength, 0); + float c1 = OCTensor_get1d(premise_tvs[0]->confidence, 0); + float s2 = OCTensor_get1d(premise_tvs[1]->strength, 0); + float c2 = OCTensor_get1d(premise_tvs[1]->confidence, 0); + + // Abduction has lower confidence than deduction + float result_strength = s2 * s1; + float result_confidence = c1 * c2 * 0.5; + + OCTensor_set1d(result->strength, 0, result_strength); + OCTensor_set1d(result->confidence, 0, result_confidence); + + return result; +} + +OCTruthValue* OCInferenceRule_revision(OCTruthValue **premise_tvs, int count) { + if (!premise_tvs || count < 2) return NULL; + + // Use the revision formula from atoms module + return OCTruthValue_revision(premise_tvs[0], premise_tvs[1]); +} + +/* Tensor-based Logical Operations */ +OCTensor* OCLogic_and(OCTensor *tensor1, OCTensor *tensor2) { + if (!tensor1 || !tensor2) return NULL; + + OCTensor *result = OCTensor_newWithTensor(tensor1); + OCTensor_cmul(result, result, tensor2); // Element-wise multiplication + + return result; +} + +OCTensor* OCLogic_or(OCTensor *tensor1, OCTensor *tensor2) { + if (!tensor1 || !tensor2) return NULL; + + // OR = tensor1 + tensor2 - tensor1 * tensor2 + OCTensor *result = OCTensor_newWithTensor(tensor1); + OCTensor *product = OCTensor_newWithTensor(tensor1); + + OCTensor_cmul(product, product, tensor2); + OCTensor_cadd(result, result, 1.0, tensor2); + OCTensor_csub(result, result, 1.0, product); + + OCTensor_free(product); + return result; +} + +OCTensor* OCLogic_not(OCTensor *tensor) { + if (!tensor) return NULL; + + OCTensor *result = OCTensor_newWithTensor(tensor); + OCTensor *ones = OCTensor_newWithSize1d(OCTensor_size(tensor, 0)); + OCTensor_ones(ones, NULL); + + OCTensor_csub(result, ones, 1.0, tensor); + + OCTensor_free(ones); + return result; +} + +OCTensor* OCLogic_implication(OCTensor *antecedent, OCTensor *consequent) { + if (!antecedent || !consequent) return NULL; + + // Implication: NOT antecedent OR consequent + OCTensor *not_antecedent = OCLogic_not(antecedent); + OCTensor *result = OCLogic_or(not_antecedent, consequent); + + OCTensor_free(not_antecedent); + return result; +} + +/* Core Inference Operations */ +void OCInferenceEngine_forwardChain(OCInferenceEngine *engine, int max_steps) { + if (!engine || !engine->atomspace) return; + + for (int step = 0; step < max_steps && step < engine->max_inference_steps; step++) { + int new_atoms_created = 0; + + // Apply each rule to all matching atom combinations + for (int rule_idx = 0; rule_idx < engine->rule_count; rule_idx++) { + OCInferenceRule *rule = engine->rules[rule_idx]; + if (!rule || !rule->tv_function) continue; + + // Simple pattern matching - look for atoms that match rule premises + // This is a simplified implementation + for (long i = 0; i < engine->atomspace->atom_count; i++) { + OCAtom *atom1 = engine->atomspace->atoms[i]; + if (!atom1 || !atom1->tv) continue; + + for (long j = i + 1; j < engine->atomspace->atom_count; j++) { + OCAtom *atom2 = engine->atomspace->atoms[j]; + if (!atom2 || !atom2->tv) continue; + + // Apply rule if confidence is above threshold + float conf1 = OCTensor_get1d(atom1->tv->confidence, 0); + float conf2 = OCTensor_get1d(atom2->tv->confidence, 0); + + if (conf1 > engine->confidence_threshold && + conf2 > engine->confidence_threshold) { + + OCTruthValue *premise_tvs[] = {atom1->tv, atom2->tv}; + OCTruthValue *result_tv = rule->tv_function(premise_tvs, 2); + + if (result_tv) { + float result_conf = OCTensor_get1d(result_tv->confidence, 0); + + // Only create new inference if confidence is significant + if (result_conf > engine->confidence_threshold * 0.5) { + // Create new atom with inferred truth value + char inferred_name[256]; + snprintf(inferred_name, sizeof(inferred_name), + "inferred_%d_%ld_%ld", rule_idx, + atom1->atom_id, atom2->atom_id); + + OCAtom *new_atom = OCAtom_new(OC_CONCEPT_NODE, inferred_name); + OCAtom_setTruthValue(new_atom, result_tv); + + // Add relationships to source atoms + OCAtom_addIncoming(new_atom, atom1); + OCAtom_addIncoming(new_atom, atom2); + + // Add to atomspace if there's room + if (OCAtomSpace_addAtom(engine->atomspace, new_atom) > 0) { + new_atoms_created++; + } + } else { + OCTruthValue_free(result_tv); + } + } + } + } + } + } + + // Stop if no new atoms were created + if (new_atoms_created == 0) break; + } +} + +OCTensor* OCInferenceEngine_computeInferenceMatrix(OCInferenceEngine *engine) { + if (!engine || !engine->atomspace) return NULL; + + // Update the inference matrix based on current atom relationships + OCTensor_zero(engine->inference_matrix); + + for (long i = 0; i < engine->atomspace->atom_count; i++) { + OCAtom *atom = engine->atomspace->atoms[i]; + if (!atom) continue; + + // Set diagonal to atom's confidence + if (atom->tv) { + float confidence = OCTensor_get1d(atom->tv->confidence, 0); + OCTensor_set2d(engine->inference_matrix, i, i, confidence); + } + + // Set relationships based on incoming/outgoing connections + for (int j = 0; j < atom->incoming_count; j++) { + OCAtom *incoming = atom->incoming[j]; + if (incoming) { + // Find incoming atom's index + for (long k = 0; k < engine->atomspace->atom_count; k++) { + if (engine->atomspace->atoms[k] == incoming) { + float weight = 0.8; // Default relationship strength + OCTensor_set2d(engine->inference_matrix, k, i, weight); + break; + } + } + } + } + + for (int j = 0; j < atom->outgoing_count; j++) { + OCAtom *outgoing = atom->outgoing[j]; + if (outgoing) { + // Find outgoing atom's index + for (long k = 0; k < engine->atomspace->atom_count; k++) { + if (engine->atomspace->atoms[k] == outgoing) { + float weight = 0.8; // Default relationship strength + OCTensor_set2d(engine->inference_matrix, i, k, weight); + break; + } + } + } + } + } + + return engine->inference_matrix; +} \ No newline at end of file diff --git a/opencog/inference/inference_engine.h b/opencog/inference/inference_engine.h new file mode 100644 index 00000000..b3e2154d --- /dev/null +++ b/opencog/inference/inference_engine.h @@ -0,0 +1,132 @@ +#ifndef OPENCOG_INFERENCE_ENGINE_H +#define OPENCOG_INFERENCE_ENGINE_H + +#include "../atoms/opencog_atoms.h" + +/* Forward declarations */ +typedef struct OCInferenceEngine OCInferenceEngine; +typedef struct OCInferenceRule OCInferenceRule; +typedef struct OCPattern OCPattern; +typedef struct OCQuery OCQuery; + +/* Inference Rule Types */ +typedef enum { + OC_DEDUCTION_RULE, + OC_INDUCTION_RULE, + OC_ABDUCTION_RULE, + OC_MODUS_PONENS_RULE, + OC_MODUS_TOLLENS_RULE, + OC_AND_RULE, + OC_OR_RULE, + OC_NOT_RULE, + OC_REVISION_RULE, + OC_TEMPORAL_RULE +} OCInferenceRuleType; + +/* Pattern for pattern matching */ +typedef struct OCPattern { + OCAtom **pattern_atoms; // Pattern template atoms + int pattern_count; + OCTensor *pattern_tensor; // Tensor representation of pattern + OCAtomType *required_types; // Required atom types for matching + int type_count; +} OCPattern; + +/* Query structure for pattern matching */ +typedef struct OCQuery { + OCPattern *pattern; + OCAtom **variables; // Variable atoms in the query + int variable_count; + OCTensor *constraint_tensor; // Tensor constraints + float min_confidence; // Minimum confidence threshold +} OCQuery; + +/* Inference Rule structure */ +typedef struct OCInferenceRule { + OCInferenceRuleType type; + char *name; + OCPattern *premise_pattern; // Pattern for premises + OCPattern *conclusion_pattern; // Pattern for conclusion + OCTensor *rule_weights; // Neural network weights for rule + float (*rule_function)(OCAtom **premises, int premise_count, + OCAtom **conclusions, int conclusion_count); + OCTruthValue* (*tv_function)(OCTruthValue **premise_tvs, int count); +} OCInferenceRule; + +/* Main Inference Engine */ +typedef struct OCInferenceEngine { + OCAtomSpace *atomspace; + OCInferenceRule **rules; // Array of inference rules + int rule_count; + int max_rules; + + OCTensor *inference_matrix; // Global inference state matrix + OCTensor *rule_activations; // Current rule activation levels + + // Neural network components for learning + OCTensor *embedding_weights; // Weights for atom embeddings + OCTensor *attention_weights; // Weights for attention mechanism + OCTensor *inference_weights; // Weights for inference decisions + + // Configuration parameters + float learning_rate; + int max_inference_steps; + float confidence_threshold; +} OCInferenceEngine; + +/* Inference Engine Operations */ +OCInferenceEngine* OCInferenceEngine_new(OCAtomSpace *atomspace); +void OCInferenceEngine_free(OCInferenceEngine *engine); +void OCInferenceEngine_addRule(OCInferenceEngine *engine, OCInferenceRule *rule); +void OCInferenceEngine_removeRule(OCInferenceEngine *engine, const char *rule_name); + +/* Pattern Matching */ +OCPattern* OCPattern_new(OCAtom **pattern_atoms, int count); +void OCPattern_free(OCPattern *pattern); +OCTensor* OCPattern_match(OCPattern *pattern, OCAtomSpace *atomspace); +OCAtom** OCPattern_findMatches(OCPattern *pattern, OCAtomSpace *atomspace, int *match_count); + +/* Query Processing */ +OCQuery* OCQuery_new(OCPattern *pattern, OCAtom **variables, int var_count); +void OCQuery_free(OCQuery *query); +OCAtom** OCQuery_execute(OCQuery *query, OCAtomSpace *atomspace, int *result_count); + +/* Inference Rule Creation */ +OCInferenceRule* OCInferenceRule_new(OCInferenceRuleType type, const char *name); +void OCInferenceRule_free(OCInferenceRule *rule); +void OCInferenceRule_setPremisePattern(OCInferenceRule *rule, OCPattern *pattern); +void OCInferenceRule_setConclusionPattern(OCInferenceRule *rule, OCPattern *pattern); + +/* Core Inference Operations */ +OCAtom** OCInferenceEngine_infer(OCInferenceEngine *engine, OCAtom **premises, + int premise_count, int *result_count); +void OCInferenceEngine_forwardChain(OCInferenceEngine *engine, int max_steps); +void OCInferenceEngine_backwardChain(OCInferenceEngine *engine, OCAtom *goal); +OCTensor* OCInferenceEngine_computeInferenceMatrix(OCInferenceEngine *engine); + +/* Neural Learning and Adaptation */ +void OCInferenceEngine_updateEmbeddings(OCInferenceEngine *engine, + OCAtom **atoms, int count, + OCTensor *target_activations); +void OCInferenceEngine_trainRule(OCInferenceEngine *engine, + OCInferenceRule *rule, + OCAtom **training_premises, int premise_count, + OCAtom **training_conclusions, int conclusion_count); + +/* Built-in Inference Rules */ +OCTruthValue* OCInferenceRule_deduction(OCTruthValue **premise_tvs, int count); +OCTruthValue* OCInferenceRule_induction(OCTruthValue **premise_tvs, int count); +OCTruthValue* OCInferenceRule_abduction(OCTruthValue **premise_tvs, int count); +OCTruthValue* OCInferenceRule_revision(OCTruthValue **premise_tvs, int count); + +/* Tensor-based Logical Operations */ +OCTensor* OCLogic_and(OCTensor *tensor1, OCTensor *tensor2); +OCTensor* OCLogic_or(OCTensor *tensor1, OCTensor *tensor2); +OCTensor* OCLogic_not(OCTensor *tensor); +OCTensor* OCLogic_implication(OCTensor *antecedent, OCTensor *consequent); + +/* Probabilistic Inference */ +OCTensor* OCProbability_bayesianUpdate(OCTensor *prior, OCTensor *likelihood, OCTensor *evidence); +OCTensor* OCProbability_markovChain(OCTensor *transition_matrix, OCTensor *initial_state, int steps); + +#endif \ No newline at end of file diff --git a/opencog/opencog.c b/opencog/opencog.c new file mode 100644 index 00000000..ea21777d --- /dev/null +++ b/opencog/opencog.c @@ -0,0 +1,497 @@ +#include "opencog.h" +#include +#include +#include +#include + +static OCError last_error = OC_SUCCESS; + +/* System Initialization and Management */ +OpenCog* OpenCog_new(OCConfig *config) { + OpenCog *opencog = (OpenCog*)malloc(sizeof(OpenCog)); + if (!opencog) { + last_error = OC_ERROR_OUT_OF_MEMORY; + return NULL; + } + + // Use provided config or defaults + if (config) { + opencog->config = *config; + } else { + OCConfig *default_config = OpenCog_getDefaultConfig(); + opencog->config = *default_config; + free(default_config); + } + + // Initialize core components + opencog->atomspace = OCAtomSpace_new(opencog->config.max_atoms); + if (!opencog->atomspace) { + free(opencog); + last_error = OC_ERROR_OUT_OF_MEMORY; + return NULL; + } + + opencog->inference = OCInferenceEngine_new(opencog->atomspace); + if (!opencog->inference) { + OCAtomSpace_free(opencog->atomspace); + free(opencog); + last_error = OC_ERROR_OUT_OF_MEMORY; + return NULL; + } + + if (opencog->config.enable_attention) { + opencog->attention = OCAttentionBank_new(opencog->atomspace); + if (!opencog->attention) { + OCInferenceEngine_free(opencog->inference); + OCAtomSpace_free(opencog->atomspace); + free(opencog); + last_error = OC_ERROR_OUT_OF_MEMORY; + return NULL; + } + + // Add default attention agents + if (opencog->config.enable_hebbian_learning) { + OCAttentionAgent *hebbian = OCAttentionAgent_new(OC_HEBBIAN_AGENT, "hebbian"); + OCAttentionBank_addAgent(opencog->attention, hebbian); + } + + OCAttentionAgent *importance_updater = OCAttentionAgent_new(OC_IMPORTANCE_UPDATING_AGENT, "importance"); + OCAttentionBank_addAgent(opencog->attention, importance_updater); + + if (opencog->config.enable_forgetting) { + OCAttentionAgent *forgetting = OCAttentionAgent_new(OC_FORGETTING_AGENT, "forgetting"); + OCAttentionBank_addAgent(opencog->attention, forgetting); + } + + OCAttentionAgent *spreading = OCAttentionAgent_new(OC_SPREADING_AGENT, "spreading"); + OCAttentionBank_addAgent(opencog->attention, spreading); + } else { + opencog->attention = NULL; + } + + // Initialize statistics + opencog->total_inferences = 0; + opencog->total_attention_cycles = 0; + opencog->system_time = 0.0; + + // Initialize callbacks to NULL + opencog->on_atom_added = NULL; + opencog->on_inference_complete = NULL; + opencog->on_attention_update = NULL; + + last_error = OC_SUCCESS; + return opencog; +} + +void OpenCog_free(OpenCog *opencog) { + if (!opencog) return; + + if (opencog->attention) OCAttentionBank_free(opencog->attention); + if (opencog->inference) OCInferenceEngine_free(opencog->inference); + if (opencog->atomspace) OCAtomSpace_free(opencog->atomspace); + + free(opencog); +} + +OCConfig* OpenCog_getDefaultConfig(void) { + OCConfig *config = (OCConfig*)malloc(sizeof(OCConfig)); + if (!config) return NULL; + + config->max_atoms = 10000; + config->max_inference_steps = 100; + config->confidence_threshold = 0.5f; + config->attention_threshold = 0.1f; + config->embedding_dimensions = 128; + config->enable_attention = 1; + config->enable_forgetting = 1; + config->enable_hebbian_learning = 1; + config->learning_rate = 0.01f; + + return config; +} + +/* High-level Knowledge Operations */ +OCAtom* OpenCog_addConcept(OpenCog *opencog, const char *name, float strength, float confidence) { + if (!opencog || !name) { + last_error = OC_ERROR_NULL_POINTER; + return NULL; + } + + OCAtom *atom = OCAtom_new(OC_CONCEPT_NODE, name); + if (!atom) { + last_error = OC_ERROR_OUT_OF_MEMORY; + return NULL; + } + + // Set truth value + OCTruthValue *tv = OCTruthValue_new(strength, confidence); + OCAtom_setTruthValue(atom, tv); + + // Add to atomspace + long atom_id = OCAtomSpace_addAtom(opencog->atomspace, atom); + if (atom_id < 0) { + OCAtom_free(atom); + last_error = OC_ERROR_SYSTEM_LIMIT_REACHED; + return NULL; + } + + // Initialize attention if enabled + if (opencog->attention) { + OCAtom_setSTI(atom, confidence * 10.0f); // Initial STI based on confidence + OCAtom_setLTI(atom, 0.0f); + OCAtom_setVLTI(atom, 0.0f); + } + + // Fire callback + if (opencog->on_atom_added) { + opencog->on_atom_added(atom); + } + + last_error = OC_SUCCESS; + return atom; +} + +OCAtom* OpenCog_addPredicate(OpenCog *opencog, const char *name) { + if (!opencog || !name) { + last_error = OC_ERROR_NULL_POINTER; + return NULL; + } + + OCAtom *atom = OCAtom_new(OC_PREDICATE_NODE, name); + if (!atom) { + last_error = OC_ERROR_OUT_OF_MEMORY; + return NULL; + } + + // Add to atomspace + long atom_id = OCAtomSpace_addAtom(opencog->atomspace, atom); + if (atom_id < 0) { + OCAtom_free(atom); + last_error = OC_ERROR_SYSTEM_LIMIT_REACHED; + return NULL; + } + + last_error = OC_SUCCESS; + return atom; +} + +OCAtom* OpenCog_addLink(OpenCog *opencog, OCAtomType type, OCAtom **atoms, int count) { + if (!opencog || !atoms || count <= 0) { + last_error = OC_ERROR_INVALID_ARGUMENT; + return NULL; + } + + char link_name[256]; + snprintf(link_name, sizeof(link_name), "link_%d", (int)type); + + OCAtom *link = OCAtom_new(type, link_name); + if (!link) { + last_error = OC_ERROR_OUT_OF_MEMORY; + return NULL; + } + + // Add outgoing atoms + for (int i = 0; i < count; i++) { + OCAtom_addOutgoing(link, atoms[i]); + OCAtom_addIncoming(atoms[i], link); + } + + // Add to atomspace + long atom_id = OCAtomSpace_addAtom(opencog->atomspace, link); + if (atom_id < 0) { + OCAtom_free(link); + last_error = OC_ERROR_SYSTEM_LIMIT_REACHED; + return NULL; + } + + last_error = OC_SUCCESS; + return link; +} + +OCAtom* OpenCog_findAtom(OpenCog *opencog, const char *name) { + if (!opencog || !name) { + last_error = OC_ERROR_NULL_POINTER; + return NULL; + } + + for (long i = 0; i < opencog->atomspace->atom_count; i++) { + OCAtom *atom = opencog->atomspace->atoms[i]; + if (atom && atom->name && strcmp(atom->name, name) == 0) { + last_error = OC_SUCCESS; + return atom; + } + } + + last_error = OC_ERROR_ATOM_NOT_FOUND; + return NULL; +} + +/* Reasoning and Inference */ +void OpenCog_forwardChain(OpenCog *opencog, int max_steps) { + if (!opencog) { + last_error = OC_ERROR_NULL_POINTER; + return; + } + + clock_t start_time = clock(); + + OCInferenceEngine_forwardChain(opencog->inference, max_steps); + opencog->total_inferences++; + + clock_t end_time = clock(); + opencog->system_time += ((double)(end_time - start_time)) / CLOCKS_PER_SEC; + + last_error = OC_SUCCESS; +} + +/* Learning and Adaptation */ +void OpenCog_associateAtoms(OpenCog *opencog, OCAtom *atom1, OCAtom *atom2, float strength) { + if (!opencog || !atom1 || !atom2) { + last_error = OC_ERROR_NULL_POINTER; + return; + } + + // Create an association link + OCAtom *atoms[] = {atom1, atom2}; + OCAtom *association = OpenCog_addLink(opencog, OC_LIST_LINK, atoms, 2); + + if (association) { + OCTruthValue *tv = OCTruthValue_new(strength, 0.9f); + OCAtom_setTruthValue(association, tv); + + // Update attention for associated atoms + if (opencog->attention) { + OCAtom_updateAttentionValue(atom1, OC_STI, strength * 5.0f); + OCAtom_updateAttentionValue(atom2, OC_STI, strength * 5.0f); + } + } + + last_error = OC_SUCCESS; +} + +/* Attention and Focus */ +void OpenCog_stepAttention(OpenCog *opencog) { + if (!opencog || !opencog->attention) { + last_error = OC_ERROR_NULL_POINTER; + return; + } + + OCAttentionBank_cycle(opencog->attention); + opencog->total_attention_cycles++; + + last_error = OC_SUCCESS; +} + +void OpenCog_boostAttention(OpenCog *opencog, OCAtom *atom, float boost) { + if (!opencog || !atom) { + last_error = OC_ERROR_NULL_POINTER; + return; + } + + if (opencog->attention) { + float old_sti = OCAtom_getSTI(atom); + OCAtom_updateAttentionValue(atom, OC_STI, boost); + float new_sti = OCAtom_getSTI(atom); + + // Fire callback + if (opencog->on_attention_update) { + opencog->on_attention_update(atom, old_sti, new_sti); + } + } + + last_error = OC_SUCCESS; +} + +OCAtom** OpenCog_getAttentionalFocus(OpenCog *opencog, int *count) { + if (!opencog || !count) { + last_error = OC_ERROR_NULL_POINTER; + return NULL; + } + + if (!opencog->attention) { + *count = 0; + return NULL; + } + + // Find atoms with highest attention + OCAtom **focus_atoms = (OCAtom**)malloc(sizeof(OCAtom*) * opencog->config.max_atoms); + if (!focus_atoms) { + last_error = OC_ERROR_OUT_OF_MEMORY; + return NULL; + } + + int focus_count = 0; + float min_attention = opencog->config.attention_threshold; + + for (long i = 0; i < opencog->atomspace->atom_count; i++) { + OCAtom *atom = opencog->atomspace->atoms[i]; + if (atom && OCAtom_getSTI(atom) > min_attention) { + focus_atoms[focus_count] = atom; + focus_count++; + } + } + + *count = focus_count; + + if (focus_count == 0) { + free(focus_atoms); + return NULL; + } + + // Resize array to actual size + focus_atoms = (OCAtom**)realloc(focus_atoms, sizeof(OCAtom*) * focus_count); + + last_error = OC_SUCCESS; + return focus_atoms; +} + +/* Pattern Matching and Search */ +float OpenCog_similarity(OpenCog *opencog, OCAtom *atom1, OCAtom *atom2) { + if (!opencog || !atom1 || !atom2) { + last_error = OC_ERROR_NULL_POINTER; + return 0.0f; + } + + OCTensor *similarity_tensor = OCAtom_computeSimilarity(atom1, atom2); + if (!similarity_tensor) { + last_error = OC_ERROR_INFERENCE_FAILED; + return 0.0f; + } + + float similarity = OCTensor_get1d(similarity_tensor, 0); + OCTensor_free(similarity_tensor); + + last_error = OC_SUCCESS; + return similarity; +} + +/* System Analysis and Monitoring */ +void OpenCog_getStats(OpenCog *opencog, char *stats_buffer, int buffer_size) { + if (!opencog || !stats_buffer) { + last_error = OC_ERROR_NULL_POINTER; + return; + } + + snprintf(stats_buffer, buffer_size, + "OpenCog Statistics:\n" + "Atoms: %ld/%ld\n" + "Inferences: %ld\n" + "Attention Cycles: %ld\n" + "System Time: %.2fs\n" + "Attention Enabled: %s\n" + "Hebbian Learning: %s\n", + opencog->atomspace->atom_count, + opencog->atomspace->max_atoms, + opencog->total_inferences, + opencog->total_attention_cycles, + opencog->system_time, + opencog->config.enable_attention ? "Yes" : "No", + opencog->config.enable_hebbian_learning ? "Yes" : "No" + ); + + last_error = OC_SUCCESS; +} + +OCTensor* OpenCog_getAtomEmbeddings(OpenCog *opencog) { + if (!opencog) { + last_error = OC_ERROR_NULL_POINTER; + return NULL; + } + + // Create matrix of all atom embeddings + OCTensor *embeddings = OCTensor_newWithSize2d(opencog->atomspace->atom_count, + opencog->config.embedding_dimensions); + + for (long i = 0; i < opencog->atomspace->atom_count; i++) { + OCAtom *atom = opencog->atomspace->atoms[i]; + if (atom && atom->embedding) { + // Copy atom embedding to row i + for (long j = 0; j < opencog->config.embedding_dimensions; j++) { + float val = OCTensor_get1d(atom->embedding, j); + OCTensor_set2d(embeddings, i, j, val); + } + } + } + + last_error = OC_SUCCESS; + return embeddings; +} + +/* Utility Functions */ +void OpenCog_printAtom(OCAtom *atom) { + if (!atom) { + printf("NULL atom\n"); + return; + } + + printf("Atom[%ld]: %s (type=%d)\n", atom->atom_id, atom->name ? atom->name : "unnamed", atom->type); + + if (atom->tv) { + float strength = OCTensor_get1d(atom->tv->strength, 0); + float confidence = OCTensor_get1d(atom->tv->confidence, 0); + printf(" TruthValue: strength=%.3f, confidence=%.3f\n", strength, confidence); + } + + if (atom->attention && OCTensor_nDimension(atom->attention) >= 3) { + float sti = OCTensor_get1d(atom->attention, 0); + float lti = OCTensor_get1d(atom->attention, 1); + float vlti = OCTensor_get1d(atom->attention, 2); + printf(" Attention: STI=%.3f, LTI=%.3f, VLTI=%.3f\n", sti, lti, vlti); + } + + printf(" Incoming: %d, Outgoing: %d\n", atom->incoming_count, atom->outgoing_count); +} + +void OpenCog_printAtomSpace(OpenCog *opencog) { + if (!opencog) { + printf("NULL OpenCog system\n"); + return; + } + + printf("=== OpenCog AtomSpace ===\n"); + printf("Total atoms: %ld\n\n", opencog->atomspace->atom_count); + + for (long i = 0; i < opencog->atomspace->atom_count; i++) { + OCAtom *atom = opencog->atomspace->atoms[i]; + if (atom) { + OpenCog_printAtom(atom); + printf("\n"); + } + } +} + +/* Error Handling */ +OCError OpenCog_getLastError(void) { + return last_error; +} + +const char* OpenCog_getErrorString(OCError error) { + switch (error) { + case OC_SUCCESS: return "Success"; + case OC_ERROR_NULL_POINTER: return "Null pointer"; + case OC_ERROR_INVALID_ARGUMENT: return "Invalid argument"; + case OC_ERROR_OUT_OF_MEMORY: return "Out of memory"; + case OC_ERROR_ATOM_NOT_FOUND: return "Atom not found"; + case OC_ERROR_INFERENCE_FAILED: return "Inference failed"; + case OC_ERROR_SERIALIZATION_FAILED: return "Serialization failed"; + case OC_ERROR_SYSTEM_LIMIT_REACHED: return "System limit reached"; + default: return "Unknown error"; + } +} + +/* Version Information */ +const char* OpenCog_getVersion(void) { + return OPENCOG_VERSION_STRING; +} + +int OpenCog_getVersionMajor(void) { + return OPENCOG_VERSION_MAJOR; +} + +int OpenCog_getVersionMinor(void) { + return OPENCOG_VERSION_MINOR; +} + +int OpenCog_getVersionPatch(void) { + return OPENCOG_VERSION_PATCH; +} \ No newline at end of file diff --git a/opencog/opencog.h b/opencog/opencog.h new file mode 100644 index 00000000..a671de09 --- /dev/null +++ b/opencog/opencog.h @@ -0,0 +1,155 @@ +#ifndef OPENCOG_H +#define OPENCOG_H + +/* + * OpenCog Multi-Dimensional Tensor Inference Engine + * + * This library implements OpenCog's cognitive architecture using + * multi-dimensional tensors as the underlying representation for + * atoms, truth values, attention allocation, and inference. + * + * Key Components: + * - Tensor-based atom representation with embeddings + * - Truth value calculations using tensor operations + * - Attention allocation with neural dynamics + * - Pattern matching and inference using tensor similarity + * - Probabilistic reasoning with tensor computations + */ + +#include "atoms/opencog_atoms.h" +#include "inference/inference_engine.h" +#include "attention/attention_allocation.h" + +/* OpenCog System Configuration */ +typedef struct OCConfig { + long max_atoms; // Maximum number of atoms + long max_inference_steps; // Maximum inference iterations + float confidence_threshold; // Minimum confidence for inference + float attention_threshold; // Minimum attention for processing + int embedding_dimensions; // Dimensionality of atom embeddings + int enable_attention; // Enable attention allocation system + int enable_forgetting; // Enable memory decay/forgetting + int enable_hebbian_learning; // Enable Hebbian learning + float learning_rate; // Global learning rate +} OCConfig; + +/* Complete OpenCog System */ +typedef struct OpenCog { + OCAtomSpace *atomspace; // Knowledge base + OCInferenceEngine *inference; // Reasoning engine + OCAttentionBank *attention; // Attention allocation + OCConfig config; // System configuration + + // System statistics + long total_inferences; // Total inferences performed + long total_attention_cycles; // Total attention cycles + double system_time; // System runtime in seconds + + // Event callbacks + void (*on_atom_added)(OCAtom *atom); + void (*on_inference_complete)(OCAtom **results, int count); + void (*on_attention_update)(OCAtom *atom, float old_sti, float new_sti); +} OpenCog; + +/* System Initialization and Management */ +OpenCog* OpenCog_new(OCConfig *config); +void OpenCog_free(OpenCog *opencog); +void OpenCog_reset(OpenCog *opencog); +OCConfig* OpenCog_getDefaultConfig(void); + +/* High-level Knowledge Operations */ +OCAtom* OpenCog_addConcept(OpenCog *opencog, const char *name, float strength, float confidence); +OCAtom* OpenCog_addPredicate(OpenCog *opencog, const char *name); +OCAtom* OpenCog_addLink(OpenCog *opencog, OCAtomType type, OCAtom **atoms, int count); +OCAtom* OpenCog_findAtom(OpenCog *opencog, const char *name); +OCAtom** OpenCog_findSimilarAtoms(OpenCog *opencog, OCAtom *query_atom, float threshold, int *count); + +/* Reasoning and Inference */ +OCAtom** OpenCog_query(OpenCog *opencog, const char *pattern, int *result_count); +OCAtom** OpenCog_infer(OpenCog *opencog, const char *premise, int max_steps, int *result_count); +void OpenCog_forwardChain(OpenCog *opencog, int max_steps); +void OpenCog_backwardChain(OpenCog *opencog, const char *goal); + +/* Learning and Adaptation */ +void OpenCog_learn(OpenCog *opencog, OCAtom **examples, int count); +void OpenCog_trainEmbedding(OpenCog *opencog, OCAtom *atom, OCTensor *target_embedding); +void OpenCog_associateAtoms(OpenCog *opencog, OCAtom *atom1, OCAtom *atom2, float strength); + +/* Attention and Focus */ +void OpenCog_setFocus(OpenCog *opencog, OCAtom **atoms, int count); +OCAtom** OpenCog_getAttentionalFocus(OpenCog *opencog, int *count); +void OpenCog_boostAttention(OpenCog *opencog, OCAtom *atom, float boost); +void OpenCog_stepAttention(OpenCog *opencog); + +/* Pattern Matching and Search */ +OCAtom** OpenCog_patternMatch(OpenCog *opencog, OCPattern *pattern, int *match_count); +OCAtom** OpenCog_search(OpenCog *opencog, const char *query, int *result_count); +float OpenCog_similarity(OpenCog *opencog, OCAtom *atom1, OCAtom *atom2); + +/* System Analysis and Monitoring */ +void OpenCog_getStats(OpenCog *opencog, char *stats_buffer, int buffer_size); +OCTensor* OpenCog_getAtomEmbeddings(OpenCog *opencog); +OCTensor* OpenCog_getAttentionMatrix(OpenCog *opencog); +OCTensor* OpenCog_getInferenceMatrix(OpenCog *opencog); + +/* Serialization and Persistence */ +int OpenCog_saveToFile(OpenCog *opencog, const char *filename); +OpenCog* OpenCog_loadFromFile(const char *filename); +char* OpenCog_serialize(OpenCog *opencog); +OpenCog* OpenCog_deserialize(const char *data); + +/* Probabilistic Reasoning */ +float OpenCog_probability(OpenCog *opencog, OCAtom *atom); +OCTruthValue* OpenCog_bayesianUpdate(OpenCog *opencog, OCTruthValue *prior, + OCTruthValue *likelihood, OCTruthValue *evidence); +OCTensor* OpenCog_uncertaintyPropagation(OpenCog *opencog, OCAtom **atoms, int count); + +/* Temporal Reasoning */ +void OpenCog_addTemporalSequence(OpenCog *opencog, OCAtom **sequence, int count, double *timestamps); +OCAtom** OpenCog_predictNext(OpenCog *opencog, OCAtom **context, int context_count, int *prediction_count); +void OpenCog_updateTemporal(OpenCog *opencog, double current_time); + +/* Multi-modal Integration */ +void OpenCog_addSensorInput(OpenCog *opencog, OCTensor *sensor_data, const char *modality); +OCTensor* OpenCog_multimodalFusion(OpenCog *opencog, OCTensor **modality_tensors, int modality_count); +OCAtom* OpenCog_groundSymbol(OpenCog *opencog, const char *symbol, OCTensor *perceptual_data); + +/* Neural Integration */ +void OpenCog_setNeuralWeights(OpenCog *opencog, OCTensor *weights, const char *component); +OCTensor* OpenCog_getNeuralWeights(OpenCog *opencog, const char *component); +void OpenCog_trainNeuralComponent(OpenCog *opencog, const char *component, + OCTensor *inputs, OCTensor *targets); + +/* Utility Functions */ +void OpenCog_printAtom(OCAtom *atom); +void OpenCog_printAtomSpace(OpenCog *opencog); +void OpenCog_visualizeAttention(OpenCog *opencog, const char *output_file); +int OpenCog_validateSystem(OpenCog *opencog); + +/* Error Handling */ +typedef enum { + OC_SUCCESS = 0, + OC_ERROR_NULL_POINTER, + OC_ERROR_INVALID_ARGUMENT, + OC_ERROR_OUT_OF_MEMORY, + OC_ERROR_ATOM_NOT_FOUND, + OC_ERROR_INFERENCE_FAILED, + OC_ERROR_SERIALIZATION_FAILED, + OC_ERROR_SYSTEM_LIMIT_REACHED +} OCError; + +OCError OpenCog_getLastError(void); +const char* OpenCog_getErrorString(OCError error); + +/* Version Information */ +#define OPENCOG_VERSION_MAJOR 1 +#define OPENCOG_VERSION_MINOR 0 +#define OPENCOG_VERSION_PATCH 0 +#define OPENCOG_VERSION_STRING "1.0.0-tensor" + +const char* OpenCog_getVersion(void); +int OpenCog_getVersionMajor(void); +int OpenCog_getVersionMinor(void); +int OpenCog_getVersionPatch(void); + +#endif \ No newline at end of file diff --git a/opencog/tensor_wrapper.c b/opencog/tensor_wrapper.c new file mode 100644 index 00000000..f6af8717 --- /dev/null +++ b/opencog/tensor_wrapper.c @@ -0,0 +1,185 @@ +#include "tensor_wrapper.h" +#include +#include +#include + +/* Tensor Creation and Management */ +OCTensor* OCTensor_new(void) { + OCTensor *tensor = (OCTensor*)malloc(sizeof(OCTensor)); + if (!tensor) return NULL; + + tensor->data = NULL; + tensor->size = NULL; + tensor->stride = NULL; + tensor->nDim = 0; + tensor->nElements = 0; + tensor->refcount = 1; + + return tensor; +} + +OCTensor* OCTensor_newWithSize1d(long size0) { + OCTensor *tensor = OCTensor_new(); + if (!tensor) return NULL; + + tensor->nDim = 1; + tensor->nElements = size0; + + tensor->size = (long*)malloc(sizeof(long)); + tensor->stride = (long*)malloc(sizeof(long)); + tensor->size[0] = size0; + tensor->stride[0] = 1; + + tensor->data = (float*)calloc(size0, sizeof(float)); + + if (!tensor->data || !tensor->size || !tensor->stride) { + OCTensor_free(tensor); + return NULL; + } + + return tensor; +} + +OCTensor* OCTensor_newWithSize2d(long size0, long size1) { + OCTensor *tensor = OCTensor_new(); + if (!tensor) return NULL; + + tensor->nDim = 2; + tensor->nElements = size0 * size1; + + tensor->size = (long*)malloc(2 * sizeof(long)); + tensor->stride = (long*)malloc(2 * sizeof(long)); + tensor->size[0] = size0; + tensor->size[1] = size1; + tensor->stride[0] = size1; // Row-major order + tensor->stride[1] = 1; + + tensor->data = (float*)calloc(size0 * size1, sizeof(float)); + + if (!tensor->data || !tensor->size || !tensor->stride) { + OCTensor_free(tensor); + return NULL; + } + + return tensor; +} + +void OCTensor_retain(OCTensor *tensor) { + if (tensor) { + tensor->refcount++; + } +} + +void OCTensor_free(OCTensor *tensor) { + if (!tensor) return; + + tensor->refcount--; + if (tensor->refcount > 0) return; + + if (tensor->data) free(tensor->data); + if (tensor->size) free(tensor->size); + if (tensor->stride) free(tensor->stride); + free(tensor); +} + +/* Data Access */ +float OCTensor_get1d(OCTensor *tensor, long index) { + if (!tensor || !tensor->data || tensor->nDim != 1 || index >= tensor->size[0]) { + return 0.0f; + } + return tensor->data[index]; +} + +float OCTensor_get2d(OCTensor *tensor, long x, long y) { + if (!tensor || !tensor->data || tensor->nDim != 2 || + x >= tensor->size[0] || y >= tensor->size[1]) { + return 0.0f; + } + return tensor->data[x * tensor->stride[0] + y * tensor->stride[1]]; +} + +void OCTensor_set1d(OCTensor *tensor, long index, float value) { + if (!tensor || !tensor->data || tensor->nDim != 1 || index >= tensor->size[0]) { + return; + } + tensor->data[index] = value; +} + +void OCTensor_set2d(OCTensor *tensor, long x, long y, float value) { + if (!tensor || !tensor->data || tensor->nDim != 2 || + x >= tensor->size[0] || y >= tensor->size[1]) { + return; + } + tensor->data[x * tensor->stride[0] + y * tensor->stride[1]] = value; +} + +/* Tensor Operations */ +void OCTensor_zero(OCTensor *tensor) { + if (!tensor || !tensor->data) return; + memset(tensor->data, 0, tensor->nElements * sizeof(float)); +} + +void OCTensor_fill(OCTensor *tensor, float value) { + if (!tensor || !tensor->data) return; + for (long i = 0; i < tensor->nElements; i++) { + tensor->data[i] = value; + } +} + +void OCTensor_copy(OCTensor *dst, OCTensor *src) { + if (!dst || !src || !dst->data || !src->data || dst->nElements != src->nElements) { + return; + } + memcpy(dst->data, src->data, src->nElements * sizeof(float)); +} + +void OCTensor_cadd(OCTensor *r, OCTensor *a, float scalar, OCTensor *b) { + if (!r || !a || !b || !r->data || !a->data || !b->data) return; + if (r->nElements != a->nElements || r->nElements != b->nElements) return; + + for (long i = 0; i < r->nElements; i++) { + r->data[i] = a->data[i] + scalar * b->data[i]; + } +} + +void OCTensor_norm(OCTensor *r, OCTensor *a, float p, int dim, int keepdim) { + // Simplified norm computation - just L2 norm of entire tensor + if (!r || !a || !r->data || !a->data) return; + + float norm_val = 0.0f; + for (long i = 0; i < a->nElements; i++) { + norm_val += a->data[i] * a->data[i]; + } + norm_val = sqrt(norm_val); + + // Store result in first element + if (r->nElements > 0) { + r->data[0] = norm_val; + } +} + +float OCTensor_dot(OCTensor *a, OCTensor *b) { + if (!a || !b || !a->data || !b->data || a->nElements != b->nElements) { + return 0.0f; + } + + float result = 0.0f; + for (long i = 0; i < a->nElements; i++) { + result += a->data[i] * b->data[i]; + } + return result; +} + +/* Utility Functions */ +long OCTensor_nElement(OCTensor *tensor) { + return tensor ? tensor->nElements : 0; +} + +long OCTensor_size(OCTensor *tensor, int dim) { + if (!tensor || dim >= tensor->nDim || dim < 0) return 0; + return tensor->size[dim]; +} + +int OCTensor_nDimension(OCTensor *tensor) { + return tensor ? tensor->nDim : 0; +} \ No newline at end of file diff --git a/opencog/tensor_wrapper.h b/opencog/tensor_wrapper.h new file mode 100644 index 00000000..9525867c --- /dev/null +++ b/opencog/tensor_wrapper.h @@ -0,0 +1,48 @@ +#ifndef OPENCOG_TENSOR_WRAPPER_H +#define OPENCOG_TENSOR_WRAPPER_H + +#include + +/* Simple tensor abstraction to avoid TH template complexity */ +typedef struct OCTensor { + float *data; // Raw data array + long *size; // Dimensions + long *stride; // Strides for each dimension + int nDim; // Number of dimensions + long nElements; // Total number of elements + int refcount; // Reference counting +} OCTensor; + +/* Tensor Creation and Management */ +OCTensor* OCTensor_new(void); +OCTensor* OCTensor_newWithSize1d(long size0); +OCTensor* OCTensor_newWithSize2d(long size0, long size1); +OCTensor* OCTensor_newWithSize3d(long size0, long size1, long size2); +OCTensor* OCTensor_newWithTensor(OCTensor *tensor); +void OCTensor_retain(OCTensor *tensor); +void OCTensor_free(OCTensor *tensor); + +/* Data Access */ +float OCTensor_get1d(OCTensor *tensor, long index); +float OCTensor_get2d(OCTensor *tensor, long x, long y); +void OCTensor_set1d(OCTensor *tensor, long index, float value); +void OCTensor_set2d(OCTensor *tensor, long x, long y, float value); + +/* Tensor Operations */ +void OCTensor_zero(OCTensor *tensor); +void OCTensor_fill(OCTensor *tensor, float value); +void OCTensor_copy(OCTensor *dst, OCTensor *src); +void OCTensor_add(OCTensor *r, OCTensor *a, OCTensor *b); +void OCTensor_cadd(OCTensor *r, OCTensor *a, float scalar, OCTensor *b); +void OCTensor_mul(OCTensor *r, OCTensor *a, float scalar); +void OCTensor_addmul(OCTensor *r, OCTensor *a, float scalar, OCTensor *b); +void OCTensor_norm(OCTensor *r, OCTensor *a, float p, int dim, int keepdim); +float OCTensor_dot(OCTensor *a, OCTensor *b); +float OCTensor_sum(OCTensor *tensor); + +/* Utility Functions */ +long OCTensor_nElement(OCTensor *tensor); +long OCTensor_size(OCTensor *tensor, int dim); +int OCTensor_nDimension(OCTensor *tensor); + +#endif \ No newline at end of file diff --git a/opencog/test_opencog.c b/opencog/test_opencog.c new file mode 100644 index 00000000..4d13a00b --- /dev/null +++ b/opencog/test_opencog.c @@ -0,0 +1,348 @@ +#include "opencog.h" +#include +#include +#include +#include + +#define TEST_ASSERT(condition, message) \ + do { \ + if (!(condition)) { \ + printf("FAIL: %s\n", message); \ + return 0; \ + } \ + printf("PASS: %s\n", message); \ + } while(0) + +/* Test basic atom creation and truth values */ +int test_basic_atoms() { + printf("\n=== Testing Basic Atom Operations ===\n"); + + OpenCog *opencog = OpenCog_new(NULL); + TEST_ASSERT(opencog != NULL, "OpenCog system creation"); + + // Test concept creation + OCAtom *cat = OpenCog_addConcept(opencog, "cat", 0.9f, 0.8f); + TEST_ASSERT(cat != NULL, "Concept atom creation"); + TEST_ASSERT(strcmp(cat->name, "cat") == 0, "Atom name setting"); + TEST_ASSERT(cat->type == OC_CONCEPT_NODE, "Atom type setting"); + + // Test predicate creation + OCAtom *animal = OpenCog_addPredicate(opencog, "animal"); + TEST_ASSERT(animal != NULL, "Predicate atom creation"); + + // Test finding atoms + OCAtom *found_cat = OpenCog_findAtom(opencog, "cat"); + TEST_ASSERT(found_cat == cat, "Atom retrieval by name"); + + // Test truth values + if (cat->tv) { + float strength = OCTensor_get1d(cat->tv->strength, 0); + float confidence = OCTensor_get1d(cat->tv->confidence, 0); + TEST_ASSERT(strength == 0.9f, "Truth value strength"); + TEST_ASSERT(confidence == 0.8f, "Truth value confidence"); + } + + OpenCog_free(opencog); + return 1; +} + +/* Test link creation and relationships */ +int test_links_and_relationships() { + printf("\n=== Testing Links and Relationships ===\n"); + + OpenCog *opencog = OpenCog_new(NULL); + + // Create some concepts + OCAtom *cat = OpenCog_addConcept(opencog, "cat", 0.9f, 0.8f); + OCAtom *animal = OpenCog_addConcept(opencog, "animal", 0.95f, 0.9f); + OCAtom *mammal = OpenCog_addConcept(opencog, "mammal", 0.92f, 0.85f); + + TEST_ASSERT(cat && animal && mammal, "Concept atoms creation"); + + // Create inheritance links: cat -> mammal -> animal + OCAtom *inheritance_atoms1[] = {cat, mammal}; + OCAtom *inheritance1 = OpenCog_addLink(opencog, OC_LIST_LINK, inheritance_atoms1, 2); + TEST_ASSERT(inheritance1 != NULL, "Inheritance link 1 creation"); + + OCAtom *inheritance_atoms2[] = {mammal, animal}; + OCAtom *inheritance2 = OpenCog_addLink(opencog, OC_LIST_LINK, inheritance_atoms2, 2); + TEST_ASSERT(inheritance2 != NULL, "Inheritance link 2 creation"); + + // Test relationship counting + TEST_ASSERT(cat->outgoing_count == 0, "Cat outgoing links"); + TEST_ASSERT(cat->incoming_count == 1, "Cat incoming links"); + TEST_ASSERT(mammal->incoming_count == 2, "Mammal incoming links"); + + OpenCog_free(opencog); + return 1; +} + +/* Test attention allocation system */ +int test_attention_system() { + printf("\n=== Testing Attention Allocation ===\n"); + + OCConfig *config = OpenCog_getDefaultConfig(); + config->enable_attention = 1; + config->enable_hebbian_learning = 1; + + OpenCog *opencog = OpenCog_new(config); + free(config); + + TEST_ASSERT(opencog->attention != NULL, "Attention bank creation"); + + // Create some atoms + OCAtom *cat = OpenCog_addConcept(opencog, "cat", 0.9f, 0.8f); + OCAtom *dog = OpenCog_addConcept(opencog, "dog", 0.85f, 0.75f); + OCAtom *animal = OpenCog_addConcept(opencog, "animal", 0.95f, 0.9f); + + // Test initial attention values + float initial_sti = OCAtom_getSTI(cat); + TEST_ASSERT(initial_sti > 0, "Initial STI assignment"); + + // Test attention boosting + OpenCog_boostAttention(opencog, cat, 20.0f); + float boosted_sti = OCAtom_getSTI(cat); + TEST_ASSERT(boosted_sti > initial_sti, "Attention boosting"); + + // Test attention cycling + OpenCog_stepAttention(opencog); + TEST_ASSERT(opencog->total_attention_cycles == 1, "Attention cycling"); + + // Test attentional focus + int focus_count; + OCAtom **focus_atoms = OpenCog_getAttentionalFocus(opencog, &focus_count); + TEST_ASSERT(focus_count > 0, "Attentional focus retrieval"); + + if (focus_atoms) { + free(focus_atoms); + } + + OpenCog_free(opencog); + return 1; +} + +/* Test similarity computation */ +int test_similarity_computation() { + printf("\n=== Testing Similarity Computation ===\n"); + + OpenCog *opencog = OpenCog_new(NULL); + + // Create atoms with different embeddings + OCAtom *cat = OpenCog_addConcept(opencog, "cat", 0.9f, 0.8f); + OCAtom *dog = OpenCog_addConcept(opencog, "dog", 0.85f, 0.75f); + OCAtom *tree = OpenCog_addConcept(opencog, "tree", 0.8f, 0.7f); + + TEST_ASSERT(cat && dog && tree, "Atoms for similarity testing"); + + // Modify embeddings to make cat and dog more similar + if (cat->embedding && dog->embedding) { + // Set similar values in embeddings + for (int i = 0; i < 10; i++) { + OCTensor_set1d(cat->embedding, i, 0.5f + i * 0.01f); + OCTensor_set1d(dog->embedding, i, 0.5f + i * 0.01f + 0.1f); // Slightly different + OCTensor_set1d(tree->embedding, i, -0.5f + i * 0.02f); // Very different + } + } + + // Test similarity computation + float cat_dog_sim = OpenCog_similarity(opencog, cat, dog); + float cat_tree_sim = OpenCog_similarity(opencog, cat, tree); + + TEST_ASSERT(cat_dog_sim > cat_tree_sim, "Similarity comparison (cat-dog > cat-tree)"); + printf(" Cat-Dog similarity: %.3f\n", cat_dog_sim); + printf(" Cat-Tree similarity: %.3f\n", cat_tree_sim); + + OpenCog_free(opencog); + return 1; +} + +/* Test inference operations */ +int test_inference_operations() { + printf("\n=== Testing Inference Operations ===\n"); + + OpenCog *opencog = OpenCog_new(NULL); + + // Create a knowledge base + OCAtom *socrates = OpenCog_addConcept(opencog, "Socrates", 0.9f, 0.9f); + OCAtom *human = OpenCog_addConcept(opencog, "human", 0.95f, 0.9f); + OCAtom *mortal = OpenCog_addConcept(opencog, "mortal", 0.98f, 0.95f); + + TEST_ASSERT(socrates && human && mortal, "Knowledge base atoms creation"); + + // Create relationships: Socrates is human, humans are mortal + OpenCog_associateAtoms(opencog, socrates, human, 0.9f); + OpenCog_associateAtoms(opencog, human, mortal, 0.95f); + + long initial_atom_count = opencog->atomspace->atom_count; + + // Run forward chaining inference + OpenCog_forwardChain(opencog, 5); + + long final_atom_count = opencog->atomspace->atom_count; + TEST_ASSERT(final_atom_count >= initial_atom_count, "Inference atom generation"); + TEST_ASSERT(opencog->total_inferences > 0, "Inference counter update"); + + printf(" Initial atoms: %ld, Final atoms: %ld\n", initial_atom_count, final_atom_count); + printf(" Total inferences: %ld\n", opencog->total_inferences); + + OpenCog_free(opencog); + return 1; +} + +/* Test learning and associations */ +int test_learning_associations() { + printf("\n=== Testing Learning and Associations ===\n"); + + OCConfig *config = OpenCog_getDefaultConfig(); + config->enable_hebbian_learning = 1; + + OpenCog *opencog = OpenCog_new(config); + free(config); + + // Create some concepts + OCAtom *red = OpenCog_addConcept(opencog, "red", 0.8f, 0.7f); + OCAtom *apple = OpenCog_addConcept(opencog, "apple", 0.9f, 0.8f); + OCAtom *fire = OpenCog_addConcept(opencog, "fire", 0.85f, 0.75f); + + TEST_ASSERT(red && apple && fire, "Learning atoms creation"); + + // Create associations + OpenCog_associateAtoms(opencog, red, apple, 0.8f); + OpenCog_associateAtoms(opencog, red, fire, 0.7f); + + // Test that association created links + long atom_count = opencog->atomspace->atom_count; + TEST_ASSERT(atom_count > 3, "Association link creation"); + + // Run some attention cycles to activate hebbian learning + if (opencog->attention) { + OpenCog_boostAttention(opencog, red, 15.0f); + OpenCog_boostAttention(opencog, apple, 10.0f); + + for (int i = 0; i < 5; i++) { + OpenCog_stepAttention(opencog); + } + + TEST_ASSERT(opencog->total_attention_cycles == 5, "Hebbian learning cycles"); + } + + OpenCog_free(opencog); + return 1; +} + +/* Test system statistics and monitoring */ +int test_system_statistics() { + printf("\n=== Testing System Statistics ===\n"); + + OpenCog *opencog = OpenCog_new(NULL); + + // Add some content + OCAtom *cat = OpenCog_addConcept(opencog, "cat", 0.9f, 0.8f); + OCAtom *dog = OpenCog_addConcept(opencog, "dog", 0.85f, 0.75f); + OpenCog_associateAtoms(opencog, cat, dog, 0.7f); + + // Test statistics retrieval + char stats_buffer[1000]; + OpenCog_getStats(opencog, stats_buffer, sizeof(stats_buffer)); + + TEST_ASSERT(strlen(stats_buffer) > 0, "Statistics generation"); + TEST_ASSERT(strstr(stats_buffer, "OpenCog Statistics") != NULL, "Statistics format"); + + printf("System Statistics:\n%s\n", stats_buffer); + + // Test embedding matrix retrieval + OCTensor *embeddings = OpenCog_getAtomEmbeddings(opencog); + TEST_ASSERT(embeddings != NULL, "Embeddings matrix retrieval"); + + if (embeddings) { + TEST_ASSERT(OCTensor_size(embeddings, 0) == opencog->atomspace->atom_count, + "Embeddings matrix rows"); + OCTensor_free(embeddings); + } + + OpenCog_free(opencog); + return 1; +} + +/* Test error handling */ +int test_error_handling() { + printf("\n=== Testing Error Handling ===\n"); + + // Test NULL pointer handling + OCAtom *result = OpenCog_findAtom(NULL, "test"); + TEST_ASSERT(result == NULL, "NULL OpenCog handling"); + TEST_ASSERT(OpenCog_getLastError() == OC_ERROR_NULL_POINTER, "NULL pointer error code"); + + OpenCog *opencog = OpenCog_new(NULL); + + // Test atom not found + OCAtom *not_found = OpenCog_findAtom(opencog, "nonexistent"); + TEST_ASSERT(not_found == NULL, "Nonexistent atom handling"); + TEST_ASSERT(OpenCog_getLastError() == OC_ERROR_ATOM_NOT_FOUND, "Atom not found error"); + + // Test error string retrieval + const char *error_str = OpenCog_getErrorString(OC_ERROR_NULL_POINTER); + TEST_ASSERT(error_str != NULL && strlen(error_str) > 0, "Error string retrieval"); + + OpenCog_free(opencog); + return 1; +} + +/* Test version information */ +int test_version_info() { + printf("\n=== Testing Version Information ===\n"); + + const char *version = OpenCog_getVersion(); + TEST_ASSERT(version != NULL, "Version string retrieval"); + TEST_ASSERT(strlen(version) > 0, "Version string non-empty"); + + int major = OpenCog_getVersionMajor(); + int minor = OpenCog_getVersionMinor(); + int patch = OpenCog_getVersionPatch(); + + TEST_ASSERT(major == OPENCOG_VERSION_MAJOR, "Version major number"); + TEST_ASSERT(minor == OPENCOG_VERSION_MINOR, "Version minor number"); + TEST_ASSERT(patch == OPENCOG_VERSION_PATCH, "Version patch number"); + + printf(" Version: %s (%d.%d.%d)\n", version, major, minor, patch); + + return 1; +} + +/* Main test runner */ +int main() { + printf("OpenCog Tensor Inference Engine Test Suite\n"); + printf("==========================================\n"); + + int tests_passed = 0; + int total_tests = 0; + + #define RUN_TEST(test_func) \ + do { \ + total_tests++; \ + if (test_func()) { \ + tests_passed++; \ + } \ + } while(0) + + RUN_TEST(test_basic_atoms); + RUN_TEST(test_links_and_relationships); + RUN_TEST(test_attention_system); + RUN_TEST(test_similarity_computation); + RUN_TEST(test_inference_operations); + RUN_TEST(test_learning_associations); + RUN_TEST(test_system_statistics); + RUN_TEST(test_error_handling); + RUN_TEST(test_version_info); + + printf("\n==========================================\n"); + printf("Test Results: %d/%d passed\n", tests_passed, total_tests); + + if (tests_passed == total_tests) { + printf("All tests PASSED!\n"); + return 0; + } else { + printf("Some tests FAILED!\n"); + return 1; + } +} \ No newline at end of file