2015年12月12日土曜日

[C++]HKM勉強したい@そのいち


始まりました、「~したい」シリーズ。
今回はHKM階層的K平均法です。


話は変わるんですけど、ワタクシ大変なことに気づいてしまいました・・・。
「~したい」シリーズのタイトルの後ろについてる「@その~」っていうバックナンバー、


そのいち、そのにぐらいまでしか続かない(^p^)


バックナンバーつける意味あるのかってね。

BBCPマコトの紹介記事とかだと結構続いたんですけどね。

飽きっぽい性格の私は一つの物事に集中して取り組めないのですよ(^p^)

いっそバックナンバー制廃止にしようかな。





まあ、それはさておいて、今回のタイトル「HKM」についてです。

HKMとは本来ならクラスタ分析をする為に使われる手法です。

今回はこれを最近傍探索に使います。

最近傍探索にはいろいろな手法があるのですが、これはKDtreeに似ているかもしれません。

KDtreeという手法は簡単に言えば

  1. 空間を分割する。
  2. クエリが分割された空間のどこに属するか調べる。
  3. クエリが属する空間の中に最近傍がある。

という手法です。

それに対してHKMは

  1. データを2つのクラスタ(データの集合)に分ける。
  2. 分けられたクラスタの中のデータをさらに2つのクラスタに分ける。
  3. クラスタの中のデータが1つになるまで1.2.を繰り返す。
  4. クエリがどのクラスタに属するか調べる。
  5. クエリが属するクラスタがの中に最近傍がある。
という手法です。

詳しいことは 知 り ま せ ん 

詳しい人は私にご教授ください。

とりあえず今回HKMを使うために使ったアルゴリズムとその紹介。

KNN(k近傍法) 

クエリの近傍をk個求める手法。

アルゴリズム

  1. クエリとデータベース全点の距離を計算。
  2. 距離を昇順にソート。
  3. 上からk個をとる。

Kmeans(k平均法)

k個のクラスタを作る手法。

アルゴリズム
  1. 空のクラスタをk個作る。
  2. それぞれのクラスタにランダムにデータを割り当てる。
  3. クラスタに含まれるデータの座標の平均をクラスタの中心とする。
  4. 各データと各クラスタ中心の距離を計算し、各データを最近傍となる各クラスタに割り当てなおす。
  5. 割り当ての変化量が一定の閾値以内になるまで3.4.を繰り返す。

HKM(階層的k平均法)

階層的にk個のクラスタを作る手法。

アルゴリズム

  1. k個のクラスタを作る。
  2. クラスタの中でさらにk個のクラスタを作る。
  3. クラスタの中のデータが1個になるまで2.を繰り返す。


こんな感じです。

最初にKNNを作って、次にKNNを使ってKmeansを作って、次にKmeansを使ってHKMを作ります。

こういうの楽しいよね。

弱い武器を強化していって最強の武器を作るみたいな感じ。

テンションが上がりますね(^p^)

それでは以下ソース
量がやばい。
#pragma once
#include"KMeansClass.h"
class HKMClass :public KMeansClass
{
public:
static struct vertex
{
vertex* left;
vertex* right;
vector<CLASTER> claster;
};
static enum CONST
{
left,
right,
hk = 2,
};
vertex *node;
HKMClass() :KMeansClass()
{}
HKMClass(const int &t) :KMeansClass(hk,t)
{
}
HKMClass(const vector<DATA> &data, const int &t) :KMeansClass(hk,t)
{
this->node = MakeHKM(data);
}
~HKMClass(){}
vertex* R_MakeHKM(const vector<DATA> &data)
{
vertex *node = new vertex();
node->claster = MakeClaster(data, hk);
if (node->claster[left].data.size() < hk)
{
node->left = NULL;
}
else
{
node->left = R_MakeHKM(node->claster[left].data);
}
if (node->claster[right].data.size() < hk)
{
node->right = NULL;
}
else
{
node->right = R_MakeHKM(node->claster[right].data);
}
return node;
}
vertex* MakeHKM(const vector<DATA> &data)
{
this->node = R_MakeHKM(data);
return this->node;
}
vector<DATA> R_Search(const DATA &query,const vertex* node)
{
size_t claster_size = node->claster.size();
if (claster_size < hk)
{
return node->claster[0].data;
}
vector<DATA> center(claster_size);
for (int i = 0; i < claster_size;++i)
{
center[i] = node->claster[i].center;
}
KNNClass knn_obj(center, 1);
int neighbor=knn_obj.KNN(query)[0].second;
if ((node->left!=NULL)&&(neighbor == left || node->right==NULL))
{
return R_Search(query, node->left);
}
else if ((node->right != NULL) && (neighbor == right || node->left == NULL))
{
return R_Search(query, node->right);
}
else if (node->left == NULL&&node->right == NULL)
{
return node->claster[0].data;
}
else
{
}
return vector<DATA>();
}
DATA Search(const DATA &query,const vertex* node)
{
return R_Search(query, node)[0];
}
DATA Search(const DATA &query)
{
return Search(query, this->node);
}
};
view raw HKMClass.h hosted with ❤ by GitHub
#pragma once
#include<vector>
#include"KNNClass.h"
#include"../../../Useful/useful.h"
using namespace std;
class KMeansClass
{
public:
typedef vector<double> DATA;
static struct CLASTER
{
vector<DATA> data;
DATA center;
};
protected:
int k;
vector<CLASTER> claster;
int threshold;
void CalcCenter(vector<CLASTER> *claster)
{
size_t feature_size = (*claster)[0].data[0].size();
for (auto &i : *claster)
{
i.center = VectorAverage(i.data);
}
}
int ReassignData(vector<CLASTER> *claster, const int &k)
{
vector<DATA> center(k);
for (int i = 0; i < k; ++i)
{
center[i] = (*claster)[i].center;
}
KNNClass knn_obj(center, 1);
int difference = 0;
for (int i = 0; i < k; i++)
{
size_t data_size = (*claster)[i].data.size();
for (int j=0;j<data_size;++j)
{
DATA* temp = &(*claster)[i].data[j];
int neighbor = knn_obj.KNN(*temp)[0].second;
if (i != neighbor)
{
++difference;
(*claster)[neighbor].data.push_back(*temp);
(*claster)[i].data.erase
(
remove
(
(*claster)[i].data.begin(), (*claster)[i].data.end(), *temp
)
);
data_size = (*claster)[i].data.size();
}
}
}
return difference;
}
void InitClasterData(vector<CLASTER> *claster)
{
for (auto &i : *claster)
{
i.data.clear();
i.center.clear();
}
}
void AllocateForNormal(vector<CLASTER> *claster, const vector<DATA> &data, const int &k)
{
int i = 0;
for (auto &j : data)
{
(*claster)[++i%k].data.push_back(j);
}
}
public:
KMeansClass()
{
SetK(1);
SetThreshold(100);
}
KMeansClass(const int &k)
{
SetK(k);
SetThreshold(100);
}
KMeansClass(const int &k, const int &t)
{
SetK(k);
SetThreshold(t);
}
KMeansClass(const vector<DATA> &data,const int &k, const int &t)
{
SetK(k);
SetThreshold(t);
MakeClaster(data);
}
~KMeansClass(){}
vector<CLASTER> MakeClaster(const vector<DATA> &data, const int &k)
{
auto claster_size = k;
vector<CLASTER> claster(k);
AllocateForNormal(&claster, data, k);
CalcCenter(&claster);
while (threshold<ReassignData(&claster, k));
this->claster = claster;
return claster;
}
vector<DATA> Search(const DATA &query)
{
int claster_size = this->claster.size();
vector<DATA> center(claster_size);
for (int i = 0; i < claster_size; ++i)
{
center[i] = this->claster[i].center;
}
KNNClass knn_obj(center, 1);
int neighbor = knn_obj.KNN(query)[0].second;
return this->claster[neighbor].data;
}
vector<CLASTER> MakeClaster(const vector<DATA> &data)
{
return MakeClaster(data, this->k);
}
void InitClasterData()
{
InitClasterData(&this->claster);
}
void SetK(const int &k)
{
this->k = k;
}
void SetThreshold(const int &t)
{
this->threshold = t;
}
vector<CLASTER> GetClaster()
{
return this->claster;
}
};
view raw KMeansClass.h hosted with ❤ by GitHub
#pragma once
#include<vector>
#include<utility>
#include<algorithm>
using namespace std;
typedef vector<double> DATA;
typedef vector<pair<double, int>> SOLVE;
class KNNClass
{
private:
vector<DATA> data_base;
int k;
double Sqare(const double &x)
{
return x*x;
}
double Distance(const DATA &a, const DATA &b)
{
auto size = a.size();
double sum = 0.;
for (auto i = 0; i < size; ++i)
{
sum += Sqare(a[i] - b[i]);
}
return sum;
}
public:
KNNClass()
{
SetK(1);
InitDataBase();
}
KNNClass(const int &k)
{
SetK(k);
InitDataBase();
}
KNNClass(const vector<DATA> &data_base)
{
SetK(1);
SetDataBase(data_base);
}
KNNClass(const vector<DATA> &data_base, const int &k)
{
SetK(k);
SetDataBase(data_base);
}
~KNNClass(){}
vector<pair<double, int>> KNN(const DATA &query, const vector<DATA> &data_base, const int &k)
{
auto size = data_base.size();
vector<pair<double, int>> distance(size);
for (auto i = 0; i < size; ++i)
{
distance[i] = make_pair(Distance(query, data_base[i]), i);
}
sort(distance.begin(), distance.end());
return vector<pair<double, int>>(distance.begin(), distance.begin() + k);
}
vector<pair<double, int>> KNN(const DATA &query, const vector<DATA> &data_base)
{
return KNN(query, data_base, this->k);
}
vector<pair<double, int>> KNN(const DATA &query, const int &k)
{
return KNN(query, this->data_base, k);
}
vector<pair<double, int>> KNN(const DATA &query)
{
return KNN(query, this->data_base, this->k);
}
void SetK(const int &k)
{
this->k = k;
}
void SetDataBase(const vector<DATA> &data_base)
{
this->data_base = data_base;
}
void InitDataBase()
{
this->data_base.clear();
}
};
view raw KNNClass.h hosted with ❤ by GitHub
説明はきっといらないよね・・・?
アルゴリズムの紹介してるしね?

未来の俺はこう言う。
「コメント文ぐらい書けよ(#^p^)」

ってか、あれ、これ・・・

そのに、そのさんに分ければよかったんじゃね??

2015年12月9日水曜日

[C++]タブーサーチ作り直したい

なんかタブーサーチ改良することになったのでもう一度あげます。

~~変更点~~

・近傍生成方法を選べるようになったよ!
今のところ
・データを入れ替える
・bitを反転させる

の二つが選べます。

説明するのは面倒なので後日暇があったら画像付きで説明します。
まぢつかれたょ。。。

以下ソース
#include <iostream>
#include <vector>
#include <algorithm>
#include<random>
#include<utility>
#include<functional>
using namespace std;
//タブーサーチクラス
template<class T_n>
class TabuSearchClass
{
private:
//現在の解
vector<T_n> current;
//最適解
vector<T_n> optimal;
//最適解のサイズ
size_t optimal_size;
//タブーリスト
vector<pair<T_n, T_n>> tabu_list;
//タブーリストのサイズ
size_t tabu_list_size;
//近傍生成方法
public:
static const enum Neighbor
{
DATASWAP,
BITINVERT,
};
private:
Neighbor neighbor;
//探索回数
size_t search_num;
//最大評価値
double max_evaluate;
//現在の評価値
double current_evaluate;
//乱数用
mt19937 mt;
//最適解と最大評価値の初期化
void Initialize()
{
optimal = vector<T_n>(this->current.begin(), current.begin() + optimal_size);
max_evaluate = current_evaluate = 0.;
}
//近傍の選択
vector<vector<T_n>> DataSwap(const vector<T_n> &current)
{
size_t current_size = current.size();
//size_t data_size = GetDataSize();
vector<vector<T_n>> neighbor(current_size, vector<T_n>(current));
for (size_t i = 0; i < current_size; i++)
{
swap(neighbor[i][0], neighbor[i][i]);
}
return vector<vector<T_n>>(neighbor.begin() + 1, neighbor.end());
}
vector<vector<T_n>> BitInvert(const vector<T_n> &current)
{
size_t current_size = current.size();
//size_t data_size = GetDataSize();
vector<vector<T_n>> neighbor(current_size, vector<T_n>(current));
for (size_t i = 0; i < current_size; i++)
{
neighbor[i][i] = (neighbor[i][i] + 1) % 2;
}
return vector<vector<T_n>>(neighbor.begin() , neighbor.end());
}
//優良解の探索
//predにはvector<T_n>の型を引数にした評価関数を渡す
template<class _Pre>
void ChoiceExellence(_Pre pred)
{
vector<vector<T_n>>(TabuSearchClass::*ChoiceNeighbor[])(const vector<T_n>&) =
{
&TabuSearchClass::DataSwap,
&TabuSearchClass::BitInvert,
};
vector<vector<T_n>> neighbor = (this->*ChoiceNeighbor[this->neighbor])(this->current);
size_t solve_size = GetSolveSize();
size_t neighbor_size = neighbor.size();
double max = 0.;
double evaluate;
vector<pair<double, int>> better;
for (size_t i = 0; i < neighbor_size; i++)
{
evaluate = pred(vector<T_n>(neighbor[i].begin(), neighbor[i].begin() + solve_size));
/*if (evaluate>=max)
{
max = evaluate;
better = i;
}*/
better.push_back(make_pair(evaluate, i));
}
sort(better.begin(), better.end(), std::greater<pair<double, int>>());
this->current_evaluate = better[0].first;
for (auto &i : better)
{
if (CheckTransition(neighbor[i.second], make_pair(this->current[0], neighbor[i.second][0])))
break;
}
//this->current_evaluate = max;
//CheckTransition(neighbor[better], make_pair(neighbor[better][0], neighbor[better][better]));
//return neighbor[better];
}
//遷移がタブーリストに含まれているか判定
//含まれていたらtrue
bool CheckTabu(const pair<T_n, T_n> &transition)
{
for (auto &i : tabu_list)
{
if (i == transition || i == make_pair(transition.second, transition.first))
{
return true;
}
}
return false;
}
//現在の解を遷移するか判定
//遷移したらtrue
bool CheckTransition(const vector<T_n> &neighbor, const pair<T_n, T_n> &transition)
{
size_t solve_size = this->GetSolveSize();
if (current_evaluate > max_evaluate)
{
this->optimal = vector<T_n>(neighbor.begin(), neighbor.begin() + solve_size);
this->current = neighbor;
max_evaluate = current_evaluate;
if (CheckTabu(transition))
{
tabu_list.erase(find(tabu_list.begin(), tabu_list.end(), transition));
tabu_list.push_back(transition);
}
else
{
tabu_list.push_back(transition);
if (CheckTabuListSizeOver())
{
tabu_list.erase(tabu_list.begin());
}
}
return true;
}
else
{
if (!CheckTabu(transition))
{
this->current = neighbor;
tabu_list.push_back(transition);
if (CheckTabuListSizeOver())
{
tabu_list.erase(tabu_list.begin());
}
return true;
}
else
return false;
}
return false;
}
//タブーリストのサイズが指定のサイズをオーバーしたか判定
//オーバーしたらtrue
bool CheckTabuListSizeOver()
{
return tabu_list.size() > tabu_list_size;
}
//重複回数をカウント、指定回数以上重複でtrueを返す
class CheckConvergence
{
private:
vector<T_n> data;
int count;
int num;
public:
//コンストラクタはコメント表示されない?
CheckConvergence(){}
//dataに初期解、numに何回解が変わらなかったら収束するかを設定
CheckConvergence(const vector<T_n> &data, const int &num)
{
this->data = data;
this->count = 0;
this->num = num;
}
~CheckConvergence(){}
//countがnumを超えたらtrue(収束)
bool operator()(const vector<T_n> &data)
{
if (this->data == data)
{
count++;
}
else
{
this->data = data;
count = 0;
}
return count > num;
}
};
public:
//デフォルト値
//最適解のvectorのサイズ
static const size_t default_optimal_size = 10;
//探索回数
static const size_t default_search_num = 100;
//タブーリストのサイズ
static const size_t default_list_size = 7;
//コンストラクタ
TabuSearchClass()
{
SetMt();
}
//最適解を見つけたいvectorをvに渡す
TabuSearchClass(const vector<T_n> &v)
{
SetMt();
SetData(v);
SetOptimalSize(default_optimal_size);
SetSeachNum(default_search_num);
this->SetTabuListSize(default_list_size);
SetNeighborMethod(DataSwap);
}
//最適解を見つけたいvectorをvに渡す
//最適解のvectorのサイズをoptimal_sizeに渡す
TabuSearchClass(const vector<T_n> &v, const size_t &optimal_size)
{
SetMt();
SetData(v);
SetOptimalSize(optimal_size);
SetSeachNum(100);
this->SetTabuListSize(7);
SetNeighborMethod(DataSwap);
}
//最適解を見つけたいvectorをvに渡す
//最適解のvectorのサイズをoptimal_sizeに渡す
//探索回数をsearch_numに渡す
TabuSearchClass(const vector<T_n> &v, const size_t &optimal_size, const size_t &search_num)
{
SetMt();
SetData(v);
SetOptimalSize(optimal_size);
SetSeachNum(search_num);
this->SetTabuListSize(7);
SetNeighborMethod(DataSwap);
}
//最適解を見つけたいvectorをvに渡す
//最適解のvectorのサイズをoptimal_sizeに渡す
//探索回数をsearch_numに渡す
//近傍生成方法をneighborに渡す
TabuSearchClass
(
const vector<T_n> &v, const size_t &optimal_size, const size_t &search_num,const Neighbor &neighbor
)
{
SetMt();
SetData(v);
SetOptimalSize(optimal_size);
SetSeachNum(search_num);
this->SetTabuListSize(7);
SetNeighborMethod(neighbor);
}
//最適解を見つけたいvectorをvに渡す
//最適解のvectorのサイズをoptimal_sizeに渡す
//探索回数をsearch_numに渡す
//タブーリストのサイズをlist_sizeに渡す
TabuSearchClass
(
const vector<T_n> &v, const size_t &optimal_size, const size_t &search_num,
const size_t &list_size
)
{
SetMt();
SetData(v);
SetOptimalSize(optimal_size);
SetSeachNum(search_num);
this->SetTabuListSize(list_size);
SetNeighborMethod(DataSwap);
}
~TabuSearchClass(){}
////最適解を見つけたいvectorをvに渡す
void SetData(const vector<T_n> &v)
{
this->current = v;
}
//最適解のvectorのサイズをoptimal_sizeに渡す
void SetOptimalSize(const size_t &size)
{
this->optimal_size = size;
}
//メルセンヌツイスタの初期化
void SetMt()
{
random_device rnd;
mt.seed(rnd());
}
//データのサイズを返す
size_t GetDataSize()const
{
return this->current.size();
}
//最適解のサイズを返す
size_t GetSolveSize()const
{
return this->optimal.size();
}
//タブーリストのサイズをsizeに設定する
void SetTabuListSize(const size_t &size)
{
this->tabu_list_size = size;
}
//タブーサーチをする
//predにはvector<T_n>の型を引数にした評価関数を渡す
template<class _Pre>
vector<T_n> TabuSearch(_Pre pred)
{
const size_t convergence_num = 5;
CheckConvergence obj(this->current, convergence_num);
Initialize();
for (int i = 0; !obj(this->current) && i < search_num; i++)
{
ChoiceExellence(pred);
//CheckTransition();
}
return optimal;
}
//探索回数をnumに設定
void SetSeachNum(const size_t &num)
{
this->search_num = num;
}
//最大評価値を返す
double GetMaxEvaluate()const
{
return max_evaluate;
}
void SetNeighborMethod(const Neighbor &neighbor)
{
this->neighbor = neighbor;
}
};
void main()
{
struct ITEM
{
public:
int num;
int income;
int weight;
bool operator==(const ITEM &i)const
{
return i.num == this->num;
}
};
ITEM a[5] =
{
{ 0, 1, 2 },
{ 1, 3, 4 },
{ 2, 5, 6 },
{ 3, 7, 8 },
{ 4, 9, 0 },
};
vector<ITEM> v(5);
for (int i = 0; i < 5;i++)
{
/*v[i].num = i;
cout << "価格:" << flush;
cin >> v[i].income;
cout << "重さ:" << flush;
cin >> v[i].weight;*/
v[i] = a[i];
}
const int max_w = 10;
vector<int> vv(5,0);
{
int weight = 0;
for (int i = 0; i < 5; i++)
{
if (v[i].weight + weight < max_w)
{
vv[i] = 1;
weight += v[i].weight;
}
}
}
TabuSearchClass<int> obj(vv, 5, 100,TabuSearchClass<int>::Neighbor::BITINVERT);
//obj.SetWeight(100);
vector<int> opt = obj.TabuSearch(
[&](vector<int> &vv)
{
int sum = 0;
int weight = 0;
int max_w = 10;
for (int i = 0; i < vv.size(); i++)
{
if (vv[i])
{
if (weight + v[i].weight < max_w)
{
weight += v[i].weight;
sum += v[i].income;
}
}
}
return sum;
}
);
for (int i = 0; i < opt.size();i++)
{
if (opt[i])
cout << v[i].num << endl;
}
}
view raw gistfile1.txt hosted with ❤ by GitHub
今回はナップサック問題(?)を解いてみました。だって友達がやれやれうるさいんだもん。
ちゃんと解けてるはず。たぶん。

2015年11月28日土曜日

[C++]タブーサーチ作りたい

タブーサーチクラスを作れたと思ったのでアップ。
2,3回動かしてうまくいっただけなのでもしかしたらバグがあるかもしれない。
まあ、今回はそれなりに満足いけたものを作れた気がする。
あと、今忙しくて全然書くことまとめれてないから今度暇なときにこの記事修正する。 
未来の自分へ
お前は次に「こんなの使わねえよww」と言う。
・・・ハッ!?



以下2015/11/30追記

いやー、やっとひと段落しました。いや、してないんですけどね。とりあえずはゆっくり記事書けるぐらいの時間は確保できたと。

それじゃあ、今回作ったタブーサーチの紹介でもしますか。

タブーサーチとは(デデン!

探索アルゴリズムの手法の一つだそうです。詳しいことはあまり知りません(^p^)

DMMのLord of Walkureというゲームでですね、討伐戦団というコンテンツがありまして。
主人公とワルキューレ(味方)×10人がボスを倒す、という内容です。
この討伐っていうのがすごく難しくて、ワルキューレの隊列の組み方で勝率に影響が出るんですよね。



例えば、A、B、C、D、Eというワルキューレがいたとして、隊列を[ABCDE]にして戦うと勝率が30%だったとします。
これを[BACDE]としただけで勝率が50%まで跳ね上がる、なんてことがあるんですよ。



ボスとは無限に戦えるわけじゃないからできるだけ勝率を高くしたい・・・。




そんなわけでシミュレータを作りました。(今回はシミュレータの方のプログラムは載せません^^;理由は後述)




Lord of Walkureは課金をしなかった場合、最大で50枚ほどのワルキューレを仲間にすることができます。その中から一番効率よくボスを倒せる10人を選ぶわけです。数式で表すと50P10です。


とりあえず4P4でシミュレーションしてみることにしました。べ、別にデータ入力が面倒だったわけじゃないんだからね(^p^)


計算結果は4秒。まあ、こんなもんかな。次に10P10で計算。

・・・計算が終わらないだと?


そうなんです。計算が終わらなかったんです。ブレークポイントを作って確認してみると計算自体はしているようでした。不思議に思いながら何も考えずに10P10を計算してみると

3628800!

300万回も計算する必要があったわけです。4P4を計算すると24になったので、一秒に6回計算できるわけです。300万回の計算には50万秒必要なわけで、50万秒はおよそ8000分で、8000分はおよそ140時間で、140時間はおよそ5日という計算になります。


本当は50P10の計算をしたいんです。
しかし、この値を計算すると37.27604302[P]となります。[P]って知ってますか?10の15乗のことらしいですよ。
僕もよくわからないんですけど、多分私が生きている間に計算を終えることが不可能なんじゃないかなと思います。

あほらしくなりましたね(^p^)


しかし、ここであきらめるほど私はヤワじゃない!



ここからようやくタブーサーチの話に入るわけです。



全件探索するから遅いんです。効率よく探索すれば早いはず!

ということで探索アルゴリズムを使うことに。

個人的には遺伝アルゴリズムなんかに興味があったのですが、「タブー探索勉強中!」といっている友人がいたのでタブー探索を使うことにしました。



アルゴリズムの内容に関してはwikipediaで調べたものを基本的に使っています。

私の日本語力がないからかもしれませんが、一部よくわからないところがあったのでそこは自分で補完しました。




以下、探索の流れ

1.初期解の生成
2.解の近傍生成
3.優良解の判定
4.現在解の更新判定
5.タブー判定
6.2.~5.を現在解が収束するか、任意の計算回数になるまでループ




とりあえずテスト。

任意の個数の数値をn個組み合わせて総和が最大になるものを探索します。
評価関数は素直に総和を返すようにします。
ちょっと何言ってるかわからないと思うので実際に見せます。
総和が一番大きくなる組み合わせになっていそうですね。









ただ、今回は並び方も考慮したいので、並び順も評価関数に組み込みたいですね。
場所によって重みをつけることにしましょう。後ろにあるほうがより重くなるということです。
7,8,9,10,11と出力してくれればうれしいです。
されたっぽいですね。
じゃあテスト終わり。




いよいよ討伐シミュレータに組み込みます。
まずは4P4をどれだけ高速化できるか・・・!
(正確には4個のデータの組み合わせです。)


計算結果・・・8秒



(#^p^)

(#^p^)(#^p^)


普通に計算した時より遅いし。
キレソウ(#^p^)


というわけでシミュレータ機能せず・・・。

タブー探索の収束条件とかもうちょっといじれそう。

ほかにも最適化できそうなところがちらほら・・・。

これを直せば早くなるんでしょうか?

教えて偉い人。



とりあえず動作はしているのでタブー探索のソースをあげます。

最適化できそうなところがあったら教えてください。
#pragma once
#include"stdafx.h"
//タブーサーチクラス
template<class T_n>
class TabuSearchClass
{
private:
//現在の解
vector<T_n> current;
//最適解
vector<T_n> optimal;
//最適解のサイズ
size_t optimal_size;
//タブーリスト
vector<pair<T_n, T_n>> tabu_list;
//タブーリストのサイズ
size_t tabu_list_size;
//探索回数
size_t search_num;
//最大評価値
double max_evaluate;
//現在の評価値
double current_evaluate;
//乱数用
mt19937 mt;
//最適解と最大評価値の初期化
void Initialize()
{
optimal = vector<T_n>(this->current.begin(), current.begin() + optimal_size);
max_evaluate = current_evaluate = 0.;
}
//近傍の選択
vector<vector<T_n>> ChoiceNeighbor(const vector<T_n> &current)
{
size_t current_size = current.size();
//size_t data_size = GetDataSize();
vector<vector<T_n>> neighbor(current_size, vector<T_n>(current));
for (size_t i = 0; i < current_size; i++)
{
swap(neighbor[i][0], neighbor[i][i]);
}
return vector<vector<T_n>>(neighbor.begin() + 1, neighbor.end());
}
//優良解の探索
//predにはvector<T_n>の型を引数にした評価関数を渡す
template<class _Pre>
void ChoiceExellence(_Pre pred)
{
vector<vector<T_n>> neighbor = ChoiceNeighbor(this->current);
size_t solve_size = GetSolveSize();
size_t neighbor_size = neighbor.size();
double max = 0.;
double evaluate;
vector<pair<double, int>> better;
for (size_t i = 0; i < neighbor_size; i++)
{
evaluate = pred(vector<T_n>(neighbor[i].begin(), neighbor[i].begin() + solve_size));
/*if (evaluate>=max)
{
max = evaluate;
better = i;
}*/
better.push_back(make_pair(evaluate, i));
}
sort(better.begin(), better.end(), std::greater<pair<double, int>>());
this->current_evaluate = better[0].first;
for (auto &i : better)
{
if (CheckTransition(neighbor[i.second], make_pair(this->current[0], neighbor[i.second][0])))
break;
}
//this->current_evaluate = max;
//CheckTransition(neighbor[better], make_pair(neighbor[better][0], neighbor[better][better]));
//return neighbor[better];
}
//遷移がタブーリストに含まれているか判定
//含まれていたらtrue
bool CheckTabu(const pair<T_n, T_n> &transition)
{
for (auto &i : tabu_list)
{
if (i == transition || i == make_pair(transition.second, transition.first))
{
return true;
}
}
return false;
}
//現在の解を遷移するか判定
//遷移したらtrue
bool CheckTransition(const vector<T_n> &neighbor, const pair<T_n, T_n> &transition)
{
size_t solve_size = this->GetSolveSize();
if (current_evaluate > max_evaluate)
{
this->optimal = vector<T_n>(neighbor.begin(), neighbor.begin() + solve_size);
this->current = neighbor;
max_evaluate = current_evaluate;
if (CheckTabu(transition))
{
tabu_list.erase(find(tabu_list.begin(), tabu_list.end(), transition));
tabu_list.push_back(transition);
}
else
{
tabu_list.push_back(transition);
if (CheckTabuListSizeOver())
{
tabu_list.erase(tabu_list.begin());
}
}
return true;
}
else
{
if (!CheckTabu(transition))
{
this->current = neighbor;
tabu_list.push_back(transition);
if (CheckTabuListSizeOver())
{
tabu_list.erase(tabu_list.begin());
}
return true;
}
else
return false;
}
return false;
}
//タブーリストのサイズが指定のサイズをオーバーしたか判定
//オーバーしたらtrue
bool CheckTabuListSizeOver()
{
return tabu_list.size() > tabu_list_size;
}
//重複回数をカウント、指定回数以上重複でtrueを返す
class CheckConvergence
{
private:
vector<T_n> data;
int count;
int num;
public:
//コンストラクタはコメント表示されない?
CheckConvergence(){}
//dataに初期解、numに何回解が変わらなかったら収束するかを設定
CheckConvergence(const vector<T_n> &data, const int &num)
{
this->data = data;
this->count = 0;
this->num = num;
}
~CheckConvergence(){}
//countがnumを超えたらtrue(収束)
bool operator()(const vector<T_n> &data)
{
if (this->data == data)
{
count++;
}
else
{
this->data = data;
count = 0;
}
return count > num;
}
};
public:
//デフォルト値
//最適解のvectorのサイズ
static const size_t default_optimal_size = 10;
//探索回数
static const size_t default_search_num = 100;
//タブーリストのサイズ
static const size_t default_list_size = 7;
//コンストラクタ
TabuSearchClass()
{
SetMt();
}
//最適解を見つけたいvectorをvに渡す
TabuSearchClass(const vector<T_n> &v)
{
SetMt();
SetData(v);
SetOptimalSize(default_optimal_size);
SetSeachNum(default_search_num);
this->SetTabuListSize(default_list_size);
}
//最適解を見つけたいvectorをvに渡す
//最適解のvectorのサイズをoptimal_sizeに渡す
TabuSearchClass(const vector<T_n> &v, const size_t &optimal_size)
{
SetMt();
SetData(v);
SetOptimalSize(optimal_size);
SetSeachNum(100);
this->SetTabuListSize(7);
}
//最適解を見つけたいvectorをvに渡す
//最適解のvectorのサイズをoptimal_sizeに渡す
//探索回数をsearch_numに渡す
TabuSearchClass(const vector<T_n> &v, const size_t &optimal_size, const size_t &search_num)
{
SetMt();
SetData(v);
SetOptimalSize(optimal_size);
SetSeachNum(search_num);
this->SetTabuListSize(7);
}
//最適解を見つけたいvectorをvに渡す
//最適解のvectorのサイズをoptimal_sizeに渡す
//探索回数をsearch_numに渡す
//タブーリストのサイズをlist_sizeに渡す
TabuSearchClass
(
const vector<T_n> &v, const size_t &optimal_size, const size_t &search_num,
const size_t &list_size
)
{
SetMt();
SetData(v);
SetOptimalSize(optimal_size);
SetSeachNum(search_num);
this->SetTabuListSize(list_size);
}
~TabuSearchClass(){}
////最適解を見つけたいvectorをvに渡す
void SetData(const vector<T_n> &v)
{
this->current = v;
}
//最適解のvectorのサイズをoptimal_sizeに渡す
void SetOptimalSize(const size_t &size)
{
this->optimal_size = size;
}
//メルセンヌツイスタの初期化
void SetMt()
{
random_device rnd;
mt.seed(rnd());
}
//データのサイズを返す
size_t GetDataSize()const
{
return this->current.size();
}
//最適解のサイズを返す
size_t GetSolveSize()const
{
return this->optimal.size();
}
//タブーリストのサイズをsizeに設定する
void SetTabuListSize(const size_t &size)
{
this->tabu_list_size = size;
}
//タブーサーチをする
//predにはvector<T_n>の型を引数にした評価関数を渡す
template<class _Pre>
vector<T_n> TabuSearch(_Pre pred)
{
const size_t convergence_num = 5;
CheckConvergence obj(this->current, convergence_num);
Initialize();
for (int i = 0; !obj(this->current) && i < search_num; i++)
{
ChoiceExellence(pred);
//CheckTransition();
}
return optimal;
}
//探索回数をnumに設定
void SetSeachNum(const size_t &num)
{
this->search_num = num;
}
//最大評価値を返す
double GetMaxEvaluate()const
{
return max_evaluate;
}
};
view raw gistfile1.txt hosted with ❤ by GitHub

あと、だれかもっと効率のいいアルゴリズム教えてください。ってかワルキューレのシミュレータ作ってください。


長すぎるんだよ!3行でまとめろよ!

Lord of Walkureの討伐戦団最適化したい
タブー探索使ってみた
でも遅いから違う方法これから探す(^p^)

2015年11月21日土曜日

[C++] クラス使いこなせるようになりたい@その1

C++を使うようになってから初めて聞いた言葉 クラス。

便利だよ、すごいんだよ、と聞かされてきた オブジェクト指向。

調べてみるも

さ っ ぱ り わ か ん ね ぇ (#^p^)


というわけで今回からクラスの勉強を始めようと思います。
将来C++のことをきれいさっぱり忘れ去ってしまった時のためになるべくわかりやすいようにしたいですね。
では早速

~とりあえずクラス宣言~

まずはクラスを宣言しなければ始まりません。
class ClassClass
{
};
view raw gistfile1.txt hosted with ❤ by GitHub

これで宣言は終わりです。

~中身を充実させる~

クラス宣言が終わりました。
これは「こんなクラスがあるよ!」と主張しているのです!
では次に「こんなことができるんだよ!」と主張しましょう。

と、その前に
クラスにはコンストラクタデストラクタ絶 対 に 必 要 で す !
コンストラクタとはクラスが使われるとき一番最初に実行される関数です。
デストラクタとはクラスが使われなくなる時に実行される関数です。
なんだそれ、と思う方もいるでしょう。というか、私がおもっています。
ですがそういうお約束なのです。
ここでは「おまじない」ということで納得しましょう。
コンストラクタはクラスと同じ名前、デストラクタはクラス名の前に~をつけます。
どちらも戻り値はありません。
class ClassClass
{
public:
ClassClass(){}
~ClassClass(){}
};
view raw gistfile1.txt hosted with ❤ by GitHub

public:ってなんだ?
「おまじない」です。(^p^)
( ){ }ってなんだ?
これはですね、( )が引数です。今回はありません。{ }が関数の中身です。これも今回はありません。
つまりなにもしません。(^p^)

~今度こそ中身を充実させる~

コンストラクタもデストラクタも作りました。
今度こそクラスの中身を充実させていきましょう。
とりあえずhello worldでも表示させてみますか。
クラスの中に関数を作っちゃいましょう。
ユーザ関数と作り方は同じです。
戻り値 名前 引数 の順番ですね。
class ClassClass
{
public:
ClassClass(){}
~ClassClass(){}
void Hello()
{
cout << "hello world" << endl;
}
};
view raw gistfile1.txt hosted with ❤ by GitHub
printfじゃなくてcoutを使ってみました。
個人的にはcoutのほうが好きです。いろいろ便利ですし。

さて、あとはこれを実行するだけです。
とりあえずソースを貼りましょう。
int _tmain(int argc, _TCHAR* argv[])
{
ClassClass obj;
obj.Hello();
_getch();
return 0;
}
view raw gistfile1.txt hosted with ❤ by GitHub
まずobjという名前でクラスを宣言します。
objの中のHelloにアクセスするためにobj.Hello()と書きます。
_getch()は一時停止だと思ってください。
これでhello worldと表示されましたね。

~何回も表示させる~

C言語入門だと最初のほうでループを勉強するので、こっちも対抗してループを勉強しましょう。
内容は
hello worldを任意の回数表示させる
for文でくくっちゃえば一発ですね。
せっかくクラスの勉強してるんだからクラスの中でループさせましょう。
ところでさっき作ったHelloという関数、クラスの中でも使えます。
ということは新しく関数を作って、その中でループを回してHelloを実行する、ということができそうです。
じゃあ関数名は何にしましょうか・・・。
じつはC++にはオーバーライドという機能があります。
簡単に言っちゃえば同じ名前で違う機能をもった関数を定義することができる機能です。
今回みたいに似たような内容の関数を作るときに役立ちますね。
というわけで、新しい関数の名前もHelloにけって~い!
ただ、オーバーライドにもルールがあります。
同じ名前の関数がいっぱいあって、しかもそれぞれで内容が違うとなるとややこしいですよね?
だから、オーバーライドするときは引数を変えて、区別する必要があります。
最初に作ったHelloは引数なしなので、今回作るHelloにはint型の引数を与えましょう。
引数で与えられた回数だけhello worldを表示する、というわけですね。
というわけで、どん。
void Hello(int num)
{
for (int i = 0; i < num; i++)
{
Hello();
}
}
view raw gistfile1.txt hosted with ❤ by GitHub
この一文をクラスの中に追加するだけです。
これであとはmain文で呼んでいるHelloに好きな数字を渡せば、その回数分だけ表示してくれるってわけです。

~好きな文字を表示させる~

クラスの世界にもなじんできたことですし、いつまでもhello worldと言っている場合ではありません。
なにかかっこいいことを言わせてみましょう。I'll be back とかどうです?
というわけで、I'll be back と表示するようにしましょう。
Helloの中でI'll be back と表示するように書き換えればいいですね。
いやいや、せっかくクラスの(ry
というわけで、何を表示させるかを取得する関数を作りましょう。
ところで、今まではクラスの中では関数しか宣言していませんでしたが、実は変数も宣言できます。
しかも、その変数(メンバ変数と呼ぶ)はクラスの中の関数(メンバ関数と呼ぶ)で使うことができます。
じゃあ、何を表示させるか取得する関数、取得したものを表示する関数を作ってみましょう。
というわけで、
string word;
void SetWord(string str)
{
this->word = str;
}
void Say()
{
cout << word << endl;
}
view raw gistfile1.txt hosted with ❤ by GitHub

SetWordの中で使われているthis->ですが、これは「こいつはこのクラスのメンバですよ」という意味です。無くてもいいけど、あると見やすいかもしれないです。
Sayの中は特に説明しなくても大丈夫ですね。余裕のある方は任意の回数表示できるように拡張してみてください。

~最初に取得~

これで好きな文字を表示できるようになったわけですが、毎回毎回SetWordを呼ぶのはめんどくさいですね。
最初に初期化みたいなことができればいいのに・・・。
・・・ハッ!?
最初に・・・。最初に・・・?
最初にといえばコンストラクタとかいうものがありましたね。
これを使って初期化してみましょう。
コンストラクタの引数をstring型にして・・・。というのはアウトです。
これも「おまじない」なのですが、引数なしのコンストラクタは絶対に必要です。
新しくstring型の引数を持つコンストラクタを作りましょう。コンストラクタのオーバーロードですね。
コンストラクタの中ではSetWordを呼び出せばよさそうです。
ついでなんで引数なしのコンストラクタではwordに空白を与えましょう。
というわけで、コチラ
class ClassClass
{
private:
string word;
public:
ClassClass()
{
SetWord("");
}
ClassClass(string str)
{
SetWord(str);
}
~ClassClass(){}
void Hello()
{
cout << "hello world" << endl;
}
void Hello(int num)
{
for (int i = 0; i < num; i++)
{
Hello();
}
}
void SetWord(string str)
{
this->word = str;
}
void Say()
{
cout << word << endl;
}
};
view raw gistfile1.txt hosted with ❤ by GitHub

おいおい、private:ってなんだよ!
はい、勝手に増やしてすみません^^;
privateっていうのはクラスの中でしか使えない、という目印です。これでwordを変更できるのはこのクラスの中だけになりました。

~加減乗除の鐘の声~

さあさあ、どんどん便利になってまいりました。
この調子でどんどん便利にしていきましょう。
次はですねー、表示する文字の付け足しでもやってみましょうか。
「醤油とってー。あ、あとマヨネーズも。」
日常ではよくある一言ですね。言った言葉に付け加える。これを実現しましょう。
Say呼んでSetWord呼んでSay呼んで、ハイ終わり。
いやいや、せっかく(ry
足し算をできるようにしましょう!
あらかじめ言わせたい言葉で初期化したクラスを二つ作り、二つの言葉を足して表示できるようにします。
ちょっと自分でも何言ってるのかわからなくなってきたので先にソースを載せましょう。
string GetWord()
{
return this->word;
}
string Add(ClassClass obj)
{
return this->word + obj.GetWord();
}
view raw gistfile1.txt hosted with ❤ by GitHub

これをクラスの中に加えたあとはmain文で
int _tmain(int argc, _TCHAR* argv[])
{
ClassClass obj1("oh"),obj2("yeah");
obj1.SetWord(obj1.Add(obj2));
obj1.Say();
_getch();
return 0;
}
view raw gistfile1.txt hosted with ❤ by GitHub

これでいいですね。
だがしかし・・・見づらい。
これは気持ち悪い。何とかしましょう。
そもそも足し算したいんだから+が使えると嬉しい。
じゃあ使えばいいんですよ。
クラスにはオペレータという機能があります。
クラスにとっての+とか-の意味を変える機能です。なんと強そうな。
早速使ってみましょう。
static const char space=' ';
string Add(ClassClass obj)
{
return this->word + space + obj.GetWord();
}
string operator+(ClassClass obj)
{
return Add(obj);
}
ClassClass& operator=(ClassClass obj)
{
SetWord(obj.GetWord());
return *this;
}
view raw gistfile1.txt hosted with ❤ by GitHub
static const ってなんですか?(#^p^)
これはクラス間で共有できる定数という意味です。今回は二語を足すとき、間に空白を入れるために使ってみました。
operator+のほうはAddの結果を返してるだけですね。
operator=のほうは戻り値とかが複雑で・・・。まあ、慣れてくれば意味が分かるようになると思うのでここでは「おまじない」ということにしておきます。
あとはmain文のほうですね。
int _tmain(int argc, _TCHAR* argv[])
{
ClassClass obj1("oh"),obj2("yeah");
obj1 = obj1 + obj2;
obj1.Say();
_getch();
return 0;
}
view raw gistfile1.txt hosted with ❤ by GitHub
どうですか?だいぶすっきりしたでしょ?

~おわり~

今回はこれで終了とします。どうですか?クラスの便利さをわかってもらえましたか?
クラスにはほかにもいろいろな機能があるのですが私自身使いこなせていないので紹介は省きました^^;
もうすこしスキルアップしたらクラスの隠された機能についても触れていこうと思います。
じゃあ、今回はこれで終わり!

今回作ったクラスの中身
#include<iostream>
#include<string>
using namespace std;
class ClassClass
{
private:
string word;
static const char space = ' ';
public:
ClassClass()
{
SetWord("");
}
ClassClass(string str)
{
SetWord(str);
}
~ClassClass(){}
void Hello()
{
cout << "hello world" << endl;
}
void Hello(int num)
{
for (int i = 0; i < num; i++)
{
Hello();
}
}
void SetWord(string str)
{
this->word = str;
}
void Say()
{
cout << word << endl;
}
void Say(int num)
{
for (int i = 0; i < num; i++)
Say();
}
string GetWord()
{
return this->word;
}
string Add(ClassClass obj)
{
return this->word + space + obj.GetWord();
}
string operator+(ClassClass obj)
{
return Add(obj);
}
ClassClass& operator=(ClassClass obj)
{
SetWord(obj.GetWord());
return *this;
}
};
view raw gistfile1.txt hosted with ❤ by GitHub


2014年12月7日日曜日

布団洗いたい

こんにちは、最近腰が痛いです。

先月あたりにちょいと無茶しちまってな・・・。

60kg×3人ぐらいをいっぺんに背負うという無謀なチャレンジを試みました。

おかげで腰がぼろぼろ・・・。

ようやく治ってきたと思った矢先に、更なる事件が・・・!



はい、ここからが本題です。

みなさん、敷布団って洗ったことありますか?

多くの人が「No」と答えるはずです。

洗いやすい大きさじゃないしね。

でもねぇ、奥さん・・・。

アレ、実は、めちゃくちゃ・・・

 汚 れ て る ん で す !!



そもそもことの発端はですね、私の脂ギッシュな体質によるものでした。

寝るときは上半身裸で寝るのが私のジャスティスなのですがね、

そうすると、シーツがすぐ汚れちゃうんですよ。

原因がわかってるんだからパジャマ着ろ、って言うそこのあなた!

習慣とは恐ろしいものです。

気づいたら上半身半裸になっているのです・・・。

まあ、たしかに不衛生ではあるので、いつかはこの癖も直さないとダメですね。



それで、ですよ。

汚れに汚れたシーツを週1のペースで洗ってたんですが、

先日、私は恐ろしいことに気づいてしまいました・・・。

敷 布 団 も 汚 れ て る

これは由々しき事態ですよ。←由々しきって使ってみたかった。

思い立ったが吉日で、布団洗濯を決行。

大きい洗濯機があれば、それにぶち込むだけですんだのですが、

あいにく、そんな大きな洗濯機は一般の家庭には滅多にないでしょう。

じゃあ、残る選択肢は

1.業者に頼む
2.手洗い

私は[2.手洗い]を選択しました。

業者に頼むと3000~5000円かかるっぽいし。



ここから、簡単に布団の洗い方を説明します。

1.浴槽にお湯をためる。
残り湯でもぜんぜんokみたいです。
私の場合は冷たくなってても大丈夫でした。

2.布団を4つ折ぐらいにして、浴槽の中にぶち込む。
丁寧に折る必要はないです。
これからグッチャグチャにします^p^

3.液体洗剤を入れます。
私は何も考えずに水30L分の洗剤を投入しました。

4.踏みます。
踏んでください。
あまり強く踏みすぎると破れる可能性があるので注意!

5.踏み続けます。
踏み続けてください。
最初は特に変化がないですが、5分も踏むと水がにごり始めます。
10分踏むとにごり過ぎて自分の足が見えなくなります。
20分も踏めば雨が降ったあとの川みたいな茶色になります。
止め時は自分で判断してください。

!~ここまでは楽しい~!
!~ここからはキツい~!

6.水を抜きます。
お風呂の栓を抜いて水を抜いてください。
やってみればわかりますが、
栓を抜いただけじゃ水は抜けません。
布団をゆすったりして、水を抜いてください。
あと、布団を持ち上げたりする場合は水気を十分とってから!
これ大事!

7.シャワーでお湯を当てます。
ここからはすすぎです。
シャワーでお湯を当てながら踏んでください。
お湯がある程度溜まったら
水の汚れ具合洗剤が残っているか
をチェックしてください。
洗剤が抜けきるまですすぎを繰り返します。

8.脱水
踏んでください。
すのこがある場合は浴槽のそこに敷いてから踏むと効率がいいです。
ある程度踏んだら、布団を浴槽のふちなどにかけて、
布団の自重で水を切るというのもいいかもしれません。

9.乾燥
ある程度脱水できたら乾かしましょう。
天日干しが一番いいですが、天候、季節の関係でできない、という場合は、
布団乾燥機を使えばいいと思います。



以上で、布団洗濯は終わりです。

大事なことなのでもう一度言いますが、

水を吸った布団は持ち上げない

ようにしましょう。

私はどちらかというと力持ちの部類ですが、

水の重さハンパねぇっす。

水を吸った布団と格闘すること10数分。

全身がプルプルしました((^p^))

おかげで腰が痛い痛い・・・。



週1でこの作業をすれば、大分いい体つきになるんじゃないでしょうか。

そんなレベルでキツいです。

握力とかが大分いい感じにつくと思います。

筋肉ムキムキになって、布団もきれいになる・・・。

一石二鳥!

さあ皆さんも布団洗濯始めましょー!









追伸.わたしはもうやりたくないです^p^



2014年7月12日土曜日

コイルガン作りたい@そのさん


さて無事に高電圧を作ることもできたわけですし、次はコンデンサに充電しましょうか。
コンデンサを充電することはそんなに難しいことではありません。
コンデンサに電源をつなげれば充電できます。

しかし、いくつか注意事項があります。

そのいち、「耐圧
耐圧とは読んで字のごとく、どれぐらいの電圧に耐えられるか、ということです。
耐圧10[V]なら10[V]まで、耐圧100[V]なら100[V]まで電圧をかけることができます。
大体はコンデンサに記入してあります。

定格電圧
↓数字\英字→ABCDEFGHJK
011.251.622.53.15456.38
11012.516202531.540506380
2100125160200250315400500630800
31,0001,2501,6002,0002,5003,1504,0005,0006,3008,000
~Wikipediaより
2Cと書いてあったら160[V]というわけです。
何も表記がない場合はググりましょう^p^


もしも耐圧以上の電圧をかけたら・・・

爆 発 し ま す ^p^

決して冗談ではなく、本当に爆発するので耐圧には十分注意しましょう。


そのに、「極性
極というのは+-のことです。コンデンサによっては+-があるので注意しましょう。
もしも極性を間違えたら・・・

爆 発 し ま す ^p^

決して冗談ではなく、本当に爆発するので耐圧には十分注意しましょう。




そのさん、「感電
読んで字のごとく、電気を感じる・・・

なんて生易しいものじゃありません

痛いです。痛みを感じます。

ここにコンデンサが二つあったとします。
片方は充電されておらず、もう片方はフル充電されています。
充電されているほうのコンデンサはどっちでしょう?

わかりません^p^

充電されているかされていないかがわからないのがコンデンサの怖いところです。
充電されていると知らずにコンデンサに触れると感電します。
コンデンサに触るときはコンデンサの足をショートしてから触りましょう。
コンデンサの両足をペンチではさめばショートできます。

ここでコンデンサの持つエネルギーについて説明します。
コンデンサに蓄えられるエネルギーは

E=0.5*CV^2

という式から求めることができます。

Cはコンデンサの「静電容量」で、大体はコンデンサに表記されています。
 123 とかかれていたら12*10^3[pF]ということです。
さらにさらに説明すると、

p(ピコ)・・・10^-12
F(ファラッド)・・・静電容量の単位

Vはコンデンサにかかっている電圧です。
耐圧ではなく実際にかかっている電圧です。

さて、インスタントカメラについているコンデンサは100[μF]、300[V](大体)なので、
蓄えられるエネルギーは4.5[J]ってとこですかね。

4.5[J]とかしょぼ!って思ったそこのあなた。
ぜんぜんしょぼくないです。ショートしてみればわかります。
火花が散ります。結構怖いです。

コイルガンの威力をあげるにはコンデンサをたくさんつなぐ必要があるのですが、
つなげばつなぐほど、コンデンサの持つエネルギーは大きくなります。

ふひひ・・・実は拙者、カメラについていたコンデンサを8つつなげて充電したでござるよ・・・
200[V]ぐらいで充電していたので大体16[J]のエネルギー。
ショート。

バンッ!

手のひらサイズの火花と、耳鳴りに襲われました^p^
あまりのショックに呆然としましたね。

もしも感電したら

最悪死にます

気をつけましょー^^

次回はコイルのつなげ方ですかね。
特筆するようなことはなかっと思いますけど。


2014年7月8日火曜日

コイルガン作りたい@そのに

うあー
うおあー
つーかーれーたー

最近暖かくなってきたから部活開始^p^
泳ぐぜー、超泳ぐぜー

水泳の話はおいといて・・・^p^

コイルガンを作りたいんですよ!
今回は具体的にどう作るか、ですね。

前回で述べたとおり、コイルに電気を流して弾を飛ばすわけですが、
流しっぱなしだと弾は飛びません。
ちょうどいいタイミングで電気を止める必要があります。

しかしこの「ちょうどいいタイミング」が難しいです。
そこで多くの先人が「コンデンサ」というものを利用しました。

コンデンサというのは簡単に言えば充電池です。
ほんのちょっとしか充電できないですけどね。

このコンデンサ君を充電してあげて、コイルにつなぐわけです。
するとコンデンサにたまった電気がコイルに流れて、弾が引き寄せられます。
コンデンサの電気が空っぽになったら、コイルに流れる電気も止まり弾が飛んでいく・・・
といった仕組みです。

ではこれをご覧ください。
コイルガンの回路図



これが「回路図」というものです。要は設計図ですね。

左にある長い線と短い線が平行にならんだものが「電源」です。長いほうが+極です。
中央下にある先が二本平行に並んだものが「コンデンサ」です。+-があるものもあります。
右にあるグルグルしてるのが「コイル」です。

簡単そうですね?すぐ作れそうですね?
これが意外と難しいんです。

電池にコンデンサとコイルをつないで実験してみてください。(おそらくコンデンサもコイルも近くにはないでしょうけどね^^;)
弾は飛びません。

流れる電気の量が少ないからです。

中学校あたりで習う「オームの法則」というものを知っていますか?
   
   V=RI

という式で、Vは「電圧」、Rは「抵抗」、Iは「電流」です。
それぞれ、「水道」、「ホースの細さ」、「ホースを流れる水の量」でたとえられることが多いです。

水道を全開に(電圧を高く)して、ホースを太く(抵抗を低く)すると、ホースを流れる水の量(電流)は増えるのです。

コイルからでる磁力は、コイルに流れる電流が大きいほど強くなります。
電流を大きくするには抵抗を低く、電圧を高くしてやればいいのですが、
抵抗の低さには限度があります。(R>0:抵抗は0よりも大きい)
しかし、電圧はいくらでも高くできます。

つまり高い電圧をコイルにかければいいのです。
高電圧をコイルにかけるには、コンデンサに高電圧で充電する必要があります。

以上を踏まえて、コイルガンを作るために必要なこと第一弾!

高電圧を作る


ではどのようにして高電圧を作るのか。
昇圧回路」というものを作ればいいのです。

昇圧回路とは読んで字のごとく、電圧を高くする回路です^p^

コッククロフト・ウォルトン回路、昇圧チョッパ回路、ZVSなどなど難しそうなものがそろっております。

電気回路が得意な方は是非、上記の回路を作ってみてください。効率がいいです。
苦手な人は使い捨てカメラの昇圧回路を流用しましょう。

カメラの昇圧回路の使い方はほかのサイトにたくさん書いてあるので割愛。

はい、これで高電圧はクリアーですね^p^


次回はコイルガンを作るために必要なこと第二弾!です。