私は odeint と推力の上に分析ツールを構築しています。このツールは、多数の初期条件の問題を解決します。私は odeint と throws のチュートリアル / デモに従って成功しました。これまで私が扱ってきたシステムには 5 つ未満の状態変数しかありませんでしたが、より多くの状態変数を処理できるようにシステムを拡張する必要があります。
チュートリアルで述べたように、thrust のタプルは最大 10 個のアイテムしか持てないという小さな問題があります。この問題は、ネストされた zip_iterators を使用することで解決できます。
チュートリアルの1つの下部近くから引用:
「Thrust のタプルの最大アリティが 10 であるという小さな問題があります。しかし、zip イテレータを詰め込んだ zip イテレータを作成できるので、これは小さな問題にすぎません。そのため、最上位の zip イテレータには、状態用の 1 つの zip イテレータと 1 つの通常のイテレータが含まれています。パラメータには 1 つの zip イテレータ、派生物には 1 つの zip イテレータを使用します。"
このソリューションを実装しましたが、機能しますが、残念ながら速度が大幅に低下します。同じシステム (8192 個の初期条件を同時に解く 2 変数システム) の場合、元のシンプルだが 5 つ以上の変数に拡張できないソリューションは 1 秒強で実行されます。
real 0m1.244s
user 0m0.798s
sys 0m0.356s
一方、より複雑ではあるが拡張可能なネストされたソリューションには、最大 2000 倍の時間がかかります!
real 4m3.613s
user 2m15.124s
sys 1m47.363s
2 つのプログラムの唯一の違いは、
functor の内部で
operator()
、状態変数と導関数を参照し、ファンクターのコンストラクター、特に
for_each
コマンド内で、zip_iterators とタプルを作成します。
以下に、各プログラムについて、これらのセクションからの抜粋を示します。この種の速度低下は壊滅的なので、ここで何か間違ったことをしているといいのですが! どんな助けでも大歓迎です。
「SIMPLE」コードの抜粋 (ネストされていないイテレータ)
//////////////////////////////////////////////////////////
//// Inside ICFunctor's operator()
// getting the state variable
value_type X = thrust::get< 0 >( t );
// setting the derivative
thrust::get< 2 >( t ) = 0.5*A - 1.5*X;
//////////////////////////////////////////////////////////
//// the for_each statement that creates the zip_iterator
thrust::for_each(
//// START INDICES
thrust::make_zip_iterator( thrust::make_tuple(
// State-variables
boost::begin( x ) + 0*m_N,
boost::begin( x ) + 1*m_N,
// Derivatives
boost::begin( dxdt ) + 0*m_N,
boost::begin( dxdt ) + 1*m_N)) ,
//// END INDICES
thrust::make_zip_iterator( thrust::make_tuple(
// State-variables
boost::begin( x ) + 1*m_N,
boost::begin( x ) + 2*m_N,
// Derivatives
boost::begin( dxdt ) + 1*m_N,
boost::begin( dxdt ) + 2*m_N)) ,
ICFunctor() );
「EXTENSIBLE」コードの抜粋 (ネストされたイテレータ)
//////////////////////////////////////////////////////////
//// Inside ICFunctor's operator()
// getting the state variable
const int STATE_VARIABLES = 0; // defined as a global constant
value_type X = thrust::get<0>(thrust::get<STATE_VARIABLES>( t ));
// setting the derivative
const int DERIVATIVES = 1; // defined as a global constant
thrust::get<0>(thrust::get<DERIVATIVES>( t )) = 0.5*A - 1.5*X;
//////////////////////////////////////////////////////////
//// the for_each statement that creates the zip_iterator
thrust::for_each(
//// START INDICES
thrust::make_zip_iterator( thrust::make_tuple(
// State variables
thrust::make_zip_iterator( thrust::make_tuple(
boost::begin( x ) + 0*m_N,
boost::begin( x ) + 1*m_N)),
// Derivatives
thrust::make_zip_iterator( thrust::make_tuple(
boost::begin( dxdt ) + 0*m_N,
boost::begin( dxdt ) + 1*m_N))
)),
//// END INDICES
thrust::make_zip_iterator( thrust::make_tuple(
// State variables
thrust::make_zip_iterator( thrust::make_tuple(
boost::begin( x ) + 1*m_N,
boost::begin( x ) + 2*m_N)),
// Derivatives
thrust::make_zip_iterator( thrust::make_tuple(
boost::begin( dxdt ) + 1*m_N,
boost::begin( dxdt ) + 2*m_N))
)),
ICFunctor() );