www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Error while generate DNA with uniform()

reply Salih Dincer <salihdb hotmail.com> writes:
Hi All,

We discovered a bug yesterday and reported it:

https://forum.dlang.org/thread/mailman.1386.1662137084.31357.digitalmars-d-bugs puremagic.com

You know, there is `generate()` depend to `std.range`. It created 
the error when we use it with the value of an enum. Which get 
their values from an `enum DNA`, we have 4 members that we want 
to generate 32 pieces randomly like this:

```d
import std;
void main()
{
   enum DNA { timin = 84,
              sitozin = 67,
              guanin = 71,
              adenin = 65
            }
   char[] gene;
   enum n = 32;
   auto range = generate!(() => uniform(DNA.min, 
DNA.max)).take(n);/*
   auto preferred = generate!(() =>
                    uniform!"[]"(DNA.min,
                                 DNA.max)).take(n);//*/

   foreach (_; 0..n)
   {
     gene ~= uniform!"[]"(DNA.min, DNA.max);
   }
   gene.writeln; // CGACGTGCTTCATCGATAGGAGCACGAGGAGC
   // If the ASCII table matches (capital group 64-95) there 
should be no problem...
}
```

If there was no alternative solution, we would generate random 
numbers between 65 and 84 that have no equivalent in DNA. We want 
to use "[]" ( closed to the left and right)  but preferred 
version doesn't compile.

Can we solve this issue with our own `generate()` structure?

SDB 79
Sep 03 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/3/22 8:09 AM, Salih Dincer wrote:
 Hi All,
 
 We discovered a bug yesterday and reported it:
 
 https://forum.dlang.org/thread/mailman.1386.1662137084.31357.digitalmars-
-bugs puremagic.com 
 
 
 You know, there is `generate()` depend to `std.range`. It created the 
 error when we use it with the value of an enum. Which get their values 
 from an `enum DNA`, we have 4 members that we want to generate 32 pieces 
 randomly like this:
 
 ```d
 import std;
 void main()
 {
    enum DNA { timin = 84,
               sitozin = 67,
               guanin = 71,
               adenin = 65
             }
    char[] gene;
    enum n = 32;
    auto range = generate!(() => uniform(DNA.min, DNA.max)).take(n);/*
    auto preferred = generate!(() =>
                     uniform!"[]"(DNA.min,
                                 
DNA.max)).take(n);//*/
I'm not sure why this doesn't work. First, I would change your enum to this (for correctness and readability): ```d enum DNA : char { timin = 'T', sitozin = 'C', guanin = 'G', adenin = 'A' } ``` There is probably a bug in generate when the element type is an `enum` which somehow makes it const. But what you need anyway is a `char`, so just return a `char`. For that, you need to specify the return type, which requires a different kind of function literal: ```d auto preferred = generate!(function char() => uniform!"[]"(DNA.min, DNA.max)).take(n); ``` That works. -Steve
Sep 03 2022
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 9/3/22 07:25, Steven Schveighoffer wrote:

 There is probably a bug in generate when the element type is an `enum`
 which somehow makes it const.
Yes, Generator is missing an Unqual: https://issues.dlang.org/show_bug.cgi?id=23319 Salih had asked:
 Can we solve this issue with our own `generate()` structure?
Yes, I did the following to determine that adding Unqual was a solution: - Copy generate() functions to your source file, - Copy the Generator struct to your source file, - Edit the definition of Generator's elem_ member as I hinted in the bug. Ali
Sep 03 2022
parent Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 3 September 2022 at 21:09:09 UTC, Ali Çehreli wrote:
 Salih had asked:

 Can we solve this issue with our own `generate()` structure?
Yes, I did the following to determine that adding Unqual was a solution: - Copy generate() functions to your source file, - Copy the Generator struct to your source file, - Edit the definition of Generator's elem_ member as I hinted in the bug.
But the bug may be in the templates, not in the structure. Maybe ` template functionTypeOf(alias func)` For example: ```d auto gen(alias fun)() { auto gen = Gen!fun(); gen.popFront(); return gen; } struct Gen(alias fn) { import std.traits: ReturnType!fn func; enum empty = false; auto front() { return func; } void popFront() { func = fn(); } } unittest { import std.random : uniform; import std.range : takeExactly; enum E { O = '0', P, Q, R, S, T, U, V, W, X, A = 'A', B, C, D, E, F } auto range = gen!(function char() => uniform!"[]"(E.min, E.max)) .takeExactly(15); assert(range.to!long(15) < long.max); } ``` SDB 79
Sep 03 2022
prev sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 3 September 2022 at 14:25:48 UTC, Steven 
Schveighoffer wrote:
  [...] what you need anyway is a `char`, so just return a 
 `char`. [...]
Clean-cut, thank you! It's very clear to me... ```d import std; void main() { alias fp = char function() system; enum DNA : char { timin = 'T', sitozin = 'C', guanin = 'G', adenin = 'A' } fp getDNA = () => uniform!"[]"(DNA.min, DNA.max); enum n = 30; auto genes = generate!getDNA.take(n).array; auto unique = genes.uniq.array; // AAAACATCATGGTAGGCCTTTCATGCGCTA assert(unique.length < n, "no repeat"); unique.writeln; // ACATCATGTAGCTCATGCGCTA } ``` SDB 79
Sep 03 2022
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 9/3/22 14:18, Salih Dincer wrote:

    uniform!"[]"(DNA.min, DNA.max);
Even cleaner: uniform!DNA() :) Ali
Sep 03 2022
prev sibling parent rassoc <rassoc posteo.de> writes:
On 9/3/22 23:18, Salih Dincer via Digitalmars-d-learn wrote:
 Clean-cut, thank you!
 It's very clear to me...
Nothing major, but instead of `uniform!"[]"(DNA.min, DNA.max)`, you can simply use `uniform!DNA`. `uniform` considers the whole enum: https://github.com/dlang/phobos/blob/v2.100.1/std/random.d#L2561 "Random variate drawn from the uniform distribution across all possible values of the [...] enum type T."
Sep 03 2022