洋裁経験ゼロから2日でつくるコスプレ衣装

Posted on

いろいろあって大学5年目ですが、先週末の学園祭には元気に参加しました!

今年の学園祭では、好きすぎて京都まで聖地巡礼に行ってきたアニメ、「いなり、こんこん、恋いろは。」のコンちゃんのコスプレをしてみました!

SONY DSC

SONY DSCしっぽも生えてるんですが、この写真だと見えないですね~。この格好でお客さんにエルニーニョの説明をしました。あんまりうまく説明出来ませんでしたけど!

たぶん「いなこん」を全話見た皆様でも「こんなキャラ居たっけ…?」みたいな感じかと思われますが、OPで一瞬だけ出てきます。

20140520_2

いなりちゃんといつも一緒にいる子狐の神使・コンちゃんが人間の姿で顕現する時の姿で、漫画ではみんなで一緒に海に行く話のあとの回で登場します。

20140520_3

何度見てもコンちゃんかわいい~!!(フサ フサ)

この話は殆ど他の話のフラグに依存しないし影響もしない、いわゆる「エピソード」なので、10話しかないアニメではカットされたのだろうと思います。漫画8巻の付属BDにはこのエピソードのアニメが入るらしいですよ!買うしか無い!買うしか無い!(回し者)

アニメには登場しないキャラなので(狐の姿なら毎回出てるけど)、当然衣装とかは売ってません。というわけで、人生初のコスプレは衣装から全部自作です!何故人はマイナーなキャラクターのコスプレをしたくなってしまうのか!!

洋裁をするのは小学校以来で、その時は間違えて縫って履けないズボンを作って、そのまま心折れて提出もせずに卒業したような気がします。そんな感じです。あと3年くらい前に女装してニコ生でiPadケース縫った気がしますが、ありゃノーカン。

作る時に考えたことを、断片的にメモっておこうと思います。

服の構成要素は既成品改造レベル

コンちゃん(人型)の可愛さに気づいて現在パソコンの背景にしている画像がこちらです。

20140520_4この画像をよく見ると、全体の衣装はファンタジーな感じでとてもかわいい1のですが、個々の要素は既存の服をすこし変えたものであることが分かります。

  • マントとフードは、レインポンチョのマントの形を変えたりフードに耳生やしたりすればいけそう
  • 上着は、和服から袖を取ったもの。帯は普通に帯。
  • ズボンは普通の半ズボンの上の部分を袴みたいにすればそれっぽくなりそう。

この時点で、既存の洋裁の型紙を改造すれば、無理をせず十分それらしい衣装が作れそうだと分かります。

あとさらに洋裁初心者には大変うれしいと思ったポイントが

  • とりあえず赤い布と白い布さえあれば作れる

というところです。たくさん材料があると混乱してミスをしてしまいそうなので、とりあえず白い布と赤い布を大量に買っておけばあとは形をどうしてどう縫うかの問題に落とし込めるのは大変好都合に見えました。

 ミシンは適当で良かったっぽい

ミシンすら持ってなかったので、適当に買いました。

ミシンもたくさん種類が出ていてどれ買えばいいの~!?という感じだったのですが、ふなっしーのコスプレをしている超上級者の友人に「3万くらいのコンピュータミシンならどれでもOKじゃない?」みたいなアドバイスをしてもらったので、適当に安いのを選びました。実際使ってみて過不足なかったので、大丈夫だったっぽい。

フットペダルはやっぱり便利ですね。あと最近の機種はみんなそうなのかもしれませんが、この機種は糸通しがミシン本体に付いてて、糸を針に通すのがめっちゃ楽でした!

ちなみにこのミシンが来たのは木曜日で、学園祭は土曜日からだったので非常にタイトなスケジュールでした。もっと計画的になろう(◞‸◟ )

既成品の型紙を集める

大学近く(といっても徒歩20分)にユザワヤが最近できたので、型紙含め材料全部買ってきました。

麻の入った朱色の布がたまたまあったのがすごいラッキーでした。結構余ったので、巫女装束とか作っても良いかな~?

制作

しっぽ⇨袋を作ってフェイクファーをはりつける

しっぽに関しては、四角い袋を適当にぬって先端を丸くしたあと、フェイクファーの帯をボンドで貼り付けまくりました。

SONY DSCそれっぽくなったものの、ボンドが固まっているので、触ると硬くなってしまってモフれないのが難点です。布状になってるフェイクファーがあれば、直接それを袋にすることも可能だったかも…。

マント⇨ほぼそのままだけど裏地大変

マントは今回の衣装にいらなさそうなディテールを適当に削りつつ、マントの形を型紙レベルで書き換えただけです。一番大変だったのは赤い裏地を付ける所で、そのために赤い布と白い布の両方で同じ型紙をカットして縫い合わせないといけないので、作業が普通に作る時の倍以上になります。

SONY DSC装飾とかは全部ボンドで貼り付けました。ボンド便利!!上の写真だと頭にちゃんと葉っぱがついてますが、この葉っぱはリアル葉っぱです(つくりものの葉っぱを買い忘れた)

ズボン⇨袴風にするためにサイドをカットする

SONY DSC袴は昔、高校(ほとんど行ってない)で剣道の授業があって着たことがあったので、それを思い出して、適当に腰のところをカットして、ゴムじゃなくて帯で腰を縛るようにしています。本当の袴はさらに前のほうは5本のひだが付いていたりするのですが、コンちゃんの衣装はそうではなさそう。

結局上着のおはしょりで隠れるのであまり意味はありませんが、しっぽがズボンに固定されていて重いので、それをしっかり持ち上げるのにはちょうど良かったです。

足が出てくるところ(ボタンがついてるところ)がすこしくびれているのがとても可愛いので、再現しようと先の方だけ細くなるように、足先につれて太くなっていた所を途中から細くなるように型紙を改造したのですが、あまりそれっぽい感じにはなってくれませんでした…。

上着⇨おはしょりを作るために長くした

上着は二部ゆかたの上の部分だけ利用することで制作しました。袖も付けていません。

SONY DSCこの二部ゆかたの型紙では、「おはしょり」は浴衣が上下に分かれていることで表現されているのですが、今回は普通に「おはしょり」を作りたかったので、上着の型紙を30cmくらい延長して、長めにしました。

「縫う」より「切る」方が大事

今回やってみて感じたのは、ミシンを使うからついつい「縫う」のが大事なように思ってしまうけど、それよりもちゃんと綺麗に型紙を布に移して、綺麗にカットするのが大事だったということです。華々しさがない作業なのでついつい手を抜きたくなってしまうのですが、ここで手を抜くと後の作業全てに響きます。

小学生の時の私はまち針とかもめんどくさくて殆ど使わなかったような記憶があるのですが、これもちゃんとまち針さして布を固定するのは非常に大事でした。

反省点

反省点もいくつか有ります。

  • 子供用のレインポンチョの型紙を使ったせいで、頭とマントの接合部が首より短くなって着れなくなってしまいました。
    無理やり布でつぎたしましたが、正直不格好。
  • 浴衣の構造を理解せず作っていたので、襟の縫い代が外に出ています。まさか、襟が胸のところまで続いてるなんて知らなかったんだもん!
  • ズボンは長すぎたと思います。足が出てくるところのくびれもとてもかわいいと思うのですが、ここがうまく再現できなかったのは残念です。

あと中の上着に袖が全くありませんが、本当はあります。

20140520_5コミケもこのコスプレしようと思ってますが、その時までに改善できるのか…!?

あと、ちさちゃん(1/6人形)と同じ格好をしてみるのが夢(?)なので、1/6サイズとかで作ってみてもいいかも!

とりあえずTwitterで「作ってみようかな」とつぶやいてみる効果

今まで、「作る」って周りに宣言しちゃうと作った気になるからあんまり言わないようにしてたのですが、今回はこの一言で「ぜったい作るぞ~」みたいな気分になってきたので、「作ろうかな」という思いつきを具体的な言葉にしてつぶやきまくってみるのは結構有用かもな~と思いました。あとは一日24時間の制約と肉体的疲労にどう打ち勝つか…(◞‸◟ )

誰も知らないキャラのコスプレってどういう行為なんだ

コスプレって、例えば初音ミクとか有名なキャラの格好をして「あっ初音ミクだ!似てる!」って思ってもらう一種の相互的なコミュニケーションだと思うんですけど、コンちゃんはほとんど誰も知らないので(とはいえ聞かれたので説明したら2人くらい分かってもらえた)、コミュニケーションが成立してない気がするんですけど、

私が満足してるのでそれでいいとおもいます(小学生並の感想)

  1. 特にマントの裏地が赤いのがほんとーにかわいーとおもいます! []

32bit GCCのunordered_mapに下位32ビットが同じキーを送り続けると死ぬ

Posted on

前回の記事の最後で「unsigned long long intのハッシュは(size_t = 32ビットの環境で)下位32ビットしか見てない」みたいな事を書きました。

これが本当にそうだとすると、この挙動に依存しているunordered_mapに、下位32ビットが同じ値のキーを送り続けるとアルゴリズムの教科書通りの最悪ケースになって悲惨なことになるのでは…!という事が容易に予想されます。

ということで、やってみました。

実験環境

  • Windows 7 64bit
  • MinGW 32 g++ 4.8.1

ソースコードはこちら。

#include <unordered_map>
#include <cstdio>
#include <chrono>
unsigned long getT()
{
    return std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
}
int main()
{
    {
        std::unordered_map<unsigned long long int, int> map;
        unsigned long t = getT();
        for(int j=0;j<100;++j)
        for(unsigned long long int i=0;i<0x1000;++i){
            map.insert(std::make_pair(i << 17, 10));
        }
        printf("Case 1 Time: %d\n", static_cast<int>(getT() - t));
    fflush(stdout);
    }
    {
        std::unordered_map<unsigned long long int, int> map;
        unsigned long t = getT();
        for(int j=0;j<100;++j)
        for(unsigned long long int i=0;i<0x1000;++i){
            map.insert(std::make_pair(i << 33, 10));
        }
        printf("Case 2 Time: %d\n", static_cast<int>(getT() - t));
    fflush(stdout);
    }
}

シフトする値だけ少し変更することで、他の要素の影響を出来る限り減らしました。

結果

g++ -o test -std=gnu++11 test.cpp
./test
Case 1 Time: 120
Case 2 Time: 67825

というわけで500倍くらい遅かったので、本当に線形探索してるっぽいです。本当にありがとうごいました。

64bit環境なら問題ありません

64bit環境のwandboxで実行すると、64bit環境ではsize_tも64ビットになってくれるので、

Start

Case 1 Time: 287
Case 2 Time: 279

0

Finish

というわけでほぼ同じ時間で終わります。

gccのunordered_mapの実装を読んでみる

Posted on

最近諸事情でアルゴリズムイントロダクションを読んでおります。

で、平均挿入・検索・削除時間がO(1)である謎のテクノロジー、ハッシュテーブルの章を読んだので、せっかくなのでSTLの実装を調べてみました。

なお、コンパイル時の条件によって色々実装が分岐するようですが、面倒臭いので適当に目についたコードを読んでいます。なので、組み合わせとして一緒に呼ばれないコードを読んでいる可能性がありますが、ご了承下さい。

とりあえず、挿入を足がかりに

std::unorderd_mapの実装は、いろいろたらい回しにされたあとbits/hashtable.hに記述されているらしいことが分かります。とりあえず挿入っぽい処理を調べてみると、こんな感じになります。

  template
    void
    _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 	       _H1, _H2, _Hash, _RehashPolicy, _Traits>::
    _M_insert_bucket_begin(size_type __bkt, __node_type* __node)
    {
      if (_M_buckets[__bkt])
	{
	  // Bucket is not empty, we just need to insert the new node
	  // after the bucket before begin.
	  __node->_M_nxt = _M_buckets[__bkt]->_M_nxt;
	  _M_buckets[__bkt]->_M_nxt = __node;
	}
      else
	{
	  // The bucket is empty, the new node is inserted at the
	  // beginning of the singly-linked list and the bucket will
	  // contain _M_before_begin pointer.
	  __node->_M_nxt = _M_before_begin._M_nxt;
	  _M_before_begin._M_nxt = __node;
	  if (__node->_M_nxt)
	    // We must update former begin bucket that is pointing to
	    // _M_before_begin.
	    _M_buckets[_M_bucket_index(__node->_M_next())] = __node;
	  _M_buckets[__bkt] = &_M_before_begin;
	}
    }

どうやら、衝突の解決には片方向リストを使った方法を使っているようです。アルゴリズムイントロダクションには「削除が必要な時は片方向リストを使った方法がいい」みたいなことが書いてあったような気がするのですが、そのとおりっぽいです。あと番兵は使ってないみたいですね。やっぱりメモリの節約が優先なのでしょうか。

バケットのインデックスは?

で、この__bktはどこから来てるのかを調べてみると、_M_bucket_indexという関数の値が実際には使われており…bits/hashtable_policy.hに次のようなコードがあります。(型の条件によって複数あるようですがこれが一番なんか読みやすそうなのでこれにしました)

      std::size_t
      _M_bucket_index(const __node_type* __p, std::size_t __n) const
	noexcept( noexcept(declval()(declval()))
		  && noexcept(declval()((__hash_code)0,
						    (std::size_t)0)) )
      { return _M_h2()(_M_h1()(_M_extract()(__p->_M_v())), __n); }

というわけで、h1に値を突っ込んでハッシュを得た後、さらにh2にそのハッシュとバケットの総数を入れてハッシュをバケット数以下にして、実際のバケットのインデックスを求めているみたいです。

__nはバケット数の最大値です。_Key&は例えばstd::unordered_map<string, int>ならstringの方です。_M_h1と_M_h2は実はbits/unorderd_map.hの最初の方にすでに書いてあって、

  template,
	   typename _Pred = std::equal_to<_Key>,
	   typename _Alloc = std::allocator<std::pair >,
	   typename _Tr = __umap_traits<__cache_default<_Key, _Hash>::value>>
    using __umap_hashtable = _Hashtable<_Key, std::pair,
                                        _Alloc, __detail::_Select1st,
				        _Pred, _Hash,
				        __detail::_Mod_range_hashing,
				        __detail::_Default_ranged_hash,
				        __detail::_Prime_rehash_policy, _Tr>;

h1の実体はstd::hash<_Key>(_key const& key)で、これは後で調べますが、とりあえず色々な型についてhash値を返してくれるSTLの公開の標準ライブラリです(皆様もお使いになれます!)

h2は__detail::_Mod_range_hashingで固定で、ユーザーが指定したりは出来ないようです。

h2はただのmod

_Mod_Range_hashingはbits/hashtable_policy.hに実体があり、

  // Many of class template _Hashtable's template parameters are policy
  // classes.  These are defaults for the policies.

  /// Default range hashing function: use division to fold a large number
  /// into the range [0, N).
  struct _Mod_range_hashing
  {
    typedef std::size_t first_argument_type;
    typedef std::size_t second_argument_type;
    typedef std::size_t result_type;

    result_type
    operator()(first_argument_type __num,
	       second_argument_type __den) const noexcept
    { return __num % __den; }
  };

というわけで、散々たらい回しにされた挙句ただのmodでした。万能ハッシュとか使ってるのかと思ったのですがそんなことはなく、h1の実体であるstd::hashに衝突の回避とかの仕事はほぼ丸投げして、バケット数とmodをとっているという感じになります。

std::hashの実体

std::hashの実体は色々なところに散らばっているのですが、std::stringの実装がやっぱり一番気になるのでそれを調べてみると、basic_string.hに実体があって、

  /// std::hash specialization for string.
  template<>
    struct hash
    : public __hash_base
    {
      size_t
      operator()(const string& __s) const noexcept
      { return std::_Hash_impl::hash(__s.data(), __s.length()); }
    };

  template<>
    struct __is_fast_hash> : std::false_type
    { };

となっております。ほかのstd::wstringとかutf16とかも全部同じ実装です。hashの先を見れば分かるのですが、この関数はvoid*を取る関数なので、文字列としての特性はとくに使わず、バイト列として解釈してhashを計算しているようです。

さて、_Hash_impl::hashはfunctional_hash.hの関数です。このseedの値の意味がよくわかりません…。

    static size_t
    hash(const void* __ptr, size_t __clength,
	 size_t __seed = static_cast(0xc70f6907UL))
    { return _Hash_bytes(__ptr, __clength, __seed); }

なんとこの先はlibsupc++という別ライブラリに投げれていて、

  inline std::size_t
  unaligned_load(const char* p)
  {
    std::size_t result;
    __builtin_memcpy(&result, p, sizeof(result));
    return result;
  }

}

namespace std
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

#if __SIZEOF_SIZE_T__ == 4

  // Implementation of Murmur hash for 32-bit size_t.
  size_t
  _Hash_bytes(const void* ptr, size_t len, size_t seed)
  {
    const size_t m = 0x5bd1e995;
    size_t hash = seed ^ len;
    const char* buf = static_cast(ptr);

    // Mix 4 bytes at a time into the hash.
    while(len >= 4)
      {
	size_t k = unaligned_load(buf);
	k *= m;
	k ^= k >> 24;
	k *= m;
	hash *= m;
	hash ^= k;
	buf += 4;
	len -= 4;
      }

    // Handle the last few bytes of the input array.
    switch(len)
      {
      case 3:
	hash ^= static_cast(buf[2]) << 16;
      case 2:
	hash ^= static_cast(buf[1]) << 8;
      case 1:
	hash ^= static_cast(buf[0]);
	hash *= m;
      };

    // Do a few final mixes of the hash.
    hash ^= hash >> 13;
    hash *= m;
    hash ^= hash >> 15;
    return hash;
  }

この関数もなんとなくバイト列中のたくさんのビットを反映させていることはなんとなく分かるのですが、謎のマジックワードもあるし、謎です。

やっぱり本と実装はすこし違いますね~とおもったのでした。おしまい。

他の型のハッシュは?

同じfunctional_hash.hにマクロがあって、

  // Explicit specializations for integer types.
#define _Cxx_hashtable_define_trivial_hash(_Tp) 	\
  template<>						\
    struct hash<_Tp> : public __hash_base  \
    {                                                   \
      size_t                                            \
      operator()(_Tp __val) const noexcept              \
      { return static_cast(__val); }            \
    };

  /// Explicit specialization for bool.
  _Cxx_hashtable_define_trivial_hash(bool)

  /// Explicit specialization for unsigned long long.
  _Cxx_hashtable_define_trivial_hash(unsigned long long)

という感じです。なんとstatic_castするだけ!型に収まってるならともかく、unsigned long longまでstatic_castしちゃうのは本当にそれでいいの?感があります。…ということは32bit環境下でunordered_mapに下32ビットが同じunsigned long longを送り続けると死ぬほど遅い可能性がある…? →実際に実験したら遅かった

ちなみにこのコードのすぐ下にありますが、double/floatに関してはバイト列として文字列と同じハッシュ関数を使っています。うーん…(^_^;)