On Friday, 25 August 2017 at 16:01:27 UTC, data pulverizer wrote:

Your wrapping strategy looks sensible though I would probably generate them all using string mixins.

See below. I haven't implemented the random variables yet, but otherwise it seems to be working well. There is some trickiness with deprecated stuff that I had to hard code, but other than that it's pretty generic. Also, I think it is ignoring my check to only include public/export stuff. Not sure why that is.

module distribAlt;

private template isMemberOf(alias T, string x)
{
    import std.traits : hasMember;

    enum bool isMemberOf = hasMember!(T, x);
}

private void hasMemberCheck(alias T, string x)()
{
static assert(isMemberOf!(T, x), T.stringof ~ " must have " ~ x ~" member to
                                        call " ~ x ~ " function");
}

private string genStructInternals(string funcName, string structName)()
{
    import dstats.distrib;
    import std.array : appender;
    import std.algorithm.searching : endsWith;

    enum spaces = "    ";

    auto aliasBuf = appender!string();
    auto importBuf = appender!string();

    enum string invName = "inv" ~ structName;

    enum bool anyPDForPMF = false;

    importBuf.put(spaces);
    importBuf.put("import dstats.distrib : ");

    foreach(member; __traits(allMembers, dstats.distrib))
    {
        static if (__traits(getProtection, member) == "public" ||
                   __traits(getProtection, member) == "export")
        {
import std.algorithm.searching : startsWith, findSplitAfter;
            import std.string : toLower;

            static if (startsWith(member, funcName))
            {
enum string memberAfter = findSplitAfter(member, funcName)[1]; enum string lowerMemberAfter = toLower(memberAfter);

                importBuf.put(member ~ ", ");

                aliasBuf.put(spaces);
                aliasBuf.put("alias " ~ lowerMemberAfter ~ " = "
~ member ~ ";");
                aliasBuf.put("\n");

                static if ((lowerMemberAfter == "pdf") ||
                           (lowerMemberAfter == "pmf"))
                {
                    aliasBuf.put(spaces);

aliasBuf.put("alias density = " ~ lowerMemberAfter ~ ";");
                    aliasBuf.put("\n");
                }
            }
            else static if (startsWith(member, invName))
            {
enum string memberAfter = findSplitAfter(member, invName)[1];

                importBuf.put(member ~ ", ");

                aliasBuf.put(spaces);
aliasBuf.put("alias i" ~ toLower(memberAfter) ~ " = " ~ member ~ ";");
                aliasBuf.put("\n");
            }
        }
    }

    if (endsWith(importBuf.data, ", "))
    {
string importOut = importBuf.data[0 .. ($ - (", ".length))] ~";\n";

        if (endsWith(aliasBuf.data, "\n"))
return importOut ~ aliasBuf.data[0 .. ($ - ("\n").length)];
        else
            assert(0, "No relevant functions in dstats.distrib");
    }
    else
    {
        assert(0, "No relevant functions in dstats.distrib");
    }
}

private string toLowerFirst(string name)()
{
    import std.string : toLower;
    import std.conv : to;

    string firstLetter = name[0].toLower.to!string;
    return firstLetter ~ name[1 .. $];
}

private string toUpperFirst(string name)()
{
    import std.string : toUpper;
    import std.conv : to;

    string firstLetter = name[0].toUpper.to!string;
    return firstLetter ~ name[1 .. $];
}

private template GenDistStruct(string name)
{
    const char[] GenDistStruct =
        "///"~ "\n" ~
        "struct " ~ toUpperFirst!(name) ~ "\n" ~
        "{\n" ~
        genStructInternals!(name, toUpperFirst!(name)) ~ "\n" ~
        "}";
}

string GenDistStructs()
{
    import dstats.distrib;
    import std.array : appender;
import std.algorithm.searching : startsWith, endsWith, canFind, findSplitBefore, findSplitAfter;

string[__traits(allMembers, dstats.distrib).length] createdStructs;
    size_t i;
    auto structsBuf = appender!string();

    foreach(member; __traits(allMembers, dstats.distrib))
    {
        static if (__traits(getProtection, member) == "public" ||
                   __traits(getProtection, member) == "export")
        {
            static if ((member.endsWith("PDF") ||
                            member.endsWith("PMF") ||
                            member.endsWith("CDF") ||
                            member.endsWith("CDFR")))
            {
                static if (member.endsWith("PDF"))
                    enum string memberBefore =
findSplitBefore(member, "PDF")[0];
                else static if (member.endsWith("PMF"))
                    enum string memberBefore =
findSplitBefore(member, "PMF")[0];
                else static if (member.endsWith("CDF"))
                    enum string memberBefore =
findSplitBefore(member, "CDF")[0];
                else static if (member.endsWith("CDFR"))
                    enum string memberBefore =
findSplitBefore(member, "CDFR")[0];

                static if (member.startsWith("inv"))
                    enum string newMember =
toLowerFirst!(findSplitAfter(memberBefore, "inv")[1]);
                else
                    enum string newMember = memberBefore;

                static if (member != "chiSqrCDF" &&
                           member != "chiSqrCDFR" &&
                           member != "invChiSqrCDFR" &&
member != "invChiSqCDFR") //Deprecated: Easiest way I found to fix it
                {
                    if (i == 0 ||
!(createdStructs[0 .. i].canFind(newMember)))
                    {
                        structsBuf.put(GenDistStruct!newMember);
                        structsBuf.put("\n");
                        createdStructs[i] = newMember;
                        i++;
                    }
                }
            }
        }
    }
    return structsBuf.data;
}

mixin(GenDistStructs());

private template GenDistFunc(string name)
{
    const char[] GenDistFunc =
        "auto " ~ name ~ "(alias T, U...)(U u)\n" ~
        "{\n" ~
        `   hasMemberCheck!(T, "` ~ name ~ `");` ~ "\n" ~
        "   return T." ~ name ~ "(u);\n" ~
        "}";
}

mixin(GenDistFunc!("pdf"));
mixin(GenDistFunc!("pmf"));
mixin(GenDistFunc!("cdf"));
mixin(GenDistFunc!("cdfr"));
mixin(GenDistFunc!("icdf"));
mixin(GenDistFunc!("density"));

void main()
{
    import std.stdio : writeln;

    writeln(Normal.cdf(0.5, 0.0, 1.0));
    writeln(cdf!Normal(0.5, 0.0, 1.0));
    writeln(icdf!Normal(cdf!Normal(0.5, 0.0, 1.0), 0.0, 1.0));

    writeln(LogNormal.cdf(0.5, 0.0, 1.0));
    writeln(cdf!LogNormal(0.5, 0.0, 1.0));
}

Reply via email to