Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Knowledge Representation for AI applications

Luciftias Neurocam
Ecosystem Design
Join date: 13 Oct 2005
Posts: 742
02-23-2006 21:19
I don't have a catchy name for this script, but I think its part of a parcel of scripts necessary to bring useful AI applications to SL. Specifically, this script represents an "ontology", a network of concepts and their implications accessible by other scripts.

Basically, I've implemented a mini-scripting language to facilitate the representation of concepts in SL scripts.

So say you wanted to describe the possible relationships entailed in the concept "dog", you'd have the following dialogue snippet with the object containing this script.

CODE
You: ADD $$ dog
Object: OK


Now the concept dog is embedded in a network of relationships:
A dog is an animal, so...

CODE
You: ADD $$ animal
Object: OK
You: ENTAILS $$ dog $$ animal
Object: OK


And an animal is also, say, a "lifeform"

CODE
You: ADD $$ lifeform
Object: OK
You: ENTAILS $$ animal $$ lifeform
Object: OK



A dog is also a pet

CODE
You: ADD $$ pet
Object: OK
You: ENTAILS $$ dog $$ pet
Object: OK


Let's check if the object knows what we think we've told it (is a dog an animal):

CODE
You: QENTAILS $$ dog $$ animal 
Object: TRUE


Is a dog a lifeform?

CODE
You: QENTAILS $$ dog $$ lifeform
Object: TRUE



Show the next concept(s) entailed by "dog"

CODE
You: SHOWENTAILS $$ dog
Object: dog>>animal
Object: dog>>pet


Show me what concept(s) "animal" contains:

CODE
You: SHOWCONTAINS $$ animal
Object: animal<<dog


Does the concept "pet" contain the concept "dog":

CODE
QCONTAINS $$ pet $$ dog
Object: TRUE





Here's the script:

CODE
list gOntology;
list gMembership;
list gQualities;
string gName="startup";
integer gLine;
key gQueryID;
list FindInstanceList(list inlist,string data)
{
list outlist;
integer i;
for(i=0;i<llGetListLength(inlist);i++)
{
if(llList2String(inlist,i)==data)
{
outlist=outlist+;
}
}
return outlist;
}

default
{
state_entry()
{
llListen(0,"","","";);
gQueryID = llGetNotecardLine(gName, gLine);
}


dataserver(key query_id, string data) {
if (query_id == gQueryID) {
if (data != EOF && data !="EMPTY";) { // not at the end of the notecard

list temp=llParseString2List(data,[" "],[]);
gOntology=gOntology+llList2List(temp,0,0);
gMembership=gMembership+llList2List(temp,1,1);
++gLine; // increase line count
gQueryID = llGetNotecardLine(gName, gLine); // request next line
}
if(data==EOF)
llSay(0,"Done loading ontology!";);
if(data=="EMPTY";)
llSay(0,"No ontology to load...enter manually.";);
}
}
listen(integer channel,string name,key id,string message)
{
//
integer stopcondition;
integer findmatch;

if(channel==0 && llGetOwner()==id)
{
string command=llList2String(llParseString2List(message,[" $$ "],[]),0);
if(command=="ADD";)
{
//check first if exists
integer ind=llListFindList(gOntology,[llList2String(llParseString2List(message,[" $$ "],[]),1)]);
if(ind==-1)
{
gOntology=gOntology+[llList2String(llParseString2List(message,[" $$ "],[]),1)];
gMembership=gMembership+["~"];
llSay(0,"OK";);
}
else
llSay(0,"already a listed element, add instances with ENTAILS command";);
}
if(command=="RESET";)
llResetScript();
if(command=="ENTAILS";)
{

integer ind=llListFindList(gOntology,[llList2String(llParseString2List(message,[" $$ "],[]),1)]);
integer ind2=llListFindList(gOntology,[llList2String(llParseString2List(message,[" $$ "],[]),2)]);
if(ind!=-1 && ind2!=-1)
{
//find out if already in ENTAILS relationship. Then add new instance to end of list with accompanying superset name
if(llList2String(gMembership,ind)=="~";)
{
gMembership=llListReplaceList(gMembership,[llList2String(llParseString2List(message,[" $$ "],[]),2)],ind,ind);
llSay(0,"OK";);

}
else
{
gMembership=gMembership+[llList2String(llParseString2List(message,[" $$ "],[]),2)];
gOntology=gOntology+[llList2String(llParseString2List(message,[" $$ "],[]),1)];
llSay(0,"OK";);
}
}
else
{
if(ind==-1)
llSay(0,llList2String(llParseString2List(message,[" $$ "],[]),1)+" is not an ontology list member";);
if(ind2==-1)
llSay(0,llList2String(llParseString2List(message,[" $$ "],[]),2)+" is not a membership class";);
}
}
if(command=="QENTAILS";)
{
findmatch==0;
integer iter=0;
string start= llList2String(llParseString2List(message,[" $$ "],[]),1);
string firststop=llList2String(llParseString2List(message,[" $$ "],[]),2);
string firststart=start;

//make sure all elements in approrpriate lists
integer OK;
if(llListFindList(gOntology,[firststart])!=-1 && llListFindList(gMembership,[firststop])!=-1)
{
OK=1;
}
else
{
OK=0;
if(llListFindList(gOntology,[firststart])==-1)
llSay(0,firststart+" not in ontology list.";);
if(llListFindList(gMembership,[firststop])==-1)
llSay(0,firststop+" not in membership list.";);
}

string stop=":";
stopcondition=0;
while(OK==1 && findmatch!=1 && iter<llGetListLength(gOntology))// && stopcondition!=1)
{
iter++;
//integer ind=iter;//llListFindList(gOntology,[start]);
gOntology=gOntology+llList2List(gOntology,0,0);
gOntology=llDeleteSubList(gOntology,0,0);
gMembership=gMembership+llList2List(gMembership,0,0);
gMembership=llDeleteSubList(gMembership,0,0);
string start= llList2String(llParseString2List(message,[" $$ "],[]),1);
string firststop=llList2String(llParseString2List(message,[" $$ "],[]),2);
string firststart=start;
string stop=":";
stopcondition=0;
while(stopcondition==0)
{

integer ind=llListFindList(gOntology,[start]);
start=llList2String(gOntology,ind);

stop = llList2String( gMembership,ind);

if(stop==firststop)
{
stopcondition=1;
findmatch=1;
}
if(stop=="~";)
{
stopcondition=1;
findmatch=0;
}
start=stop;
}

}
if(findmatch==1)
{
llSay(0,"TRUE";);
// llSay(0,stop+" "+firststop);
}
else
llSay(0,"FALSE";);
}



if(command=="SHOWENTAILS";)
{
list indices=FindInstanceList(gOntology,llList2String(llParseString2List(message,[" $$ "],[]),1));
integer i;
integer index;
string chain;
for(i=0;i<llGetListLength(indices);i++)
{

chain=llList2String(gOntology,(integer)llList2String(indices,i)) +">>"+llList2String(gMembership,(integer)llList2String(indices,i));



llSay(0,chain);
}

}


if(command=="SHOWCONTAINS";)
{
list indices=FindInstanceList(gMembership,llList2String(llParseString2List(message,[" $$ "],[]),1));
integer i;
integer index;
string chain;
for(i=0;i<llGetListLength(indices);i++)
{

chain=llList2String(gMembership,(integer)llList2String(indices,i)) +"<<"+llList2String(gOntology,(integer)llList2String(indices,i));



llSay(0,chain);
}

}
if(command=="DUMP";)
{
integer i;
for(i=0;i<llGetListLength(gOntology);i++)
{
string s1=llList2String(gOntology,i);
string s2=llList2String(gMembership,i);
llOwnerSay(s1+" "+s2);
}
}
if(command=="QCONTAINS";)
{
findmatch==0;
integer iter=0;
string start= llList2String(llParseString2List(message,[" $$ "],[]),1);
string firststop=llList2String(llParseString2List(message,[" $$ "],[]),2);
string firststart=start;
integer OK;
if(llListFindList(gMembership,[firststart])!=-1 && llListFindList(gOntology,[firststop])!=-1)
{
OK=1;
}
else
{
OK=0;
if(llListFindList(gMembership,[firststart])==-1)
llSay(0,firststart+" not in membership list.";);
if(llListFindList(gOntology,[firststop])==-1)
llSay(0,firststop+" not in ontology list.";);
}
string stop=":";
stopcondition=0;
while(OK==1 && findmatch!=1 && iter<llGetListLength(gOntology))// && stopcondition!=1)
{
iter++;
//integer ind=iter;//llListFindList(gOntology,[start]);
gOntology=gOntology+llList2List(gOntology,0,0);
gOntology=llDeleteSubList(gOntology,0,0);
gMembership=gMembership+llList2List(gMembership,0,0);
gMembership=llDeleteSubList(gMembership,0,0);
string start= llList2String(llParseString2List(message,[" $$ "],[]),1);
string firststop=llList2String(llParseString2List(message,[" $$ "],[]),2);
string firststart=start;
string stop=":";
stopcondition=0;
while(stopcondition==0)
{

integer ind=llListFindList(gMembership,[start]);
start=llList2String(gMembership,ind);

stop = llList2String( gOntology,ind);
// start=stop;

//if(stop==firststart)
//{
// stopcondition=1;
// findmatch=1;
//}

if(stop==firststop)
{
stopcondition=1;
findmatch=1;
}
if(start=="~";)
{
stopcondition=1;
findmatch=0;
}
if(ind==-1)
{
stopcondition=1;
findmatch=0;
}
start=stop;
}

}
if(findmatch==1)
{
llSay(0,"TRUE";);
// llSay(0,stop+" "+firststop);
}
else
llSay(0,"FALSE";);
}

}
}
}


To run the script, just place it in an object with a notecard named "startup".
The notecard should, initially, only contain the word "EMPTY", in all caps.

In order to back up ontologies, you can get the script to dump the contents of its knowledge base to text simply by typing "DUMP". The script will use llOwnerSay to dump 2 columns of data to chat channel 0. the first column represents the actually ontology, while the second column the entailed concepts by the elements in column A. Cut and paste the columns from the chat window and replace the word "EMPTY" in the startup card. Make sure you're only including the 2 columns and not the "Object: " (or whatever your script container is called) preceding the first column. Then say RESET (all caps) and the saved ontology will be loaded into memory. If startup only contains "EMPTY", RESET will simply prompt you to enter a new ontology.
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Discussion Thread
02-24-2006 08:01
/54/2a/90075/1.html
_____________________
i've got nothing. ;)