Re: Clojure code optimizer

2012-04-06 Thread Sanel Zukan
Very good solution :)

To continue this discussion, feel free to mail me; we will also reduce some 
noise here on the list.

Sanel

On Friday, April 6, 2012 6:47:37 PM UTC+2, Andru Gheorghiu wrote:
>
> It's ok now. The problem was in the let of the optimize function... 
> initially I had: 
>   (let [reduced (reverse (into nil (eval-deep exprs)))] 
> because exprs was a lazy sequence and I wanted to turn it into a list. 
> I replaced the "(reverse (into nil ..." part with "(apply list ..." 
> and it works just fine :) 
>
> The problem is that this implementation doesn't account for variable 
> scoping, I need to fix that. 
> For example if I have 
>
> (def n 10) 
> (let [ n 5 ] (+ (+ n 6) something)) 
>
> If i try to optimize the let it will return 
>
> (let [ n 5 ] (+ 16 something)) 
>
> Because it uses the global n defined outside the let. 
>
> Andru Gheorghiu 
>
> On Apr 6, 10:56 am, Sanel Zukan  wrote: 
> > This looks really nice; good work! 
> > 
> > To force evaluation of lazy constructs, you can use 'doall' and 'dorun'. 
> > Can you show the snippet with this problem? 
> > 
> > Sanel 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > On Thursday, April 5, 2012 1:19:32 AM UTC+2, Andru Gheorghiu wrote: 
> > 
> > > Sorry for dropping off the radar, I was caught up in some homework for 
> > > college. 
> > > I've written a very simple program for a limited form of constant 
> > > folding: 
> > 
> > > ; Forces evaluation of an expression or returns the expression if 
> > > ; it can be evaluated 
> > > (defn force-eval [exprs] 
> > >   (try (eval exprs) 
> > > (catch Exception e exprs))) 
> > 
> > > ; Recursively evaluates expressions and subexpressions achieving 
> > > ; constant folding 
> > > (defn eval-deep [exprs] 
> > >   (if (not (list? exprs)) 
> > >   exprs 
> > >   (let [evaled (force-eval exprs)] 
> > > (if (list? evaled) 
> > > (map eval-deep evaled) 
> > > evaled 
> > 
> > > ; Checks if the given argument is a boolean type 
> > > (defn boolean? [x] 
> > >   (or (true? x) (false? x))) 
> > 
> > > ; Replaces an if for which the test condition is known with the 
> > > ; corresponding branch (then for true, else for false) 
> > > (defn replace-if [exprs] 
> > >   (cond (or (not (list? exprs)) (empty? exprs)) exprs 
> > > (= (first exprs) 'if) 
> > >   (if (boolean? (nth exprs 1)) 
> > > (if (nth exprs 1) 
> > >   (first (replace-if (drop 2 exprs))) 
> > >   (first (replace-if (drop 3 exprs 
> > >   (map replace-if exprs)) 
> > > :else (map replace-if exprs))) 
> > 
> > > ; Combines eval-deep and replace-if 
> > > (defn optimize [exprs] 
> > >   (let [reduced (reverse (into nil (eval-deep exprs)))] 
> > > (replace-if reduced))) 
> > 
> > > The basic idea was to use exception handlers to try to evaluate and 
> > > expression if it can be evaluated and if so, replace it with it's 
> > > evaluated form. Then recursively apply this function to an expression 
> > > and, if necessary, all subexpressions. 
> > > I've also added a function to reduce if statements. Similar functions 
> > > can be written for cond, condp, case. 
> > 
> > > I did have a problem: for some reason my eval-deep function returns a 
> > > lazy sequence for the expressions that can't be evaluated. This was an 
> > > inconvenient when I was trying to apply another function (namely 
> > > replace-if) on the result of eval-deep. To get around this I converted 
> > > the lazy sequence into a persistent list, but this lead to that ugly 
> > > application of functions in the let in optimize. How could I have 
> > > avoided this? 
> > 
> > > Andru Gheorghiu 
> > 
> > > On Mar 22, 1:41 pm, Andru Gheorghiu  wrote: 
> > > > Thank you for the responses. I'm looking into the resources you gave 
> > > > me. 
> > 
> > > > Andru Gheorghiu 
> > 
> > > > On Mar 21, 1:16 pm, Sanel Zukan  wrote: 
> > 
> > > > >  I'm happy to see you are familiar with the subject :) 
> > 
> > > > > I was thinking that a 
> > 
> > > > > > similar program forClojurecould detect stack recursive functions 
> and 
> > > > > > replace them with their iterative counterparts, though this can 
> be 
> > > > > > somewhat difficult as various loop-holes can arise that would 
> "fool" 
> > > > > > the program. 
> > 
> > > > > This isn't a big issue, as recursive functions aren't much advised 
> in 
> > > > >Clojure. However, ideal solution would be to detect tail calls and 
> > > rewrite 
> > > > > block in loop/recur combo. This would allowClojureto fully reuse 
> TCO 
> > > > > without waiting for JVM to implement it (which will probably never 
> > > happen). 
> > 
> > > > > I suppose an approach can be found which makes the best out of 
> both 
> > 
> > > > > > worlds: a tree shaker and constant folding implementation + an 
> > > > > > automated program which detects recursions and replaces them 
> with 
> > > more 
> > > > > > efficient versions and a rule-based sys

Re: Clojure code optimizer

2012-04-06 Thread Andru Gheorghiu
It's ok now. The problem was in the let of the optimize function...
initially I had:
  (let [reduced (reverse (into nil (eval-deep exprs)))]
because exprs was a lazy sequence and I wanted to turn it into a list.
I replaced the "(reverse (into nil ..." part with "(apply list ..."
and it works just fine :)

The problem is that this implementation doesn't account for variable
scoping, I need to fix that.
For example if I have

(def n 10)
(let [ n 5 ] (+ (+ n 6) something))

If i try to optimize the let it will return

(let [ n 5 ] (+ 16 something))

Because it uses the global n defined outside the let.

Andru Gheorghiu

On Apr 6, 10:56 am, Sanel Zukan  wrote:
> This looks really nice; good work!
>
> To force evaluation of lazy constructs, you can use 'doall' and 'dorun'.
> Can you show the snippet with this problem?
>
> Sanel
>
>
>
>
>
>
>
> On Thursday, April 5, 2012 1:19:32 AM UTC+2, Andru Gheorghiu wrote:
>
> > Sorry for dropping off the radar, I was caught up in some homework for
> > college.
> > I've written a very simple program for a limited form of constant
> > folding:
>
> > ; Forces evaluation of an expression or returns the expression if
> > ; it can be evaluated
> > (defn force-eval [exprs]
> >   (try (eval exprs)
> >     (catch Exception e exprs)))
>
> > ; Recursively evaluates expressions and subexpressions achieving
> > ; constant folding
> > (defn eval-deep [exprs]
> >   (if (not (list? exprs))
> >       exprs
> >       (let [evaled (force-eval exprs)]
> >         (if (list? evaled)
> >             (map eval-deep evaled)
> >             evaled
>
> > ; Checks if the given argument is a boolean type
> > (defn boolean? [x]
> >   (or (true? x) (false? x)))
>
> > ; Replaces an if for which the test condition is known with the
> > ; corresponding branch (then for true, else for false)
> > (defn replace-if [exprs]
> >   (cond (or (not (list? exprs)) (empty? exprs)) exprs
> >         (= (first exprs) 'if)
> >           (if (boolean? (nth exprs 1))
> >             (if (nth exprs 1)
> >               (first (replace-if (drop 2 exprs)))
> >               (first (replace-if (drop 3 exprs
> >           (map replace-if exprs))
> >         :else (map replace-if exprs)))
>
> > ; Combines eval-deep and replace-if
> > (defn optimize [exprs]
> >   (let [reduced (reverse (into nil (eval-deep exprs)))]
> >     (replace-if reduced)))
>
> > The basic idea was to use exception handlers to try to evaluate and
> > expression if it can be evaluated and if so, replace it with it's
> > evaluated form. Then recursively apply this function to an expression
> > and, if necessary, all subexpressions.
> > I've also added a function to reduce if statements. Similar functions
> > can be written for cond, condp, case.
>
> > I did have a problem: for some reason my eval-deep function returns a
> > lazy sequence for the expressions that can't be evaluated. This was an
> > inconvenient when I was trying to apply another function (namely
> > replace-if) on the result of eval-deep. To get around this I converted
> > the lazy sequence into a persistent list, but this lead to that ugly
> > application of functions in the let in optimize. How could I have
> > avoided this?
>
> > Andru Gheorghiu
>
> > On Mar 22, 1:41 pm, Andru Gheorghiu  wrote:
> > > Thank you for the responses. I'm looking into the resources you gave
> > > me.
>
> > > Andru Gheorghiu
>
> > > On Mar 21, 1:16 pm, Sanel Zukan  wrote:
>
> > > >  I'm happy to see you are familiar with the subject :)
>
> > > > I was thinking that a
>
> > > > > similar program forClojurecould detect stack recursive functions and
> > > > > replace them with their iterative counterparts, though this can be
> > > > > somewhat difficult as various loop-holes can arise that would "fool"
> > > > > the program.
>
> > > > This isn't a big issue, as recursive functions aren't much advised in
> > > >Clojure. However, ideal solution would be to detect tail calls and
> > rewrite
> > > > block in loop/recur combo. This would allowClojureto fully reuse TCO
> > > > without waiting for JVM to implement it (which will probably never
> > happen).
>
> > > > I suppose an approach can be found which makes the best out of both
>
> > > > > worlds: a tree shaker and constant folding implementation + an
> > > > > automated program which detects recursions and replaces them with
> > more
> > > > > efficient versions and a rule-based system to cover some cases which
> > > > > the first approach misses.
>
> > > > Using all this tasks would impose a bit of work to complete them all.
> > I
> > > > would advise taking smaller steps in form of real tasks, followed with
> > > > rigorous tests. It can look like this:
>
> > > >  * constant folding
> > > >  * empty let removal
> > > >  * lambda reduction
> > > >  * TCO
> > > >  * simplification (using Kibit or directly core.logic)
> > > >  * ...
>
> > > > If you decide to work on this, for the starting point you can look at
> > > > "optimizer.scm" (from CHICKEN source) wh

Re: Clojure code optimizer

2012-04-06 Thread Sanel Zukan
This looks really nice; good work!

To force evaluation of lazy constructs, you can use 'doall' and 'dorun'. 
Can you show the snippet with this problem?

Sanel

On Thursday, April 5, 2012 1:19:32 AM UTC+2, Andru Gheorghiu wrote:
>
> Sorry for dropping off the radar, I was caught up in some homework for 
> college. 
> I've written a very simple program for a limited form of constant 
> folding: 
>
> ; Forces evaluation of an expression or returns the expression if 
> ; it can be evaluated 
> (defn force-eval [exprs] 
>   (try (eval exprs) 
> (catch Exception e exprs))) 
>
> ; Recursively evaluates expressions and subexpressions achieving 
> ; constant folding 
> (defn eval-deep [exprs] 
>   (if (not (list? exprs)) 
>   exprs 
>   (let [evaled (force-eval exprs)] 
> (if (list? evaled) 
> (map eval-deep evaled) 
> evaled 
>
> ; Checks if the given argument is a boolean type 
> (defn boolean? [x] 
>   (or (true? x) (false? x))) 
>
> ; Replaces an if for which the test condition is known with the 
> ; corresponding branch (then for true, else for false) 
> (defn replace-if [exprs] 
>   (cond (or (not (list? exprs)) (empty? exprs)) exprs 
> (= (first exprs) 'if) 
>   (if (boolean? (nth exprs 1)) 
> (if (nth exprs 1) 
>   (first (replace-if (drop 2 exprs))) 
>   (first (replace-if (drop 3 exprs 
>   (map replace-if exprs)) 
> :else (map replace-if exprs))) 
>
> ; Combines eval-deep and replace-if 
> (defn optimize [exprs] 
>   (let [reduced (reverse (into nil (eval-deep exprs)))] 
> (replace-if reduced))) 
>
> The basic idea was to use exception handlers to try to evaluate and 
> expression if it can be evaluated and if so, replace it with it's 
> evaluated form. Then recursively apply this function to an expression 
> and, if necessary, all subexpressions. 
> I've also added a function to reduce if statements. Similar functions 
> can be written for cond, condp, case. 
>
> I did have a problem: for some reason my eval-deep function returns a 
> lazy sequence for the expressions that can't be evaluated. This was an 
> inconvenient when I was trying to apply another function (namely 
> replace-if) on the result of eval-deep. To get around this I converted 
> the lazy sequence into a persistent list, but this lead to that ugly 
> application of functions in the let in optimize. How could I have 
> avoided this? 
>
> Andru Gheorghiu 
>
> On Mar 22, 1:41 pm, Andru Gheorghiu  wrote: 
> > Thank you for the responses. I'm looking into the resources you gave 
> > me. 
> > 
> > Andru Gheorghiu 
> > 
> > On Mar 21, 1:16 pm, Sanel Zukan  wrote: 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > >  I'm happy to see you are familiar with the subject :) 
> > 
> > > I was thinking that a 
> > 
> > > > similar program forClojurecould detect stack recursive functions and 
> > > > replace them with their iterative counterparts, though this can be 
> > > > somewhat difficult as various loop-holes can arise that would "fool" 
> > > > the program. 
> > 
> > > This isn't a big issue, as recursive functions aren't much advised in 
> > >Clojure. However, ideal solution would be to detect tail calls and 
> rewrite 
> > > block in loop/recur combo. This would allowClojureto fully reuse TCO 
> > > without waiting for JVM to implement it (which will probably never 
> happen). 
> > 
> > > I suppose an approach can be found which makes the best out of both 
> > 
> > > > worlds: a tree shaker and constant folding implementation + an 
> > > > automated program which detects recursions and replaces them with 
> more 
> > > > efficient versions and a rule-based system to cover some cases which 
> > > > the first approach misses. 
> > 
> > > Using all this tasks would impose a bit of work to complete them all. 
> I 
> > > would advise taking smaller steps in form of real tasks, followed with 
> > > rigorous tests. It can look like this: 
> > 
> > >  * constant folding 
> > >  * empty let removal 
> > >  * lambda reduction 
> > >  * TCO 
> > >  * simplification (using Kibit or directly core.logic) 
> > >  * ... 
> > 
> > > If you decide to work on this, for the starting point you can look at 
> > > "optimizer.scm" (from CHICKEN source) which is nicely summarized at 
> [1] and 
> > > Egi'scode[2]. Both of them applies common techniques in quite readable 
> > > manner. Of course, if someone else have additional resource, please 
> share 
> > > it :) 
> > 
> > > Sanel 
> > 
> > > [1]
> http://wiki.call-cc.org/chicken-internal-structure#the-optimizer-opti... 
> > > [2]https://bitbucket.org/egi/compiler/src 
> > 
> > > On Tuesday, March 20, 2012 7:30:41 PM UTC+1, Andru Gheorghiu wrote: 
> > 
> > > > Thank you for the clarifications and the resources, I understand now 
> > > > what tree shaking is. In fact, I had a project last year at our 
> > > > college to implement (in Scheme) a constant foldingoptimizerfor 
> > > > Scheme programs, I now

Re: Clojure code optimizer

2012-04-05 Thread Andru Gheorghiu
Sorry for dropping off the radar, I was caught up in some homework for
college.
I've written a very simple program for a limited form of constant
folding:

; Forces evaluation of an expression or returns the expression if
; it can be evaluated
(defn force-eval [exprs]
  (try (eval exprs)
(catch Exception e exprs)))

; Recursively evaluates expressions and subexpressions achieving
; constant folding
(defn eval-deep [exprs]
  (if (not (list? exprs))
  exprs
  (let [evaled (force-eval exprs)]
(if (list? evaled)
(map eval-deep evaled)
evaled

; Checks if the given argument is a boolean type
(defn boolean? [x]
  (or (true? x) (false? x)))

; Replaces an if for which the test condition is known with the
; corresponding branch (then for true, else for false)
(defn replace-if [exprs]
  (cond (or (not (list? exprs)) (empty? exprs)) exprs
(= (first exprs) 'if)
  (if (boolean? (nth exprs 1))
(if (nth exprs 1)
  (first (replace-if (drop 2 exprs)))
  (first (replace-if (drop 3 exprs
  (map replace-if exprs))
:else (map replace-if exprs)))

; Combines eval-deep and replace-if
(defn optimize [exprs]
  (let [reduced (reverse (into nil (eval-deep exprs)))]
(replace-if reduced)))

The basic idea was to use exception handlers to try to evaluate and
expression if it can be evaluated and if so, replace it with it's
evaluated form. Then recursively apply this function to an expression
and, if necessary, all subexpressions.
I've also added a function to reduce if statements. Similar functions
can be written for cond, condp, case.

I did have a problem: for some reason my eval-deep function returns a
lazy sequence for the expressions that can't be evaluated. This was an
inconvenient when I was trying to apply another function (namely
replace-if) on the result of eval-deep. To get around this I converted
the lazy sequence into a persistent list, but this lead to that ugly
application of functions in the let in optimize. How could I have
avoided this?

Andru Gheorghiu

On Mar 22, 1:41 pm, Andru Gheorghiu  wrote:
> Thank you for the responses. I'm looking into the resources you gave
> me.
>
> Andru Gheorghiu
>
> On Mar 21, 1:16 pm, Sanel Zukan  wrote:
>
>
>
>
>
>
>
> >  I'm happy to see you are familiar with the subject :)
>
> > I was thinking that a
>
> > > similar program forClojurecould detect stack recursive functions and
> > > replace them with their iterative counterparts, though this can be
> > > somewhat difficult as various loop-holes can arise that would "fool"
> > > the program.
>
> > This isn't a big issue, as recursive functions aren't much advised in
> >Clojure. However, ideal solution would be to detect tail calls and rewrite
> > block in loop/recur combo. This would allowClojureto fully reuse TCO
> > without waiting for JVM to implement it (which will probably never happen).
>
> > I suppose an approach can be found which makes the best out of both
>
> > > worlds: a tree shaker and constant folding implementation + an
> > > automated program which detects recursions and replaces them with more
> > > efficient versions and a rule-based system to cover some cases which
> > > the first approach misses.
>
> > Using all this tasks would impose a bit of work to complete them all. I
> > would advise taking smaller steps in form of real tasks, followed with
> > rigorous tests. It can look like this:
>
> >  * constant folding
> >  * empty let removal
> >  * lambda reduction
> >  * TCO
> >  * simplification (using Kibit or directly core.logic)
> >  * ...
>
> > If you decide to work on this, for the starting point you can look at
> > "optimizer.scm" (from CHICKEN source) which is nicely summarized at [1] and
> > Egi'scode[2]. Both of them applies common techniques in quite readable
> > manner. Of course, if someone else have additional resource, please share
> > it :)
>
> > Sanel
>
> > [1]http://wiki.call-cc.org/chicken-internal-structure#the-optimizer-opti...
> > [2]https://bitbucket.org/egi/compiler/src
>
> > On Tuesday, March 20, 2012 7:30:41 PM UTC+1, Andru Gheorghiu wrote:
>
> > > Thank you for the clarifications and the resources, I understand now
> > > what tree shaking is. In fact, I had a project last year at our
> > > college to implement (in Scheme) a constant foldingoptimizerfor
> > > Scheme programs, I now see the resemblance with what you described.
> > > The program would optimize functions like:
>
> > > (define some-function
> > >     (lambda (x)
> > >          (if (> x (+ 2 4))
> > >             (- 7 (car ‘(1 2 3)))
> > >             (cons x 4)))
>
> > > Turning it into
>
> > > (define some-function
> > >     (lambda (x)
> > >        (if (> x 6)
> > >            6
> > >            (cons x 4
>
> > > Also, when finding conditional statements in which the test condition
> > > is known (can be evaluated) to replace it with thecodewhich runs on
> > > the appropriate branch. For example, repl

Re: Clojure code optimizer

2012-03-22 Thread Andru Gheorghiu
; >   (defonce *always-true* true)
> > >   (if *always-true*
> > >      (println "Always executed")
> > >      (println "Never executed"))
>
> > > Matching this case could be hard for pattern matching tools; they often
> > do
> > > not understand the content outside given pattern. True optimizer would
> > pick
> > > up *always-true* and notice it will never be changed for this block.
> > > However, if I do some weird magic inside some function and globally
> > change
> > > the value of *always-true* at some point, optimizer should recognize
> > this
> > > case or would remove valid code.
>
> > > Also, often case for optimizers is to precompute simple expressions in
> > > compilation phase yielding static values, like:
>
> > >   (let [a 0
> > >          b (+ a 1)]
> > >     (if something
> > >       b))
>
> > > here it could rewrite whole block as:
>
> > >  (if something
> > >    1)
>
> > > or even can recognize Clojure patterns like:
>
> > >  (apply + (range 1 10))
>
> > > where the pattern matching approach could rewrite expression to (+ 1 2 3
> > 4
> > > 5 6 ... 9) and optimizer would simply produce 45. Using this case you
> > can
> > > see how pattern matching can be a part of optimizer.
>
> > > I'm hoping I manage to fully describe you an idea behind this proposal.
> > Of
> > > course, taking some expert system approach and doing Kibit-style
> > matching
> > > can be a good starting point too :)
>
> > > Also, if you are interested to take tree shaking way, a good starting
> > point
> > > can be SBCL alpha shaker athttp://jsnell.iki.fi/tmp/shake.lisp.
> > > Unfortunately without documentation, but the code is quite easy to
> > follow.
>
> > > Sanel
>
> > > On Saturday, March 17, 2012 10:59:44 PM UTC+1, Andru Gheorghiu wrote:
>
> > > > Hello,
>
> > > > I am a third year student majoring in computer science and I am
> > > > interested in the Clojure code optimizer project proposed for GSoC
> > > > 2012. Could you please give more details (or examples) on the types of
> > > > optimizations the optimizer should be able to do? Also, what is a tree
> > > > shaker implementation?
> > > > I was thinking that an optimizer could be implemented as a rule engine
> > > > similar to Jess or CLIPS in which rules contains patterns which need
> > > > to be replaced and the code to replace them with. For example one
> > > > could write patterns for generic linear recursive functions that
> > > > should be replaced with linear iterative functions. Similarly patterns
> > > > can be written for functions which replicate the behavior of an
> > > > already existing function (such as reverse, map, apply etc) and a rule
> > > > to replace those functions with the predefined ones.
>
> > > > Thank you,
> > > > Andru Gheorghiu

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Clojure code optimizer

2012-03-21 Thread Daniel Gagnon
>
> This isn't a big issue, as recursive functions aren't much advised in
> Clojure. However, ideal solution would be to detect tail calls and rewrite
> block in loop/recur combo. This would allow Clojure to fully reuse TCO
> without waiting for JVM to implement it (which will probably never happen).
>

Not all tail calls are self-recursion. If you call a different function in
tail position, there would be no TCO which if I remember correctly is why
Rich added recur instead of optimizing self-recursion. He doesn't want to
fool you into believing that Clojure supports TCO when it doesn't.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Clojure code optimizer

2012-03-21 Thread Sanel Zukan
 globally 
> change 
> > the value of *always-true* at some point, optimizer should recognize 
> this 
> > case or would remove valid code. 
> > 
> > Also, often case for optimizers is to precompute simple expressions in 
> > compilation phase yielding static values, like: 
> > 
> >   (let [a 0 
> >  b (+ a 1)] 
> > (if something 
> >   b)) 
> > 
> > here it could rewrite whole block as: 
> > 
> >  (if something 
> >1) 
> > 
> > or even can recognize Clojure patterns like: 
> > 
> >  (apply + (range 1 10)) 
> > 
> > where the pattern matching approach could rewrite expression to (+ 1 2 3 
> 4 
> > 5 6 ... 9) and optimizer would simply produce 45. Using this case you 
> can 
> > see how pattern matching can be a part of optimizer. 
> > 
> > I'm hoping I manage to fully describe you an idea behind this proposal. 
> Of 
> > course, taking some expert system approach and doing Kibit-style 
> matching 
> > can be a good starting point too :) 
> > 
> > Also, if you are interested to take tree shaking way, a good starting 
> point 
> > can be SBCL alpha shaker athttp://jsnell.iki.fi/tmp/shake.lisp. 
> > Unfortunately without documentation, but the code is quite easy to 
> follow. 
> > 
> > Sanel 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > On Saturday, March 17, 2012 10:59:44 PM UTC+1, Andru Gheorghiu wrote: 
> > 
> > > Hello, 
> > 
> > > I am a third year student majoring in computer science and I am 
> > > interested in the Clojure code optimizer project proposed for GSoC 
> > > 2012. Could you please give more details (or examples) on the types of 
> > > optimizations the optimizer should be able to do? Also, what is a tree 
> > > shaker implementation? 
> > > I was thinking that an optimizer could be implemented as a rule engine 
> > > similar to Jess or CLIPS in which rules contains patterns which need 
> > > to be replaced and the code to replace them with. For example one 
> > > could write patterns for generic linear recursive functions that 
> > > should be replaced with linear iterative functions. Similarly patterns 
> > > can be written for functions which replicate the behavior of an 
> > > already existing function (such as reverse, map, apply etc) and a rule 
> > > to replace those functions with the predefined ones. 
> > 
> > > Thank you, 
> > > Andru Gheorghiu

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Clojure code optimizer

2012-03-20 Thread Andru Gheorghiu
Thank you for the clarifications and the resources, I understand now
what tree shaking is. In fact, I had a project last year at our
college to implement (in Scheme) a constant folding optimizer for
Scheme programs, I now see the resemblance with what you described.
The program would optimize functions like:

(define some-function
(lambda (x)
 (if (> x (+ 2 4))
(- 7 (car ‘(1 2 3)))
(cons x 4)))

Turning it into

(define some-function
(lambda (x)
   (if (> x 6)
   6
   (cons x 4

Also, when finding conditional statements in which the test condition
is known (can be evaluated) to replace it with the code which runs on
the appropriate branch. For example, replacing:

(if (or #f #t)
then-code
else-code)

With

then-code

Same thing for cond.

Another part of the project was to classify recursive functions into
stack recursive, tree recursive or iterations. I was thinking that a
similar program for Clojure could detect stack recursive functions and
replace them with their iterative counterparts, though this can be
somewhat difficult as various loop-holes can arise that would "fool"
the program.
I suppose an approach can be found which makes the best out of both
worlds: a tree shaker and constant folding implementation + an
automated program which detects recursions and replaces them with more
efficient versions and a rule-based system to cover some cases which
the first approach misses.

Andru Gheorghiu

On Mar 20, 1:31 am, Sanel Zukan  wrote:
> Hi Andru and thank you for expressing interest in this proposal.
>
> > Could you please give more details (or examples) on the types of
> > optimizations the optimizer should be able to do? Also, what is a tree
> > shaker implementation?
>
> As David wrote, this is dead code elimination and in LISP world is also
> known as tree shaking. Contrary to pattern matching (for which you
> expressed desire), dead code elimination is usually more advanced approach,
> sometimes requiring passing through the code multiple times, inspecting
> compiler facilities or simply doing a bunch of tricks to remove obvious and
> not so obvious unused code.
>
> Take this example:
>
>   (defonce *always-true* true)
>   (if *always-true*
>      (println "Always executed")
>      (println "Never executed"))
>
> Matching this case could be hard for pattern matching tools; they often do
> not understand the content outside given pattern. True optimizer would pick
> up *always-true* and notice it will never be changed for this block.
> However, if I do some weird magic inside some function and globally change
> the value of *always-true* at some point, optimizer should recognize this
> case or would remove valid code.
>
> Also, often case for optimizers is to precompute simple expressions in
> compilation phase yielding static values, like:
>
>   (let [a 0
>          b (+ a 1)]
>     (if something
>       b))
>
> here it could rewrite whole block as:
>
>  (if something
>    1)
>
> or even can recognize Clojure patterns like:
>
>  (apply + (range 1 10))
>
> where the pattern matching approach could rewrite expression to (+ 1 2 3 4
> 5 6 ... 9) and optimizer would simply produce 45. Using this case you can
> see how pattern matching can be a part of optimizer.
>
> I'm hoping I manage to fully describe you an idea behind this proposal. Of
> course, taking some expert system approach and doing Kibit-style matching
> can be a good starting point too :)
>
> Also, if you are interested to take tree shaking way, a good starting point
> can be SBCL alpha shaker athttp://jsnell.iki.fi/tmp/shake.lisp.
> Unfortunately without documentation, but the code is quite easy to follow.
>
> Sanel
>
>
>
>
>
>
>
> On Saturday, March 17, 2012 10:59:44 PM UTC+1, Andru Gheorghiu wrote:
>
> > Hello,
>
> > I am a third year student majoring in computer science and I am
> > interested in the Clojure code optimizer project proposed for GSoC
> > 2012. Could you please give more details (or examples) on the types of
> > optimizations the optimizer should be able to do? Also, what is a tree
> > shaker implementation?
> > I was thinking that an optimizer could be implemented as a rule engine
> > similar to Jess or CLIPS in which rules contains patterns which need
> > to be replaced and the code to replace them with. For example one
> > could write patterns for generic linear recursive functions that
> > should be replaced with linear iterative functions. Similarly patterns
> > can be written for functions which replicate the behavior of an
> > already existing function (such as reverse, map, apply etc) and a rule
> > to re

Re: Clojure code optimizer

2012-03-19 Thread Sanel Zukan
Hi Andru and thank you for expressing interest in this proposal.
 

> Could you please give more details (or examples) on the types of 
> optimizations the optimizer should be able to do? Also, what is a tree 
> shaker implementation?
>

As David wrote, this is dead code elimination and in LISP world is also 
known as tree shaking. Contrary to pattern matching (for which you 
expressed desire), dead code elimination is usually more advanced approach, 
sometimes requiring passing through the code multiple times, inspecting 
compiler facilities or simply doing a bunch of tricks to remove obvious and 
not so obvious unused code.

Take this example:

  (defonce *always-true* true)
  (if *always-true*
 (println "Always executed")
 (println "Never executed"))

Matching this case could be hard for pattern matching tools; they often do 
not understand the content outside given pattern. True optimizer would pick 
up *always-true* and notice it will never be changed for this block. 
However, if I do some weird magic inside some function and globally change 
the value of *always-true* at some point, optimizer should recognize this 
case or would remove valid code.

Also, often case for optimizers is to precompute simple expressions in 
compilation phase yielding static values, like:

  (let [a 0
 b (+ a 1)]
(if something
  b))

here it could rewrite whole block as:

 (if something
   1)

or even can recognize Clojure patterns like:

 (apply + (range 1 10))

where the pattern matching approach could rewrite expression to (+ 1 2 3 4 
5 6 ... 9) and optimizer would simply produce 45. Using this case you can 
see how pattern matching can be a part of optimizer.

I'm hoping I manage to fully describe you an idea behind this proposal. Of 
course, taking some expert system approach and doing Kibit-style matching 
can be a good starting point too :)

Also, if you are interested to take tree shaking way, a good starting point 
can be SBCL alpha shaker at http://jsnell.iki.fi/tmp/shake.lisp. 
Unfortunately without documentation, but the code is quite easy to follow.

Sanel

On Saturday, March 17, 2012 10:59:44 PM UTC+1, Andru Gheorghiu wrote:
>
> Hello, 
>
> I am a third year student majoring in computer science and I am 
> interested in the Clojure code optimizer project proposed for GSoC 
> 2012. Could you please give more details (or examples) on the types of 
> optimizations the optimizer should be able to do? Also, what is a tree 
> shaker implementation? 
> I was thinking that an optimizer could be implemented as a rule engine 
> similar to Jess or CLIPS in which rules contains patterns which need 
> to be replaced and the code to replace them with. For example one 
> could write patterns for generic linear recursive functions that 
> should be replaced with linear iterative functions. Similarly patterns 
> can be written for functions which replicate the behavior of an 
> already existing function (such as reverse, map, apply etc) and a rule 
> to replace those functions with the predefined ones. 
>
> Thank you, 
> Andru Gheorghiu 
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Clojure code optimizer

2012-03-19 Thread David Nolen
On Sat, Mar 17, 2012 at 5:59 PM, Andru Gheorghiu wrote:

> Hello,
>
> I am a third year student majoring in computer science and I am
> interested in the Clojure code optimizer project proposed for GSoC
> 2012. Could you please give more details (or examples) on the types of
> optimizations the optimizer should be able to do? Also, what is a tree
> shaker implementation?
>

As far as I know this is dead-code elimination.


> I was thinking that an optimizer could be implemented as a rule engine
> similar to Jess or CLIPS in which rules contains patterns which need
> to be replaced and the code to replace them with. For example one
> could write patterns for generic linear recursive functions that
> should be replaced with linear iterative functions. Similarly patterns
> can be written for functions which replicate the behavior of an
> already existing function (such as reverse, map, apply etc) and a rule
> to replace those functions with the predefined ones.
>
> Thank you,
> Andru Gheorghiu


There's actually some work happening along these lines with Kibit,
https://github.com/jonase/kibit. Is this something that interests you?

David

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Clojure code optimizer

2012-03-18 Thread Andru Gheorghiu
Hello,

I am a third year student majoring in computer science and I am
interested in the Clojure code optimizer project proposed for GSoC
2012. Could you please give more details (or examples) on the types of
optimizations the optimizer should be able to do? Also, what is a tree
shaker implementation?
I was thinking that an optimizer could be implemented as a rule engine
similar to Jess or CLIPS in which rules contains patterns which need
to be replaced and the code to replace them with. For example one
could write patterns for generic linear recursive functions that
should be replaced with linear iterative functions. Similarly patterns
can be written for functions which replicate the behavior of an
already existing function (such as reverse, map, apply etc) and a rule
to replace those functions with the predefined ones.

Thank you,
Andru Gheorghiu

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en