I'm writting a program that simplifies polynimials, only addition and multiplication for now.
I've been slamming my head agains the keyboard for hours now and figure it was time to ask for some help.
(defun simplify (lis)
(if (eq (car lis) '+)
(cons '+ (simplify-addition (cdr lis)))
(if (eq (car lis) '*)
(cons '* (simplify-multiplication (cdr lis)))
)
)
)
(defun simplify-addition (lis)
(if (not (null lis))
(if (listp (car lis))
(list (simplify (car lis)) (simplify-addition (cdr lis)))
(if (numberp (car lis))
(if (eq (car lis) 0)
(simplify-addition (cdr lis))
(if (null (cdr lis))
lis
(cons (car lis) (simplify-addition (cdr lis)))
)
)
(if (eq (car lis) '+)
(list (car lis) (simplify-addition (cdr lis)))
(if (eq (car lis) '*)
(list (car lis) (simplify-addition (cdr lis)))
lis
)
)
)
)
)
)
(defun simplify-multiplication (lis)
(if (not (null lis))
(if (listp (car lis))
(if (find 0 (car lis))
0
(list (simplify (car lis)) (simplify-multiplication (cdr lis)))
)
(if (numberp (car lis))
(if (null (cdr lis))
lis
(cons (car lis) (simplify-multiplication (cdr lis)))
)
(if (eq (car lis) '+)
(list (car lis) (simplify-multiplication (cdr lis)))
(if (eq (car lis) '*)
(list (car lis) (simplify-multiplication (cdr lis)))
lis
)
)
)
)
)
)
This is what should happen:
(simplify ‘(+ x ( + 0 3 ) ( * 1 5 ) ( * ( * x y z ) 0 ) )) --> ( + x 3 5 )
(simplify ‘(* (+ 6 0) (* 1 6 2))) --------------------------------> (* 6 (* 6 2))
but instead i either get the same polynomial i sent in, or something completely off
EDIT:
The simplification that i need is to remove 0 from additions, so that:
(+ 3 0) --> 3
(+ 4 0 6) --> (+ 4 6)
and the multiplication with zero are removed
(* 6 0 7) --> 0
First you might want to improve your coding style a bit to make it readable.
don't put parentheses on their own lines. This just wastes space and doesn't help at all.
don't use CAR and CDR in domain specific code. The domain is mathematics. You use expressions (operator arg1 arg2). Instead using CAR and CDR define functions OPERATOR and ARGUMENTS and use them.
use CASE, COND and other multiway conditional expressions, instead of nested IF - where useful.
try to extract the traversal of data structures from domain code. Use higher order functions instead of recursion (MAP, REDUCE, ...).
Example:
Some basic domain functions:
(defun operator (expression)
(first expression))
(defun arguments (expression)
(rest expression))
(defun make-expression (operator arguments)
(if (= (length arguments) 1)
(first arguments)
(cons operator arguments)))
(defun is-zero? (expression)
(and (numberp expression)
(= expression 0)))
Now the simplifications:
(defun simplify (expression)
(if (atom expression)
expression
(case (operator expression)
(+ (make-expression '+ (simplify-addition (arguments expression))))
(* (make-expression '* (simplify-multiplication (arguments expression)))))))
(defun simplify-addition (expressions)
(remove-if #'is-zero?
(mapcar #'simplify
(remove-if #'is-zero? expressions))))
(defun simplify-multiplication (expressions)
(if (member-if #'is-zero? expressions)
(list 0)
(let ((expressions1 (mapcar #'simplify expressions)))
(if (member-if #'is-zero? expressions1)
(list 0)
expressions1))))
See, how much more readable the code is? No more CAR, LIS, CDR. The intention of the recursive invocations is also much clearer to understand.
It still not optimal, but it should get you going.
I've only looked at simplify-multiplication but there are a number of issues here.
On a general note, you want to recursively simplify first, then check for specific constants afterwards. (A post-order traversal, I guess.)
Second, I don't see you checking for 1 anywhere so I don't see how (* 1 5) ==> 5 is supposed to work.
Third, let's step through (simplify '(* (+ 2 0) 3)) for a bit:
(defun simplify-multiplication (lis)
; lis = '((+ 2 0) 3)
(if (not (null lis))
; ==> t
(if (listp (car lis))
; (car lis) = '(+ 2 0), so (listp '(+ 2 0)) ==> t
(if (find 0 (car lis))
; succeeds because '(+ 2 0) contains 0
; this is completely wrong! you're not supposed to check sublists of lis
0
; ... yeah, you just returned 0 just because there was a 0 *somewhere*
(list (simplify (car lis)) (simplify-multiplication (cdr lis)))
)
...
Or (simplify '(* 0 2)):
(defun simplify-multiplication (lis)
; lis = '(0 2)
(if (not (null lis))
; ==> t
(if (listp (car lis))
; (car lis) = 0, so (listp 0) ==> nil
(if (find 0 (car lis))
0
(list (simplify (car lis)) (simplify-multiplication (cdr lis)))
)
(if (numberp (car lis))
; (numberp 0) ==> t
(if (null (cdr lis))
; (cdr lis) = '(2), so (null '(2)) ==> nil
lis
(cons (car lis) (simplify-multiplication (cdr lis)))
; ... wait, what?
; you're just recursively walking through the list without
; checking what numbers you actually got. this won't simplify
; anything.
)
(if (eq (car lis) '+)
; what is this branch for? it can only succeed if you have code of the form
; (* 1 + 2)
; which is a syntax error
(list (car lis) (simplify-multiplication (cdr lis)))
(if (eq (car lis) '*)
; this branch is for code like (* * *). huh???
(list (car lis) (simplify-multiplication (cdr lis)))
lis
)
)
)
)
)
)
Related
i have a simple boolean expression presented as a lisp list like this :
'(OR 0 (AND A1 A2))
the previous list is the presentation of ((A1 AND A2)OR 0).
anyway , i am writing a function to simplify this expression ..
for example :
calling the function "reduce" like this :
(reduce '(OR 0 (AND A1 A2)))
would yield
(AND A1 A2)
i firstly tried to create base rules , so i defined
the following identities:
(AND 1 S) == S,
(OR 0 S ) == S,
(AND 0 S) == 0,
( OR 1 S) == 1,
(NOT O) == 1,
(NOT 1) == 0.*
i was thinking of defining 6 functions , one for each rule , and then
call them one by one in a wrapper , i am new to lisp so i don't have a clue to implement that , i made it in java once , but i dont know how to handle such problem using the syntax of lisp so please help me ..
Given the complexity of your solution, here's my implementation that's a lot shorter and more readable:
(defun reduc (exp)
(if (atom exp)
exp
(flet ((helper (op args n) ; and and or is nearly the same code so we factor it out
(let ((newargs (remove n args)) (cn (- 1 n)))
(cond
((null newargs) n)
((some (lambda (e) (eql cn e)) newargs) cn)
((null (cdr newargs)) (car newargs))
((cons op newargs))))))
(let ((op (car exp)) (args (mapcar #'reduc (cdr exp))))
(ecase op
((not) (if (= 1 (length args))
(let ((arg1 (car args)))
(if (and (numberp arg1) (<= 0 arg1 1)) (- 1 arg1) exp))
(error "'not' must have exactly one parameter")))
((and) (helper op args 1))
((or) (helper op args 0)))))))
Testing:
? (reduc '(OR 0 (AND A1 A2)))
(AND A1 A2)
? (reduc '(OR 0 (AND A1 1 A2)))
(AND A1 A2)
? (reduc '(or ERROR (not 0)))
1
? (reduc '(AND ERROR (not 0)))
ERROR
? (reduc '(OR 0 (AND A1 0)))
0
? (reduc '(OR 0 (AND A1 1)))
A1
i finally came up with this solution .
(defun simplify (EXPR)
(simplify-expr NIL EXPR))
(defun simplify-expr (EXPR1 EXPR2)
(cond
((or (atom EXPR2) (equal EXPR1 EXPR2)) EXPR2)
(T (simplify-expr EXPR2 (simplify-boolean-expr EXPR2)))))
(defun simplify-boolean-expr (EXPR)
(cond
((and (equal (first EXPR) `and) (>= (length EXPR) 3))
(simplify-and-expr (rest EXPR)))
((and (equal (first EXPR) `or) (>= (length EXPR) 3))
(simplify-or-expr (rest EXPR)))
((and (equal (first EXPR) `not) (= (length EXPR) 2))
(simplify-not-expr (rest EXPR)))
(T
(error "~S is not a valid circuit descriptor expression or has an unknown operator." EXPR))))
(defun simplify-and-expr (EXPR)
(let ((SIMPLIFIED_EXPR (remove `T (remove-duplicates EXPR))))
(cond
((null SIMPLIFIED_EXPR) `T)
((member `NIL SIMPLIFIED_EXPR) `NIL)
((null (second SIMPLIFIED_EXPR)) (first SIMPLIFIED_EXPR))
(T (cons `and (simplify-operand SIMPLIFIED_EXPR))))))
(defun simplify-or-expr (EXPR)
(let ((SIMPLIFIED_EXPR (remove `NIL (remove-duplicates EXPR))))
(cond
((null SIMPLIFIED_EXPR) `NIL)
((member `T SIMPLIFIED_EXPR) `T)
((null (second SIMPLIFIED_EXPR)) (first SIMPLIFIED_EXPR))
(T (cons `or (simplify-operand SIMPLIFIED_EXPR))))))
(defun simplify-not-expr (EXPR)
(cond
((equal (first EXPR) `NIL) `T)
((equal (first EXPR) `T) `NIL)
((and (listp (first EXPR)) (equal (first (first EXPR)) `not))
(first (rest (first EXPR))))
(T (cons `not (simplify-operand EXPR)))))
(defun simplify-operand (OPERAND_LIST)
(cond
((null OPERAND_LIST) NIL)
((atom (first OPERAND_LIST))
(cons (first OPERAND_LIST) (simplify-operand (rest OPERAND_LIST))))
(T
(cons (simplify-expr NIL (first OPERAND_LIST)) (simplify-operand (rest OPERAND_LIST))))))
it takes (nil , T) for (0 , 1) and reduces any boolean expression , i tried it and it works fine .
I am trying to create a lisp function that evaluates and simplifies multiplication and addition arithmetic.
The function should work such that when the user calls a function
(simplify-Mult'(* 1 2)) it prints just 2 or
(simplify-Mult '(*0 3 3 7)) prints just 0.
So far I have this
(defun simplify-multiplication (lis)
(if (not (null lis))
(if (member '0 lis) 0
(if (member '1 lis) cdr lis
(if (listp (car lis))
(cons(simplify(car lis)))
(if (numberp (car lis))
(if (null (cdr lis))
lis
(cons (car lis) (simplify-multiplication (cdr lis)))
)
(if (eq (car lis) '+)
(cons (car lis) (simplify-multiplication (cdr lis)))
(if (eq (car lis) '*)
(cons (car lis) (simplify-multiplication (cdr lis)))
lis
)
)
)
)
)
)
)
)
You can write one single function simplify which applies the simplification rules for both multiplication and addition. If you want to recursively simplify an expression, first you have to simplify each one of the arguments and then apply the simplification rules for the corresponding operation.
The following could be a starting point:
(defun simplify (lis)
(if (atom lis)
lis
(let ((args (mapcar #'simplify (cdr lis))))
(cond
((eql (car lis) '+)
(setq args (remove 0 args))
(case (length args)
(0 0)
(1 (car args))
(otherwise (cons '+ args)) ))
((eql (car lis) '*)
(if (member 0 args)
0
(progn
(setq args (remove 1 args))
(case (length args)
(0 1)
(1 (car args))
(otherwise (cons '* args)) ))))
(T (cons (car lis) args)) ))))
You would probably want to add other simplification rules, such as (* 2 (* 3 4)) => (* 2 3 4), etc.. as well as detecting wrong expressions such as (simplify '(+)).
This is my function that's supposed to implement infix evaluation for * and + operations.
(defun calculate(l)
(cond
((eql (cadr l) '+) (+ (car l) (cddr l)))
((eql (cadr l) '*) (- (car l) (cddr l)))
)
)
When I run this with the list '(3 + 4) it gives me an error saying "(4) is not a number". Any ideas what the problem might be?
Symbols can be called as functions. Thus your code is just this:
(defun calculate (l)
(funcall (second l) (first l) (third l)))
or
(defun calculate (l)
(destructuring-bind (arg1 op arg2)
l
(funcall op arg1 arg2)))
Example:
CL-USER 77 > (calculate '(20 + 30))
50
The part with (cddr l) should be (caddr l). You have to access the first element of the list, not the list. The code should be then:
(defun calculate(l)
(cond
((eql (cadr l) '+) (+ (car l) (caddr l)))
((eql (cadr l) '*) (- (car l) (caddr l)))
)
)
beginner in LISP here. I'm preparing myself for my upcoming exam in LISP and I've come across a problem I can't solve, so I was hoping someone more experienced might help me out.
Anyways, here is my problem :
You are given a list that may contain lists as elements. Your task is to delete an atomic element at a given position.
The list and the position are given as input parameters.
Example : Position=5 , List=(1 (2 3) ((4)) (5 (6))) , should return (1 (2 3) ((4)) ((6))).
Here is what i got so far...(PS the code below works thanks to the assistance of imMaw , you can check edit to see my previous mistake ).
(defun number_of_atoms(List)
(atoms List 0)
)
(defun atoms(List Number)
(cond
((null List) Number)
((atom (car List)) (atoms (cdr List) (+ 1 Number)))
((+ (atoms (car List) Number) (atoms (cdr List) 0)))
)
)
(defun deleteElement(Pos List)
(deleteElementAcc Pos 1 List)
)
(defun deleteElementAcc(Pos CurrPos List)
(cond
((null List) nil)
((and (atom (car List)) (not(eql CurrPos Pos))) (cons (car List) (deleteElementAcc Pos (+ CurrPos 1) (cdr List))))
((and (atom (car List)) (eql CurrPos Pos)) (deleteElementAcc Pos (+ CurrPos 1) (cdr List)))
((cons (deleteElementAcc Pos CurrPos (car List))
(deleteElementAcc Pos (+ CurrPos (number_of_atoms(car List))) (cdr List))))
)
)
Why are you spelling Pos and CurrPos with z's in half the places?
And the problem in your code lies in the last branch of the cond. When you recurse on the cdr of List, CurrPos needs to be advanced by the number of elements in (car List). And a simple (length List) won't work, because it needs to recursively count elements in sublists.
Edit: more elaboration
Say we call
(deleteElement 3 '((1 2) (3 4)))
You turn this into
(deleteElementPos 3 1 '((1 2) (3 4))),
which falls into the last case of the cond, and you get
(cons (deleteElementAcc 3 1 '(1 2))
(deleteElementAcc 3 1 '((3 4))))
notice that currPos is wrong for the cdr of the list - it should be 3, not 1. You actually want your code to turn into
(cons (deleteElementAcc 3 1 '(1 2))
(deleteElementAcc 3 (+ 1 2) '((3 4))))
because (car List) has 2 elements in it.
So, you just need to change
(deleteElementAcc Pos CurrPos (cdr List))
into
(deleteElementAcc Pos (+ CurrPos (recursive-length (car List))) (cdr List))
and program recursive-length, which is a pretty simple function. It should count elements in sublists, so for example (recursive-length '((1 2) ((3)))) returns 3.
While solving this problem in just any way isn't particularly difficult, it is really non-trivial to solve it well. By well I mean both big O's and code complexity, just as well as handling of corner cases. I'm not sure this code will handle even improper lists, and it has parts that could be certainly reduced in verbosity, but, technically, it is there. It walks through the tree in exactly O(n), where n is the number of elements in the tree, and it uses O(n + 2 * (maximum depth)) space, i.e. it will use the memory already used by the tree and in addition the memory proportional to the maximum depth of the tree.
No attempt was made to identify cyclic lists or duplicates:
(defun remove-from-tree-linear (tree &rest positions)
(loop with node = tree
with nilcar = (gensym)
with positions = (sort (remove-duplicates positions) #'<)
with counter = 0
with copy = nil
with root = nil
with stack = nil
with backrefs = nil
while (or node stack) do
(cond
((null node)
(setf backrefs (cdr backrefs))
(when (car stack)
(setf copy (car backrefs)))
(setf node (car stack) stack (cdr stack)))
((consp (car node))
(if copy
(if (eq (car copy) nilcar)
(setf (car copy) (list nilcar)
copy (car copy)
(car backrefs) copy)
(setf (cdr copy) (list nilcar)
copy (cdr copy)
(car backrefs) copy))
(setf copy (list nilcar)
root copy))
(setf backrefs (cons copy backrefs))
(setf stack (cons (cdr node) stack)
node (car node)))
(t (if (and positions (= counter (car positions)))
(setf positions (cdr positions))
(if copy
(progn
(if (eq (car copy) nilcar)
(setf (car copy) (list (car node))
copy (car copy))
(setf (cdr copy) (list (car node))
copy (cdr copy)))
(setf (car backrefs) copy))
(setf copy (list (car node))
root copy
backrefs (list copy))))
(setf node (cdr node))))
(incf counter)
finally (return root)))
(define length1
(lambda (lat)
(cond
((null? lat) 0)
(else (+ 1 (length1 (cdr lat)))))))
for example: display the number (or anything else) when call length1 in cond
for common lisp you can use (progn (...) (...) ...) to group together multiple expressions into one.
the equivalent in scheme is (begin (...) (...) ...).
so:
(define length1
(lambda (lat)
(cond
((null? lat) 0)
(else (begin (display "hello world") (+ 1 (length1 (cdr lat))))))))
or maybe you want:
(define length1
(lambda (lat)
(cond
((null? lat) 0)
(else (let ((or-anything-else (+ 1 (length1 (cdr lat)))))
(display or-anything-else)
or-anything-else)))
and that's about exhausted my patience.