週に一回は書きますよ 月に4つ記事を書けばノルマは満たされます。
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

前回の話: C++で多次元のvectorを多次元の配列で初期化したいのですが、どうしたらマクロを使わずにできるでしょう。

リンク先のように書けばうまく動きました。これでboost::mplも、マクロも書かなくてすみます。助かりました。

目標. 次のようなものをつくる。

int kArray[3][2] = {{1,2}, {4, 5}, {6, 7}};
vector<vector<int> > a(array2Vector(kArray));

配列を渡してvectorに変換する関数です。コンテナのテストに必須です。多次元配列を扱う必要があります。

まず、次のようなことはできません。配列を渡してもまったく処理してくれません。

  • 追記(2009.11.29 20:00): このコードは返り値が間違ってます。これだとint[2][3]がvectorに変換されてしまいます。正しいコードは解答編に。
template<typename T_, int SIZE_>
std::vector<T_> generateVector(T_ array[SIZE_]) {
  std::vector<T_> res;
  for (int i = 0; i < SIZE_; ++i)
    res.push_back(generateVector(array[i]));
  return res;
}
int generateVector(int i) {return i;}

次にboost::mplを使用して、サイズを事前にわたすようにしました。大幅な妥協です。for文を書いて初期化するよりはましです。

template <typename T_, typename B_, typename E_>
class VUVectorInitializerInternal_;

template <typename T_>
class VUIdentity_ {
public:
  typedef T_ result_type;
  typedef T_ parameter_type;
  template <typename U_>
  T_ initialize(U_ rhs) { return rhs;}
};

template <typename T_, typename NC_, typename B_, typename E_>
class VUExpand_ {
public:
  enum { size = NC_::value };
  typedef VUVectorInitializerInternal_<T_, B_, E_> child_type;
  typedef std::vector<typename child_type::result_type> result_type;
  typedef typename child_type::result_type parameter_type[size];
  result_type initialize(parameter_type rhs) {
    result_type result;
    result.reserve(size);
    child_type child;
    for (int i = 0; i < size; ++i)
      result.push_back(child.initialize(rhs[i]));
    return result;
  }
};

template <typename T_, typename B_, typename E_>
class VUVectorInitializerInternal_ :
  public boost::mpl::if_<typename boost::is_same<B_, E_>::type,
                             VUIdentity_<T_>,
                             VUExpand_<T_,
                                       typename boost::mpl::deref<B_>::type,
                                       typename boost::mpl::next<B_>::type, 
                                       E_> >::type {};

template <typename T_, typename A_>
class VectorInitializer :
  public VUVectorInitializerInternal_<T_,
                                      typename boost::mpl::begin<A_>::type,
                                      typename boost::mpl::end<A_>::type> {};

int test() {
  int kArray[3][2] = {{1,2}, {4, 5}, {6, 7}};
  vector<vector<int> > a =
    VectorInitializer<int, boost::mpl::vector_c<int, 3, 2> >().
    initialize(kArray);
}

コンパイルすると次のようなことを言われます。

vectorutil_test.cc:35: error: no matching function for call to 'VectorInitializer<int, boost::mpl::vector_c<int, 3l, 2l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l, 9223372036854775807l> >::initialize(int [3][2])'
vectorutil.h:42: note: candidates are: (以下略)

読めるように翻訳.

vectorutil_test.cc:35: error: no matching function for call to
'VectorInitializer<int, boost::mpl::vector_c<int, 3, 2> >::
  initialize(int [3][2])'
vectorutil.h:42: note: candidates are:
std::vector<typename VUVectorInitializerInternal_<T_, B_, E_>::result_type>
  VUExpand_<T_, NC_, B_, E_>::initialize(
    typename VUVectorInitializerInternal_<T_, B_, E_>::result_type*)
[
  with
    T_ = int,
    NC_ = mpl_::integral_c<int, 3>,
    B_ = boost::mpl::v_iter<boost::mpl::vector_c<int, 3, 2>, 1>,
    E_ = boost::mpl::v_iter<boost::mpl::vector_c<int, 3, 2>, 2>
]

引数のresult_type[3]がresult_type*になっています。つまり次の部分がまずくて、配列型ではなくてポインタになっていると。

  typedef typename child_type::result_type parameter_type[size];

つまり配列型と明示できていないか、あるいは配列型とポインタ型との区別がそもそも付かないか。

C/C++の多次元配列は苦手なので避けていました。その弊害が来たのでしょう。ということで勉強勉強。

こういうときこそマクロの出番かも。

ICFPCのvisualiserをjavascript + canvasで再生産してみました。firefox 3.0.10とGoogle Chrome Linux 3.0.190.2で検証。IEは無理です。Safari 4 winとfirefox 3.0は遅くて、Chromeかfirefox 3.5ならまともに動きます。

  • 3003
  • データが大きいのでブラウザクラッシャ注意! 4001

手元に本番提出データがなかったので実験用のデータを適当に使っています。まだtargetが12個あると思っていたときのデータです。

正直重すぎます。軌跡を書くところだけが重いのでここを再利用できると良いのですが。

javascriptなんて殆どまともに書いてないのできっちりと罠にかかりました。

  • context.beginPath(), moveTo, lineTo, closePathまでやってfillを忘れる。
  • closePathの役目はglEndではない。終点と始点とを繋げる。
  • 関数を呼ぶ代わりに関数を渡してしまう。その逆も。
  • javascriptを編集してからリロードをかけると時々firebugが発狂。
  • functionのスコープ。これは知っていたので回避。
    • 別のタブであらためてロードすると大丈夫だったり。
  • 配列をfor in で回ろうとする。
  • onmousedownで渡されるイベントからクリックされた場所を探す方法。
  • onmousedown, onmousemove, onmouseupだけじゃなくてonmouseoutも使うとよい。
  • cssはコピペ。

ネット上にものすごい勢いで情報があるので、調べながらやってもそれほど難しくはありませんでした。スクロールバーなど一部は明らかにやっつけですが。

ICFP PC 2009にチームIntercamlで参加していました。フリーズ前に6位程度。

チームメンバー

言語はC++/C/Java。どこにIntercalcamlがあるのでしょうか。

「去年よりは」問題が楽な気がします。火星人いないし。ちゃんと楽しめたし差もある程度付いたのでよし。marathon matchなどもう少し期間の長いコンテストだともっと完璧に解かれたりするのでしょうか。

  • 基本Hohmann遷移。これが最も楽で燃料も使わないはずです。ChunがHohmann遷移を濫用したコードを書いて、それをベースに使っていました。
    • 他の遷移もいろいろ考えてみたものの楕円の交差とかちょっと理解できない。
  • 楕円運動が面倒。
    • 長径と遠点までの距離とを誤解。
    • それは初等関数では表わせない。
      • 今考えると二分探索とか手法はあったはず。
    • 「ランダウによるとwikipediaの式であってる。」

戦略としては、まず衛星の動きを円運動に制限して、その状態で相手を待ちます。300x系では、自分の動きを円運動に修正して、相手の近点に接する円に遷移して、それから相手と同じ楕円に遷移。400x系は相手と同じ楕円に入る必要がないのでもうすこしフリーダムにできます。

そのほか

  • visualizer超重要。
    • この技術身に付けるべきだな...
  • nyaさんのVMオブジェクトが非常に秀逸でした。
  • 最後のほうはちょっとoverfittingが心配です。これ本当にverificationで点数取れるのでしょうか。
  • 最後のパラメータプログラム内で自動調整してないのだけどこれじゃ駄目..?

前回のiGoogleでのはまりどころがよくわからないうちに解決しました。

  • おもむろにiGoogle sandboxに行ってみる。
  • Developer tab上で、「このgadgetはコミュニティ情報にアクセスするけどそれを許可するか」(意訳)というダイアログボックスがあらわれる。
  • 許可したところ、友人に登録した人は見えるようになり、ガジェットも動くように。

まだ不審な点は数多くあります。しかし友人リストが見えるのは非常に大きな進歩です。

  • Friendsに登録したリストの一部しか出てこない。
    • 扱えるのはgmail accountだけかな。
  • iGoogleでもmixiと同じく、friends.getByIdがnullを返す。もう私がまちがっている可能性のほうがずっと高くなりました。
    • 追記21:50:なんだこいつは!!! html.push('<option value=">', person.getId(), '">', person.getDisplayName(), '</option>');
    • 解決しました。
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。