[ANN] clojure.data.priority-map 0.0.3

2013-10-23 Thread Mark Engelberg
https://github.com/clojure/data.priority-map/

A priority map is similar to a sorted map, but sorts the entries by the
values rather than the keys in the map.  Think of it as a kind of priority
queue with a full map-like API to query, add, adjust, and remove items and
their priorities.

The new 0.0.3 version addresses a common need where the items map to
complex values which contain the priority, or from which the priority can
be derived.
For example, consider a map:
{:apple {:weight 2, :color :red}, :orange {:weight 2, color :orange},
:banana {:weight 3, color :yellow}}
where you want to sort the map by the fruit's weight.

A common pitfall was to try to solve this with a custom comparator which
compares only on weight.  This doesn't work properly because of the
Clojure/Java rule that valid comparators must be total orders.  Among
other things, this means the comparator can't have ties between unequal
objects (known as the trichotomy property).

[See https://groups.google.com/forum/#!msg/clojure/VKvH_eg_FtE/Kpy18zGtio4Jfor
one such discussion about this pitfall]

Users were instructed to rework their comparator into a total order, but
for some use cases, this can be a tricky proposition.

To address this need, the new version allows one to specify a keyfn which
extracts or computes the sort keys (i.e., priority) from the map's values.

This is done with one of two new constructors:
priority-map-keyfn (takes a custom keyfn)
priority-map-keyfn-by (takes a custom keyfn and custom comparator)

So for example, the above map could be expressed as:
(priority-map-keyfn :weight
  :apple {:weight 2, :color :red}, :orange {:weight 2, color :orange},
  :banana {:weight 3, color :yellow})

See the README for further explanation, and let me know if you have any
questions.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


[ANN] Teuta - laughingly simple dependency injection container

2013-10-23 Thread vmarcinko
Hi all,

I'm still fresh to Clojure, so be gentle :)

Like so many Java-to-Clojure converts out there, my mind is used to 
structuring apps using DI containers (a-la Spring), and since I don't see 
that DI components are going against FP nature of Clojure, so I decided to 
create my own little DI container. There are some other Clojure libs that 
tackle this same space, but they are somewhat different than what a typical 
java developer is used to.

Anyway, here is blog post about it:
http://pannoniancoder.blogspot.com/2013/10/introducing-teuta-laughingly-simple.html

And the project is at:
https://github.com/vmarcinko/teuta

Any feedback more than welcome.

Regards,
Vjeran

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: jdbc timestamp automatic timezone

2013-10-23 Thread Vincent Liard


 I ended up using a workaround: formatting the timestamps using the 
 timezone offset. However I'm sure there is a better way.

 Thank you Manuel, I didn't find a better way either.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: JVM assertions in Clojure

2013-10-23 Thread lopusz

Clearly, global overhead of assertions depends on number and type of 
invariants that you check.
My experience was simliar to Paul's. Compililng/disabling the assertions 
away helps a great deal in many cases.

Paul !  I've started using pjstadig.assertions and it works like a charm :)
**Thank you very much for sharing!**

Best regards,
Michał

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Paul Butcher
On 22 Oct 2013, at 20:20, David Nolen dnolen.li...@gmail.com wrote:

 On Tue, Oct 22, 2013 at 3:11 PM, Paul Butcher p...@paulbutcher.com wrote:
 Yeah - I have tried giving it more RAM without any effect on the timing 
 whatsoever. And I couldn't see the point of stopping people with less RAM 
 than that from being able to run it :-)
 
 But without enough RAM most JVMs will thrash in GC when running that code.

Yes, of course. But as I said, I tried giving it more RAM (the same 12G as the 
Scala solution) and it made no difference whatsoever. In fact, YourKit shows me 
that, even after running for an hour (i.e. more than 10x longer than the Scala 
version takes to return the full solution) the Clojure version is still using 
less than 2G. Whatever is going on, it's not a result of a lack of RAM.

 Saying both run in less than a second is not particularly informative for the 
 small problems :) Does Scala take 4ms and Clojure takes 400ms on the small 
 problems? That's a big difference.


Yes, of course. But my experience with small problems has been that differences 
between execution time, especially when talking about runtimes as dissimilar as 
the Clojure and Scala runtimes, are meaningless. Those differences tend to have 
more to do with startup costs and the vagaries of when hotspot happens to 
optimise things than anything fundamental.

But you asked, so here it is:

For Clojure, the 3x3 problem takes 7ms and the 4x4 problem takes 78ms. For 
Scala, it's 15ms and 252ms respectively.

--
paul.butcher-msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: p...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

On 22 Oct 2013, at 20:20, David Nolen dnolen.li...@gmail.com wrote:

 On Tue, Oct 22, 2013 at 3:11 PM, Paul Butcher p...@paulbutcher.com wrote:
 Yeah - I have tried giving it more RAM without any effect on the timing 
 whatsoever. And I couldn't see the point of stopping people with less RAM 
 than that from being able to run it :-)
 
 But without enough RAM most JVMs will thrash in GC when running that code.
 
 Saying both run in less than a second is not particularly informative for the 
 small problems :) Does Scala take 4ms and Clojure takes 400ms on the small 
 problems? That's a big difference.
 
 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
 --- 
 You received this message because you are subscribed to the Google Groups 
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Clojure can't import some Java classes

2013-10-23 Thread Colin Fleming
I've also had a lot of problems with def'ed forms. For example, if I do
this:

(def no-spacing (Spacing/createSpacing 0 0 0 false 0))

Which looks like this:

  public static Spacing createSpacing(int minSpaces,
  int maxSpaces,
  int minLineFeeds,
  boolean keepLineBreaks,
  int keepBlankLines) {
return myFactory.createSpacing(minSpaces, maxSpaces, minLineFeeds,
keepLineBreaks, keepBlankLines);
  }

myFactory is injected at some earlier point:

  static void setFactory(SpacingFactory factory) {
myFactory = factory;
  }

But during compilation that obviously hasn't happened and I get an NPE
during compilation. It's a little annoying that there really seems to be no
good way to create this value at namespace load time if I'm AOT compiling.
I can obviously defer it using defn with memoize or something, but that
seems clunky for what doesn't seem like that crazy a use case.


On 23 October 2013 15:21, Zach Oakes zsoa...@gmail.com wrote:

 Here's the error I get when I import LibGDX's Timer class:

 http://pastebin.com/q7wys8yi


 On Tuesday, October 22, 2013 9:55:16 PM UTC-4, Alex Miller wrote:

 I'd love to see a stack trace when that happens (could even be triggered
 by dumping stack in your static initializer if nothing else).

 On Saturday, October 12, 2013 3:17:50 AM UTC-5, Wujek Srujek wrote:

 So you are saying compilation is trying to instantiate class and run
 static initializers? This seems very backward, are you sure?


 On Sat, Oct 12, 2013 at 8:30 AM, Zach Oakes zso...@gmail.com wrote:

 I should add, I am aware I can bring in a class dynamically with
 Class/forName, and that is what I ended up doing for the Timer class.
 However, this is not always practical, and sometimes is simply not an
 option if aot-compilation is required.


 On Saturday, October 12, 2013 2:28:38 AM UTC-4, Zach Oakes wrote:

 I recently learned that merely importing a Java class in Clojure
 causes static initializers to be run. Sometimes, this causes compilation
 errors, because they are written with the assumption that they will only 
 be
 run during runtime.

 I ran into this just now while trying to make a simple Clojure game
 with LibGDX. After simply importing its Timer class, I began getting
 compilation errors. The stack trace shows it is due to a static
 initializerhttps://github.com/libgdx/libgdx/blob/511b557c1a2d23bf8110a05b0ef54cc20b7f958d/gdx/src/com/badlogic/gdx/utils/Timer.java#L32attempting
  to instantiate the class!

 I also ran into this recently while trying to use RoboVM. My question
 is, do I have any options? I haven't found many discussions about this 
 here
 or elsewhere. This surprises me, because it seems like something more
 people should be running into.

  --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@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+u...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/**group/clojure?hl=enhttp://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send
 an email to clojure+u...@googlegroups.com.
 For more options, visit 
 https://groups.google.com/**groups/opt_outhttps://groups.google.com/groups/opt_out
 .


  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to 

Re: Request for help optimising a Clojure program

2013-10-23 Thread David Nolen
Those numbers make the larger problem runtime suspect. How are you running
the Clojure version? With Lein?

On Wednesday, October 23, 2013, Paul Butcher wrote:

 On 22 Oct 2013, at 20:20, David Nolen 
 dnolen.li...@gmail.comjavascript:_e({}, 'cvml', 'dnolen.li...@gmail.com');
 wrote:

 On Tue, Oct 22, 2013 at 3:11 PM, Paul Butcher 
 p...@paulbutcher.comjavascript:_e({}, 'cvml', 'p...@paulbutcher.com');
  wrote:

 Yeah - I have tried giving it more RAM without any effect on the timing
 whatsoever. And I couldn't see the point of stopping people with less RAM
 than that from being able to run it :-)


 But without enough RAM most JVMs will thrash in GC when running that code.


 Yes, of course. But as I said, I tried giving it more RAM (the same 12G as
 the Scala solution) and it made no difference whatsoever. In fact, YourKit
 shows me that, even after running for an hour (i.e. more than 10x longer
 than the Scala version takes to return the full solution) the Clojure
 version is still using less than 2G. Whatever is going on, it's not a
 result of a lack of RAM.

 Saying both run in less than a second is not particularly informative for
 the small problems :) Does Scala take 4ms and Clojure takes 400ms on the
 small problems? That's a big difference.


 Yes, of course. But my experience with small problems has been that
 differences between execution time, especially when talking about runtimes
 as dissimilar as the Clojure and Scala runtimes, are meaningless. Those
 differences tend to have more to do with startup costs and the vagaries of
 when hotspot happens to optimise things than anything fundamental.

 But you asked, so here it is:

 For Clojure, the 3x3 problem takes 7ms and the 4x4 problem takes 78ms. For
 Scala, it's 15ms and 252ms respectively.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com javascript:_e({}, 'cvml',
 'p...@paulbutcher.com');
 AIM: paulrabutcher
 Skype: paulrabutcher

 On 22 Oct 2013, at 20:20, David Nolen 
 dnolen.li...@gmail.comjavascript:_e({}, 'cvml', 'dnolen.li...@gmail.com');
 wrote:

 On Tue, Oct 22, 2013 at 3:11 PM, Paul Butcher 
 p...@paulbutcher.comjavascript:_e({}, 'cvml', 'p...@paulbutcher.com');
  wrote:

 Yeah - I have tried giving it more RAM without any effect on the timing
 whatsoever. And I couldn't see the point of stopping people with less RAM
 than that from being able to run it :-)


 But without enough RAM most JVMs will thrash in GC when running that code.

 Saying both run in less than a second is not particularly informative for
 the small problems :) Does Scala take 4ms and Clojure takes 400ms on the
 small problems? That's a big difference.

 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.comjavascript:_e({}, 'cvml', 
 '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 javascript:_e({}, 'cvml',
 'clojure+unsubscr...@googlegroups.com');
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com javascript:_e({}, 'cvml',
 'clojure+unsubscr...@googlegroups.com');.
 For more options, visit https://groups.google.com/groups/opt_out.


  --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to 
 clojure@googlegroups.comjavascript:_e({}, 'cvml', 
 '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 javascript:_e({}, 'cvml',
 'clojure%2bunsubscr...@googlegroups.com');
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com javascript:_e({}, 'cvml',
 'clojure%2bunsubscr...@googlegroups.com');.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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 

Re: Request for help optimising a Clojure program

2013-10-23 Thread Timothy Baldridge
Lein does some odd stuff to the JVM when it runs. Try adding ^:replace to
jvm-opts:

:jvm-opts ^:replace []

That being said, the #1 rule of benchmarking with lein is don't benchmark
with lein. The JVM lein spins up has a different set of goals (namely
startup time). The best way to benchmark is to run the test several
thousand times, from a jar created with lein uberjar.

Timothy


On Wed, Oct 23, 2013 at 5:22 AM, Paul Butcher p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 12:21, David Nolen dnolen.li...@gmail.com wrote:

 Those numbers make the larger problem runtime suspect. How are you running
 the Clojure version? With Lein?


 Yes - lein run.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.




-- 
“One of the main causes of the fall of the Roman Empire was that–lacking
zero–they had no way to indicate successful termination of their C
programs.”
(Robert Firth)

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread David Nolen
Lein doesn't use your specified JVM settings, you must override with
^:replace. It's also a good idea to set -server as Lein does not default
to this.

On Wednesday, October 23, 2013, Paul Butcher wrote:

 On 23 Oct 2013, at 12:21, David Nolen 
 dnolen.li...@gmail.comjavascript:_e({}, 'cvml', 'dnolen.li...@gmail.com');
 wrote:

 Those numbers make the larger problem runtime suspect. How are you running
 the Clojure version? With Lein?


 Yes - lein run.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com javascript:_e({}, 'cvml',
 'p...@paulbutcher.com');
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to 
 clojure@googlegroups.comjavascript:_e({}, 'cvml', 
 '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 javascript:_e({}, 'cvml',
 'clojure%2bunsubscr...@googlegroups.com');
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com javascript:_e({}, 'cvml',
 'clojure%2bunsubscr...@googlegroups.com');.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Timothy Baldridge
Great! you have a profiler, use that. Find the hotspots, use YourKit to
find where the .cons is being called from, find things to optimize, and go
from there. This is exactly the same process I would use any optimizations
I attempted.

Timothy


On Wed, Oct 23, 2013 at 6:09 AM, Paul Butcher p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 12:44, Timothy Baldridge tbaldri...@gmail.com wrote:

 That being said, the #1 rule of benchmarking with lein is don't benchmark
 with lein. The JVM lein spins up has a different set of goals (namely
 startup time). The best way to benchmark is to run the test several
 thousand times, from a jar created with lein uberjar.


 I'm well aware of the issues associated with micro-benchmarking on the
 JVM. Bear in mind that what I'm doing isn't micro-benchmarking. I have a
 Scala program that runs in 2.5 minutes, which when re-implemented in
 Clojure doesn't finish after being run overnight. I.e. the Clojure is (at
 least) 2 orders of magnitude slower than the Scala.

 I'd love to be able to run it just once - running it thousands of times
 with its current performance would require *years*.

 I've now got it recompiled as an uberjar and I'm running it with 12G RAM
 (-Xms12G -Xmx12G). So far, it's been running for 12 minutes (i.e. 6x longer
 than the Scala version takes to complete) and YourKit shows me that it's
 used less than 300MB RAM (i.e. the vast majority of the 12G is unused).

 YourKit also shows me that it's still the case that it's spending 99% of
 its time in PersistentHashSet.cons.

 I completely understand that playing around with pre-compilation and JVM
 settings will make a difference to the observed performance. But not two
 orders of magnitude difference, surely?

 It strikes me that there's clearly something that I'm missing in the
 Clojure implementation that's making a dramatic difference to performance.
 I'd love some help determining what that something is.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.




-- 
“One of the main causes of the fall of the Roman Empire was that–lacking
zero–they had no way to indicate successful termination of their C
programs.”
(Robert Firth)

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Timothy Baldridge
This code will have a ton of allocations:

(defn solve [rows cols pieces]
  (if (empty? pieces)
#{#{}}
(set
  (let [candidate (first pieces)]
(for [solution (solve rows cols (rest pieces))
  x (range 0 cols)
  y (range 0 rows)
  :when (allowed? candidate [x y] solution)]
  (conj solution [candidate [x y]]))


Every item in the cons will require an allocation. After that, the
entire thing has to be turned into a set. This entire thing is also
recursive, so that compounds the problem. Perhaps re-write this as a
reducer?

Timothy



On Wed, Oct 23, 2013 at 6:18 AM, Timothy Baldridge tbaldri...@gmail.comwrote:

 Great! you have a profiler, use that. Find the hotspots, use YourKit to
 find where the .cons is being called from, find things to optimize, and go
 from there. This is exactly the same process I would use any optimizations
 I attempted.

 Timothy


 On Wed, Oct 23, 2013 at 6:09 AM, Paul Butcher p...@paulbutcher.comwrote:

 On 23 Oct 2013, at 12:44, Timothy Baldridge tbaldri...@gmail.com wrote:

 That being said, the #1 rule of benchmarking with lein is don't benchmark
 with lein. The JVM lein spins up has a different set of goals (namely
 startup time). The best way to benchmark is to run the test several
 thousand times, from a jar created with lein uberjar.


 I'm well aware of the issues associated with micro-benchmarking on the
 JVM. Bear in mind that what I'm doing isn't micro-benchmarking. I have a
 Scala program that runs in 2.5 minutes, which when re-implemented in
 Clojure doesn't finish after being run overnight. I.e. the Clojure is (at
 least) 2 orders of magnitude slower than the Scala.

 I'd love to be able to run it just once - running it thousands of times
 with its current performance would require *years*.

 I've now got it recompiled as an uberjar and I'm running it with 12G RAM
 (-Xms12G -Xmx12G). So far, it's been running for 12 minutes (i.e. 6x longer
 than the Scala version takes to complete) and YourKit shows me that it's
 used less than 300MB RAM (i.e. the vast majority of the 12G is unused).

 YourKit also shows me that it's still the case that it's spending 99% of
 its time in PersistentHashSet.cons.

 I completely understand that playing around with pre-compilation and JVM
 settings will make a difference to the observed performance. But not two
 orders of magnitude difference, surely?

 It strikes me that there's clearly something that I'm missing in the
 Clojure implementation that's making a dramatic difference to performance.
 I'd love some help determining what that something is.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.




 --
 “One of the main causes of the fall of the Roman Empire was that–lacking
 zero–they had no way to indicate successful termination of their C
 programs.”
 (Robert Firth)




-- 
“One of the main causes of the fall of the Roman Empire was that–lacking
zero–they had no way to indicate successful termination of their C
programs.”
(Robert Firth)

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Timothy Baldridge
Eh, I said cons, but it's 6:30 in the morning. I meant the for's lazy seq
requires at least one allocation per item. Your time spent in
PersistentHashSet.cons is probably due to the use of set.

Timothy


On Wed, Oct 23, 2013 at 6:21 AM, Timothy Baldridge tbaldri...@gmail.comwrote:

 This code will have a ton of allocations:

 (defn solve [rows cols pieces]
   (if (empty? pieces)
 #{#{}}

 (set
   (let [candidate (first pieces)]
 (for [solution (solve rows cols (rest pieces))
   x (range 0 cols)
   y (range 0 rows)
   :when (allowed? candidate [x y] solution)]
   (conj solution [candidate [x y]]))



 Every item in the cons will require an allocation. After that, the entire 
 thing has to be turned into a set. This entire thing is also recursive, so 
 that compounds the problem. Perhaps re-write this as a reducer?

 Timothy



 On Wed, Oct 23, 2013 at 6:18 AM, Timothy Baldridge 
 tbaldri...@gmail.comwrote:

 Great! you have a profiler, use that. Find the hotspots, use YourKit to
 find where the .cons is being called from, find things to optimize, and go
 from there. This is exactly the same process I would use any optimizations
 I attempted.

 Timothy


 On Wed, Oct 23, 2013 at 6:09 AM, Paul Butcher p...@paulbutcher.comwrote:

 On 23 Oct 2013, at 12:44, Timothy Baldridge tbaldri...@gmail.com
 wrote:

 That being said, the #1 rule of benchmarking with lein is don't
 benchmark with lein. The JVM lein spins up has a different set of goals
 (namely startup time). The best way to benchmark is to run the test several
 thousand times, from a jar created with lein uberjar.


 I'm well aware of the issues associated with micro-benchmarking on the
 JVM. Bear in mind that what I'm doing isn't micro-benchmarking. I have a
 Scala program that runs in 2.5 minutes, which when re-implemented in
 Clojure doesn't finish after being run overnight. I.e. the Clojure is (at
 least) 2 orders of magnitude slower than the Scala.

 I'd love to be able to run it just once - running it thousands of times
 with its current performance would require *years*.

 I've now got it recompiled as an uberjar and I'm running it with 12G RAM
 (-Xms12G -Xmx12G). So far, it's been running for 12 minutes (i.e. 6x longer
 than the Scala version takes to complete) and YourKit shows me that it's
 used less than 300MB RAM (i.e. the vast majority of the 12G is unused).

 YourKit also shows me that it's still the case that it's spending 99% of
 its time in PersistentHashSet.cons.

 I completely understand that playing around with pre-compilation and JVM
 settings will make a difference to the observed performance. But not two
 orders of magnitude difference, surely?

 It strikes me that there's clearly something that I'm missing in the
 Clojure implementation that's making a dramatic difference to performance.
 I'd love some help determining what that something is.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send
 an email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.




 --
 “One of the main causes of the fall of the Roman Empire was that–lacking
 zero–they had no way to indicate successful termination of their C
 programs.”
 (Robert Firth)




 --
 “One of the main causes of the fall of the Roman Empire was that–lacking
 zero–they had no way to indicate successful termination of their C
 programs.”
 (Robert Firth)




-- 
“One of the main causes of the fall of the Roman Empire was that–lacking
zero–they had no way to indicate successful termination of their C
programs.”
(Robert Firth)

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving 

Re: Request for help optimising a Clojure program

2013-10-23 Thread Timothy Baldridge
From what I can tell, Clojure uses persistent hash sets inside of set. This
can be fixed by replacing set with (into #{} data). Into uses transients
internally and should be much faster.

I don't know Scala, but from I can tell, Scala is using mutable
collections. I think the combination of these two things (immutable
collections plus lack of transients) could be causing some performance
impact. I wouldn't expect it to be 1000x but it's a starting place.

Timothy


On Wed, Oct 23, 2013 at 6:36 AM, Paul Butcher p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 13:18, Timothy Baldridge tbaldri...@gmail.com wrote:

 Great! you have a profiler, use that. Find the hotspots, use YourKit to
 find where the .cons is being called from, find things to optimize, and go
 from there. This is exactly the same process I would use any optimizations
 I attempted.


 I fear I may have failed to convey the question I'm trying to answer.

 I'm sure that I could create a faster solution in Clojure - that's not the
 question I'm trying to answer though.

 What I'm trying to answer is why the *exact same* algorithm implemented in
 Scala is 1000x faster.

 As far as I know, the Scala version of the algorithm creates exactly as
 many sets and performs exactly as many set operations as the Clojure does.
 But the Clojure version is 1000x slower. That strikes me as very strange
 and worth getting to the bottom of?

 I have, of course, looked at the result of the profiler. And what it seems
 to be saying is that set operations in Clojure are ruinously slow. I'm not
 sure that I believe that though - I can't think of any reason why Clojure's
 sets should be 1000x slower than Scala's? So I'm asking for the help of
 this list.

 Of course, I can't rule out the possibility that I've failed to convert
 the Scala version to Clojure and they're actually implementing very
 different algorithms - but I've had several people look at the
 implementations and confirm that they appear to be the same. Nevertheless,
 if there is a problem there, I'd also be interested to find it as I'm sure
 that it will teach me something.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.




-- 
“One of the main causes of the fall of the Roman Empire was that–lacking
zero–they had no way to indicate successful termination of their C
programs.”
(Robert Firth)

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Paul Butcher
On 23 Oct 2013, at 14:18, David Nolen dnolen.li...@gmail.com wrote:

 If set construction was 1000X worse why don't the smaller problem sizes 
 exhibit exactly the same issue? If the Scala version requires 12G why is the 
 Clojure version steady at 300M?

Both excellent questions.

 Aren't Scala for comprehensions optimized now into lower level loops? Clojure 
 for comprehensions generate lazy sequences and all the allocation and forcing 
 of thunks that implies.

I don't think so - AFAIK Scala's for statement is rewritten into flatMap and 
map under the hood. Happy to be corrected though.

--
paul.butcher-msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: p...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Paul Butcher
On 23 Oct 2013, at 14:19, David Nolen dnolen.li...@gmail.com wrote:

 The Scala code is using immutable sets.

Correct - the Scala is immutable throughout.

--
paul.butcher-msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: p...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Clojure can't import some Java classes

2013-10-23 Thread Aaron Cohen
I'm not sure if this is related to the original problem.

 How is the setFactory method expected to be invoked, through some sort of
dependency injection framework?


On Wed, Oct 23, 2013 at 7:06 AM, Colin Fleming
colin.mailingl...@gmail.comwrote:

 I've also had a lot of problems with def'ed forms. For example, if I do
 this:

 (def no-spacing (Spacing/createSpacing 0 0 0 false 0))

 Which looks like this:

   public static Spacing createSpacing(int minSpaces,
   int maxSpaces,
   int minLineFeeds,
   boolean keepLineBreaks,
   int keepBlankLines) {
 return myFactory.createSpacing(minSpaces, maxSpaces, minLineFeeds,
 keepLineBreaks, keepBlankLines);
   }

 myFactory is injected at some earlier point:

   static void setFactory(SpacingFactory factory) {
 myFactory = factory;
   }

 But during compilation that obviously hasn't happened and I get an NPE
 during compilation. It's a little annoying that there really seems to be no
 good way to create this value at namespace load time if I'm AOT compiling.
 I can obviously defer it using defn with memoize or something, but that
 seems clunky for what doesn't seem like that crazy a use case.


 On 23 October 2013 15:21, Zach Oakes zsoa...@gmail.com wrote:

 Here's the error I get when I import LibGDX's Timer class:

 http://pastebin.com/q7wys8yi


 On Tuesday, October 22, 2013 9:55:16 PM UTC-4, Alex Miller wrote:

 I'd love to see a stack trace when that happens (could even be triggered
 by dumping stack in your static initializer if nothing else).

 On Saturday, October 12, 2013 3:17:50 AM UTC-5, Wujek Srujek wrote:

 So you are saying compilation is trying to instantiate class and run
 static initializers? This seems very backward, are you sure?


 On Sat, Oct 12, 2013 at 8:30 AM, Zach Oakes zso...@gmail.com wrote:

 I should add, I am aware I can bring in a class dynamically with
 Class/forName, and that is what I ended up doing for the Timer class.
 However, this is not always practical, and sometimes is simply not an
 option if aot-compilation is required.


 On Saturday, October 12, 2013 2:28:38 AM UTC-4, Zach Oakes wrote:

 I recently learned that merely importing a Java class in Clojure
 causes static initializers to be run. Sometimes, this causes compilation
 errors, because they are written with the assumption that they will only 
 be
 run during runtime.

 I ran into this just now while trying to make a simple Clojure game
 with LibGDX. After simply importing its Timer class, I began getting
 compilation errors. The stack trace shows it is due to a static
 initializerhttps://github.com/libgdx/libgdx/blob/511b557c1a2d23bf8110a05b0ef54cc20b7f958d/gdx/src/com/badlogic/gdx/utils/Timer.java#L32attempting
  to instantiate the class!

 I also ran into this recently while trying to use RoboVM. My question
 is, do I have any options? I haven't found many discussions about this 
 here
 or elsewhere. This surprises me, because it seems like something more
 people should be running into.

  --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@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+u...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/**group/clojure?hl=enhttp://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send
 an email to clojure+u...@googlegroups.com.
 For more options, visit 
 https://groups.google.com/**groups/opt_outhttps://groups.google.com/groups/opt_out
 .


  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


  --
 --
 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, 

Re: Clojure can't import some Java classes

2013-10-23 Thread Aaron Cohen
So, is this a correct summary of the problem?

Importing a class in clojure causes static initializers to run. This
differs from Java where static initializers don't run until the first
'initialization' (either the invocation of a constructor, or invocation of
a 'main' method) of a class. In some cases, this makes it impossible to
create the environment that java classes expect to be present before they
are initialized.

On Tuesday, October 22, 2013, Zach Oakes wrote:

 Here's the error I get when I import LibGDX's Timer class:

 http://pastebin.com/q7wys8yi

 On Tuesday, October 22, 2013 9:55:16 PM UTC-4, Alex Miller wrote:

 I'd love to see a stack trace when that happens (could even be triggered
 by dumping stack in your static initializer if nothing else).

 On Saturday, October 12, 2013 3:17:50 AM UTC-5, Wujek Srujek wrote:

 So you are saying compilation is trying to instantiate class and run
 static initializers? This seems very backward, are you sure?


 On Sat, Oct 12, 2013 at 8:30 AM, Zach Oakes zso...@gmail.com wrote:

 I should add, I am aware I can bring in a class dynamically with
 Class/forName, and that is what I ended up doing for the Timer class.
 However, this is not always practical, and sometimes is simply not an
 option if aot-compilation is required.


 On Saturday, October 12, 2013 2:28:38 AM UTC-4, Zach Oakes wrote:

 I recently learned that merely importing a Java class in Clojure
 causes static initializers to be run. Sometimes, this causes compilation
 errors, because they are written with the assumption that they will only 
 be
 run during runtime.

 I ran into this just now while trying to make a simple Clojure game
 with LibGDX. After simply importing its Timer class, I began getting
 compilation errors. The stack trace shows it is due to a static
 initializerhttps://github.com/libgdx/libgdx/blob/511b557c1a2d23bf8110a05b0ef54cc20b7f958d/gdx/src/com/badlogic/gdx/utils/Timer.java#L32attempting
  to instantiate the class!

 I also ran into this recently while trying to use RoboVM. My question
 is, do I have any options? I haven't found many discussions about this 
 here
 or elsewhere. This surprises me, because it seems like something more
 people should be running into.



-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Clojure can't import some Java classes

2013-10-23 Thread Alex Miller
That's how I read things. Importing a class causes the class to be loaded 
(via Class.forName()) so that it can be stored in the namespace's mappings. 
My impression from the commented out older code is that some prior 
incarnation of the code used class names instead of Class objects in some 
prior incarnation which would avoid the loading. Seems like importing could 
potentially defer loading till use (and loading could still be forced via 
Class.forName() if needed).

On Wednesday, October 23, 2013 9:00:28 AM UTC-5, Aaron Cohen wrote:

 So, is this a correct summary of the problem?

 Importing a class in clojure causes static initializers to run. This 
 differs from Java where static initializers don't run until the first 
 'initialization' (either the invocation of a constructor, or invocation of 
 a 'main' method) of a class. In some cases, this makes it impossible to 
 create the environment that java classes expect to be present before they 
 are initialized.

 On Tuesday, October 22, 2013, Zach Oakes wrote:

 Here's the error I get when I import LibGDX's Timer class:

 http://pastebin.com/q7wys8yi

 On Tuesday, October 22, 2013 9:55:16 PM UTC-4, Alex Miller wrote:

 I'd love to see a stack trace when that happens (could even be triggered 
 by dumping stack in your static initializer if nothing else).

 On Saturday, October 12, 2013 3:17:50 AM UTC-5, Wujek Srujek wrote:

 So you are saying compilation is trying to instantiate class and run 
 static initializers? This seems very backward, are you sure?


 On Sat, Oct 12, 2013 at 8:30 AM, Zach Oakes zso...@gmail.com wrote:

 I should add, I am aware I can bring in a class dynamically with 
 Class/forName, and that is what I ended up doing for the Timer class. 
 However, this is not always practical, and sometimes is simply not an 
 option if aot-compilation is required.


 On Saturday, October 12, 2013 2:28:38 AM UTC-4, Zach Oakes wrote:

 I recently learned that merely importing a Java class in Clojure 
 causes static initializers to be run. Sometimes, this causes compilation 
 errors, because they are written with the assumption that they will only 
 be 
 run during runtime.

 I ran into this just now while trying to make a simple Clojure game 
 with LibGDX. After simply importing its Timer class, I began getting 
 compilation errors. The stack trace shows it is due to a static 
 initializerhttps://github.com/libgdx/libgdx/blob/511b557c1a2d23bf8110a05b0ef54cc20b7f958d/gdx/src/com/badlogic/gdx/utils/Timer.java#L32attempting
  to instantiate the class!

 I also ran into this recently while trying to use RoboVM. My question 
 is, do I have any options? I haven't found many discussions about this 
 here 
 or elsewhere. This surprises me, because it seems like something more 
 people should be running into.

  

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread David Powell
When you say it is spending 99% of its time in PersistentHashSet.cons, is
that the time spent in just that method, or the time spent in that method
and the methods that it calls?

Given that (set ...) is one of the first things called by (solve..), and
that its contents are produced lazily by a for comprehension, if you are
looking at the total time spent in PersistentHashSet.assoc, then maybe that
will be particularly slow.  Not that that solves the problem, but I was
wondering if PersistentHashSet.assoc might be a red herring.

Also, out of interest, are you using a sampling profiler, or an
instrumenting one?


Sometimes the built-in hprof profiler is good for this sort of thing:

java -Xrunhprof:cpu=times,depth=4 -Xmx2g -jar
target\chess-clojure-0.1.0-SNAPSHOT-standalone.jar

  - you can use either cpu=times for instrumenting, or cpu=samples for
sampling.

It is nice because the depth parameter lets you find hotspots including a
few steps up the stacktrace (4 in this case).  And you can use Ctrl-\ /
Ctrl-Break / SIG_QUIT to get it to dump the current stats while the program
is still running to see if some methods are getting worse over time.




On Wed, Oct 23, 2013 at 1:36 PM, Paul Butcher p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 13:18, Timothy Baldridge tbaldri...@gmail.com wrote:

 Great! you have a profiler, use that. Find the hotspots, use YourKit to
 find where the .cons is being called from, find things to optimize, and go
 from there. This is exactly the same process I would use any optimizations
 I attempted.


 I fear I may have failed to convey the question I'm trying to answer.

 I'm sure that I could create a faster solution in Clojure - that's not the
 question I'm trying to answer though.

 What I'm trying to answer is why the *exact same* algorithm implemented in
 Scala is 1000x faster.

 As far as I know, the Scala version of the algorithm creates exactly as
 many sets and performs exactly as many set operations as the Clojure does.
 But the Clojure version is 1000x slower. That strikes me as very strange
 and worth getting to the bottom of?

 I have, of course, looked at the result of the profiler. And what it seems
 to be saying is that set operations in Clojure are ruinously slow. I'm not
 sure that I believe that though - I can't think of any reason why Clojure's
 sets should be 1000x slower than Scala's? So I'm asking for the help of
 this list.

 Of course, I can't rule out the possibility that I've failed to convert
 the Scala version to Clojure and they're actually implementing very
 different algorithms - but I've had several people look at the
 implementations and confirm that they appear to be the same. Nevertheless,
 if there is a problem there, I'd also be interested to find it as I'm sure
 that it will teach me something.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Clojure can't import some Java classes

2013-10-23 Thread Alex Miller
Agreed - merely importing this class shouldn't be an issue (which is the 
issue at hand). 

If you need to configure Spacing, you should do that prior to using it in 
your def, but that should work fine. If that needs to happen at runtime, 
then you shouldn't do this in a def. 

On Wednesday, October 23, 2013 9:01:15 AM UTC-5, Aaron Cohen wrote:

 I'm not sure if this is related to the original problem.

  How is the setFactory method expected to be invoked, through some sort of 
 dependency injection framework?


 On Wed, Oct 23, 2013 at 7:06 AM, Colin Fleming 
 colin.ma...@gmail.comjavascript:
  wrote:

 I've also had a lot of problems with def'ed forms. For example, if I do 
 this:

 (def no-spacing (Spacing/createSpacing 0 0 0 false 0))

 Which looks like this:

   public static Spacing createSpacing(int minSpaces,
   int maxSpaces,
   int minLineFeeds,
   boolean keepLineBreaks,
   int keepBlankLines) {
 return myFactory.createSpacing(minSpaces, maxSpaces, minLineFeeds, 
 keepLineBreaks, keepBlankLines);
   }

 myFactory is injected at some earlier point:

   static void setFactory(SpacingFactory factory) {
 myFactory = factory;
   }

 But during compilation that obviously hasn't happened and I get an NPE 
 during compilation. It's a little annoying that there really seems to be no 
 good way to create this value at namespace load time if I'm AOT compiling. 
 I can obviously defer it using defn with memoize or something, but that 
 seems clunky for what doesn't seem like that crazy a use case.


 On 23 October 2013 15:21, Zach Oakes zso...@gmail.com javascript:wrote:

 Here's the error I get when I import LibGDX's Timer class:

 http://pastebin.com/q7wys8yi


 On Tuesday, October 22, 2013 9:55:16 PM UTC-4, Alex Miller wrote:

 I'd love to see a stack trace when that happens (could even be 
 triggered by dumping stack in your static initializer if nothing else).

 On Saturday, October 12, 2013 3:17:50 AM UTC-5, Wujek Srujek wrote:

 So you are saying compilation is trying to instantiate class and run 
 static initializers? This seems very backward, are you sure?


 On Sat, Oct 12, 2013 at 8:30 AM, Zach Oakes zso...@gmail.com wrote:

 I should add, I am aware I can bring in a class dynamically with 
 Class/forName, and that is what I ended up doing for the Timer class. 
 However, this is not always practical, and sometimes is simply not an 
 option if aot-compilation is required.


 On Saturday, October 12, 2013 2:28:38 AM UTC-4, Zach Oakes wrote:

 I recently learned that merely importing a Java class in Clojure 
 causes static initializers to be run. Sometimes, this causes 
 compilation 
 errors, because they are written with the assumption that they will 
 only be 
 run during runtime.

 I ran into this just now while trying to make a simple Clojure game 
 with LibGDX. After simply importing its Timer class, I began getting 
 compilation errors. The stack trace shows it is due to a static 
 initializerhttps://github.com/libgdx/libgdx/blob/511b557c1a2d23bf8110a05b0ef54cc20b7f958d/gdx/src/com/badlogic/gdx/utils/Timer.java#L32attempting
  to instantiate the class!

 I also ran into this recently while trying to use RoboVM. My 
 question is, do I have any options? I haven't found many discussions 
 about 
 this here or elsewhere. This surprises me, because it seems like 
 something 
 more people should be running into.

  -- 
 -- 
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@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+u...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/**group/clojure?hl=enhttp://groups.google.com/group/clojure?hl=en
 --- 
 You received this message because you are subscribed to the Google 
 Groups Clojure group.
 To unsubscribe from this group and stop receiving emails from it, 
 send an email to clojure+u...@googlegroups.com.
 For more options, visit 
 https://groups.google.com/**groups/opt_outhttps://groups.google.com/groups/opt_out
 .


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

Re: Request for help optimising a Clojure program

2013-10-23 Thread Paul Butcher
On 23 Oct 2013, at 15:32, David Powell djpow...@djpowell.net wrote:

 When you say it is spending 99% of its time in PersistentHashSet.cons, is 
 that the time spent in just that method, or the time spent in that method and 
 the methods that it calls?

The latter.

 Given that (set ...) is one of the first things called by (solve..), and that 
 its contents are produced lazily by a for comprehension, if you are looking 
 at the total time spent in PersistentHashSet.assoc, then maybe that will be 
 particularly slow.  Not that that solves the problem, but I was wondering if 
 PersistentHashSet.assoc might be a red herring.

Ah - that's entirely plausible. I have basically no experience of profiling 
Clojure, or understanding the way in which laziness affects doing so (I suspect 
that it complicates things somewhat?).

 Also, out of interest, are you using a sampling profiler, or an instrumenting 
 one?

Sampling.

 Sometimes the built-in hprof profiler is good for this sort of thing:
 
 java -Xrunhprof:cpu=times,depth=4 -Xmx2g -jar 
 target\chess-clojure-0.1.0-SNAPSHOT-standalone.jar
 
   - you can use either cpu=times for instrumenting, or cpu=samples for 
 sampling.
 
 It is nice because the depth parameter lets you find hotspots including a few 
 steps up the stacktrace (4 in this case).  And you can use Ctrl-\ / 
 Ctrl-Break / SIG_QUIT to get it to dump the current stats while the program 
 is still running to see if some methods are getting worse over time.

I've not used hprof before - I'll see if I can divine anything useful from it.

Thanks.

--
paul.butcher-msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: p...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
For those of you playing along at home, I also ran Paul's chess program in
YourKit with the sampling profiler.  Here are all the calls that appear in
the HotSpots view, along with time spent in those methods.

java.io.PushbackInputStream.read() 422977
clojure.lang.PersistentHashMap$HashCollisionNode.findIndex(Object) 206687
clojure.lang.Util.equiv(Object, Object) 204984
clojure.lang.PersistentHashMap$BitmapIndexedNode.find(int, int, Object,
Object) 145968
clojure.lang.PersistentHashMap$NodeSeq.create(Object[]) 81031
clojure.lang.APersistentVector.doEquiv(IPersistentVector, Object) 41656
clojure.lang.Util.dohasheq(IHashEq) 31453
clojure.lang.RT.next(Object) 28671
clojure.lang.PersistentHashMap$NodeSeq.next() 24484
clojure.lang.PersistentVector$1.init(PersistentVector, int, int) 24015

I concur with Paul that it looks like the program is spending nearly all
its time mired in hashing.  Even the calls on here that aren't obviously
related to hashing turn out on further inspection to be related to hashing.

For example, doing a backtrace on Util.equiv, one sees that the = operation
in the allowed? function is taking negligible time and the equiv method
time is almost entirely spent in hash set lookup resolution.  Similarly,
the RT.next method is negligible time spent stepping through his for
sequence, and appears to be almost entirely about stepping through hash
collision nodes.

My best guess at this point is that there is some sort of bug with the set
implementation causing too many items to hash to the same bucket.  I have
seen this behavior before from time to time when profiling some of my own
code (a suspiciously inordinate amount of time spent resolving hash
collisions) but have never been able to pin it down with such a pure
example.

I'll admit that my skills in reading and making sense out of profiler
output is pretty weak, but it looks to me that that's what is going on here.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Andy Fingerhut
Mark, I think you have hit the nail on the head.  I have instrumented a
copy of Paul's Clojure program to print the hash code of all of the
solutions in the set returned by solve, and there are *many* pairs of
solutions that have identical hash values, and thus collide in a
PersistentHashSet.  Below is an excerpt from that output:

97392280 = (hash #{[:N [2 0]] [:R [4 2]] [:K [0 0]] [:Q [1 3]] [:B [3
0]]})
97392280 = (hash #{[:N [3 0]] [:K [0 0]] [:R [1 2]] [:Q [4 3]] [:B [2
0]]})
97392280 = (hash #{[:N [3 0]] [:K [0 0]] [:R [2 1]] [:Q [1 4]] [:B [4
0]]})
97392280 = (hash #{[:N [4 0]] [:K [0 0]] [:R [3 3]] [:Q [1 2]] [:B [2
0]]})
97392280 = (hash #{[:N [3 0]] [:K [1 0]] [:R [0 2]] [:Q [2 3]] [:B [4
0]]})
97392280 = (hash #{[:N [3 0]] [:K [1 0]] [:R [2 3]] [:Q [0 2]] [:B [4
0]]})
97392280 = (hash #{[:N [4 0]] [:K [1 0]] [:R [0 2]] [:Q [2 3]] [:B [3
0]]})
97392280 = (hash #{[:N [4 0]] [:K [1 0]] [:R [2 3]] [:Q [0 2]] [:B [3
0]]})
97392280 = (hash #{[:K [3 0]] [:N [0 0]] [:Q [4 2]] [:R [2 3]] [:B [1
0]]})
97392280 = (hash #{[:K [3 0]] [:N [0 0]] [:R [4 2]] [:Q [2 3]] [:B [1
0]]})
97392280 = (hash #{[:N [1 0]] [:K [3 0]] [:Q [4 2]] [:R [2 3]] [:B [0
0]]})
97392280 = (hash #{[:N [1 0]] [:K [3 0]] [:R [4 2]] [:Q [2 3]] [:B [0
0]]})
97392280 = (hash #{[:K [4 0]] [:N [0 0]] [:Q [3 2]] [:R [1 3]] [:B [2
0]]})
97392280 = (hash #{[:K [4 0]] [:N [1 0]] [:R [3 2]] [:Q [0 3]] [:B [2
0]]})
97392280 = (hash #{[:K [4 0]] [:N [1 0]] [:R [2 1]] [:Q [3 4]] [:B [0
0]]})
97392280 = (hash #{[:N [2 0]] [:K [4 0]] [:R [0 2]] [:Q [3 3]] [:B [1
0]]})

The hash value of a set is the sum of the hashes of its elements, because
sets are not ordered.  The hash of a vector is dependent on the order of
the elements.  In fact, for 2-element vectors it is 31*(hash of 1st elem) +
(hash of 2nd elem).  The hash value of a small integer is just the integer
value itself.

Thus with many small integers in 2-element vectors like in this problem,
all it takes is having a set of vectors where the first elements sum to the
same value, and the second elements sum to the same value, and the hash of
the whole set of vectors will be equal.

Exactly what would be the best way to improve the hash code for situations
like this, I am not sure yet.

Andy


On Wed, Oct 23, 2013 at 8:46 AM, Mark Engelberg mark.engelb...@gmail.comwrote:

 For those of you playing along at home, I also ran Paul's chess program in
 YourKit with the sampling profiler.  Here are all the calls that appear in
 the HotSpots view, along with time spent in those methods.

 java.io.PushbackInputStream.read() 422977
 clojure.lang.PersistentHashMap$HashCollisionNode.findIndex(Object) 206687
 clojure.lang.Util.equiv(Object, Object) 204984
 clojure.lang.PersistentHashMap$BitmapIndexedNode.find(int, int, Object,
 Object) 145968
 clojure.lang.PersistentHashMap$NodeSeq.create(Object[]) 81031
 clojure.lang.APersistentVector.doEquiv(IPersistentVector, Object) 41656
 clojure.lang.Util.dohasheq(IHashEq) 31453
 clojure.lang.RT.next(Object) 28671
 clojure.lang.PersistentHashMap$NodeSeq.next() 24484
 clojure.lang.PersistentVector$1.init(PersistentVector, int, int) 24015

 I concur with Paul that it looks like the program is spending nearly all
 its time mired in hashing.  Even the calls on here that aren't obviously
 related to hashing turn out on further inspection to be related to hashing.

 For example, doing a backtrace on Util.equiv, one sees that the =
 operation in the allowed? function is taking negligible time and the equiv
 method time is almost entirely spent in hash set lookup resolution.
 Similarly, the RT.next method is negligible time spent stepping through his
 for sequence, and appears to be almost entirely about stepping through hash
 collision nodes.

 My best guess at this point is that there is some sort of bug with the set
 implementation causing too many items to hash to the same bucket.  I have
 seen this behavior before from time to time when profiling some of my own
 code (a suspiciously inordinate amount of time spent resolving hash
 collisions) but have never been able to pin it down with such a pure
 example.

 I'll admit that my skills in reading and making sense out of profiler
 output is pretty weak, but it looks to me that that's what is going on here.

 --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit 

Re: Request for help optimising a Clojure program

2013-10-23 Thread Paul Butcher
On 23 Oct 2013, at 17:06, Andy Fingerhut andy.finger...@gmail.com wrote:

 I have instrumented a copy of Paul's Clojure program to print the hash code 
 of all of the solutions in the set returned by solve, and there are *many* 
 pairs of solutions that have identical hash values


Aha! The smoking gun :-)

Very many thanks, Andy.

--
paul.butcher-msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: p...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Andy Fingerhut
Paul, your function solve returns a set of solutions, but there is nothing
on the program that seems to rely upon being able to quickly test whether a
particular solution is in such a set.  Returning a sequence from solve is
much faster, since it avoids the PersistentHashSet hash collision issue
entirely.

Just replace #{#{}} with [#{}], and remove the call to 'set' in solve.

Andy


On Wed, Oct 23, 2013 at 9:18 AM, Paul Butcher p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 17:06, Andy Fingerhut andy.finger...@gmail.com wrote:

 I have instrumented a copy of Paul's Clojure program to print the hash
 code of all of the solutions in the set returned by solve, and there are
 *many* pairs of solutions that have identical hash values


 Aha! The smoking gun :-)

 Very many thanks, Andy.

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Paul Butcher
On 23 Oct 2013, at 17:43, Andy Fingerhut andy.finger...@gmail.com wrote:

 Paul, your function solve returns a set of solutions, but there is nothing on 
 the program that seems to rely upon being able to quickly test whether a 
 particular solution is in such a set.  Returning a sequence from solve is 
 much faster, since it avoids the PersistentHashSet hash collision issue 
 entirely.
 
 Just replace #{#{}} with [#{}], and remove the call to 'set' in solve.

The problem with that, Andy, is that it will result in a lot of duplicates. For 
the 4x4 problem, for example, that approach raises the size of the returned 
collection from 8 to 384.

My guess is that for the 6x9 problem it will just remove the set handling 
problem and replace it with a memory/time issue as the search space grows (and 
I only have 16G in my MacBook Pro :-)

I don't need to get this working - I only knocked it together as an interesting 
exercise. And if it's helped to track down an issue in the Clojure runtime, 
it's already achieved far more than I expected it to :-)

Thanks again,

--
paul.butcher-msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: p...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Andy Fingerhut
One possibility of a change to PersistentHashSet and PersistentHashMap that
would help avoid these cases with pathologically bad performance:

If we had a 'universal comparator', i.e. a comparison function that
provided a total order on any pair of values that anyone would ever want to
put into a set or use as a map key, then instead of having linked lists for
values that collide, we could have trees like those in the implementations
of sorted-maps and sorted-sets today.  Such a comparison function might
look something like 'cc-cmp' a couple of pages down from this link:


https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/comparators.md#comparators-that-work-between-different-types

However, I believe there will always be some types where such a comparator
will fail, and thus not truly be 'universal'.  Still, if it hit the sweet
spot of 99.99% of the use cases people cared about, it might be good to
have.

Andy


On Wed, Oct 23, 2013 at 9:06 AM, Andy Fingerhut andy.finger...@gmail.comwrote:

 Mark, I think you have hit the nail on the head.  I have instrumented a
 copy of Paul's Clojure program to print the hash code of all of the
 solutions in the set returned by solve, and there are *many* pairs of
 solutions that have identical hash values, and thus collide in a
 PersistentHashSet.  Below is an excerpt from that output:

 97392280 = (hash #{[:N [2 0]] [:R [4 2]] [:K [0 0]] [:Q [1 3]] [:B [3
 0]]})
 97392280 = (hash #{[:N [3 0]] [:K [0 0]] [:R [1 2]] [:Q [4 3]] [:B [2
 0]]})
 97392280 = (hash #{[:N [3 0]] [:K [0 0]] [:R [2 1]] [:Q [1 4]] [:B [4
 0]]})
 97392280 = (hash #{[:N [4 0]] [:K [0 0]] [:R [3 3]] [:Q [1 2]] [:B [2
 0]]})
 97392280 = (hash #{[:N [3 0]] [:K [1 0]] [:R [0 2]] [:Q [2 3]] [:B [4
 0]]})
 97392280 = (hash #{[:N [3 0]] [:K [1 0]] [:R [2 3]] [:Q [0 2]] [:B [4
 0]]})
 97392280 = (hash #{[:N [4 0]] [:K [1 0]] [:R [0 2]] [:Q [2 3]] [:B [3
 0]]})
 97392280 = (hash #{[:N [4 0]] [:K [1 0]] [:R [2 3]] [:Q [0 2]] [:B [3
 0]]})
 97392280 = (hash #{[:K [3 0]] [:N [0 0]] [:Q [4 2]] [:R [2 3]] [:B [1
 0]]})
 97392280 = (hash #{[:K [3 0]] [:N [0 0]] [:R [4 2]] [:Q [2 3]] [:B [1
 0]]})
 97392280 = (hash #{[:N [1 0]] [:K [3 0]] [:Q [4 2]] [:R [2 3]] [:B [0
 0]]})
 97392280 = (hash #{[:N [1 0]] [:K [3 0]] [:R [4 2]] [:Q [2 3]] [:B [0
 0]]})
 97392280 = (hash #{[:K [4 0]] [:N [0 0]] [:Q [3 2]] [:R [1 3]] [:B [2
 0]]})
 97392280 = (hash #{[:K [4 0]] [:N [1 0]] [:R [3 2]] [:Q [0 3]] [:B [2
 0]]})
 97392280 = (hash #{[:K [4 0]] [:N [1 0]] [:R [2 1]] [:Q [3 4]] [:B [0
 0]]})
 97392280 = (hash #{[:N [2 0]] [:K [4 0]] [:R [0 2]] [:Q [3 3]] [:B [1
 0]]})

 The hash value of a set is the sum of the hashes of its elements, because
 sets are not ordered.  The hash of a vector is dependent on the order of
 the elements.  In fact, for 2-element vectors it is 31*(hash of 1st elem) +
 (hash of 2nd elem).  The hash value of a small integer is just the integer
 value itself.

 Thus with many small integers in 2-element vectors like in this problem,
 all it takes is having a set of vectors where the first elements sum to the
 same value, and the second elements sum to the same value, and the hash of
 the whole set of vectors will be equal.

 Exactly what would be the best way to improve the hash code for situations
 like this, I am not sure yet.

 Andy


 On Wed, Oct 23, 2013 at 8:46 AM, Mark Engelberg 
 mark.engelb...@gmail.comwrote:

 For those of you playing along at home, I also ran Paul's chess program
 in YourKit with the sampling profiler.  Here are all the calls that appear
 in the HotSpots view, along with time spent in those methods.

 java.io.PushbackInputStream.read() 422977
 clojure.lang.PersistentHashMap$HashCollisionNode.findIndex(Object) 206687
 clojure.lang.Util.equiv(Object, Object) 204984
 clojure.lang.PersistentHashMap$BitmapIndexedNode.find(int, int, Object,
 Object) 145968
 clojure.lang.PersistentHashMap$NodeSeq.create(Object[]) 81031
 clojure.lang.APersistentVector.doEquiv(IPersistentVector, Object) 41656
 clojure.lang.Util.dohasheq(IHashEq) 31453
 clojure.lang.RT.next(Object) 28671
 clojure.lang.PersistentHashMap$NodeSeq.next() 24484
 clojure.lang.PersistentVector$1.init(PersistentVector, int, int) 24015

 I concur with Paul that it looks like the program is spending nearly all
 its time mired in hashing.  Even the calls on here that aren't obviously
 related to hashing turn out on further inspection to be related to hashing.

 For example, doing a backtrace on Util.equiv, one sees that the =
 operation in the allowed? function is taking negligible time and the equiv
 method time is almost entirely spent in hash set lookup resolution.
 Similarly, the RT.next method is negligible time spent stepping through his
 for sequence, and appears to be almost entirely about stepping through hash
 collision nodes.

 My best guess at this point is that there is some sort of bug with the
 set implementation causing too many items 

Re: Request for help optimising a Clojure program

2013-10-23 Thread Andy Fingerhut
Ah, right you are.  I missed that.

I think the collisions possible with PersistentHashSet and
PersistentHashMap were 'well known', at least to a subset of people.  What
is probably less well known is a nice small program that caused many
collisions with today's hash functions, and an explanation of why.  Thanks
for that.

Andy


On Wed, Oct 23, 2013 at 10:13 AM, Paul Butcher p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 17:43, Andy Fingerhut andy.finger...@gmail.com wrote:

 Paul, your function solve returns a set of solutions, but there is nothing
 on the program that seems to rely upon being able to quickly test whether a
 particular solution is in such a set.  Returning a sequence from solve is
 much faster, since it avoids the PersistentHashSet hash collision issue
 entirely.

 Just replace #{#{}} with [#{}], and remove the call to 'set' in solve.


 The problem with that, Andy, is that it will result in a lot of
 duplicates. For the 4x4 problem, for example, that approach raises the size
 of the returned collection from 8 to 384.

 My guess is that for the 6x9 problem it will just remove the set handling
 problem and replace it with a memory/time issue as the search space grows
 (and I only have 16G in my MacBook Pro :-)

 I don't need to get this working - I only knocked it together as an
 interesting exercise. And if it's helped to track down an issue in the
 Clojure runtime, it's already achieved far more than I expected it to :-)

 Thanks again,

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Paul Butcher
On 23 Oct 2013, at 18:15, Andy Fingerhut andy.finger...@gmail.com wrote:

 If we had a 'universal comparator', i.e. a comparison function that provided 
 a total order on any pair of values that anyone would ever want to put into a 
 set or use as a map key, then instead of having linked lists for values that 
 collide, we could have trees like those in the implementations of sorted-maps 
 and sorted-sets today.

Wouldn't it be better to improve the way that hashes are calculated for 
vectors? A good hash function should make it unlikely that similar values have 
the same hash. The current algorithm seems to make that more likely than it 
should?

--
paul.butcher-msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: p...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Andy Fingerhut
If you can think of a different hash function for vectors that doesn't lead
to these types of collisions, I'm all ears.  The issue is that the hash
function for sets adds up the hash values of its elements.  Those sums of
vector hash values are what are colliding, not the individual vector hash
values themselves.

Andy


On Wed, Oct 23, 2013 at 10:28 AM, Paul Butcher p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 18:15, Andy Fingerhut andy.finger...@gmail.com wrote:

 If we had a 'universal comparator', i.e. a comparison function that
 provided a total order on any pair of values that anyone would ever want to
 put into a set or use as a map key, then instead of having linked lists for
 values that collide, we could have trees like those in the implementations
 of sorted-maps and sorted-sets today.


 Wouldn't it be better to improve the way that hashes are calculated for
 vectors? A good hash function should make it unlikely that similar values
 have the same hash. The current algorithm seems to make that more likely
 than it should?

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread David Nolen
The problem here is that you're not following your Scala solution closely
enough. I suspect if you used defrecords to represent the pieces the way
that you used a class in Scala you can avoid the number of collisions for
larger problems.

Not tested much but I tried something like the following and I no longer
see hash collisions dominating in YourKit:

(defrecord Piece [name pos])

(defn piece [name  pos]
  (Piece. name pos))

(defn takes? [name [dx dy]]
  (case name
:K (and (= dx 1) (= dy 1))
:Q (or (zero? dx) (zero? dy) (== dx dy))
:R (or (zero? dx) (zero? dy))
:B (== dx dy)
:N (or (and (== dx 1) (== dy 2)) (and (== dx 2) (== dy 1)

(defn allows? [{name :name [px py] :pos} [x y]]
  (let [delta [(Math/abs (int (- px x))) (Math/abs (int (- py y)))]]
(and (not (and (== px x) (== py y))) (not (takes? name delta)

(defn allowed? [{cname :name cpos :pos :as cand} solution]
  (every?
(fn [{pos :pos :as piece}]
  (and (allows? piece cpos) (allows? cand pos)))
solution))

(defn solve [rows cols pieces]
  (if (empty? pieces)
#{#{}}
(set
  (let [name (first pieces)]
(for [solution (solve rows cols (rest pieces))
  x (range 0 cols)
  y (range 0 rows)
  :let [cand (piece name [x y])]
  :when (allowed? cand solution)]
  (conj solution cand))

David

On Wed, Oct 23, 2013 at 1:28 PM, Paul Butcher p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 18:15, Andy Fingerhut andy.finger...@gmail.com wrote:

 If we had a 'universal comparator', i.e. a comparison function that
 provided a total order on any pair of values that anyone would ever want to
 put into a set or use as a map key, then instead of having linked lists for
 values that collide, we could have trees like those in the implementations
 of sorted-maps and sorted-sets today.


 Wouldn't it be better to improve the way that hashes are calculated for
 vectors? A good hash function should make it unlikely that similar values
 have the same hash. The current algorithm seems to make that more likely
 than it should?

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Pablo Nussembaum
What do you think of adding odd elements and substract even ones?

[1 2] = 1 - 2 = -1
[2 1] = 2 - 1 = 1

On 10/23/2013 02:30 PM, Andy Fingerhut wrote:
 If you can think of a different hash function for vectors that doesn't
 lead to these types of collisions, I'm all ears.  The issue is that
 the hash function for sets adds up the hash values of its elements. 
 Those sums of vector hash values are what are colliding, not the
 individual vector hash values themselves.

 Andy


 On Wed, Oct 23, 2013 at 10:28 AM, Paul Butcher p...@paulbutcher.com
 mailto:p...@paulbutcher.com wrote:

 On 23 Oct 2013, at 18:15, Andy Fingerhut andy.finger...@gmail.com
 mailto:andy.finger...@gmail.com wrote:

 If we had a 'universal comparator', i.e. a comparison function
 that provided a total order on any pair of values that anyone
 would ever want to put into a set or use as a map key, then
 instead of having linked lists for values that collide, we could
 have trees like those in the implementations of sorted-maps and
 sorted-sets today.

 Wouldn't it be better to improve the way that hashes are
 calculated for vectors? A good hash function should make it
 unlikely that similar values have the same hash. The current
 algorithm seems to make that more likely than it should?

 --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com http://www.paulbutcher.com//
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com mailto:p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

 -- 
 -- 
 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
 mailto: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
 mailto:clojure%2bunsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To unsubscribe from this group and stop receiving emails from it,
 send an email to clojure+unsubscr...@googlegroups.com
 mailto:clojure%2bunsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


 -- 
 -- 
 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
 ---
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send
 an email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
On Wed, Oct 23, 2013 at 10:39 AM, Pablo Nussembaum bau...@gmail.com wrote:

  What do you think of adding odd elements and substract even ones?

 [1 2] = 1 - 2 = -1
 [2 1] = 2 - 1 = 1


Wouldn't multiplying the hash values of the items in a set (rather than
adding) result in far fewer accidental collisions from similar items?

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Andy Fingerhut
That makes them each different, but if you put them in a set together, like
#{[1 2] [2 1]}, the hash of the set is 1-1=0 no matter what order those
vectors are put into the set.

That is the difficulty.


On Wed, Oct 23, 2013 at 10:39 AM, Pablo Nussembaum bau...@gmail.com wrote:

  What do you think of adding odd elements and substract even ones?

 [1 2] = 1 - 2 = -1
 [2 1] = 2 - 1 = 1


 On 10/23/2013 02:30 PM, Andy Fingerhut wrote:

 If you can think of a different hash function for vectors that doesn't
 lead to these types of collisions, I'm all ears.  The issue is that the
 hash function for sets adds up the hash values of its elements.  Those sums
 of vector hash values are what are colliding, not the individual vector
 hash values themselves.

 Andy


 On Wed, Oct 23, 2013 at 10:28 AM, Paul Butcher p...@paulbutcher.comwrote:

  On 23 Oct 2013, at 18:15, Andy Fingerhut andy.finger...@gmail.com
 wrote:

  If we had a 'universal comparator', i.e. a comparison function that
 provided a total order on any pair of values that anyone would ever want to
 put into a set or use as a map key, then instead of having linked lists for
 values that collide, we could have trees like those in the implementations
 of sorted-maps and sorted-sets today.


  Wouldn't it be better to improve the way that hashes are calculated for
 vectors? A good hash function should make it unlikely that similar values
 have the same hash. The current algorithm seems to make that more likely
 than it should?

  --
 paul.butcher-msgCount++

 Snetterton, Castle Combe, Cadwell Park...
 Who says I have a one track mind?

 http://www.paulbutcher.com/
 LinkedIn: http://www.linkedin.com/in/paulbutcher
 MSN: p...@paulbutcher.com
 AIM: paulrabutcher
 Skype: paulrabutcher

   --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Michael Gardner
On Oct 23, 2013, at 12:30 , Andy Fingerhut andy.finger...@gmail.com wrote:

 If you can think of a different hash function for vectors that doesn't lead 
 to these types of collisions, I'm all ears.  The issue is that the hash 
 function for sets adds up the hash values of its elements.  Those sums of 
 vector hash values are what are colliding, not the individual vector hash 
 values themselves.

What about the formula used by Boost's hash_combine?

http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
Another example of why this has more to do with the hashing of sets, than
underlying elements:
= (hash #{#{1 2} 3})
6
= (hash #{#{1 3} 2})
6

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Michael Gardner
On Oct 23, 2013, at 14:34 , Mark Engelberg mark.engelb...@gmail.com wrote:

 Another example of why this has more to do with the hashing of sets, than 
 underlying elements:
 = (hash #{#{1 2} 3})
 6
 = (hash #{#{1 3} 2})
 6

The hash-combining function for sets must be commutative. But in order for the 
hashes of #{#{1 2} 3} and #{#{1 3} 2} to be unequal, it must also be 
non-associative. That's possible, but I'm not sure what would be a good 
candidate function. Something involving averaging, perhaps?

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Clojure can't import some Java classes

2013-10-23 Thread Colin Fleming
Right, my Spacing problem is not related to the static initializer problem
(which I also suffer from) but it is another example of (what seems to me)
a fairly standard pattern that I can't use in Clojure if I AOT and which
doesn't have an obvious workaround.


On 24 October 2013 03:32, Alex Miller a...@puredanger.com wrote:

 Agreed - merely importing this class shouldn't be an issue (which is the
 issue at hand).

 If you need to configure Spacing, you should do that prior to using it in
 your def, but that should work fine. If that needs to happen at runtime,
 then you shouldn't do this in a def.


 On Wednesday, October 23, 2013 9:01:15 AM UTC-5, Aaron Cohen wrote:

 I'm not sure if this is related to the original problem.

  How is the setFactory method expected to be invoked, through some sort
 of dependency injection framework?


 On Wed, Oct 23, 2013 at 7:06 AM, Colin Fleming colin.ma...@gmail.comwrote:

  I've also had a lot of problems with def'ed forms. For example, if I
 do this:

 (def no-spacing (Spacing/createSpacing 0 0 0 false 0))

 Which looks like this:

   public static Spacing createSpacing(int minSpaces,
   **int maxSpaces,
   **int minLineFeeds,
   **boolean keepLineBreaks,
   **int keepBlankLines) {
 return myFactory.createSpacing(**minSpaces, maxSpaces,
 minLineFeeds, keepLineBreaks, keepBlankLines);
   }

 myFactory is injected at some earlier point:

   static void setFactory(SpacingFactory factory) {
 myFactory = factory;
   }

 But during compilation that obviously hasn't happened and I get an NPE
 during compilation. It's a little annoying that there really seems to be no
 good way to create this value at namespace load time if I'm AOT compiling.
 I can obviously defer it using defn with memoize or something, but that
 seems clunky for what doesn't seem like that crazy a use case.


 On 23 October 2013 15:21, Zach Oakes zso...@gmail.com wrote:

 Here's the error I get when I import LibGDX's Timer class:

 http://pastebin.com/q7wys8yi


 On Tuesday, October 22, 2013 9:55:16 PM UTC-4, Alex Miller wrote:

 I'd love to see a stack trace when that happens (could even be
 triggered by dumping stack in your static initializer if nothing else).

 On Saturday, October 12, 2013 3:17:50 AM UTC-5, Wujek Srujek wrote:

 So you are saying compilation is trying to instantiate class and run
 static initializers? This seems very backward, are you sure?


 On Sat, Oct 12, 2013 at 8:30 AM, Zach Oakes zso...@gmail.com wrote:

 I should add, I am aware I can bring in a class dynamically with
 Class/forName, and that is what I ended up doing for the Timer class.
 However, this is not always practical, and sometimes is simply not an
 option if aot-compilation is required.


 On Saturday, October 12, 2013 2:28:38 AM UTC-4, Zach Oakes wrote:

 I recently learned that merely importing a Java class in Clojure
 causes static initializers to be run. Sometimes, this causes 
 compilation
 errors, because they are written with the assumption that they will 
 only be
 run during runtime.

 I ran into this just now while trying to make a simple Clojure game
 with LibGDX. After simply importing its Timer class, I began getting
 compilation errors. The stack trace shows it is due to a static
 initializerhttps://github.com/libgdx/libgdx/blob/511b557c1a2d23bf8110a05b0ef54cc20b7f958d/gdx/src/com/badlogic/gdx/utils/Timer.java#L32attempting
  to instantiate the class!

 I also ran into this recently while trying to use RoboVM. My
 question is, do I have any options? I haven't found many discussions 
 about
 this here or elsewhere. This surprises me, because it seems like 
 something
 more people should be running into.

  --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@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+u...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/**group**/clojure?hl=enhttp://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To unsubscribe from this group and stop receiving emails from it,
 send an email to clojure+u...@googlegroups.com.
 For more options, visit 
 https://groups.google.com/**grou**ps/opt_outhttps://groups.google.com/groups/opt_out
 .


  --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@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+u...@**googlegroups.com
 For more options, visit this group at
 

Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
It is true that it must be commutative, but not true that it must be
non-associative.  Here is a sample implementation of a hash function for
sets that is commutative and associative but doesn't collide for these
sorts of common rearrangements.  The idea of this proof of concept is that
the hash value of a set is the sum of (expt 3 (abs (hash item))) for each
item in the set.

Implementation:

;; First a wrap-around implementation of expt
(defn- expt [base pow]
  (if (zero? pow) 1
(loop [n (int pow), y (int 1), z (int base)]
  (let [t (even? n), n (quot n 2)]
(cond
  t (recur n y (unchecked-multiply-int z z))
  (zero? n) (unchecked-multiply-int z y)
  :else (recur n (unchecked-multiply-int z y)
(unchecked-multiply-int z z)))

(declare my-hash)

(defn set-hash [coll]
  (reduce + (for [item (seq coll)] (expt 3 (my-hash item)

(defn my-hash [i]
  (if (set? i) (set-hash i) (hash i)))

= (my-hash #{#{1 2} 3})
531468
= (my-hash #{#{1 3} 2})
-1010140990

= (my-hash #{#{1 3} #{2 4}})
-2065039966
= (my-hash #{#{1 2} #{3 4}})
-868484254

= (my-hash #{[1 2] [2 1]})
-3497906806
= (my-hash #{[1 1] [2 2]})
-443882362


So this is certainly a solvable problem, the real question is how to go
about designing such a hash function around a smaller number of simple
arithmetic operations.  Also, the above implementation is kind of lame
because that expt function treats the hash value of the item as a positive
number, effectively cutting the possible hash values in half.  So this
implementation isn't practical, but should serve as an illustration of what
could be done.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Michael Gardner
On Oct 23, 2013, at 17:03 , Mark Engelberg mark.engelb...@gmail.com wrote:

 It is true that it must be commutative, but not true that it must be 
 non-associative.  Here is a sample implementation of a hash function for sets 
 that is commutative and associative but doesn't collide for these sorts of 
 common rearrangements.  The idea of this proof of concept is that the hash 
 value of a set is the sum of (expt 3 (abs (hash item))) for each item in the 
 set.

Associativity is only meaningful for binary operators-- I was assuming a binary 
hash-combining function that would be applied via reduce or such. The function 
you've described can't be implemented as a binary operator without changing its 
behavior, so it can't be described as associative. But you're right that Set's 
hash function doesn't need to be associative, since it doesn't actually need to 
be a binary operator.

BTW, while looking into this I discovered that Clojure already defines a 
function clojure.lang.Util/hashCombine that uses Boost's hash-combining 
algorithm, but it doesn't seem to be used for anything except Symbols at the 
moment.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
OK, here is a more serious proposal, comprised of simple, fast operations:

To hash a set, you take each of the items in the set, compute the hash
value, xor it with the golden number, and square it.
Add these results together.

Essentially, it's the sum of the squares of the hashes, the xor is thrown
in there primarily so common numbers like 0 have a meaningful effect on the
hash (without the xor there's no difference between #{0 1} and #{1}, for
example).

Here's Clojure code:

(declare my-hash)

(defn set-hash [coll]
  (reduce + (for [item (seq coll)]
  (let [hash-item (.intValue (bit-xor 0x9e3779b9 (my-hash
item)))]
(unchecked-multiply-int hash-item
hash-item)

(defn my-hash [i]
  (if (set? i) (set-hash i) (hash i)))

Note that the .intValue call can go away if you convert this to Java and
use int xor rather than Clojure's xor.

This gives really nice spread-out results for similar sets:

= (my-hash #{{1 2} 3})
1067103816
= (my-hash #{{1 3} 2})
3094912306
= (my-hash #{{1 4} {2 3}})
-3227863472
= (my-hash #{{1 3} {2 4}})
2855562010
= (my-hash #{[1 1] [2 2]})
3474272896
= (my-hash #{[1 2] [2 1]})
-1060041718

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Confusing ArityExceptions from macros

2013-10-23 Thread James Gatannah
Oh, nice! I've been wondering what this error means for at least a month 
now.

Thanks,
James


On Thursday, October 17, 2013 1:14:21 PM UTC-5, Alex Coventry wrote:

 If you've ever had a confusing 
 ArityExceptionhttp://clojure-log.n01se.net/date/2013-10-16.html#19:37 while 
 working with macros, the reason may be that 
 clojure.lang.Compiler.macroexpand1 rethrows any 
 ArityExceptionshttps://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L6475it
  catches from a call to a macro, in order to reduce the number of 
 arguments reported.  This messes up the stack, potentially destroying 
 information about where the ArityException occurred if it did not occur 
 from the call to the macro itself.  For instance:

 user (do (defn inner [] (assoc)) (defmacro f [] (inner)) (f))
 ArityException Wrong number of args (-2) passed to: core$assoc 
  clojure.lang.Compiler.macroexpand1 (Compiler.java:6488)
 user (use 'clojure.repl) (pst)
 nil
 ArityException Wrong number of args (-2) passed to: core$assoc
 clojure.lang.Compiler.macroexpand1 (Compiler.java:6488)
 clojure.lang.Compiler.macroexpand (Compiler.java:6544)
 clojure.lang.Compiler.eval (Compiler.java:6618)
 clojure.lang.Compiler.eval (Compiler.java:6624)
 clojure.lang.Compiler.eval (Compiler.java:6597)
 clojure.core/eval (core.clj:2864)
 clojure.main/repl/read-eval-print--6596/fn--6599 (main.clj:260)
 clojure.main/repl/read-eval-print--6596 (main.clj:260)
 clojure.main/repl/fn--6605 (main.clj:278)
 clojure.main/repl (main.clj:278)
 clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn--1251 
 (interruptible_eval.clj:56)
 clojure.core/apply (core.clj:617)
 nil
 user 


 Note that the call to inner is not in the stack trace, and the number of 
 arguments to it have been reduced by 2, leading to a nonsensical result in 
 this case.

 The patch at http://dev.clojure.org/jira/browse/CLJ-1279 fixes this bug. 
  Might save you some time, if you're developing macros.

 Best regards,
 Alex


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
I'd like to point out that my proposed hash function lends itself nicely to
incremental hashing for sets.

Furthermore, maps also have very weak hashing, and would benefit from a
similar change.  Right now:
= (hash {1 1})
0
= (hash {1 1 2 2})
0
= (hash {1 1 2 2 3 3})
0
= (hash {1 2 2 3 3 1})
6
= (hash {1 3 2 1 3 2})
6

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
Perhaps I don't understand your point, but vector hashing is not currently
the sum of hashes.  It's a more complex computation.

= (hash [0 2])
963
= (hash [2 0])
1023
= (hash [2])
33

The fact that numbers hash to themselves means that the resulting hashes
are not hugely spread apart, but collisions don't seem to be as common as
with sets and maps.  I'm sure it could be improved, but vector/sequence
hashing doesn't strike me as a huge issue.


On Wed, Oct 23, 2013 at 5:31 PM, Cedric Greevey cgree...@gmail.com wrote:

 There's still a problem with collisions among *vectors* though.

 I'd say the real underlying problem is that small integers hash to
 themselves. If you let N be a fairly large number satisfying GCD(N, 2^32 -
 1) = 1, then multiplying 32-bit integers by N would send nearby integers to
 widely separated ones, while inducing a permutation on nonzero integers --
 the hash space wouldn't be any smaller. That alone won't help much with the
 vector problem, since 3N + 2N = 5N just as 3 + 2 = 5, though it may help
 avoid collisions with small integers in small hash maps when the hash is
 being used modulo a small hash-table length. What might help with vectors,
 sets, and other small data structures containing integers (but would shrink
 the hash space by about half) is to additionally square the result (all
 operations being 2s-complement 32-bit integer operations with wrapping --
 Java int arithmetic). Now 1 and 4 won't give the same summed hashes as 3
 and 2, and 0 and 5 will be different again. You might also want to add some
 constant to avoid 0 hashing to 0.



-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Stuart Halloway
Is the Scala for lazy or eager?  If the latter, you are not comparing
apples to apples (separate from the other differences David already pointed
out.)

Stu


On Wed, Oct 23, 2013 at 8:41 PM, Mark Engelberg mark.engelb...@gmail.comwrote:

 Perhaps I don't understand your point, but vector hashing is not currently
 the sum of hashes.  It's a more complex computation.

 = (hash [0 2])
 963
 = (hash [2 0])
 1023
 = (hash [2])
 33

 The fact that numbers hash to themselves means that the resulting hashes
 are not hugely spread apart, but collisions don't seem to be as common as
 with sets and maps.  I'm sure it could be improved, but vector/sequence
 hashing doesn't strike me as a huge issue.



 On Wed, Oct 23, 2013 at 5:31 PM, Cedric Greevey cgree...@gmail.comwrote:

 There's still a problem with collisions among *vectors* though.

 I'd say the real underlying problem is that small integers hash to
 themselves. If you let N be a fairly large number satisfying GCD(N, 2^32 -
 1) = 1, then multiplying 32-bit integers by N would send nearby integers to
 widely separated ones, while inducing a permutation on nonzero integers --
 the hash space wouldn't be any smaller. That alone won't help much with the
 vector problem, since 3N + 2N = 5N just as 3 + 2 = 5, though it may help
 avoid collisions with small integers in small hash maps when the hash is
 being used modulo a small hash-table length. What might help with vectors,
 sets, and other small data structures containing integers (but would shrink
 the hash space by about half) is to additionally square the result (all
 operations being 2s-complement 32-bit integer operations with wrapping --
 Java int arithmetic). Now 1 and 4 won't give the same summed hashes as 3
 and 2, and 0 and 5 will be different again. You might also want to add some
 constant to avoid 0 hashing to 0.

  --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
Even though vectors aren't as prone to collision between similar-looking
vectors, I think you are right that the smallness of the numbers is a
problem:

Consider the following:

= (count (set (for [x (range 200) y (range 200)] (hash [x y]
6369

This means that out of 40,000 common ordered pairs, there are only 6369
distinct hash values.  That's not good.

So yes, upon further thought, I think sequence hashing should be improved
as well.

I want to emphasize that I don't view this as merely a theoretical
problem.  I have noticed for over a year now, when profiling my Clojure
code, that a surprising amount of time was spent on dealing with hash
collisions.  I chalked it up as the natural behavior of hash tables which
will occasionally have collisions, and just learned to live with it, but
the more I play around with the existing hash function on data similar to
what I use (with small numbers in slightly varying structures), the more
I'm convinced that Clojure's weak hashing strategy explains the performance
issues I've had.  Would love to see the Clojure community tackle this
head-on; I think there's a lot of performance to be gained for many real
apps by doing this.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Experiences using SQLite with Clojure? Recommendations?

2013-10-23 Thread John Gabriele
How have your experiences been using SQLite with Clojure?

Back when org.xerial/sqlite-jdbc was at v3.7.2, I'd heard some complaints. 
But I notice that the project appears to be fairly actively maintained (see 
its [mailing list] and [project page]). The current version is 3.7.15-M1.

[mailing list]: https://groups.google.com/forum/?hl=en#!forum/xerial
[project page]: https://bitbucket.org/xerial/sqlite-jdbc

Any recommendations for or against using SQLite with Clojure?

digression navel-gazing-level=8
I wonder if use of SQLite with the JVM platform increases as alternative 
JVM languages become more popular...
/digression

Thanks!

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Experiences using SQLite with Clojure? Recommendations?

2013-10-23 Thread Zach Oakes
I'm a proponent of using H2 http://www.h2database.com/html/main.html via 
clojure.java.jdbc https://github.com/clojure/java.jdbc. H2 is written in 
Java, so it'll work everywhere your Clojure code does, and it has a lot of 
stuff not built into SQLite such as encryption.

On Wednesday, October 23, 2013 10:14:59 PM UTC-4, John Gabriele wrote:

 How have your experiences been using SQLite with Clojure?

 Back when org.xerial/sqlite-jdbc was at v3.7.2, I'd heard some complaints. 
 But I notice that the project appears to be fairly actively maintained (see 
 its [mailing list] and [project page]). The current version is 3.7.15-M1.

 [mailing list]: https://groups.google.com/forum/?hl=en#!forum/xerial
 [project page]: https://bitbucket.org/xerial/sqlite-jdbc

 Any recommendations for or against using SQLite with Clojure?

 digression navel-gazing-level=8
 I wonder if use of SQLite with the JVM platform increases as alternative 
 JVM languages become more popular...
 /digression

 Thanks!



-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mikera
On Thursday, 24 October 2013 09:12:21 UTC+8, puzzler wrote:

 Even though vectors aren't as prone to collision between similar-looking 
 vectors, I think you are right that the smallness of the numbers is a 
 problem:

 Consider the following:

 = (count (set (for [x (range 200) y (range 200)] (hash [x y]
 6369

 This means that out of 40,000 common ordered pairs, there are only 6369 
 distinct hash values.  That's not good.

 So yes, upon further thought, I think sequence hashing should be improved 
 as well.

 I want to emphasize that I don't view this as merely a theoretical 
 problem.  I have noticed for over a year now, when profiling my Clojure 
 code, that a surprising amount of time was spent on dealing with hash 
 collisions.  I chalked it up as the natural behavior of hash tables which 
 will occasionally have collisions, and just learned to live with it, but 
 the more I play around with the existing hash function on data similar to 
 what I use (with small numbers in slightly varying structures), the more 
 I'm convinced that Clojure's weak hashing strategy explains the performance 
 issues I've had.  Would love to see the Clojure community tackle this 
 head-on; I think there's a lot of performance to be gained for many real 
 apps by doing this.


You can't change the hashCode of lists / vectors without breaking the 
contract for java.util.List (which PersistentList and PersistentVector both 
implement) - 
http://docs.oracle.com/javase/7/docs/api/java/util/List.html#hashCode()

I don't think breaking this would be a good idea.

The java.util.List hashCode isn't actually too bad.  It's a decent 
compromise between an efficient implementation and reasonably effective 
hashing for most real-world use cases.

Sure you can construct artificial examples where you get some collisions, 
but that's true of any hash code function. But note that the maximum number 
of collisions is still pretty low:

(apply max (vals (frequencies (for [x (range 200) y (range 200)] (hash [x 
y])
= 7

That's actually the number you really care about, since it is the number of 
objects in the same hash bucket that drives the pathological O(n^2) 
behaviours.
 

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


The Problem with Threads

2013-10-23 Thread Rich Morin
I just read The Problem with Threads and found it very interesting.
Although it's a bit dated (2006), it brings some useful and interesting
insights to the discussion.

  The Problem with Threads, Edward A. Lee
  http://www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.pdf
  
-r

 -- 
http://www.cfcl.com/rdmRich Morin
http://www.cfcl.com/rdm/resume r...@cfcl.com
http://www.cfcl.com/rdm/weblog +1 650-873-7841

Software system design, development, and documentation


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mark Engelberg
OK, I get that if lists have to match the Java hash code, then it's a
nonstarter to try to improve it.  However, Clojure makes a distinction
between hasheq and hashCode, one of which is used within Clojure and one of
which is used for Java interop, and I don't think they necessarily need to
match.

I don't really consider this to be a contrived case.  It's pretty typical,
in my experience, for Clojure programmers to choose to represent a 2D array
as a map from [x y] to values.  That's often more practical to intialize
and work with than a vectors-in-vector layout.  So a map with keys ranging
from [0 0] to [199 199] would be what you'd get for a 200x200 array.

Having 6-7 objects per bucket isn't the end of the world, but it means that
all your lookups are several times slower than they could be.

All that said, I think that improving set hashing is a more pressing issue.



On Wed, Oct 23, 2013 at 9:05 PM, Mikera mike.r.anderson...@gmail.comwrote:

 On Thursday, 24 October 2013 09:12:21 UTC+8, puzzler wrote:

 Even though vectors aren't as prone to collision between similar-looking
 vectors, I think you are right that the smallness of the numbers is a
 problem:

 Consider the following:

 = (count (set (for [x (range 200) y (range 200)] (hash [x y]
 6369

 This means that out of 40,000 common ordered pairs, there are only 6369
 distinct hash values.  That's not good.

 So yes, upon further thought, I think sequence hashing should be improved
 as well.

 I want to emphasize that I don't view this as merely a theoretical
 problem.  I have noticed for over a year now, when profiling my Clojure
 code, that a surprising amount of time was spent on dealing with hash
 collisions.  I chalked it up as the natural behavior of hash tables which
 will occasionally have collisions, and just learned to live with it, but
 the more I play around with the existing hash function on data similar to
 what I use (with small numbers in slightly varying structures), the more
 I'm convinced that Clojure's weak hashing strategy explains the performance
 issues I've had.  Would love to see the Clojure community tackle this
 head-on; I think there's a lot of performance to be gained for many real
 apps by doing this.


 You can't change the hashCode of lists / vectors without breaking the
 contract for java.util.List (which PersistentList and PersistentVector both
 implement) -
 http://docs.oracle.com/javase/7/docs/api/java/util/List.html#hashCode()

 I don't think breaking this would be a good idea.

 The java.util.List hashCode isn't actually too bad.  It's a decent
 compromise between an efficient implementation and reasonably effective
 hashing for most real-world use cases.

 Sure you can construct artificial examples where you get some collisions,
 but that's true of any hash code function. But note that the maximum number
 of collisions is still pretty low:

 (apply max (vals (frequencies (for [x (range 200) y (range 200)] (hash [x
 y])
 = 7

 That's actually the number you really care about, since it is the number
 of objects in the same hash bucket that drives the pathological O(n^2)
 behaviours.


 --
 --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Request for help optimising a Clojure program

2013-10-23 Thread Mikera
Agreed, set hashing is definitely a bigger issue.

Also agree array indexing is is a pretty common use case, though if people 
care about performance for manipulating arrays of data with integer indexes 
then they should probably be looking at core.matrix rather than trying to 
simulate array programming with maps and vectors. Right tool for the right 
job, and all that.

On Thursday, 24 October 2013 12:40:13 UTC+8, puzzler wrote:

 OK, I get that if lists have to match the Java hash code, then it's a 
 nonstarter to try to improve it.  However, Clojure makes a distinction 
 between hasheq and hashCode, one of which is used within Clojure and one of 
 which is used for Java interop, and I don't think they necessarily need to 
 match.

 I don't really consider this to be a contrived case.  It's pretty typical, 
 in my experience, for Clojure programmers to choose to represent a 2D array 
 as a map from [x y] to values.  That's often more practical to intialize 
 and work with than a vectors-in-vector layout.  So a map with keys ranging 
 from [0 0] to [199 199] would be what you'd get for a 200x200 array.

 Having 6-7 objects per bucket isn't the end of the world, but it means 
 that all your lookups are several times slower than they could be.

 All that said, I think that improving set hashing is a more pressing issue.



 On Wed, Oct 23, 2013 at 9:05 PM, Mikera mike.r.an...@gmail.comjavascript:
  wrote:

 On Thursday, 24 October 2013 09:12:21 UTC+8, puzzler wrote:

 Even though vectors aren't as prone to collision between similar-looking 
 vectors, I think you are right that the smallness of the numbers is a 
 problem:

 Consider the following:

 = (count (set (for [x (range 200) y (range 200)] (hash [x y]
 6369

 This means that out of 40,000 common ordered pairs, there are only 6369 
 distinct hash values.  That's not good.

 So yes, upon further thought, I think sequence hashing should be 
 improved as well.

 I want to emphasize that I don't view this as merely a theoretical 
 problem.  I have noticed for over a year now, when profiling my Clojure 
 code, that a surprising amount of time was spent on dealing with hash 
 collisions.  I chalked it up as the natural behavior of hash tables which 
 will occasionally have collisions, and just learned to live with it, but 
 the more I play around with the existing hash function on data similar to 
 what I use (with small numbers in slightly varying structures), the more 
 I'm convinced that Clojure's weak hashing strategy explains the performance 
 issues I've had.  Would love to see the Clojure community tackle this 
 head-on; I think there's a lot of performance to be gained for many real 
 apps by doing this.


 You can't change the hashCode of lists / vectors without breaking the 
 contract for java.util.List (which PersistentList and PersistentVector both 
 implement) - 
 http://docs.oracle.com/javase/7/docs/api/java/util/List.html#hashCode()

 I don't think breaking this would be a good idea.

 The java.util.List hashCode isn't actually too bad.  It's a decent 
 compromise between an efficient implementation and reasonably effective 
 hashing for most real-world use cases.

 Sure you can construct artificial examples where you get some collisions, 
 but that's true of any hash code function. But note that the maximum number 
 of collisions is still pretty low:

 (apply max (vals (frequencies (for [x (range 200) y (range 200)] (hash [x 
 y])
 = 7

 That's actually the number you really care about, since it is the number 
 of objects in the same hash bucket that drives the pathological O(n^2) 
 behaviours.
  

 -- 
 -- 
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@googlegroups.comjavascript:
 Note that posts from new members are moderated - please be patient with 
 your first post.
 To unsubscribe from this group, send email to
 clojure+u...@googlegroups.com javascript:
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 --- 
 You received this message because you are subscribed to the Google Groups 
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to clojure+u...@googlegroups.com javascript:.
 For more options, visit https://groups.google.com/groups/opt_out.




-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to