2017-03-09 5 views
1

私の2日目ジュリアの学習と実験。私は、メタプログラミングに関するドキュメンタントを慎重に読んでいますが(注意深くはないかもしれませんが)、いくつかの疑似スレッドを読んでいます。私はまだ関数の中でそれをどのように使うことができるのか分かりません。これによりmetaprogrammingを関数argsで使用するには?

using Distributions 
function gendata(N,NLATENT,NITEMS) 
    latent = repeat(rand(Normal(6,2),N,NLATENT), inner=(1,NITEMS)) 
    errors = rand(Normal(0,1),N,NLATENT*NITEMS) 
    x = latent+errors 
end 

: は、私はより柔軟ないくつかのデータのシミュレーションのための次の関数を作るためにしようと試み

using Distributions 
function gendata(N,NLATENT,NITEMS,LATENT_DIST="Normal(0,1)",ERRORS_DIST="Normal(0,1)") 
    to_eval_latent = parse("latent = repeat(rand($LATENT_DIST,N,NLATENT), inner=(1,NITEMS))") 
    eval(to_eval_latent) 
    to_eval_errors = parse("error = rand($ERRORS_DIST,N,NLATENT*NITEMS)") 
    eval(to_eval_errors) 
    x = latent+errors 
end 

しかし、evalはローカルスコープでは動作しませんので、それはいけない仕事。これを取り巻く仕事をするために私は何ができますか?

また、もともとの機能は、それほど高速ではないようですが、性能に関して大きなミスを犯しましたか?

私は本当にお勧めを薦めます。 ありがとうございます。

+1

ディストリビューションを引数として渡すだけで何が問題になりますか? 'eval'を使うのはあまりにも複雑です。 – phg

+0

@phgあまりにも複雑すぎるとは思われません。このコードは最初はRスクリプトからのものでしたが、これは多かれ少なかれ必要なものです。あなたは反復がとても遅いというアイデアはありますか? BLASなので、稲妻のように速くなければならない、それは機能の中で最も遅い部分です。 – AaronP

答えて

5

evalを使用する必要はありません。配布タイプをキーワードargs(またはデフォルト値で名前付きargs)として渡すことで、同じ柔軟性を保持できます。 "文字列型の"引数を解析して評価すると、しばしば最適化が無効になるため、避けるべきです。

function gendata(N,NLATENT,NITEMS; LATENT_DIST=Normal(0,1),ERRORS_DIST=Normal(0,1)) 
     latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS)) 
     errors = rand(ERRORS_DIST,N,NLATENT*NITEMS) 
     x = latent+errors 
end 


julia> gendata(10,2,3, LATENT_DIST=Pareto(.3)) 
... 


julia> gendata(10,2,3, ERRORS_DIST=Gamma(.6)) 
... 

などあなたが本当にここevalを使用することになっていない

0

(遅く、型情報は生成されませんなど、コンパイルに干渉します)が、場合にあなたは何を理解しようとしていますどちらの

コードの残りの部分から分離:間違っていた、ここにあなたがそれを行うだろうかだ

function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)") 

    # Eval your expressions separately 

    LATENT_DIST = eval(parse(LDIST_EX)) 
    ERRORS_DIST = eval(parse(EDIST_EX)) 

    # Do your thing 

    latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS)) 
    errors = rand(ERROR_DIST,N,NLATENT*NITEMS) 
    x = latent+errors  
end 

または引用された表現で補間を使用します。

function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)") 

    # Obtain expression objects 

    LATENT_DIST = parse(LDIST_EX) 
    ERRORS_DIST = parse(EDIST_EX) 

    # Eval but interpolate in everything that's local to the function 
    # And you can't introduce local variables with eval so keep them 
    # out of it. 

    latent = eval(:(repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS)))) 
    errors = eval(:(rand($ERRORS_DIST, $N, $NLATENT*$NITEMS))) 
    x = latent+errors 
end 

あなたはまた、自己完結型のスコープを導入するのletブロックで単一のevalを使用することができます。

function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)") 

    LATENT_DIST = parse(LDIST_EX) 
    ERRORS_DIST = parse(EDIST_EX) 
    x = 
    @eval let 
    latent = repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS)) 
    errors = (rand($ERRORS_DIST, $N, $NLATENT*$NITEMS)) 
    latent+errors 
    end 
end 

((@eval x) == eval(:(x)))

さてを、あなたは少し良くeval事を理解してほしいです。 2日目私はあなたが実験しているはずです;)

+0

ありがとうございました。 "eval"をよりよく理解するのに非常に役立ちます。しかし、私は先の答えからの解決策に行きます。ここで私の解決策はビット速度の最適化である: ディストリビューションを使用する function gendata(N、NLMSENT、NITEMS; LATENT_DIST =ノーマル(0,1)、ERRORS_DIST =ノーマル(0,1)) latent = repmat(rand(LATENT_DIST、潜在eachindexで私のためにN、NLATENT)、1、をnitems) ()潜在 [I] =潜在[i]が+ランド(ERRORS_DIST) 終了 潜在 エンド – AaronP

+0

しかし、私は実際に取得しないものがあります、パフォーマンスを最適化しようとしている間に、関数はリピートではなくリパートで10倍速くなっていますが、それはどうですか?どちらもBLASであり、Docsの線形代数部から来ています。 – AaronP

+0

お受け取りいただきありがとうございますが、他の解決策が良ければ、代わりにそれを受け入れるべきです。これは補完的なものです。 (私が直接問題に取り組んでいる間、私は代替案を提示する方がこの場合にはより良いと思う) – phicr

関連する問題