Besides text, a chatbot should also be able to handle other types of basic data, like numbers, date-time and time-spans.

Numbers

The engine of the chatbot designer app will automatically convert every part of the input text that it can, into an integer or double. Furthermore, with the aid of the thesaurus, you are also able to pick up words that represent numbers and convert them into their corresponding number values. This allows us to easily work with and manipulate these numbers. Here are a few input pattern examples:

^n:number

^n:integer

^n:double

^n:noun.(language unit).numeral

The first 3 examples are the simplest: you can read a double (floating number), an integer or if you don’t care which, you can simply use ‘number’. The last one is a bit more interesting. Here we use the thesaurus to catch words like ‘one’, ‘two’,… Of course, that’s very limiting, cause this way, you’d have to declare a thesaurus-entry for every single number in the universe, which is, well…, impossible. So better to write the last pattern like so:

^n:noun.(language unit).numeral { [and] ^n:noun.(language unit).numeral}

The {} operator is used to find a repeating block in the input. So this catches things like: two thousand and five hundred.  As you can see, we use the same variable name for the number in the front and repeating part. This means that most likely, the ‘n’ variable will contain a list of words instead of just 1. Also, we don’t collect the ‘and’ cause it would screw up the conversion procedure. A small warning about the {} operator though: The application can’t find duplicate patterns when the {} operator is used, so watch out for this.

For completion, you could also include a pattern that handles mixed numbers and words. The conversion algorithm is perfectly capable of handling this mixed type of input.

Working with numbers

So, now that we can read in the numbers, lets look at how we can use them. let me just pick up where we ended: with word-numbers. Right now, the variable is still containing words (or a mix of words and numbers), but we actually need a single number, so this needs to be converted. Luckily, you don’t need to do this manually, but there’s already a function available for this. Here’s a usage example:

$value = $n:ToNumber

:ToNumber will convert the content of the variable into a number (only integers are currently supported, a ‘.’ is not yet recognized). Each individual word is converted using the thesaurus and finally added/multiplied together to form a single number. Now, this conversion algorithm is language dependent and at the time of writing, there is only an implementation for English. If you need it for a different language, best to contact me.

Of course, the primary purpose for having real numbers, is so that we can do calculations with them. As you’ll soon see though, this is done a little bit different compared to a traditional programming language. That’s because the chatbot designer’s pattern definition language is text oriented and not math. This means that if you were to type something like $n + $w, it would not perform the calculation, but print/store the ‘+’ sign in between the 2 numbers. So, to perform arithmetic, you need to use functions. here are some examples:

$result = $n:add

$result = $n:add($w)

$result = $n:subtract($w,$d,$f)

$result = $n:subtract($w,$d,$f:Add($h))

The basic principle is always the same: since a variable can contain a list of items (a set), it doesn’t really need arguments to perform the arithmetic operation, as long as it has enough items in the list. Because of this, most mathematical operations can be performed on more then 2 items. So you don’t write a+b+c, but if all 3 are in the same variable, you simply write :add.

If the variable doesn’t contain enough values or you want to include additional values, you can add those as arguments. For most functions, this list is unlimited and can always be nested, so you can do mathematical operations inside others.

For completion, here are all the currently supported mathematical operators:

Function Description Nr of arguments
Add Adds all the numbers any length
Subtract subtracts each item from the first any length
Multiply multiplies each item with the first any length
Divide divides each item with the first any length
Modulus returns the modulus of the 2 numbers 2 items
Complete completes the sequence of the 3 numbers 3 items
Count counts the nr of items in the list any length
StDev calculates the standard deviation of the values any length
Min returns the smallest number in the list any length
Max returns the biggest number in the list any length
Avg gets the average of all the values. any length
Complement removes all the items in the argument from the input variable and returns the result (the difference between the 2). any length
Reverse Reversed the order of the items in the list (last becomes first) any length
Distinct Removes all duplicates. If there are any arguments, these are first added to the end of the list before duplicates are removed. any length
Union Adds the arguments to the end of the input items. any length

Date and time

Next on the menu are dates and times. These are very closely related to numbers. Internally, the system doesn’t see a difference between a date and a time, it’s always a DateTime. Depending how you use the value, you can regard it as a date, time or DateTime.

First of, there is a special variable to get to the current system date/time: $time. This returns a DateTime-cluster which contains a list of numbers that together form the date and time. The order is predetermined by the system to make it language independent. For ease of use, there are functions to get to each part of the date, so you don’t need to memorize each position in the format (though it helps for putting dates back together). Here’s a table of all the functions to get each part of the date list (+ the index position of the item in the list):

Index Function Meaning
0 Year Gets the year number.
1 Month Gets the month of the year.
2 Day Gets the day of the month.
3 Hour Gets the hour (24 hours in a day)
4 Minute gets the minutes (60 per hour)
5 Second gets the nr of seconds (60 per minute)
6 DayOfWeek gets the nr day number of the week (0=Sunday, 1= Monday,…)

And here are some output patterns to show how you can use them:

$time:day/$time:month/$time:year

$time:hour : $time:minutes : $time:second

The current month is ^noun.month[$time:month-1]

Note that I deliberately put spaces between the variables and the  time indicator (‘:’)  to avoid using the escape character (\). Also, in the last example, we get the name of the month from the thesaurus through the index number.  A thesaurus child at a specific index position can be accessed with the [] operator in the variable path. Because there’s no point of putting words between the brackets and this so often requires a small calculation (0 vs 1 based indexes), I have opted here for a more traditional calculus notation. Supported operators are: +-*/%.

Often it’s also useful to recompose a date, based on a series of numbers. For instance, to build the birthday of someone. As you probably already suspected, there are functions to do just that. Here are some examples:

$date = $list:ToDate

$time = $list:ToTime

$date = $year:ToDate($month,$day)

For building the date, the first value in the list has to be the year. This is the only required item, but more can follow: month, day, hour, minute, second. In that order.  To build a time value, the first item has to be the hour. Minutes and seconds are optional, but have to be provided in the previously mentioned order. If you want to omit the minutes (or any other) part , use 0 instead.

Why not simply store the date values as individual numbers in memory fields yourself, you might wonder instead of going through the hassle of converting a number into another number (which these conversion functions basically do). Well, that will become apparent in the next section.

querying on date

The date and time values are stored in such a way that a year, month, day, minute, second or week in a date is always represented by the same neuron. This means that you can easily find all the dates (and therefor the attached assets) that meet certain criteria (all in the month June for instance). This is very useful in queries like “Who else is born in the same year and month as I am?”. Getting the date objects is real easy. Here’s an example:

$people= #user.birthday:year:GetDates:ValueFor(birthday)

$people = $people:Complement(#user)

$people = #($people).name

–or, for year and month:–

$people= #user.birthday:year:GetDates(#user.birthday:Month):ValueFor(birthday)

$people = $people:Complement(#user)

$people = #($people).name

Note: For a full example, check the Date-Time demo found at {documents}\nnd\demos\dateTime.dpl.

In the first line, we get the year section of the user’s birthday. With the ‘:GetDates’ function, we retrieve all the date objects that the system has stored for the same year as the user’s birthday.  If you supply extra arguments, those values will also have to be included in the date, as is shown in the second example. With ‘:ValueFor’ we retrieve all the assets that link to the date. The ‘birthday’ argument, specifies that we only want the assets that link to the date value with the ‘birthday’ attribute. We could have omitted this, in which case we would have gotten all the assets, no matter how they are linked (it could be a ‘when’ reference for instance). Or, we could also have given more arguments, specifying a list of possible attribute values.

At this point, we have a list of assets that reference a date of the same year as the user’s birthday. There are still 2 things that need to be done: first we need to remove the ‘#user’ from the asset list, cause the ‘GetDates’ returns all objects, including the date object that represents the user’s birthday, but since the bot was asked ‘who else’, we need to remove the ‘#user’. This is done with the ‘:complement’ function. This is a mathematical function (borrowed from set-theories) and will return a list that contains all the items from the input with all the arguments removed.

We do the call to ‘:Complement’ on a different code line and not on the first one for a very specific reason: asset paths, like in the first assignment, always provide a single value as input to each function in the path, so even if ‘GetDates’ returns a list of items, ‘ValueFor’ will always work on a single value. At the end, the asset path joins all the results together. This, of course, is of no use for the Complement function, cause we need to remove the items from the list and not from a single value. Luckily, regular variable paths do provide a list of items as input values. That’s why we started a new assignment, using a variable path to calculate the complement. There are a couple of other functions (like Interleaf, Filter, Add, Multiply, Avg, Min, Max,…) which require a list of items as input. These should never be used in an asset path, but only in variable paths, for the reason explained above.

In the last line, we get the name value of all the assets that we found. This is again on a different line cause we need an asset path to get the ‘name’ of an asset. Regular variable paths don’t know how to do this. Hence the extra 3th line.  And thus, we get the names of the known objects that have a birthday in the same year as the user.

Time ranges

Besides the Date-Time type, there is also a Time-Span type. This specifies a length of time instead of a specific moment. You get a Time-Span by building it with a function, or as the result of some Date-Time calculations (see later). To build a time range (or time-span), you can do something like:

$range = $list:ToTimeSpan

$range = $days:ToTimeSpan($Hours)

Unlike a DateTime, a timespan contains the number of: days, hours, minutes and seconds (no year or month sections). so there are only 4 elements in the list. The first item in the list should always be the nr of days, possibly followed by the hours,… Missing data is set to 0. Like with :ToDate and :ToTime, you can also specify missing data as arguments. The same order applies.

For retrieving values in a TimeSpan, you can use the same functions as for the DateTime. They operate in exactly the same way, but the index position of the actual items in the list is different compared to a DateTime. here’s an overview:

Index Function Meaning
1 Day Gets the total nr of days in the range.
2 Hour Gets the remaining nr of hours.
3 Minute gets the remaining nr of minutes.
4 Second gets the remaining nr o seconds.

At the time of writing, TimeSpans don’t yet support the same level of querying as the DateTime object does. If anyone has an urgent need for this, let me know, and I’ll see what I can do.

Calculating with dates and times

Like with regular numbers, you can also perform some calculations on dates, like subtracting one date from another. The syntax for arithmetic with dates/times is exactly the same as with numbers. Here’s an overview of what’s supported:

Function combination results
Add Time + {range} Time
range + {range} Range
Subtract Time – {Time} Range
Min Time, Time,… Time
range, range,.. Range
Max Time, Time,… Time
range, range,.. Range
Avg Time, Time,… Time
range, range,.. Range
StDev Time, Time,… Time
range, range,.. Range

In general, the principle is always the same: the function input determines the type of the result, except for ‘Subtract’ which always returns a range and only works on Time values.

Boolean operations

As a final topic, perhaps a word about logical or Boolean operations on numbers, dates and ranges. Well, for the most part, these work as you would expect both for regular numbers and times/ranges. There’s just 1 small twist. The mathematical people out there will probably have noticed that set-theory is very present in this system: all variables can contain a list of items. This means that Boolean operators need to be prepared for this. Here’s an overview on how each operator handles lists:

  • Equality (==): If the left part contains a list, the right side must have the exact same list: with the same nr of items, in the same order.
  • Difference (!=) If the left part contains a list, the right side is different if it contains a different amount of items, the sequence is different or one or more of the items differ.
  • Contains (contains): The right side of the operator should be part of the list found on the left side of the operation.
  • doesn’t contain (!Contains): The right side of the operator should not be part of the list found on the left side of the operation.
  • >, >=, <, <= (Bigger, bigger or equal, smaller, smaller or equal): If the left part contains a list, each item in the list will be evaluated to each item found on the right side. The operation succeeds if all items are compared and none failed.

There is plenty more to say about this topic. But my time-range has run out, a time to move on has been reached. All that’s left for me to say is: Stay tuned and CY later.

© 2012 Neural Network Design blog Suffusion theme by Sayontan Sinha