Boosting AutoLISP Performance

  • Controlling the Machine is no longer being updated. Don't worry, though, you can still follow Nate Holt at his new blog, AutoCAD Electrical Etcetera. You'll find it at http://nateholt.wordpress.com. Or you can subscribe to his feed to get latest words of wisdom automatically: http://nateholt.wordpress.com/feed/. You also can continue to view the Controlling Machine archives for Nate's AutoCAD Electrical tips and tricks.

    About Nate

Latest Post

  • Boosting AutoLISP Performance
    November 7, 2008, 09:25 PM Nate Holt

    I learned this the hard way... and am happy to share it now.

    CONS versus APPEND

    The cons function adds an element to the beginning of a list. The append function can be used to give the equivalent of adding an element to the beginning or end of a list.

    Using the cons function can be MUCH faster than using append to build up a large list.

    We'll run two tests to create a dummy list of 10,000 integer numbers. The first test is using the "cons" function. Appload and type test1 [enter] at the command prompt.

    (defun c:test1 ( / )
      (setq i 1)
      (setq lst nil) ; start out with a blank list
      (repeat 10000
        (setq lst (cons i lst)) ; add next element to beginning of list
        (setq i (1+ i))
      )
      (setq lst (reverse lst)) ; put list back into correct order
      (princ)
    )

    The second test yields the same result but uses the "append" function:

    (defun c:test2 ( / )
      (setq i 1)
      (setq lst nil) ; start out with a blank list
      (repeat 10000
        (setq lst (append lst (list i))) ; append next element on to end of list
        (setq i (1+ i))
      )
      (princ)
    )

    The first test using "cons" builds the 10,000 element list in memory in less than 0.01 seconds (on my average notebook).The second test using "append" builds the exact same 10,000 element list in memory but takes a full 3.55 seconds to execute ( ! ). Dealing with large lists, it appears that the "cons" function is many, many times faster.

    FOREACH versus NTH

    Let's say you need to cycle through a huge list, one list element at a time. There are two different functions that can cycle through a list, "foreach" and "nth" combined with a "while" loop. When dealing with a very large list, the "foreach" function can be much faster than using a while loop / nth function to index through the list.

    These tests use the 10,000 element list held in memory created be either of the above two tests. This next test uses "foreach" to cycle through the 10,000 element list.

    (defun c:test3 ( / )
      ; use 10,000 element "lst" created by test1 or test2
      (setq find_int (getint "\nFind integer="))
      (setq foundit nil)
      (foreach x lst
        (if (AND (not foundit) (= x find_int))
          (progn
            (setq foundit T)
            (princ " found") 
        ) )   
      )
      (princ)
    )

    This next test does the same thing but uses a "while" loop and the "nth" function to index its way through the 10,000 element list:

    (defun c:test4 ( / )
      ; use 10,000 element "lst" created by test1 or test2
      (setq find_int (getint "\nFind integer="))
      (setq foundit nil)
      (setq ix 0)
      (setq slen (length lst))
      (while (AND (not foundit)(< ix slen))
        (if (= (nth ix lst) find_int) ; look for match
          (progn ; Found the target element
            (setq foundit T)
            (princ " found") 
        ) )
        (setq ix (1+ ix))  
      )
      (princ)
    )

    For the test, looking for integer value 5000 (halfway into the list). The "foreach" function finds and exits in less than 0.01 second. The while loop using the "nth" function finds and exits in 0.07 seconds. Using foreach is significantly faster in processing this large list.

    [UPDATE: here's another...]

    MEMBER versus WHILE / NTH

    Let's say you have two very large, parallel lists. You need to search the first list, "lst", for a specific element. If found, then go to the parallel list "lst2" and pull out the associated value.

    In the first test, we'll just use a "while" loop and pull out each item from the first "lst" and look for a match. We'll track where we are by incrementing an index counter "ix". When match found then we will use "nth ix" to get the value from the parallel list.

    (defun c:test5 ( / )
      ; "lst" = first list to search
      ; "lst2" = parallel data list
      (setq find (getstring " first list element ="))
      (setq ix 0)
      (setq foundit nil)
      (setq slen (length lst))
      (while (AND (not foundit) (< ix slen))
        (if (= (nth ix lst) find)
          (progn ; found target element in "lst" list
            (setq foundit T)
            (setq parallel_val (nth ix lst2)) ; pull out of parallel list
            (princ " found=") 
            (princ parallel_val)
        ) )
        (setq ix (1+ ix)) ; increment index   
      )
      (princ)
    )

    The alternative is to use the "member" function to search a list for the first occurance of a given element. Here is the same funtion using "member" instead of a while loop to find and pull out the data from the parallel list:

    (defun c:test6 ( / )
      ; "lst" = first list to search
      ; "lst2" = parallel data list
      (setq find (getstring " first list element ="))
      (if (setq x (member find_int lst))
        (progn ; found target element in "lst" list
          ; Pull out value from same position in
          ; the parallel "lst2" list
          (setq parallel_val (nth (- (length lst)(length x)) lst2))
          (princ " found=") 
          (princ parallel_val)
        )
      )
      (princ)
    )

    For test5 on a set of 10000 element lists, the average search and return time was 0.11 seconds on my machine. For the exact same result using the "member" function in test6, the time was 0.0 seconds - not measurable on my machine. Significant improvement!

    0 Comment | Add Comment Controlling the Machine >

Comments



You must be logged in to post a comment.

Subscribe to Blog

Want to keep up with the latest? Subscribe to the RSS feed today.

RSS

Tags

You must be logged in to add a tag.

Send to a Peer

You must login to share pages.

Feedback

Tell us what you think of the site.

Send Feedback