Skip to content

Commit

Permalink
Merge pull request #35 from opennars/MoreAtomsSupport
Browse files Browse the repository at this point in the history
Update: Variable, Narsese, Config: Allow and use short for atoms inst…
  • Loading branch information
patham9 authored Mar 20, 2020
2 parents c1c6894 + 6162e04 commit d24096d
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 39 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Narsese:
./NAR shell < ./examples/nal/example1.nal
```

English: (will be updated to Python3 at some point as well...)
English: (needs NLTK v3.4.5, will be updated to Python3 at some point as well...)

```
python2 english_shell.py < ./examples/english/story1.english
Expand Down
2 changes: 1 addition & 1 deletion examples/nal/school.nal
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,5 @@
<<clock --> [large]> =/> <floor --> [?what]>>?
//expected: Answer: <<clock --> [large]> =/> <floor --> [red]>>. Truth: frequency=0.964794, confidence=0.449068
//If you are where the floor is red, where do you need to go to see a cyan floor?
<(<floor --> [red]> &/ <({SELF} * ?2) --> ^go>) =/> <floor --> [cyan]>>?
<(<floor --> [red]> &/ <({SELF} * ?where) --> ^go>) =/> <floor --> [cyan]>>?
//expected: Answer: <(<floor --> [red]> &/ <({SELF} * kitchen) --> ^go>) =/> <floor --> [cyan]>>. Truth: frequency=1.000000, confidence=0.01029
4 changes: 2 additions & 2 deletions src/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@
//Maximum compound term size
#define COMPOUND_TERM_SIZE_MAX 64
//Max. amount of atomic terms, must be <= 2^(sizeof(Atom)*8)
#define TERMS_MAX 256
#define TERMS_MAX 65536
//The type of an atom
#define Atom unsigned char
#define Atom unsigned short
//Maximum size of atomic terms in terms of characters
#define ATOMIC_TERM_LEN_MAX 30
//Maximum size of Narsese input in terms of characters
Expand Down
2 changes: 2 additions & 0 deletions src/Globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,7 @@
void assert(bool b, char* message);
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
//Number of elements of compile time allocated array:
#define NUM_ELEMENTS(array) (sizeof(array)/sizeof(array[0]))

#endif
2 changes: 1 addition & 1 deletion src/NAL.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static void NAL_GenerateConclusionTerm(char *premise1, char *premise2, char* con
//skip double/single premise rule if single/double premise
if(doublePremise) { printf("if(!doublePremise) { goto RULE_%d; }\n", ruleID); }
if(!doublePremise) { printf("if(doublePremise) { goto RULE_%d; }\n", ruleID); }
puts("Term substitutions[TERMS_MAX] = {0}; Term subtree = {0};");
puts("Term substitutions[27+NUM_ELEMENTS(Narsese_RuleTableVars)] = {0}; Term subtree = {0};"); //27 because of 9 indep, 9 dep, 9 query vars
for(int i=0; i<COMPOUND_TERM_SIZE_MAX; i++)
{
NAL_GeneratePremisesUnifier(i, term1.atoms[i], 1);
Expand Down
43 changes: 30 additions & 13 deletions src/Narsese.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
//whether the package is initialized
static bool initialized = false;
//SELF atom, avoids strcmp for checking operator format
Atom SELF;
Atom SELF;

//Replace copulas with canonical single-char copulas, including sets and set elements!
char* replaceWithCanonicalCopulas(char *narsese, int n)
Expand Down Expand Up @@ -228,13 +228,12 @@ int skipCompound(char** tokens, int i, int nt)
return i;
}

static char* canonical_copulas = "@*&|;:=$'\"/\\.-%#~+!";
char** Narsese_PrefixTransform(char* narsese_expanded)
{
static char* tokens[NARSESE_LEN_MAX+1]; //there cannot be more tokens than chars
memset(tokens, 0, (NARSESE_LEN_MAX+1)*sizeof(char*)); //and last one stays NULL for sure
char* token = strtok(narsese_expanded, " ");
int nt=0, nc = strlen(canonical_copulas);
int nt = 0, nc = NUM_ELEMENTS(Naresese_CanonicalCopulas) - 1;
while(token)
{
tokens[nt] = token;
Expand All @@ -247,7 +246,7 @@ char** Narsese_PrefixTransform(char* narsese_expanded)
{
for(int k=0; k<nc; k++)
{
if(tokens[i+1][0]==(int)canonical_copulas[k] && tokens[i+1][1] == 0)
if(tokens[i+1][0] == (int) Naresese_CanonicalCopulas[k] && tokens[i+1][1] == 0)
{
goto Continue;
}
Expand Down Expand Up @@ -360,11 +359,13 @@ void buildBinaryTree(Term *bintree, char** tokens_prefix, int i1, int tree_index
Term Narsese_Term(char *narsese)
{
assert(initialized, "Narsese not initialized, call Narsese_INIT first!");
//parse Narsese by expanding it, bringing into prefix form, then building a binary tree, and normalizing variables
Term ret = {0};
char *narsese_expanded = Narsese_Expand(narsese);
char** tokens_prefix = Narsese_PrefixTransform(narsese_expanded);
int nt = 0; for(;tokens_prefix[nt] != NULL; nt++){}
buildBinaryTree(&ret, tokens_prefix, 0, 1, nt);
Variable_Normalize(&ret);
return ret;
}

Expand Down Expand Up @@ -573,16 +574,31 @@ void Narsese_INIT()
{
memset(&Narsese_operatorNames[i], 0, ATOMIC_TERM_LEN_MAX);
}
//index the copulas at first, to make sure these will have same index on next run
for(int i=0; i<(int) strlen(canonical_copulas); i++)
//index variables at first, these atoms come first as also used by Substitution struct
for(int i=1; i<=9; i++)
{
char cop[2] = {canonical_copulas[i], 0};
char dep_varname[3] = "#1";
char indep_varname[3] = "$1";
char query_varname[3] = "?1";
query_varname[1] = indep_varname[1] = dep_varname[1] = (char) ('0' + i);
Narsese_AtomicTerm(dep_varname);
Narsese_AtomicTerm(indep_varname);
Narsese_AtomicTerm(query_varname);
}
//index rule table variables next:
for(unsigned int i=0; i<NUM_ELEMENTS(Narsese_RuleTableVars)-1; i++)
{
char varname[2] = " ";
varname[0] = Narsese_RuleTableVars[i];
Narsese_AtomicTerm(varname);
}
//index the copulas as well, to make sure these will have same index on next run
for(int i=0; i<(int)strlen(Naresese_CanonicalCopulas); i++)
{
char cop[2] = { Naresese_CanonicalCopulas[i], 0 };
Narsese_AtomicTermIndex(cop);
}
SELF = Narsese_AtomicTermIndex("SELF");
Narsese_AtomicTermIndex("$1");
Narsese_AtomicTermIndex("$2");
Narsese_AtomicTermIndex("#1");
initialized = true;
}

Expand Down Expand Up @@ -638,7 +654,8 @@ Term Narsese_GetPreconditionWithoutOp(Term *precondition)

bool Narsese_IsNonCopulaAtom(Atom atom)
{
return (Narsese_atomNames[(int) atom - 1][0] >= 'a' && Narsese_atomNames[(int) atom - 1][0] <= 'z') ||
(Narsese_atomNames[(int) atom - 1][0] >= 'A' && Narsese_atomNames[(int) atom - 1][0] <= 'Z') ||
(Narsese_atomNames[(int) atom - 1][0] >= '0' && Narsese_atomNames[(int) atom - 1][0] <= '9');
return atom > 0 &&
((Narsese_atomNames[(int) atom - 1][0] >= 'a' && Narsese_atomNames[(int) atom - 1][0] <= 'z') ||
(Narsese_atomNames[(int) atom - 1][0] >= 'A' && Narsese_atomNames[(int) atom - 1][0] <= 'Z') ||
(Narsese_atomNames[(int) atom - 1][0] >= '0' && Narsese_atomNames[(int) atom - 1][0] <= '9'));
}
2 changes: 2 additions & 0 deletions src/Narsese.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
char Narsese_atomNames[TERMS_MAX][ATOMIC_TERM_LEN_MAX];
char Narsese_operatorNames[OPERATIONS_MAX][ATOMIC_TERM_LEN_MAX];
extern Atom SELF;
#define Narsese_RuleTableVars "ABCMRSPXYZ"
#define Naresese_CanonicalCopulas "@*&|;:=$'\"/\\.-%#~+!"

//Methods//
//-------//
Expand Down
85 changes: 65 additions & 20 deletions src/Variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Substitution Variable_Unify(Term *general, Term *specific)
{
if(Variable_isVariable(general_atom))
{
assert(general_atom <= 27, "Variable_Unify: Problematic variable encountered, only $1-$9, #1-#9 and ?1-?9 are allowed!");
Term subtree = Term_ExtractSubterm(specific, i);
if(Variable_isQueryVariable(general_atom) && Variable_isVariable(subtree.atoms[0])) //not valid to substitute a variable for a question var
{
Expand Down Expand Up @@ -98,7 +99,9 @@ Term Variable_ApplySubstitute(Term general, Substitution substitution, bool *suc
for(int i=0; i<COMPOUND_TERM_SIZE_MAX; i++)
{
Atom general_atom = general.atoms[i];
if(substitution.map[(int) general_atom].atoms[0] != 0)
bool is_variable = Variable_isVariable(general_atom);
assert(!is_variable || general_atom <= 27, "Variable_ApplySubstitute: Problematic variable encountered, only $1-$9, #1-#9 and ?1-?9 are allowed!");
if(is_variable && substitution.map[(int) general_atom].atoms[0] != 0)
{
if(!Term_OverrideSubterm(&general, i, &substitution.map[(int) general_atom]))
{
Expand All @@ -118,7 +121,8 @@ static void countExtensionTerms(Term *cur_inheritance, int *appearing)
Term subject = Term_ExtractSubterm(cur_inheritance, 1);
for(int i=0; i<COMPOUND_TERM_SIZE_MAX; i++)
{
if(Narsese_IsNonCopulaAtom(subject.atoms[i]))
Atom atom = subject.atoms[i];
if(Narsese_IsNonCopulaAtom(atom))
{
appearing[(int) subject.atoms[i]] += 1;
}
Expand Down Expand Up @@ -153,33 +157,74 @@ Term IntroduceImplicationVariables(Term implication, bool *success)
left_side = Term_ExtractSubterm(&left_side, 1);
}
countExtensionTerms(&left_side, appearing);
Substitution subs = { .success = true };
int depvar_i = 1;
int indepvar_i = 1;
bool already_handled[TERMS_MAX] = {0};
char depvar_i = 1;
char indepvar_i = 1;
char variable_id[TERMS_MAX] = {0};
Term implication_copy = implication;
for(int i=0; i<COMPOUND_TERM_SIZE_MAX; i++)
{
Atom atom = implication.atoms[i];
if(!already_handled[(int) atom] && appearing[(int) atom] > 1)
Atom atom = implication_copy.atoms[i];
if(appearing[(int) atom] > 1)
{
if(right_contains[(int) atom])
{
assert(indepvar_i <= 9, "More than 9 variables being introduced? That's not supported.");
char varname[3] = "$1";
varname[1] = (char) ('0' + indepvar_i);
subs.map[(int) atom] = Narsese_AtomicTerm(varname);
indepvar_i++;
int var_id = variable_id[(int) atom] = variable_id[(int) atom] ? variable_id[(int) atom] : indepvar_i++;
if(var_id <= 9) //can only introduce up to 9 variables
{
char varname[3] = { '$', ('0' + var_id), 0 }; //$i
Term varterm = Narsese_AtomicTerm(varname);
if(!Term_OverrideSubterm(&implication, i, &varterm))
{
*success = false;
return implication;
}
}
}
else
{
assert(depvar_i <= 9, "More than 9 variables being introduced? That's not supported.");
char varname[3] = "#1";
varname[1] = (char) ('0' + depvar_i);
subs.map[(int) atom] = Narsese_AtomicTerm(varname);
depvar_i++;
int var_id = variable_id[(int) atom] = variable_id[(int) atom] ? variable_id[(int) atom] : depvar_i++;
if(var_id <= 9) //can only introduce up to 9 variables
{
char varname[3] = { '#', ('0' + var_id), 0 }; //#i
Term varterm = Narsese_AtomicTerm(varname);
if(!Term_OverrideSubterm(&implication, i, &varterm))
{
*success = false;
return implication;
}
}
}
}

}
*success = true;
return implication;
}

void Variable_Normalize(Term *term)
{
int independent_i = 1, dependent_i = 1, query_i = 1;
bool normalized[COMPOUND_TERM_SIZE_MAX] = {0};
//replace variables with numeric representation, then return the term
for(int j=0; j<COMPOUND_TERM_SIZE_MAX; j++)
{
Atom atom = term->atoms[j];
char varType = Variable_isIndependentVariable(atom) ? '$' : (Variable_isDependentVariable(atom) ? '#' : '?');
int *varIndex = Variable_isIndependentVariable(atom) ? &independent_i : (Variable_isDependentVariable(atom) ? &dependent_i : &query_i);
if(!normalized[j] && Variable_isVariable(atom))
{
assert(*varIndex<=9, "Variable overflow in variable normalization!");
char varname[3] = { varType, ('0' + *varIndex), 0 }; //$i, #j, ?k
(*varIndex)++;
for(int k=j; k<COMPOUND_TERM_SIZE_MAX; k++)
{
Atom atom2 = term->atoms[k];
if(atom == atom2)
{
term->atoms[k] = Narsese_AtomicTermIndex(varname);
normalized[k] = true;
}
}
}
already_handled[(int) atom] = true;
}
return Variable_ApplySubstitute(implication, subs, success);
}
12 changes: 11 additions & 1 deletion src/Variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,29 @@
//--------------//
//Substitution, mapping variable atoms to terms
typedef struct {
Term map[TERMS_MAX];
Term map[27+1]; //there can only be 27 variables: $1 to $9 and #1 to #9 and ?1 to ?9, but it can't be 0
bool success;
} Substitution;

//Methods//
//-------//
//Whether the atom is an independent variable, $i
bool Variable_isIndependentVariable(Atom atom);
//Whether the atom is a dependent variable, #1
bool Variable_isDependentVariable(Atom atom);
//Whether the atom is a query variable, ?1
bool Variable_isQueryVariable(Atom atom);
//Whether the atom is any variable
bool Variable_isVariable(Atom atom);
//Whether the term has variables of certain kind
bool Variable_hasVariable(Term *term, bool independent, bool dependent, bool query);
//Unify two terms, returning the substitution/unifier
Substitution Variable_Unify(Term *general, Term *specific);
//Applying the substitution to a term, returning success
Term Variable_ApplySubstitute(Term term, Substitution substitution, bool *success);
//Introduce variables in an implications
Term IntroduceImplicationVariables(Term implication, bool *success);
//Normalize variables, transforming ?what to ?1 for instance.
void Variable_Normalize(Term *term);

#endif

0 comments on commit d24096d

Please sign in to comment.