Author Topic: Structures in AutoLISP  (Read 5483 times)

0 Members and 1 Guest are viewing this topic.

hermanm

  • Bull Frog
  • Posts: 282
Structures in AutoLISP
« on: July 01, 2009, 07:35:27 PM »
Inspired by this thread:

http://discussion.autodesk.com/forums/thread.jspa?threadID=733295&tstart=30

attached file is work in progress.

Constructive criticism always welcome.

Code: [Select]
Sample usage:

Command: (load "AXStruct")

AXStruct V0.6 © 2009 Herman Mayfarth.

Command: (axstruct 'dog (list 'breed 'name 'sex 'color 'wt 'tagno))
((DOG (BREED . 0) (NAME . 1) (SEX . 2) (COLOR . 3) (WT . 4) (TAGNO . 5)))

Command: (axstruct 'cat (list 'variety 'name 'sex 'color 'wt))
((CAT (VARIETY . 0) (NAME . 1) (SEX . 2) (COLOR . 3) (WT . 4)) (DOG (BREED .
0)
(NAME . 1) (SEX . 2) (COLOR . 3) (WT . 4) (TAGNO . 5)))

Command: (axstruct 'horse (list 'breed 'name 'sex 'color 'height 'weight))
((HORSE (BREED . 0) (NAME . 1) (SEX . 2) (COLOR . 3) (HEIGHT . 4) (WEIGHT .
5))
(CAT (VARIETY . 0) (NAME . 1) (SEX . 2) (COLOR . 3) (WT . 4)) (DOG (BREED .
0)
(NAME . 1) (SEX . 2) (COLOR . 3) (WT . 4) (TAGNO . 5)))

Command: (axstruct-types)
(HORSE CAT DOG)

Command: (setq mydog (axstruct-new 'dog (list "Bull Terrier" "George" "Male"
"White" 65.0 "B00123")))
(DOG #<safearray...>)

Command: (axstruct->list mydog)
(DOG "Bull Terrier" "George" "Male" "White" 65.0 "B00123")

Command: (axstruct-getval mydog 'name)
"George"

Command: (axstruct-setval mydog 'wt 70.0)
70.0

Command: (axstruct->list mydog)
(DOG "Bull Terrier" "George" "Male" "White" 70.0 "B00123")

Command: (setq newcat mydog)
(DOG #<safearray...>)

Command: (if (not (eq (car newcat) 'cat)) (progn (princ "\nThis ain't no
cat,
Leroy!")(princ)))

This ain't no cat, Leroy!

Command: (setq stray-dog (axstruct-new 'dog nil))
(DOG #<safearray...>)

Command: (axstruct->list stray-dog)
(DOG nil nil nil nil nil nil)

Command: (axstruct-setval stray-dog "sex" "Female")
"Female"

Command: (axstruct-setval stray-dog 'wt 85)
85

Command: (axstruct-setval stray-dog "color" "Brown")
"Brown"

Command: (axstruct->list stray-dog)
(DOG nil nil "Female" "Brown" 85 nil)



If you don't know where you are going, you might not get there.
  - L.P. Berra

CAB

  • Global Moderator
  • Seagull
  • Posts: 10369
Re: Structures in AutoLISP
« Reply #1 on: July 02, 2009, 11:23:33 AM »
Herman,
Looks like a set of database utilities.
For me it would be easier to use lists ILO safearrays.

I think Seven had a similar thread years ago. Maybe he will remember it?

I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: Structures in AutoLISP
« Reply #2 on: July 02, 2009, 12:25:57 PM »
Cool! can you stick #<SUBR @... > in there, and make a class   :laugh:

hermanm

  • Bull Frog
  • Posts: 282
Re: Structures in AutoLISP
« Reply #3 on: July 02, 2009, 12:26:44 PM »
For me it would be easier to use lists ILO safearrays

That was pretty much my comment to the OP of the referenced thread.

However, he sparked my curiousity, to see if there was a way to beat safearrays into a more usable form, and Tony T. provided a reference to a Common LISP primer online:

http://www.cs.ucla.edu/classes/winter04/cs161/l1/lispPrimer/lp.html

which in turn led to the semi-official reference:

http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/clm/node1.html

node which explains structures in Common LISP:

http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/clm/node168.html#SECTION002300000000000000000


One motivator for me is to see if using the AX datatypes to store data is faster or slower than sticking with native AutoLISP, in this instance.

Tony's post over on a.a.c.  was in fact just a bit of "sleight of hand," if you will, for accessing good old AutoLISP lists. ("Crude" was how he described his own demonstration.)

I intend to develop this a bit further.





If you don't know where you are going, you might not get there.
  - L.P. Berra

hermanm

  • Bull Frog
  • Posts: 282
Re: Structures in AutoLISP
« Reply #4 on: July 02, 2009, 12:30:30 PM »
Cool! can you stick #<SUBR @... > in there, and make a class   :laugh:

We'll see where this leads, Daniel.

I intend to at least allow nested structures (not there yet).

To quote our Governor, "I'll be back."
:)
If you don't know where you are going, you might not get there.
  - L.P. Berra

hermanm

  • Bull Frog
  • Posts: 282
Re: Structures in AutoLISP
« Reply #5 on: July 02, 2009, 03:58:53 PM »
Small update:
Code: [Select]
;;; Function: axstruct-create-accessors
;;; Params: symbol: symbol which is first element of structure
;;--------------
(defun axstruct-create-accessors (symbol / index param struct)
;;allow passing symbol as a string
  (if (= (type symbol) 'STR) (setq symbol (read symbol)))
;if the structure type is defined
  (if (setq index (member symbol (axstruct-types)))
;;get the structure definition
    (progn
      (setq index (- (length axstruct-structures) (length index))
            struct (nth index axstruct-structures))
;;create list-<type> function
      (setq stype (vl-symbol-name (car struct)))
      (eval
      (list 'defun
                  (read (strcat "list-" stype))
                  (list 'param)
                  (list
                    'if
                    (list
                      'eq
                      (list 'car 'param)
                      (list 'quote symbol)
                    )
                    (list 'axstruct->list 'param)
                  )
      );list
      );eval
;create new-<type> function
;;to do
;create get-<type>-<property> functions
;;to do
;create set-<type>-<property> functions
;;to do
    );progn
  );if
);axstruct-create-accessors

Sample usage:
Code: [Select]
Command: (axstruct-create-accessors 'dog)
LIST-DOG

Command: (axstruct-create-accessors 'cat)
LIST-CAT

Command: (list-dog mydog)
(DOG "Bull Terrier" "George" "Male" "White" 70.0 "B00123")

Command: (list-cat mydog)
nil

More later...
If you don't know where you are going, you might not get there.
  - L.P. Berra

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9277
Re: Structures in AutoLISP
« Reply #6 on: July 03, 2009, 11:59:55 AM »
I remember the idea not the thread. Chapter two of SICP; data abstraction and operations on rational numbers...yeah that was fun. I remember getting into it pretty deep; I even eventually tried to `make a class' for a more complex example. Not fun.

Why do people try and compiare Comon lisp and Autolisp; they have very little in common. Compire Scheme and Autolisp at least the languages are closer IMO.

I dont think the idea on a larger scale then simple structures is...`valid' at all.

Here is a small scale `structure' and `class' (about as complex as you should get IMO).
:)

Code: [Select]
(defun gcd (a b)
  ;; Find the greatest comon denom of a number
  (if (= b 0)
      a
      (gcd b (rem a b))))

(defun make-rat (n d / x)
  ;; support procedure to ''create'' a rational number
  ;; a ''class'' if you will.
  (setq x (gcd n d))
  (list (/ n x) (/ d x)))

(defun numer (x)
  ;; return the numerator of a rat class.
  (car x))

(defun denom (x)
  ;; return the denom of a rat class.
  (cadr x))

(defun print-rat (x)
  ;; support proced to print the rat class in a pretty format.
  (princ "\n ")
   (princ (numer x))
   (princ "/")
   (princ (denom x))(princ))

(defun add-rat (x y)
  ;; rat class addition.
  (make-rat (+ (* (numer x) (denom y))
               (* (numer y) (denom x)))
            (* (denom x) (denom y))))

(defun sub-rat (x y)
  ;; rat class subtraction
  (make-rat (- (* (numer x) (denom y))
               (* (numer y) (denom x)))
            (* (denom x) (denom y))))

(defun mul-rat (x y)
  ;; rat class multiply
  (make-rat (* (numer x) (numer y))
            (* (denom x) (denom y))))

(defun div-rat (x y)
  ;; rat class divide
  (make-rat (* (numer x) (denom y))
            (* (denom x) (numer y))))

(defun equal-rat? (x y)
  ;; support proced to see if one rat equals another.
  (= (* (numer x) (denom y))
     (* (numer y) (denom x))))


Trial run
Code: [Select]
(setq one-third (make-rat 1 3))
(print-rat (add-rat one-third one-third))


BTW, whats wrong with XML? You would be pairing key to data but...
“Common sense is not so common.” ~Voltaire

--> Donate to TheSwamp.org <--

hermanm

  • Bull Frog
  • Posts: 282
Re: Structures in AutoLISP
« Reply #7 on: July 03, 2009, 02:54:35 PM »
Well, I'm having fun, anyway.:)

Version 0.667 (the Neighbor of the Beast) is attached.

Features:

(axstruct-create-accessors) is complete.

At present it must be explicitly called once a structure is created. ITLR this should optionally be automatic.

Here is the function:
Code: [Select]
;;; Function: axstruct-create-accessors
;;; Purpose: create list-, new-, get-<type>-prop & set-<type>-prop functions
;;; Params: symbol: symbol which is first element of structure
;;--------------
(defun axstruct-create-accessors (symbol / index
                                           param1
                                           param2
                                           proplist
                                           struct
                                           stype)
;;allow passing symbol as a string
  (if (= (type symbol) 'STR) (setq symbol (read symbol)))
;if the structure type is defined
  (if (setq index (member symbol (axstruct-types)))
;;get the structure definition
    (progn
      (setq index (- (length axstruct-structures) (length index))
            struct (nth index axstruct-structures)
            stype (vl-symbol-name symbol);(car struct))
            proplist (mapcar 'car (cdr struct)))
;;create list-<type> function
      (eval
        (list 'defun
              (read (strcat "list-" stype));function name
              (list 'param1)
              (list ;check structure type
                'if
                (list
                  'eq
                  (list 'car 'param1)
                  (list 'quote symbol)
                )
                (list 'axstruct->list 'param1)
              )
        );list
      );eval
;create new-<type> function
      (eval
        (list 'defun
              (read (strcat "new-" stype))
              (list 'param1)
              (list 'axstruct-new stype 'param1)
        );list
      );eval
;create get-<type>-<property> functions
      (foreach prop proplist
        (eval
          (list 'defun
                (read (strcat "get-" stype "-" (vl-symbol-name prop)))
                (list 'param1)
                (list ;check structure type
                 'if
                 (list
                    'eq
                    (list 'car 'param1)
                    (list 'quote symbol)
                  )
                 (list 'axstruct-getval 'param1
                  (list 'quote prop)
                 )
                )
          );list
        );eval
      );foreach
;create set-<type>-<property> functions
      (foreach prop proplist
        (eval
          (list 'defun
                (read (strcat "set-" stype "-" (vl-symbol-name prop)))
                (list 'param1 'param2)
                (list ;check structure type
                 'if
                 (list
                    'eq
                    (list 'car 'param1)
                    (list 'quote symbol)
                  )
                 (list 'axstruct-setval 'param1
                  (list 'quote prop)
                  'param2
                 )
                )
          );list
        );eval
      );foreach
    );progn
  );if
);axstruct-create-accessors

So we can do this:

Code: [Select]
Command: (axstruct 'dog '(name breed sex color wt tagno))
((DOG (NAME . 0) (BREED . 1) (SEX . 2) (COLOR . 3) (WT . 4) (TAGNO . 5)))

Command: (axstruct-create-accessors 'dog)
SET-DOG-TAGNO

Command: !get-dog-name
#<SUBR @0ba57a8c GET-DOG-NAME>

Command: !set-dog-name
#<SUBR @0ba57d48 SET-DOG-NAME>

Command: !get-dog-breed
#<SUBR @0ba57b04 GET-DOG-BREED>

Command: !set-dog-breed
#<SUBR @0ba57dc0 SET-DOG-BREED

etc.

and:

Code: [Select]
Command: (setq lassie (new-dog nil))
(DOG #<safearray...>)

Command: (set-dog-name lassie "lassie")
"lassie"

Command: (set-dog-breed lassie "Collie")
"Collie"

Command: (list-dog lassie)
(DOG "lassie" "Collie" nil nil nil nil)

Command: (setq Rin-Tin-Tin (new-dog '("Rin Tin Tin" "German Shepherd" "Male"
"Black & Brown" 85 "002")))
(DOG #<safearray...>)

Command: (set-dog-wt Rin-Tin-Tin 90.5)
90.5

Command: (list-dog Rin-Tin-Tin)
(DOG "Rin Tin Tin" "German Shepherd" "Male" "Black & Brown" 90.5 "002")


There is no type checking at the element level, since the data is stored in a safearray of variants.

Hasta luego,

HM
If you don't know where you are going, you might not get there.
  - L.P. Berra

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9277
Re: Structures in AutoLISP
« Reply #8 on: July 05, 2009, 01:01:48 PM »
That's all that counts (having fun). You might as well take it as far as you can. Keep going.

I had a problem with the memory usage (theory only) aspect; I was affraid that the allocation and destruction of all the variables would chew up more memory then...well C++ is `managed' (is that the word for the dynamic garbage collection or whatever its called). Because of that i tried to use more Free variables instead of bound whenever i could, and then got lost in my code (black box will kill ya on large scale projects).  I was also hoping free vars would give me speed as well.

Later,

“Common sense is not so common.” ~Voltaire

--> Donate to TheSwamp.org <--

It's Alive!

  • BricsCAD
  • Needs a day job
  • Posts: 6963
  • AKA Daniel
Re: Structures in AutoLISP
« Reply #9 on: July 05, 2009, 09:46:17 PM »
Isn't that the whole point? I mean every time you modify an element in a list, a new
list is created and the old is put in garbage collection queue, where as Herman's struct
would not have that overhead, It seems that Herman's struct would be more efficient than a
list at using memory.

IMHO, the problem is the overhead of getval/setval may be greater than creating a new list.. we shall see

Please continue, I look forward in seeing your results

hermanm

  • Bull Frog
  • Posts: 282
Re: Structures in AutoLISP
« Reply #10 on: July 06, 2009, 01:24:08 AM »
Quote
IMHO, the problem is the overhead of getval/setval may be greater than creating a new list..

That is the $64 question.

Quote
we shall see

We shall, indeed.:)

thanks for the words of encouragement, Dan.

Later,

hm
If you don't know where you are going, you might not get there.
  - L.P. Berra

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9277
Re: Structures in AutoLISP
« Reply #11 on: July 06, 2009, 08:46:17 AM »
I'm most certainly interested as well!

I dont think i follow your thoughts but you guys are way over my head anyways so i will just sit back and watch (I dont want to muck up any progress with my muddling's).
“Common sense is not so common.” ~Voltaire

--> Donate to TheSwamp.org <--

hermanm

  • Bull Frog
  • Posts: 282
Re: Structures in AutoLISP
« Reply #12 on: July 08, 2009, 12:04:11 PM »
Version 0.75 is attached.
In this version:
1.accessor functions are automatic when a type is created
2.types may be redefined or deleted
3.partial initialization of a type instance is possible

new function definitions:
axstruct-redefine - redefine a structure type
axstruct-delete - delete a defined structure type - used by axstruct-redefine
axstruct-destroy-accessors - destroy accessor functions for a structure type - used by axstruct-delete

modified functions:
axstruct-getval - simplified index calculation
axstruct-setval - same as getval
axstruct-new - allow partial initialization

Usage:
Code: [Select]
Command: (axstruct 'dog '(name breed sex color))
SET-DOG-COLOR

Command: (list-dog (new-dog '(:color "White" :breed "Bull Terrier")))
(DOG nil "Bull Terrier" nil "White")

Command: (list-dog (new-dog '("Fred" "Mixed" :color "Brown")))
(DOG "Fred" "Mixed" nil "Brown")

Command: (list-dog (new-dog '(:name "Fido" "Bowser" "Mutt" "Male" "Black")))
(DOG "Fido" "Bowser" "Mutt" "Male")

Command: (list-dog (new-dog '(:name "Fido" "Mutt" "Male" :color "Black")))
(DOG "Fido" "Mutt" "Male" "Black")

Command: (list-dog (new-dog '(:name "Fido" "Mutt" "Male" :name "Bowser")))
(DOG "Bowser" "Mutt" "Male" nil)

Command: (axstruct-delete 'dog)
nil

Command: !list-dog
nil

Command: (axstruct 'dog '(name breed sex color))
SET-DOG-COLOR

Command: (axstruct-get-type 'dog)
(DOG (NAME . 0) (BREED . 1) (SEX . 2) (COLOR . 3))

Command: (axstruct-redefine 'dog '(name breed sex color tagno))
SET-DOG-TAGNO

Command: (axstruct-get-type 'dog)
(DOG (NAME . 0) (BREED . 1) (SEX . 2) (COLOR . 3) (TAGNO . 4))


Please note that redefining a type does not update instances of the type (analogous to block INSERTs in AutoCAD not updating attributes automatically when the block definition is changed.

to do:
axstruct-update - update instances of a redefined type

If you don't know where you are going, you might not get there.
  - L.P. Berra