freenode/#lisp - IRC Chatlog
Search
3:09:09
jeosol
In my bid to improve code design for clarity, maintainability, and extension, I try to think of better design so subsequently added codes are progressively better. That being said, I have some CLOS design question I'll like to discuss here.
3:14:09
jeosol
Let's say I want to write a program to optimize a car and I can optimize some aspects of the car, e.g., the type (sedan, SUV, ...), tire size (e.g., 20-inch, 22-inch, etc), number of seats (2,4,6), etc. The options (combinations) can be large but countable.
3:16:07
jeosol
So I want to design a CLOS class with goals stated earlier. I can construct one massive class (defclass optimize-car-type-tire-seat () ...) and have a bunch of slots
3:18:35
jeosol
but I will prefer to have it broken down into small units (classes) with the inheritance. So a user may say they want a sedan (for type), 20-inch tire size, but not sure about the seat. I can then create the instantiate the correct object where only the number of seats will be a variable
3:19:04
jeosol
and then the optimal condition is determined from the optimization. I apologize if this is not clear, but
3:19:34
White_Flame
and you have a list of information that needs to be completed in order to consider the car complete
3:23:40
jeosol
oh ok. it is a simple optimization problem, i imagine the car analogy was poor, if let's say, the tire was the variable in the above case. We then optimize for the tire size of thread based on the performance of the car in a given environment
3:25:13
jeosol
oh, ok. Ii see you want detail. It's stochastic optimization, GA, PS, etc. The actual technique is not the problem, but the idea is to be able to gather as much information and automatically determine what to optimize based on what the user has selected
3:25:30
White_Flame
well, the data representation might be more useful depending on how the optimization is
3:25:52
White_Flame
if you know that you have a fixed set of slots, then I would allow NIL in each to simply indicate whether it "has a value" or not, to the code
3:26:23
White_Flame
the annoying thing is that you have to check all pertinent slots for non-NILness to see if you've found enough stuff
3:26:41
White_Flame
however, if you have temporary values in those slots that you're searching through, then you might want a separate state indicator for each slot
3:26:55
White_Flame
and that sort of thing does get kind of annoying with forcing everything OO, and you might want more simple data structures
3:27:25
jeosol
I just pulled out my Sonja Keene book, and the closest example is the make-stream example (defun make-stream (device-type direction element-type name) ...) and there is a function (select-stream-class direction element-type device-type) which essentially determines the right stream class to create and creates the correct instance
3:29:57
jeosol
I agree with your comments White_Flame. I have a case that works but the derived cases (possible options) are becoming large to manage. The whole setup runs, but I am thinking may be the one large class, with appropriate slots and if something is nil, then it's not to be optimized. This option seems more manageable
3:30:55
jeosol
No it's not, I am trying to abstract the problem such that I can create the right class, and default the other parameters (based on other inputs the user will also specify).
3:31:50
White_Flame
I would think that would reside in whatever the optimization loop is, and the instance simply being the current data point for testing fitness
3:33:27
jeosol
So, class provides contains the settings for initializing the variables for optimization. So in the example I had above, you can have a case with multiple different car scenarios (optimizing car type, car size, ...) in the same optimization run
3:34:26
jeosol
With the single, massive class, you will have to process the results to figure out which type/scenario it was, but if I had the right classes to start with, I can tell from the class, and that can be used for subsequent step or optimization.
3:35:37
White_Flame
you have a list of key/value pairs, and each has some initialization state, some range of values to search over (presumably), and the entire set should be able to be tested & manipulated regardless of what the overall set of slots are
3:36:58
White_Flame
if you want to change the number of slots, that would be a pretty heavyweight change with classes, and scanning the slots
3:37:03
jeosol
hmm, guess, I am not explaining things clearly. The operations performed on the object during the optimization depends on the class, that's why I go that route. I define some defmethods on base classes.
3:38:43
White_Flame
that still sounds like a bag of CLOS objects, each representing a searchable value with its own definitions
3:40:47
jeosol
I agree with that, my point was for one of flexibility in code design. I have a few cases with inheritance for other problems with 2 or 3 levels/options. But here it is may be too much because of the number of options
3:41:34
jeosol
White_Flame, I am not actually, CLOS does fit the other aspects of the code I was writing very well (:before, :around, :after methods), I don't use it everywhere though.
3:43:11
jeosol
That's the repo for the application I am working on. It's a fairly large code base and careful code design was important to be able to manage it so far
3:45:27
White_Flame
sometimes it is more flexible and forward-compatible to use the dynamic properties of the language
3:46:16
White_Flame
I mean, it does need to dispatch on each individual adjustable value, that's well suited to defmethod on the class of the value
3:46:46
White_Flame
but it sounds like your main question is how to aggregate those adjustable values together, and that's where a looser dynamic data structure would work
3:49:11
jeosol
Yes, White_Flame. I am just shooting for better design. May a general class and just deal with the issues of scanning the slots.
3:52:27
White_Flame
however, there might be optimization benefits to using a class, depending on if you're CPU-bound
3:52:28
jeosol
hmm, but managing the additional functions for those cases will be harder to manage? you don't think.
3:53:41
White_Flame
well, it depends on where the work is focused. If the fitness function is massive, then you should optimize access of the values
3:54:19
White_Flame
if the mutation is the more complex part, then treating the aggregate as a simple collection makes it much easier to walk through your values to adjust
3:54:20
jeosol
the function evals are expensive, but the design considerations is one of ease to be able to change optimizations, or run optimization with one setting, and use conditions from one class into another seamlessly. The choice is also to simplify the search process
3:56:51
White_Flame
you also might be better served in creating a small DSL for this, to allow you both to represent all the bits easier, as well as be able to output precise code that runs dedicated to each value
3:58:55
jeosol
That's true. I asked something related and similar to this, and Dim Fontaine (?) suggested a DSL and writing some reader to take in simplify input and map accordingly.
3:59:52
jeosol
The issue is managing the many options and combinations, and also take advantage of some operations created for the base classes.
4:02:22
jeosol
Another analogy for the use case is: one needs to draw an arbitrary line in space by specify two points, (x1,y1,z1) and (x2,y2,z2) and there are constraints on the line length, (e.g., length within some interval) and location in space to maximize a resource.
4:04:07
nullnullnull
btw why sbcl --eval is not working like --load? (if i put the whole script into --eval it will not load the "require" packages)
4:04:59
jeosol
One can start the search by assuming the lines are vertical so only 4 variables (x1,y1,z1,z2) with (x2=x1, and y2=y1) to fine the best part of the environments and then later relax the constraint. The latter case, the optimization for the first search has 4 variables, in the latter we could relax constraints on z1, and z2 and perform another search
4:05:47
jeosol
with the others fixed or allowed to vary over small spaces. This is not guaranteed to get the global optimum, but not get quick solution.
4:06:57
jeosol
In both case, by calling a function (run-optimizer object), it will automatically perform the correct search based on what can be optimized.
4:14:01
jeosol
White_Flame Do you have some library or resource you recommend for the example DSL you mentioned above?
4:23:35
jeosol
ok doki. I didn't mean the exact thing I wanted, but something like a tutorial, an example, etc.
4:24:32
jeosol
but your point is taken. Will do. I hope I can get something clean and easily maintainable towards my goal of automated systems.
4:24:33
White_Flame
across the many DSLs and data-driven systems I've written, the reason they were written was to solve a very specific representation problem with the exact problem at hand
4:25:25
White_Flame
but you start with "How would I ideally wish to represent this?", write down some pseudocode/data/declarations, then write Lisp to transform/execute those
5:22:48
jeosol
haha. Edgar. By physical I meant book. I check on Amazon, I saw 600 box for a hard cover one time, but later saw some for around $70-$90 box
5:43:27
edgar-rft
jeosol: I printed one myself from the DVI version available at https://www.cs.cmu.edu/Groups/AI/html/cltl/cltl2.html
5:53:26
edgar-rft
jeosol: here in europe there are also lots of online book stores selling old books from libraries. If you'e lucky you can get a copy for a few bucks.
6:09:08
edgar-rft
jeosol: I just looked at ebay and instantly found three copies below 10 bucks fom the USA, shipping costs more expensive than the book itself
7:18:58
LdBeth
edgar-rft: there’s one line footnote exceeding the page boundary in the DVI version available