After many years of development, Perl6 has finally been released around the beginning of this new year 2016. We now position the emerging AI Perlmind as a killer app for the emerging Perl6 programming language. Yesterday we uploaded the Perl6 AI Manual to the Web for use with both P5 AI and P6 AI.
Apparently both Perl5 and Perl6 will have problems in accepting each single keystroke of input from a human user. Therefore we should shift our AI input target away from immediate human keyboard entry and towards the opening and reading of computer files by the AI Mind. Since we envision that a P6AI will sit quietly on a webserver and ingest both local and remote computer files, it makes sense now to channel input into the AI as a file rather than as dynamic keyboard entry.
Today we have created C:\Strawberry\perl_tests\input.txt as a textfile containing simply "boys play games john is a boy" as its only content. Then we have copied the code-sequence of AudInput() as FileInput() and we have made the necessary changes to accept input from an input.txt file instead of from the keyboard.
Today we need to figure out how to read in each line of input.txt and how to transfer each English word into quasi-auditory memory.
In the FileInput() subroutine of the mind0029.pl source, it looks as though the WHILE loop for reading a file may be running through completely before any individual line of input is extracted for AI processing. We move the NewConcept() and AudMem() calls into the WHILE loop so that each line of input is processed separately. However, not just each line, but each word within a line, needs to be processed separately.
A line of text input needs to be broken up into individual words. First we learn from the PERL Black Book, page 568, that the getc function lets us fetch each single character in a line from our input.txt file. Therefore in the FileInput() module of mind0031.pl we use the "#" symbol to comment out the WHILE-loop that was transferring a whole message "$msg" into AudMem(). Then we use getc in a new WHILE-loop to transfer a series of incoming characters from input.txt into AudMem(), where we comment out the string-reversing and chopping code and we convert a do-loop into a simple series of non-looping instructions, because the looping is being done up in the FileInput() module. We see that the program is now transferring individual input characters into auditory memory. Later we will need to make the transfers stop at the end of each input word, shown by a blank space or punctuation or some other indicator. The new code is messy, but we should upload it to the Web and clean it up when we continue programming.
In the FileInput() module of the mind0032.pl AI we are inserting the call to NewConcept() so that AudMem() will show an incrementing concept number for each word being stored in auditory memory. Uh-oh, running the AI shows that each stored character is getting its own concept number. Obviously, we will have to call NewConcept() only when an entire new word is being stored, not each individual character.
We were able to test for a blank space (probably not enough) after an input word in FileInput(), then order a "return" out of the WHILE-loop. We had to put "{ return }" in brackets to avoid crashing the program. Now the AI loads a first word "boys" over and over into auditory memory, but we have made progress.
Let us see what happens if we run the Perl AI with no input.txt available for the AI to read. We save input.txt elsewhere and then we delete input.txt from the perl_tests directory. We run the mind0033.pl AI program without an input.txt file available, and it goes into an infinite loop. We change the FileInput() code that opens the input.txt file by adding the "or die" function to halt the program and issue an error message. It works and we no longer get an infinite loop. Then we add the input.txt file back into the directory.
Now we need to work on getting the AI to store the first word of input and to move on to each succeeding word of input.
When we inspect the MindForth code, we see that the AudInput module first calls OldConcept at the end of a word, and only calls NewConcept if the incoming word is not recognized as an old concept. So we should create an OldConcept() module in the Perl AI program.
In the FileInput() module, we might just wait for a blank space-character and use it to initiate the saving of the word and the calling of both OldConcept and NewConcept(). Even if everything pauses to store the word and either recognize it or create a new concept, the reading of the input file should simply resume and there should be no special need to keep track of the position in the input-line.
In accordance with the MindForth code, any non-space character coming in should go into AudMem(). An ASCII-32 space character does not get stored, but rather a storage-space of one time-point gets skipped, because MindForth AudInput increments time "t" for all non-zero chararacters coming in. In other words, skipping one time-point in auditory memory makes it look as if a space-character were being stored.
It turns out that time "$t" was not yet being incremented in the mind0033.pl AI, so we put an autoincrement into the FileInput() module.
It is time in mind0034.pl to create the AudBuffer() module to be called by AudInput() or FileInput() and VerbGen(). The primitive coding may be subject to criticism, since the module treats a series of variables as a storage array, but the albeit primitive code not only serves its purpose but is easily understandable by the AI coder or system maintainer. For now we merely insert a stub of the AudBuffer() module.
After wondering where to place the AudBuffer() module, today we re-arrange all the mind-modules to be in the same sequence as MindForth has them, so that it will be easier in inspecting code to move among the Forth and JavaScript and Perl AI programs. MindForth compels a certain sequence because a module in a Forth program can call only modules higher up in the code.
The mind0035.pl program is going to get extremely serious and extremely complicated now, because for the first time in about eighteen years we are going to change the format of the storage of quasi-acoustic engrams in auditory memory. We are going to change the six auditory panel-flags from "pho act pov beg ctu audpsi" down to a group of only three: "pho" for the phoneme or character of auditory input; "act" for the activation-level; and "audpsi" for the concept number in the @psi conceptual memory array.
The point-of-view "pov" variable will no longer be stored in auditory memory, and instead other functions of memory will have to remember, if possible, who generated a sentence or a thought stored in auditory memory. Over the years it has been helpful to inspect the auditory memory array and to see whether a sentence came from the AI itself or from an external source.
The flag-variables "beg" for beginning of a word and "ctu" for continuation of a word served a purpose in the early AI Minds but are now ready for extinction. The Perl language is so powerful that it should simply detect the beginning or ending of a word without relying on superfluous flags stored in the engram itself. Removing obsolete flags makes the code easier to understand and easier to develop further.
We should probably next code the EnVocab() module for storing the fetch-tags of English vocabulary, because the @psi concept array will need to direct pointers into the @en array. In MindForth, EnVocab comes in between InStantiate for "psi" concepts and EnParser for English parts of speech. Oh, we already have a stub of EnVocab(). Then it is time to flesh out the module.
First we create the number-flag $num for grammatical number, which is important for the retrieval of a stored word in English or German or Russian. Then we create the masculine-feminine-neuter flag mfn for tracking the gender of a word in the @en English array.
We may now be able to discontinue the use of the fex flag for "fiber-out" and fin for "fiber-in". These flags were helpful for interpreting pronouns like "I" and "me" as referring to the AI itself or to an external person. The Perlmind should be able to use point-of-view "pov" code to catch pronouns or verb-forms that need routing to the correct concept.
We still need a part-of-speech pos flag to keep track of words in the @en array. We also need the $aud flag as an auditory recall-tag for activating engrams in the @aud array, unless it conflicts with the @aud designation and needs to be replaced with something like $rv for recall-vector.
The $nen flag is already incremented in NewConcept(), and now we begin storing $nen during the operation of EnVocab(). Then we had many problems because in TabulaRasa() we had filled the @en English array with zeroes instead of blank spaces.
In the mind0036.pl program we continue working on EnVocab() for English vocabulary being stored in the @en array. Today we create the variable $audbeg for auditory beginning of an auditory word-engram stored in the @aud array. We also create the variable $audnew to hold onto the value of a recall-vector onset-tag for the start of a word in memory while the rest of the word is still coming in. By setting the $audnew flag only if it is at zero, we keep the flag from changing its truly original value until the whole word has been stored and the $audnew value has been reset to zero for the sake of the next word coming in.
Today for a bug in the AI we kept getting a message something like, "Use of unitialized value in concatenation <.> or string at mind0036.pl line 295" at a point where we were trying to show the contents of a row in the @en English lexical array. In TabulaRasa() we solved the bug by declaring $en[$trc] = "0,0,0,0,0,0,0"; with seven flags set to zero. Apparently TabulaRasa() initializes all the items in the array.
In the mind0037.pl AI Perlmind, let us see what happens at each stage of reading an input.txt file.
The MainLoop calls sensorium() which in turn calls the FileInput() module. FileInput() goes into a WHILE-loop of reading with getc (get character) for as long as the resulting $char remains defined. As each character comes in, FileInput() calls AudMem() to store the character in auditory memory. Each time that $char becomes an empty non-letter at the end of an input word, FileInput() increments the $onset flag from $audnew and calls NewConcept(), because the AI must learn each new word as a new concept.
NewConcept() increments the number-of-English $nen lexical identifier and calls the English vocabulary EnVocab() module to set up a row of data in the @en array. NewConcept() calls the stub of the English parser EnParser() module. FileInput() calls the stub of the OldConcept() module.
The MainLoop module calls the Think() module which calls Speech() to output a word as if it were a thought, but the AI has not yet quickened and so the AI is not yet truly thinking. At the end of the mind0037.pl program, the MainLoop displays the contents of the experiential memory for the sake of troubleshooting the AI.
The mind0038.pl program is ready to instantiate the InStantiate() module for creating concepts in the @psi array of the artificial Mind. Let us change the @psi array into the @psy array so that a $psi variable will not conflict with the name of the conceptual array.
With mind0039.pl we may need to remove the activation-flag from the flag-panel of the @en English lexical array. In the previous Forth and JavaScript AI Minds, we had "act" there in case we needed it. Now it seems that in MindForth only the KbSearch module uses "act" in the English array, and the module could probably use @psy for searches instead of the @en lexicon.
There is some question whether part-of-speech $pos should be in the @psy conceptual array or in the @en lexical array. A search for "6 en{" in the MindForth code of 24 July 2014 reveals that no use seems to be made of part-of-speech "pos" in MindForth. Apparently part-of-speech has already been dealt with during the functions that use the Psi array, and therefore the English array does not concern itself with part-of-speech. So part-of-speech could be dropped from the @en English array.
It looks as though part-of-speech has to be assigned in the @psy array before inflections are fetched in a lexical array. If a person says, "I house you in a tent," then a word that is normally a noun becomes a verb, "to house." The software should override any knowledge of "house" as being a noun and store the specific, one-time usage of "house" as a verb. Then the AI robot can respond with "house" as a verb to suit the occasion: "Please house me in a shed." OldConcept() should not automatically insist that a known word always has a particular part-of-speech. In a German AI, VerbGen() should be called to create verb-endings as needed, if not already stored in auditory memory.
In the @psy concept array we should have seven flags: psi, act, pos, jux, pre, tkb, and seq. If we now change the tqv variable from MindForth to $tkb in the Perl AI, it clearly becomes "time-in-knowledge-base" for Perl coders and AI maintainers.
It suddenly dawns on us that we no longer need an enx flag in the @psy array. We may still need the $enx variable for passing a fetch-value, but it looks like the @psy concept number and the @en lexical number will always be the same, since we coded MindForth to find inflections for an unchanging concept number.
Now mind0040.pl invites us to make a drastic simplification by merging the @psy array and the @en array, because any distinction between the two arrays has gradually become redundant. The @psy array has psi, act, pos, jux, pre, tkb, seq flags. The @en array has nen, num, mfn, dba, rv flags. We could joint them together into one @psy conceptual array with psi, act, pos, jux, pre, tkb, seq, num, mfn, dba, rv flags.
The first thing we do is in TabulaRasa(), where we fill each row of the @psy array with eleven zeroes for the eleven flags. Next we have the InStantiate() module store all eleven flags in the combined flag-panel. We run the Perl AI and it makes no objections. Then we have InStantiate() announce the values of all eleven flags before storing them.
In the flag-panel of the @psy array, we should probably add a human-language-code "hlc" so that an AI can detect English or German or Russian and think in the indicated language.
In mind0042.pl where we have merged the @en array into the @psy conceptual array, we gradually need to eliminate the $nen variable. However, we need a replacement other than the $psi variable so that the replacement variable can hold steady and wait for each new word being learned in English, German, Russian or whatever human language is involved. Let us try using $nxt as the next-word-to-be-learned.
In mind0043.pl we are now trying to code the AudRecog() module taken from MindForth, although the timing may be premature.
As we began coding AudRecog() in the mind0043.pl AI, we discovered that the primitive EnBoot() sequence did not contain enough English words to serve as comparands with a word being processed in the AudRecog() module, so we must suspend the AudRecog() coding and fill up the EnBoot sequence properly before we resume coding AudRecog().
Today we rename the English bootstrap EnBoot() sequence as MindBoot() because the Perl AI with Unicode will not be limited to thinking only in English, but will eventually be able to think also in German and in Russian.
In mind0044.pl we are replacing the Think() module with EnThink() for English thinking, and we are declaring DeThink() as a future German thinking module and RuThink() as a future Russian thinking module.
Coding the AudRecog() module in Perl5, we move left-to-right through the nested if-clauses. At the surface we test for a matching $pho. Nested down one layer, we test for zero activation on the matching $pho, because we do not want a match-in-progress. At the second depth of nesting, we test for the onset-character of a word. In the previous AI Minds coded in Forth and JavaScript, we still had the "beg(inning)" flag to fasten upon a beginning character at the start of a comparand word in auditory memory. Now in Perl killer app AI we must rely on the $audnew variable which is set during FileInput() but which we have apparently neglected to reset to zero again. Let us try setting $audnew back to zero just before we close the audinput.txt file. Oh no, $audnew won't work here, because $audnew applies only to the beginning of an input word, not to the beginning of a word stored in memory. Maybe we can try testing for not only a zero-activation matching $pho but also for an adjacent blank space.
Now, we are going backwards in memory from space-time $spt down to $midway, which is set to zero in the primitive AI. The $i variable is being decremented at each step backwards. We would like to know if going one step further encounters the space before a word. We might have to start searching forwards through memory if we want to trap the occurrence of an initial character in a stored word. If we go forwards through memory, we could have a $penult variable that would always hold the value of each preceding moment in time. For the chain of activations resulting in recognition, it should not matter if the sweep goes backwards or forwards.
Now in mind0045.pl we will stop searching backwards in AudRecog() and search forwards so that it will be easier to find the beginning of a comparand word stored in auditory memory.
As we debug the mind0045.pl AI, we notice that the MindBoot sequence is not a subroutine, as EnBoot was in the previous AI Minds. We should call MindBoot() as a one-time subroutine from the MainLoop. We establish TabulaRasa() and MindBoot() as subroutines and we give them a one-time call from the MainLoop.
Throughout many tests we were puzzled because AudRecog() was not recognizing an initial "b" at zero activation preceded by a zero $penult string. Finally it dawned on us that the MindBoot() "BOY" was in uppercase, so for a test we switched to lowercase "boy", and suddenly the proper recognition of the initial character "b" was made. But we will need to make input characters go into uppercase, so that AudRecog() will not have to make distinctions.
Moving into mind0046.pl, we need to consult our Perl reference books for how to shift input words into UPPERCASE. The index of Perl by Example has no entry for "uppercase". None also for "lowercase". However, the index of the Perl Black Book says, "Uppercase, 341-342," BINGO! Mr. Steve Holzner explains the "uc" function quite well on page 341. Let us turn the page and see if we need any more info. Gee, page 342 says that you can use "ucfirst" to capitalize only the first character in a string sentence -- one more example of how powerful Perl is. Resident webserver superintelligence, here we come.
Now let us try to use the "uc" function in the free Perl AI source code of mind0046.pl as we continue. We had better look into the FileInput() module first. Hmm, let us go back to the index of Perl by Example, where in the index we find "uc function, 702." Okay, let us try using "uc $char" at the start of the input WHILE-loop in the FileInput() module. Huh? It did not work. Uh-oh. Houston, we have a problem. Our mission-critical Perl Supermind is stuck in lowercase. Here we have been trying to learn Perl, but we have never coded any Perl program other than artificial intelligence. Even our very first "Hello world" Perl program was a "mind.pl" program and we never did any scratch-pad Perl coding. Meanwhile there are legions of Perl coders waiting for us to finish the port of AI Minds first into Perl5 and then into Perl6. Let us check the Perl Black Book again. Let us try, $char = "uc . $char"; in the FileInput() module. We drag-and-drop the line of code from this journal entry straight into the AI code. Then we issue the MS-DOS command, "perl mind0046.pl" and take a look. Oh no, the "uc" itself is going into memory as if it were the input. Hey, it finally worked when we used $char = uc $char; as the line of code. Now the contents of auditory memory are being displayed in uppercase. We can go back to coding the AudRecog() module.
Although we have done away with the ctu-flag of MindForth in the Perl AI, because we want to reduce the number of flags stored in the @aud auditory memory, in AudRecog() we may create a non-engram "ctu" or its equivalent by using the split function to look ahead one array-row and see whether a stored comparand word continues beyond any given character.
In mind0050.pl we would like to have the FileInput() module call the human-computer-interaction AudInput() module if the input.txt file is not found. In that way, we can simply remove input.txt to have a coding session of direct human interaction with the AI Perlmind.
In mind0052.pl we are continuing to improve AudInput() towards equal functionality as we developed in FileInput().
The line of input goes into a $msg string, which AudInput() needs to process in the same way as FileInput() processes the input.txt file, except that AudInput() only has to deal with one line at a time, which is presumably one sentence or one thought at a time.
Today in mind0053.pl we hope to fix a problem that we noticed yesterday after we uploaded mind0052.pl to the Web. We had carefully gone about sending the input $pho (phoneme) into AudMem() and AudRecog(), but no word was being recognized in AudRecog() -- which we had coded for six hours straight three days ago. Then yesterday we saw that we had left a "Temporary test for audrec" in the AudMem() module and that the code was arbitrarily changing the $audpsi from any recognized $audrec concept to the $nxt (next) concept about to be named in the NewConcept() module. Now we will comment out that pesky test code and see if AudRecog() can recognize a word. Hmm, commenting out the code did not seem to work.
We hate to debug the pristine Perl AudRecog() by inserting diagnostic message triggers into it, but we start doing so, and pretty soon we discover that we neglected to begin AudRecog() with the activation-carrier $act set to eight (8), as it is in the predecessor Mindforth AI. So let us set $act to eight in the AudRecog() Perl code and see what happens. Uh-oh, it still does not work.
But gradually we got AudRecog() to work. Now in the mind0054.pl AI we are working on the AudMem() module. We want it to store each $pho phoneme in the @ear array as $audpsi if there has been an auditory recognition, and as simply $nxt if only the next word from NewConcept() is being stored.
The $audpsi shall be stored if the next time-point is caught by the ($nxr[0] !~ /[A-Z]/) test as not being a character of the alphabet.
Yesterday we got the Perl AI to either recognize a known word and store it in the @ear array with the correct $audpsi tag, or instead to store a word as a new concept with the $nxt identifier tag. However, in the @psy conceptual array, the Perlmind is improperly incrementing the $nxt tag because we have not yet figured out how to declare that a character flowing by is the last character in a word. Bulbflash: Maybe we can store the $nxt tag at the end of each @ear row, erasing it when each successive character comes in, so that only the last letter of the word will end up having the $nxt tag.