trueagi-io / metta-examples Goto Github PK
View Code? Open in Web Editor NEWDiscussion of MeTTa programming with examples
License: MIT License
Discussion of MeTTa programming with examples
License: MIT License
It takes about 1 minute to create a list of 24 elements in minimal Metta.
Is there a way to make it work faster?
(= (makelist $x)
(if (== () $x) Nil (let $_cdr (cdr-atom $x)
(Cons (car-atom $x) (makelist $_cdr)))
)
)
!(makelist (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24))
[(Cons 1 (Cons 2 (Cons 3 (Cons 4 (Cons 5 (Cons 6 (Cons 7 (Cons 8 (Cons 9 (Cons 10 (Cons 11 (Cons 12 (Cons 13 (Cons 14 (Cons 15 (Cons 16 (Cons 17 (Cons 18 (Cons 19 (Cons 20 (Cons 21 (Cons 22 (Cons 23 (Cons 24 Nil))))))))))))))))))))))))]
I've got some question regarding possibility to replace scheme's cond
with metta's case
. Is it possible? I've tried to write simple check function to see if my idea works:
(= (check $x $y)
(case $x
((0 1)
((> $x $y) $x)
($_ $y))))
But apparently it doesn't work since, as i understand case, it will check not if $x larger than $y but instead if (== $x (> $x $y))
(expression equality). Is there some way to write this code using case in current metta state? Or only consequent if's are usable in that case? @vsbogd @Necr0x0Der
Let's we have the following "knowledge graph"
(parent Tom Bob)
(parent Pam Bob)
(parent Tom Liz)
(parent Bob Ann)
(parent Bob Pat)
(parent Pat Jim)
(female Pam)
(male Tom)
(male Bob)
(female Liz)
(female Pat)
(female Ann)
(male Jim)
What is the canonical way to write the following request to this knowledge graph:
(it would be great if aunt is somehow be defined via sister and parent_of)
It is possible to write the following implementation inspired by Prolog (@mvpeterson ):
(= (_parent $x $y) (match &self (parent $x $y) $x))
(= (_male $x) (match &self (male $x) $x))
(= (_female $x) (match &self (female $x) $x))
(= (_different $x $y)
( if (== $x $y)
Empty
$x
)
)
(= (_sister $x $y)
( let* ( ($q (_female $x))
($r (_parent (_parent $z $q) $y))
)
(_different $q $y)
)
)
(= (_aunt $x $y) (_sister $x (_parent $q $y)))
!(_aunt $x Jim)
; It will return correct answer [Ann]
But this implementation is extremely slow.
So what would be the metta way here?
@Necr0x0Der @vsbogd
So, probably it is a messy issue name, but I'll try to explain.
I'm currently working on symbolic differentiation example from SICP book. It is restricted currently to several possible input functions (type of functions). Every consequent exercise asks to extend possible function types which function could differentiate. Anyway, here is the current state of deriv function with other functions needed to launch it:
(= (null? $expr)
(== $expr ()))
(= (cons $x $y)
(cons-atom $x $y))
(= (car $x)
(car-atom $x))
(= (cdr $x)
(cdr-atom $x))
(= (cddr $x)
(cdr (cdr $x)))
(= (cadr $x)
(car (cdr $x)))
(= (caddr $x)
(car (cdr (cdr $x))))
(= (number? $x) (and (== (get-type $x) Number) (not (== (get-metatype $x) Expression))))
(= (variable? $x) (== (get-metatype $x) Symbol))
(= (same-variable? $v1 $v2)
(and$ ((variable? $v1) (variable? $v2) (== $v1 $v2))))
(= (sum? $x)
(and (== (get-metatype $x) Expression) (== (car $x) '+)))
(= (addend ('+ $x $y)) $x)
(= (augend ('+ $x $y)) $y)
(= (product? $x)
(and (== (get-metatype $x) Expression) (== (car $x) '*)))
(= (multiplier ('* $x $y)) $x)
(= (multiplicand ('* $x $y)) $y)
(= (and$ $list)
(if (null? $list)
True
(and (car $list) (and$ (cdr $list)))))
(= (make-sum $a1 $a2)
(if (=number? $a1 0)
$a2
(if (=number? $a2 0)
$a1
(if (and (number? $a1) (number? $a2))
(+ $a1 $a2)
('+ $a1 $a2)))))
(= (=number? $exp $num)
(and (number? $exp) (== $exp $num)))
(= (make-product $m1 $m2)
(if (or (=number? $m1 0) (=number? $m2 0))
0
(if (=number? $m1 1)
$m2
(if (=number? $m2 1)
$m1
(if (and (number? $m1) (number? $m2))
(* $m1 $m2)
('* $m1 $m2))))))
(= (deriv $exp $var)
(if (number? $exp)
0
(if (variable? $exp)
(if (same-variable? $exp $var) 1 0)
(if (sum? $exp)
(make-sum (deriv (addend $exp) $var)
(deriv (augend $exp) $var))
(if (product? $exp)
(make-sum
(make-product (multiplier $exp)
(deriv (multiplicand $exp) $var))
(make-product (deriv (multiplier $exp) $var)
(multiplicand $exp)))
(if (exponentiation? $exp)
(make-exponentiation (base $exp) (deriv (base $exp) $var) (exponent $exp))
(Error (deriv $exp $var) "Unknown expression type")))))))
(= (exp) ('+ x ('+ x 1)))
!(assertEqual
(deriv (exp) x)
2)
Okay, here everything works. But next exercise asks to extend functions added, augend, multiplier and multiplicand so we can evaluate deriv for sums/products of several (more than 2) terms. In this case, I've introduced following changes:
(= (length $items)
(if (null? $items)
0
(+ 1 (length (cdr $items)))))
(= (addend $x) (cadr $x))
(= (augend $x)
(if (> (length $x) 3)
(cons '+ (cddr $x))
(caddr $x)))
(= (multiplier $x) (cadr $x))
(= (multiplicand $x)
(if (> (length $x) 3)
(cons '* (cddr $x))
(cddr $x)))
And here deriv becomes unstable (of course I've deleted previous augend/addend/multiplier/multiplicand). Lets take same example:
!(deriv (exp) x)
(if (and (number? (if (=number? (Error (deriv True x) "Unknown expression type") 0) 1 (if (and (number? 1) (number? (Error (deriv True x) "Unknown expression type"))) (+ 1 (Error (deriv True x) "Unknown expression type")) ('+ 1 (Error (deriv True x) "Unknown expression type"))))) False) 1 (if (and (number? 1) (number? (if (=number? (Error (deriv True x) "Unknown expression type") 0) 1 (if (and (number? 1) (number? (Error (deriv True x) "Unknown expression type"))) (+ 1 (Error (deriv True x) "Unknown expression type")) ('+ 1 (Error (deriv True x) "Unknown expression type")))))) (+ 1 (if (=number? (Error (deriv True x) "Unknown expression type") 0) 1 (if (and (number? 1) (number? (Error (deriv True x) "Unknown expression type"))) (+ 1 (Error (deriv True x) "Unknown expression type")) ('+ 1 (Error (deriv True x) "Unknown expression type"))))) ('+ 1 (if (=number? (Error (deriv True x) "Unknown expression type") 0) 1 (if (and (number? 1) (number? (Error (deriv True x) "Unknown expression type"))) (+ 1 (Error (deriv True x) "Unknown expression type")) ('+ 1 (Error (deriv True x) "Unknown expression type")))))))
So for the same input deriv now outputs garbage. Moreover, for some reason, $exp somehow becomes True
as we can see from (Error (deriv True x) "Unknown expression type")
. I don't know how is this possible. If we will use previous augend/multiplicand this problem will disappear (but of course previous functions don't know about possible several terms in sums and products). And I don't get where this True comes from? Since there is no debug in Metta, I've tried to go step-by-step through deriv just by calling consequent lines outside the function and wasn't able to get this behavior anywhere. Here is an interesting thing:
!(augend (exp))
gives
('+ x 1)
which is correct.
!(deriv (augend (exp)) x)
gives 1
which is correct. But it doesn't work inside function deriv for some reason. I've spent many hours to "debug" this problem and wasn't able to do this. I don't get where is True coming from. The only possible way of getting it inside $exp variable is that augend with if added returns "True" instead of evaluation of its first line. Is it even possible? And why it's not happening when I'm calling augend outside the deriv function? I'm beaten here so I'll be really glad to hear possible solutions. I've thought about introducing type for augend, but since its input and output are %Undefined% it makes no difference. I need to tell this function that it could output anything BUT Bool, but how? And will it work?
I cannot emulate lambda calculus, I would say due to a lack of support for scopes in MeTTa.
Run the following code
(= ((λ $x $f) $y) (let $x $y $f))
!((λ $x ($x $x)) (λ $y ($y $y)))
It outputs []
.
It should never halt, as per the mockingbird infinite loop (M M)
.
The problem comes the fact that
((λ $x ($x $x)) (λ $y ($y $y)))
reduces to
(let $x (λ $y ($y $y)) ($x $x))
which reduces to
((λ $y ($y $y)) (λ $y ($y $y)))
which finally reduces to
(let $y (λ $y ($y $y)) ($y $y))
which fails because $y
does not unify with (λ $y ($y $y))
.
You can see that this is caused by the absence of alpha-conversion, because λ
is not treated as a scope.
Do we need scopes in MeTTa?
If the answer is no, then how to emulate lambda calculus in MeTTa?
There was an inner conversation regarding my suggestion on how to improve performance of some functions. This issue is the result of this conversation. I'm wrapping it here since it could be useful for those who starts to learn Metta.
So, let's start with a code. Here is a two possible ways to implement factorial:
(= (fac $x) (if (== $x 0 ) 1 ( * (fac (- $x 1)) $x )))
(= (fac2 0)
1)
(= (fac2 $x)
(if (> $x 0)
(* (fac2 (- $x 1)) $x)
(empty)))
And, similarly, two ways to implement Fibonacci number generator:
(= (fib $n)
(if (== $n 0)
0
(if (== $n 1)
1
(+ (fib (- $n 1)) (fib (- $n 2))))))
(= (fib2 0)
0)
(= (fib2 1)
1)
(= (fib2 $x)
(if (> $x 1)
(+ (fib2 (- $x 1)) (fib2 (- $x 2)))
(empty)))
In each example, second implementation is faster than first one. For example, (fib 100) vs (fib2 100) is 48.808s vs 19.594s . And bigger the input number - bigger the difference in performance. Difference for factorial is not so impressive. At least for 100 as input. 10.303s vs 9.703s .
Anyway, @Necr0x0Der said that these hacks is not appropriate since they can be applied only to current state of metta interpreter and further interpreter optimizations could make these hacks obsolete. So better way to implement fib will be one of those:
; Recursive
(= (fib $n)
(if (< $n 2)
$n
(+ (fib (- $n 1)) (fib (- $n 2)))))
!(assertEqual
(fib 7)
13)
; Iterative
(= (ifib $n)
(fib-iter 1 0 $n))
(= (fib-iter $a $b $count)
(if (== $count 0)
$b
(fib-iter (+ $a $b) $a (- $count 1))))
!(assertEqual
(ifib 7)
13)
Iterative variant should be quicker, but in current metta interpreter's state it is quite opposite due to interpreter cashes all calls during evaluation (@Necr0x0Der will probably explain this better). In minimal-metta this behavior could be different.
It’s not clear how to process (or present) complex expressions like
(a (c b1 b2) (c b3 b4)
with nested subexpressions using metta. For example, there are expressions that specify line segments
(seg (point 1 1) (point 1 2))
(seg (point 1 1) (point 2 1))
I would like to have a function that would return all vertical lines
(_vertical $x)
Here we need to match segments with the same X coordinate at the points. It is not clear then how to proceed to matching two points if one argument is supplied to (_vertical $x)
.
One can write
(= (_vertical $x $y) (match &self (seg $x $y) ($x $y)))
and points will be returned
[((point 1 1) (point 1 2)), ((point 1 1) (point 2 1))]
But then it is not clear how to match them, since they are specified in the subexpression (seg . .)
Of course, we can write this manually
(= (_vertical $x $y1 $x $y2) (match &self (seg (point $x $y1) (point $x $y2)) (seg (point $x $y1) (point $x $y2)) ))
!(_vertical $x $y1 $x $y2)
It seems to work like this, but what if there are many more such subexpressions?
I've met some issue (probably it is my misunderstanding of how metta works with typed functions though) when adding types to functions. Here is the code and it works fine. It counts leaves of tree as name states.
(= (null? $expr)
(== $expr ()))
(= (list $expr)
(if (null? $expr)
Nil
(if (== (get-type $expr) Number)
$expr
(Cons (list (car-atom $expr)) (list (cdr-atom $expr))))))
(= (count-leaves Nil)
0)
(= (count-leaves $x)
(if (== (get-type $x) Number)
1
(empty)))
(= (count-leaves (Cons $x $xs))
(+ (count-leaves $x)
(count-leaves $xs)))
!(assertEqual
(count-leaves (list (1 2 3 4)))
4)
!(assertEqual
(count-leaves (Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil)))))
4)
(= (x) (list ((1 2 3) 3 4)))
!(assertEqual
(count-leaves (x))
5)
!(assertEqual
(count-leaves (Cons (Cons 1 (Cons 2 (Cons 3 Nil))) (Cons 3 (Cons 4 Nil))))
5)
Problems starts when I'm trying to add types here. They are not actually needed but I was checking Anatoly's suggestion about influence of types on script's performance. Anyway, I've inserted those lines:
(: List (-> $a Type))
(: Nil (List $a))
(: Cons (-> $a (List $a) (List $a)))
(: count-leaves (-> Number Number))
(: count-leaves (-> (List Number) Number))
After this, strange behavior (at least in my understanding) happened.
Launching
!(count-leaves (list (1 2 3 4)))
gives [4,4]
, not just 4
and launching
!(count-leaves (Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil)))))
gives [4]
which is correct. But i don't understand how is it possible since (list (1 2 3 4))
and (Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil))))
should be the same. What am i missing?
Almost same goes to the tree example:
(= (x) (list ((1 2 3) 3 4)))
!(count-leaves (x)) ; gives [5,5]
!(count-leaves (Cons (Cons 1 (Cons 2 (Cons 3 Nil))) (Cons 3 (Cons 4 Nil)))) ; [(Error (count-leaves (Cons (Cons 1 (Cons 2 (Cons 3 Nil))) (Cons 3 (Cons 4 Nil)))) NoValidAlternatives)]
Though, once again, (x)
and (Cons (Cons 1 (Cons 2 (Cons 3 Nil))) (Cons 3 (Cons 4 Nil)))
should be the same. Though it is not true. This one works:
!(assertEqual
(list (1 2 3 4))
(Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil)))))
But this one - not:
!(assertEqual
(Cons (Cons 1 (Cons 2 (Cons 3 Nil))) (Cons 3 (Cons 4 Nil)))
(x))
It gives:
Expected: [(Cons (Cons 1 (Cons 2 (Cons 3 Nil))) (Cons 3 (Cons 4 Nil)))]
Got: [(Error 3 BadType)]
Missed result: (Cons (Cons 1 (Cons 2 (Cons 3 Nil))) (Cons 3 (Cons 4 Nil))))]
In case of tree (x) it is probably related to types of List and Cons. So, questions are:
(Cons (Cons 1 (Cons 2 (Cons 3 Nil))) (Cons 3 (Cons 4 Nil)))
as it is it produces an error.!(count-leaves (list (1 2 3 4)))
but not for !(count-leaves (Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil)))))
? Why behavior is different for same (as I understand) input?My opinion is that it can be related to different evaluation sequence with and without types.
Thanks in advance.
Hi,
From child_ai.py
we have
# Initial data preparation
data_motivation = {
'Time': [1],
'Motivation': ['Reflex'],
'Need': ['Pay Attention on Unusual Event'],
'Action': ['Research Unusual Event'],
'Result': ['Understand Unusual Event'],
'Status': [[['Visual', 'Other'],['Hearing', 'Other'],['Touch', 'Other']]]
}
Motivation_Global = pd.DataFrame(data_motivation)
then
# Business logic of curiosity behaviour of Child
def curiosity_behavior(Start, End):
for t in range(Start, End+1):
Motivation_item = Motivation_Global[Motivation_Global['Time']==t]
if Motivation_item.size != 0:
Is_Result_Achieved = PDCA_func(Motivation_item)
if Is_Result_Achieved:
print("Result is achieved! Time: ", t)
t = t + 1
print("curiosity_behavior ends.")
Motivation_Global['Time']
is equal to [1]
, so basically [1]
will never be equal to 1 or 2 or 3 etc. that's why I don't understand this line:
Motivation_item = Motivation_Global[Motivation_Global['Time']==t]
Furthermore, Motivation_Global['Time']==t
will return either True or False, but Motivation_Global[True]
or Motivation_Global[False]
does not exists...
Thanks
Monkey and banana problem
Initial state: Monkey is at door, Monkey is on floor, Box is at window, Monkey does not have a banana
(state at_door on_floor at_window hasnot)
The target state: Monkey is at the middle of the room, Monkey is on box, Box is at the middle, Monkey has the banana
(state at_middle on_box at_middle has)
Allowed moves:
Grasp banana
(move (state at_middle on_box at_middle hasnot) (grasp) (state at_middle on_box at_middle has))
Climb box
(move (state $p on_floor $p $h) (climb) (state $p on_box $p $h))
Push box from p1 to p2
(move (state $p1 on_floor $p1 $h) (push $p1 $p2) (state $p2 on_floor $p2 $h))
Walk from p1 to p2
(move (state $p1 on_floor $b $h) (walk $p1 $p2) (state $p2 on_floor $b $h))
(= (_move $state1 $m $state2) (match &self (move $state1 $m $state2) (trace! ($state1 $m $state2) $state2)))
(= (_canget (state $x $y $z $h)) ( if (== $h has) True (_canget (_move (state $x $y $z $h) $m $state2))))
This command don't get out of recursion
!(_canget (state at_door on_floor at_window hasnot))
But if I call the (_move)
function on certain states step by step, it can be seen that the target state can be reached.
!(_move (state at_door on_floor at_window hasnot) $m $state2)
;[(state $p2#2566 on_floor at_window hasnot)]
!(_move (state $x on_floor at_window hasnot) $m $state2)
;[(state $p2#10412 on_floor at_window hasnot), (state at_window on_box at_window hasnot), (state $p2#10406 on_floor $p2#10406 hasnot)]
!(_move (state $x on_floor $x hasnot) $m $state2)
;[(state $p2#28360 on_floor $x hasnot), (state $x on_box $x hasnot), (state $p2#28354 on_floor $p2#28354 hasnot)]
!(_move (state $x on_box $x hasnot) $m $state2)
;[(state at_middle on_box at_middle has)]
For the second call I get three matches, and the desired option is the third. Does this mean that it will never be selected because subsequent recursion calls will use the options preceding the third one, and they will also produce several options in turn?
Will the first option be taken and will it be evaluated until it is reduced? And after that the second option will be processed and so on?
Hello,
From the doc I have done these steps
It results in the folders/files structure:
hyperon-experimental/
lib/
Cargo.toml
src/
lib.rs
child_ai/
child_ai.py
graph_kb.rs
mod.rs
Since there is no documentation on how to run this code, I tried:
python child_ai.py
Which returns a Python: command not found. Yet, I am using the docker container (so I guess Python should be available by default), so I tried sudo apt install python wich returns a Package 'python' has no installation candidate
python3 child_ai.py would work, but then no module named numpy.
Anyway, just to say that I am not sure if the Docker image you propose is up to date
Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.