Re: Range of random numbers

2012-04-25 Thread Christophe Travert
"bearophile" , dans le message (digitalmars.D.learn:35148), a écrit :
> Why don't you write a little benchmark to compare the performance 
> of the two versions?

Because I'm interested in the code's meaning for the human reader, not 
the performance.

I actually think : "map!(_=> uniform(a, b))(repeat(0))" is better, 
because it puts the call to uniform first, and the _ indicates that the 
rest is unimportant.


For you curiosity, this is the benchmark using:
gdc (GCC) 4.7.0 20120322 (gdc 0.31 - r805:0414cec152c7, using dmd 2.057)
and
gdc -O3 testRNG.d && ./a.out


import std.array, std.range, std.algorithm, std.random, std.stdio, 
std.datetime;

auto uniformRange1(T1, T2, T3)(T1 a, T2 b, T3 gen)
{
  return map!((x) {return x();} ) (repeat((){return uniform(a, b, gen);}));
}

auto uniformRange2(T1, T2, T3)(T1 a, T2 b, T3 gen)
{
  return map!((x) { return uniform(a, b, gen); })(repeat(0));
}

auto uniformRange3(T1, T2, T3)(T1 a, T2 b, T3 gen)
{
  return map!((x) { return uniform(a, b, gen); })(cycle([0]));
}

void f1() { auto ur = array(take(uniformRange1(0, 10, Xorshift(1)), 
1000)); }
void f2() { auto ur = array(take(uniformRange2(0, 10, Xorshift(1)), 
1000)); }
void f3() { auto ur = array(take(uniformRange3(0, 10, Xorshift(1)), 
1000)); }

void main() {
  auto b=benchmark!(f1, f2, f3)(1000);
  writeln(b[0].to!("seconds",double),"s,  ", b[1].to!("seconds",double),
"s, ", b[2].to!("seconds",double),"s." );
  // outputs :
  // 0.040437s,  0.0393537s, 0.0486439s
}


f2 performs 23% better than f3, and 3% better than f1.

-- 
Christophe


Re: Range of random numbers

2012-04-24 Thread Joseph Rushton Wakeling

On 24/04/12 13:50, Christophe wrote:

We could also use a template to make a range out of a delegate and avoid
this workarround...


What I'd _really_ like to see is something which would allow you to generate a 
range of random numbers with an expression like,


auto rr = randomRange!distribution(/* distribution parameters */);

or,

auto rr = randomRange!distribution(size_t n, /* distribution parameters */);

... which would generate you either an infinite or length-n range of random 
numbers generated by the specified distribution, with the passed parameters.


So, you could call e.g.,

auto rr = randomRange!(uniform!"()")(100, 0.0, 1.0);

auto rr = randomRange!pareto(100, alpha, sigma);

auto rr = randomRange!exponential(lambda);

... etc.  But I'm not sure if this is feasible.


Re: Range of random numbers

2012-04-24 Thread bearophile

trav...@phare.normalesup.org:


That looks like a workarround, not meaningful code.


It wasn't terrible code :-)



How about
  return repeat(_ =>uniform(lower, upper)).map!(x => x())();
?


Why don't you write a little benchmark to compare the performance 
of the two versions?


Using uniform(lower, upper, gen)  with
auto gen = Xorshift(1);
to reduce influence from the random generator.

Bye,
bearophile


Re: Range of random numbers

2012-04-24 Thread Christophe
"bearophile" , dans le message (digitalmars.D.learn:35108), a écrit :
> What about (untested):
> 
> auto uniformRange(T1 lower, T2 upper) {
>  return count().map!(_ => uniform(lower, upper))();
> }

That looks like a workarround, not meaningful code.

How about
  return repeat(_ =>uniform(lower, upper)).map!(x => x())();
?

We could also use a template to make a range out of a delegate and avoid 
this workarround...

struct RepeatDg(T)
{
  T delegate() dg;
  this(T delegate() dg_) { dg = dg_; }

  @property enum bool empty = false;
  @property T front() { return dg(); }
  @property void popFront() {}
}
  


Re: Range of random numbers

2012-04-23 Thread bearophile

Count(5) is easy to replace with iota(5, int.max),


This also means that for the OP problem, using repeat(0) is more 
correct than using count(), because count on default yields ints, 
that are limited to about 2 milliards.


Bye,
bearophile


Re: Range of random numbers

2012-04-23 Thread bearophile

jerro:

Couldn't it just be iota with no parameters?


The Count range has a helper count() function similar to this, 
that's meant to have an argument that defaults to zero:


Count!T count(T)(T start=0) if (isIntegral!T) { return 
Count!T(start); }


The argument allows it to start from another starting point, and 
it allows you to specify the type of the numbers it yields, while 
in iota() without arguments it's less easy to specify the type of 
the numbers it yields.


Count(5) is easy to replace with iota(5, int.max), but 
count(BigInt(0)) is less easy to replace with iota, because it 
doesn't give you a way to denote a right-open BigInt interval. 
And using iota(BigInt(0), BigInt(ulong.max)) is not that good. 
Currently using BigInt in iota seems to not even being 
supported...


Bye,
bearophile


Re: Range of random numbers

2012-04-23 Thread jerro
It's for a different purpose. So the count() I was proposing 
will need a different name.


Couldn't it just be iota with no parameters?


Re: Range of random numbers

2012-04-23 Thread Ali Çehreli

On 04/23/2012 10:56 AM, Joseph Rushton Wakeling wrote:

On 23/04/12 19:46, Joseph Rushton Wakeling wrote:

On 23/04/12 18:56, bearophile wrote:

jerro:


return repeat(0).map!(_ => uniform(lower, upper))();



Yes, this works nicely. Thanks very much!


Is this a new addition? With GDC I get a compiler error:

expression expected, not '>'

... suggesting => isn't supported.



The lambda syntax was added in 2.058:

  http://dlang.org/changelog.html

Ali


Re: Range of random numbers

2012-04-23 Thread Joseph Rushton Wakeling

On 23/04/12 19:46, Joseph Rushton Wakeling wrote:

On 23/04/12 18:56, bearophile wrote:

jerro:


return repeat(0).map!(_ => uniform(lower, upper))();



Yes, this works nicely. Thanks very much!


Is this a new addition?  With GDC I get a compiler error:

  expression expected, not '>'

... suggesting => isn't supported.



Re: Range of random numbers

2012-04-23 Thread Joseph Rushton Wakeling

On 23/04/12 18:56, bearophile wrote:

jerro:


return repeat(0).map!(_ =>  uniform(lower, upper))();

repeat(0) returns the same sequence as cycle([0]) and is as fast
as it gets, since popFront does nothing and empty is an enum.


Good idea.


Yes, this works nicely.  Thanks very much!


Re: Range of random numbers

2012-04-23 Thread bearophile
jerro:

> return repeat(0).map!(_ => uniform(lower, upper))();
> 
> repeat(0) returns the same sequence as cycle([0]) and is as fast
> as it gets, since popFront does nothing and empty is an enum.

Good idea.

---

Dmitry Olshansky:

> What's wrong with:
> http://dlang.org/phobos/std_algorithm.html#count

It's for a different purpose. So the count() I was proposing will need a 
different name.

Bye,
bearophile


Re: Range of random numbers

2012-04-23 Thread jerro

What about (untested):

auto uniformRange(T1 lower, T2 upper) {
return count().map!(_ => uniform(lower, upper))();
}

Where count() is just:
http://d.puremagic.com/issues/show_bug.cgi?id=7839

In the meantime cycle([0]) is acceptable but slower (untested):

return cycle([0]).map!(_ => uniform(lower, upper))();


He could also use repeat in this case:

return repeat(0).map!(_ => uniform(lower, upper))();

repeat(0) returns the same sequence as cycle([0]) and is as fast
as it gets, since popFront does nothing and empty is an enum.


Re: Range of random numbers

2012-04-23 Thread Dmitry Olshansky

On 23.04.2012 17:52, bearophile wrote:

Joseph Rushton Wakeling:


struct UniformRange(T1, T2)
{
T1 _lower;
T2 _upper;

@property enum bool empty = false;

this(T1 a, T2 b)
{
_lower = a;
_upper = b;
}

@property auto ref front()
{
assert(!empty);
return uniform(_lower, _upper);
}

void popFront()
{
}
}


What about (untested):

auto uniformRange(T1 lower, T2 upper) {
return count().map!(_ => uniform(lower, upper))();
}

Where count() is just:
http://d.puremagic.com/issues/show_bug.cgi?id=7839



What's wrong with:
http://dlang.org/phobos/std_algorithm.html#count


In the meantime cycle([0]) is acceptable but slower (untested):

return cycle([0]).map!(_ => uniform(lower, upper))();

Bye,
bearophile



--
Dmitry Olshansky


Re: Range of random numbers

2012-04-23 Thread bearophile

Joseph Rushton Wakeling:


struct UniformRange(T1, T2)
{
T1 _lower;
T2 _upper;

@property enum bool empty = false;

this(T1 a, T2 b)
{
_lower = a;
_upper = b;
}

@property auto ref front()
{
assert(!empty);
return uniform(_lower, _upper);
}

void popFront()
{
}
}


What about (untested):

auto uniformRange(T1 lower, T2 upper) {
return count().map!(_ => uniform(lower, upper))();
}

Where count() is just:
http://d.puremagic.com/issues/show_bug.cgi?id=7839

In the meantime cycle([0]) is acceptable but slower (untested):

return cycle([0]).map!(_ => uniform(lower, upper))();

Bye,
bearophile


Range of random numbers

2012-04-23 Thread Joseph Rushton Wakeling

For some reason this got lost in the ether, so I'm resending.

Related to my earlier question on passing a function -- I was wondering if 
there's a trivial way of generating a lazily-evaluated range of random numbers 
according to a given distribution and parameters.


I wrote up the code below to generate a range of uniformly-distributed
numbers, but am not sure how to generalize it for arbitrary distribution and/or
parameters, and I'm also not sure that I'm overcomplicating what might be more
easily achieved with existing D functionality.

The larger goal here is that I want some way to pass an _arbitrary_ number 
source (may be deterministic, may be stochastic) to a function.  A range seemed 
a good way to do that (after all, in the deterministic case I can just pass an 
array, no?).


... but I couldn't work out how to generalize the stochastic case beyond what's 
shown here.


///
import std.array, std.random, std.range, std.stdio;

struct UniformRange(T1, T2)
{
T1 _lower;
T2 _upper;

@property enum bool empty = false;

this(T1 a, T2 b)
{
_lower = a;
_upper = b;
}

@property auto ref front()
{
assert(!empty);
return uniform(_lower, _upper);
}

void popFront()
{
}
}

auto uniformRange(T1, T2)(T1 a, T2 b)
{
return UniformRange!(T1, T2)(a, b);
}

auto uniformRange(T1, T2)(size_t n, T1 a, T2 b)
{
return take(UniformRange!(T1, T2)(a, b), n);
}

void main()
{
auto ur = uniformRange!(double, double)(5, 10.0, 20.0);
double[] x = array( take(uniformRange(1.0, 2.0), 5) );
double[] y = array(x);

foreach(r; ur)
writeln(r);
writeln;

foreach(r; ur)
writeln(r);
writeln;

foreach(r; x)
writeln(r);
writeln;

foreach(r; y)
writeln(r);
writeln;
}