memory error

Discussion in 'AutoCAD' started by cnbetts, Nov 16, 2004.

  1. cnbetts

    cnbetts Guest

    I am getting a the following error; "Hard error occurred - internal stack limit reached (simulated)" in one of my autolisp functions. I have double checked the source code and even rewritten and ran the same function in DrScheme (where it works fine), so I am confident there is nothing wrong with the code. I have two questions:
    1. Is there a hard limit to function recursion in autolisp (I have AutoCAD 2004)?
    2. Can I increase autolip's stack space, and if so, how?
    Thanks for any assistance.
     
    cnbetts, Nov 16, 2004
    #1
  2. cnbetts

    Doug Broad Guest

    I agree with Jon. It is still highly likely that you have a mistake
    in your code. The only time I get that message is when I fail to
    correctly write the recursive cond by checking for the logical
    end condition first. The order of checks in a recursive cond is
    of critical importance.

    I have yet to see a practical situation that recursion could not do with
    ACAD 2000+ that iteration could do. Iteration is often 10-15% faster
    though.

    Regards,
    Doug

    (simulated)" in one of my autolisp functions. I have double checked the source code and
    even rewritten and ran the same function in DrScheme (where it works fine), so I am
    confident there is nothing wrong with the code. I have two questions:
     
    Doug Broad, Nov 16, 2004
    #2
  3. cnbetts

    liftedaxis Guest

    these guys are way off-base.
    recursion is, in any language, the single-most efficient way to achieve many large computational tasks. Take as the simplest example, finding a large prime number. Without recursion, you'd lock up your computer for weeks.
    The simplest reason why your recursive loop is hitting a stack limit is probably that you aren't declaring your local variables. Also, you might want to double-check your "switch-back" possibilities -- for instance, in many recursive loops that we have, checking objects that are connected to each other, you have to double-check that the entity you are about to recurse to isn't either (1) the object you are currently processing or (2) an object you've already processed.
    go ahead and post the basics of your loop and I can take a look at it.

    --Jeremiah
     
    liftedaxis, Nov 16, 2004
    #3
  4. cnbetts

    Doug Broad Guest

    <ROTFL> ;-)

    Thanks Jeremiah. You made my day.

    computational tasks. Take as the simplest example, finding a large prime number. Without
    recursion, you'd lock up your computer for weeks.
    you aren't declaring your local variables. Also, you might want to double-check your
    "switch-back" possibilities -- for instance, in many recursive loops that we have,
    checking objects that are connected to each other, you have to double-check that the
    entity you are about to recurse to isn't either (1) the object you are currently
    processing or (2) an object you've already processed.
     
    Doug Broad, Nov 16, 2004
    #4
  5. cnbetts

    Tom Smith Guest

    these guys are way off-base.

    Jeremiah, apparently you don't know who Jon and Doug are, and haven't seen
    the many threads in which these issues have been taken apart in infinite
    detail.
     
    Tom Smith, Nov 16, 2004
    #5
  6. There is no actual stack limit set in Visual LISP. The "(simulated)" limit
    exists only if the VLIDE has been run. If you are certain your code is
    correct you can try running it without starting the VLIDE.

    Please note that you will need to restart AutoCAD. Closing the VLIDE window
    does not remove the "(simulated)" stack check.


    limit reached (simulated)" in one of my autolisp functions. I have double
    checked the source code and even rewritten and ran the same function in
    DrScheme (where it works fine), so I am confident there is nothing wrong
    with the code. I have two questions:
     
    Steve Mighetto, Nov 16, 2004
    #6
  7. cnbetts

    David Bethel Guest

    As far back as R10 & R11, standard AutoLisp HEAP + STACK could not
    exceed 45,000 bytes. The total extended AutoLisp of HEAP + STACK had a
    14MB limit. I think these values still hold true in plain AutoLisp. So
    there has always been a physical limit to memory usage. I believe these
    were changed to preset values in R12 whereas you could specify them in
    prior releases. -David
     
    David Bethel, Nov 16, 2004
    #7
  8. cnbetts

    liftedaxis Guest

    i present two case examples, both sharing highly similar code.
    Electrical diagram, with each object and stretch of wire having extended entity data saving each piece of connected equipment. Alternately, irrigation equipment, with likewise each piece of pipe or equipment saving what they are connected to.
    recursion will be the most efficient way to manipulate either drawing. though it will exponentially faster than any iteration routine, speed won't necessarily be noticeable on any modern machine.
    we're looking at the difference between:
    recurse objectx
    foreach i objectx
    recurse objectx

    as compared to:
    foreach i drawing
    foreach objectx drawing
    foreach j drawing
    if j = objectx

    the difference is astounding.

    hey, at least i was able to make him laugh.

    --J
     
    liftedaxis, Nov 16, 2004
    #8
  9. There is no 14MB limit as of AutoCAD 2000. Visual LISP replaced the
    original XLISP based AutoLISP in AutoCAD 2000. When that happened the hard
    coded HEAP + STACK limit simply went away. The size is now limited only by
    the amount of virtual memory available on the system.

    Saying "plain AutoLISP" is an easy way to say you are not using any of the
    language extensions that became available with Visual LISP but Visual LISP
    is what you are running if you have AutoCAD 2000 or above. An easy way to
    see this is to type "(ver)" in at the command line.
     
    Steve Mighetto, Nov 17, 2004
    #9
  10. cnbetts

    cnbetts Guest

    Jeremiah,
    Thanks for the reply and the offer to look at my code, I'll take you up on that. I agree that recursion is very clean and efficient. In fact, the function in question is really just a programming exercise as I have been trying to write more strict "functional" code lately. Some additional background info: The code does work on relatively small numbers (x < 20000). I have written a comparable function using iteration and they give the same results (but the iteration function does not cause an error on larger numbers). I get the same error whether or not VLIDE has been run. Virtually identical code sort of runs correctly in a DrScheme interpreter, correct output but as the input number gets big the function gets very, very SLOW. Thanks for your time.

    Chris

    Here's the code:
    (Note- xufl is a list containing the unique prime factors of x)

    ;accept: y = INTEGER, xufl = LIST
    ;return: BOOLEAN (true if common factors)
    (defun get-totients (y xufl)
    (if xufl
    (if (= (rem y (car xufl)) 0)
    t
    (get-totients y (cdr xufl)))
    nil))

    ;accept: x,y = INTEGER, xufl,xtl = LIST
    ;return: LIST (totatives of x)
    (defun get-totient-list (x y xufl xtl)
    (if (< y x)
    (if (get-totients y xufl)
    (get-totient-list x (+ y 1) xufl xtl)
    (get-totient-list x (+ y 1) xufl (cons y xtl)))
    (reverse xtl)))
     
    cnbetts, Nov 19, 2004
    #10
  11. cnbetts

    liftedaxis Guest

    first, it'd be nice if you could include an example of the initial values of x, y, xufl, and xtl.
    second, include some documentation on what each varaible is, and what they are doing.
    all that aside, the first thing I noticed, is that you are never modifying the xufl list -- get-totients does a cdr on it, but it isn't changed. so it seems this routine is going to just keep running forever without modifying xufl. that's probably your main error.

    then, it just seems that the line:
    (get-totient-list x (+ y 1) xufl (cons y xtl))
    should be:
    (get-totient-list x (1+ y) xufl (cons (1+ y) xtl))
    yes?

    but the main thing, especially with recursive loops like this, is some documentation, so that you (and people like me) can see what the heck is going on. for instance, what is xtl? shouldn't those two recursive calls to get-totient-list be setting xtl to the results? what are the exit conditions? what is this routine testing for?

    anyway, let me know if that helped at all. and with a little more info, I can try to help more.

    --Jeremiah
     
    liftedaxis, Nov 19, 2004
    #11
  12. cnbetts

    cnbetts Guest

    Sorry, here's (hopefully) all the relevant info: the purpose of the functions is for get-totient-list to return the list of totatives for x. Initial values for get-totient-list are:
    x = integer in question (never changed)
    y = integer - initial value of 1, then y+1 up to x
    xufl = list of unique prime factors of x (never changed in get-totient-list)
    xtl = list of totatives of x (ultimate return value)

    get-totients is supposed to compare y to each number in xufl and test if there are any common factors. If a common factor is found it should end and return TRUE, if not, it should end (after running through xufl) and return FALSE.

    It is my understanding that because, once I am inside get-totients, I keep calling get-totients recursively with (cdr xufl) so that the parameter xufl will eventually be nil (e.g., cdr of a one-member list) so that the first if-statement will evaluate to false and get-totients will end and return nil to get-totient-list. With a small enough value for x, I get a correct result fairly quickly so get-totients is not looping forever. I was thinking that maybe the opposite condition might be a problem; when I do find a common factor and get-totients returns TRUE but does not necessarily run through all values of xufl? Maybe since xufl never evaluates to nil within that particular function call. What do you think?

    Again, with my recursive calls to get-totient-list, it is my understanding that passing xtl to get-totient-list as a parameter is setting xtl to the results without the need for a setq. Is this incorrect?

    I really appreciate the assistance.

    Chris
     
    cnbetts, Nov 19, 2004
    #12
  13. cnbetts

    liftedaxis Guest

    can you give me an example of what it's supposed to return?

    it seems you really need a top-level function like this:
    (defun gettots (x)
    ; we want a list of totatives of x
    (get-totient-list x 1 nil nil)
    ) ; gettots

    right?
    but what is the list it should be returning?
    I just need an example case.
    thanks.

    --Jeremiah
     
    liftedaxis, Nov 19, 2004
    #13
  14. cnbetts

    liftedaxis Guest

    in the meantime, here's what I've changed it to:

    (defun get-totients (y xufl)
    ; let's divide y by everything in xufl, see if they have any common factors
    (if xufl
    (if (zerop (rem y (car xufl)))
    t
    (get-totients y (cdr xufl))
    ) ; if
    ; xufl is still empty, so we need to divide x by y
    (zerop (rem x y))
    ) ; if
    ) ; defun

    (defun gettots (x / i xufl)
    ; we want a list of totatives of x
    (setq i (1- x))
    (while (> i 0)
    (if (get-totients i xufl)
    (setq xufl (cons i xufl))
    ) ; if
    (setq i (1- i))
    ) ; while

    xufl
    ) ; gettots

    I started by replacing your basic recursive loop with a much simpler itiration one. But that was never returning anything, so I realized you calc function needs to account for xufl initially being nil, so it should divide x by y.
    this way, it at least returns a factorial list, but I don't think that's what you want. it's at least better than returning every number less than x, which is what the initial code was doing.

    --Jeremiah
     
    liftedaxis, Nov 19, 2004
    #14
  15. cnbetts

    cnbetts Guest

    The ultimate goal is for get-totient-list to return the totatives of x as a list. The totatives of x are all positive integers < x that are relatively prime to x (contain no factors in common with x).
    Example for x=24, the call to get-totient-list is
    (get-totient-list 24 1 (2 3) nil) -- Note that (2 3) is the unique prime factor list for 24 (i.e., the prime factor list for 24 is (2 2 2 3), but I only need to check for factors of 2 once for each value of y, so I can reduce this to a list of unique prime factors).
    Next, I need to test all integers 1 <= y < 24 to see if 2 or 3 are factors of y. If they are, I disregard that value of y, if they are not (meaning that particular value of y is relatively prime to 24) then I add that value of y to xtl.
    So for x=24, get-totient-list should return the value of xtl as the list (1 5 7 11 13 17 19 23).
    What is frustrating is that I get correct results for x < 20000 (approximately), so its not that the function doesn't work at all, it just cannot process large values for x.
    Also, I mentioned that the function gives correct results for all values of x in DrScheme (which is very similar to Visual Lisp), but it is extremely slow, whereas almost all of my other functions that I have written as recursive routines have shown improvements in execution time. So on some level the program is working, but there must be a serious flaw somewhere in memory utilization that DrScheme can handle but Visual Lisp cannot. Let me know if you have any ideas. Thanks.

    Chris
     
    cnbetts, Nov 19, 2004
    #15
  16. cnbetts

    cnbetts Guest

    Thanks a lot, with the few minor changes shown below, your gettots function works perfectly.

    (defun gettots (x / i xufl xtl)
    ;we want a list of totatives of x
    (setq i (fix x)
    xufl (get-unique-members (get-prime-factor-list x) ()) ; xufl is returned by other existing functions, value is never nil
    xtl ()) ; list of totatives of x, initially set to nil
    (while (> (setq i (1- i)) 0)
    (if (not (get-totients i xufl))
    (setq xtl (cons i xtl))
    ) ; if
    ) ; while
    xtl) ; gettots

    It is actually very similar to what I had as my original iterative function. But as I said, I have been using these functions as a programming exercise in an attempt to write cleaner, more "elegent" (in my opinion), purely recursive code, without using any local variables. I still (stubbornly) want to do it.

    If you get a chance take a look at my 15:46 (PST) reply and see if that gives you any other ideas. By the way, I know I am terrible at commenting my code. I am the only programmer at my company and nobody else ever looks at my code, so I get really lazy on comments. So thanks a lot for searching through everything. I really appreciate your time.
     
    cnbetts, Nov 20, 2004
    #16
  17. cnbetts

    cnbetts Guest

    Over the weekend I did some additional research on recursion vs iteration, which was very informative. I also fixed my DrScheme functions (using pure recursion) and my Visual Lisp functions (using pure iteration), so my preoccupation with "elegant" code is satisfied. I seems like the recursive functions are a little faster but that is probably the different environments as much or more than the the programming style. Thanks a lot to everyone who replied.

    Chris
     
    cnbetts, Nov 22, 2004
    #17
  18. cnbetts

    liftedaxis Guest

    glad to help.
    I had some thoughts over the weekend as well. The first thought was to add on database connectivity, assuming the purpose of the routine is to locate large prime numbers -- by saving the primes found, you can just instantly start at the last one checked, say 2 ^ 20 + 1.
    Secondly, it seems it would benefit to follow other prime number tracking tricks, such as beginning from 0.5 * x.
    Lastly, the basic loop of your function really should be iterive, but the meat of it, the gettotients subroutine, is always going to be faster being recursive.
    If you want to have more fun with recursion, you can take a look at a previous post of mine regarding the TEA encryption algorithm -- integrate that with your large prime numbers, and you'll have a wicked encryption engine.

    --Jeremiah
     
    liftedaxis, Nov 22, 2004
    #18
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.