仮想計算機構

IT業界と無縁な派遣社員のブログ

tracerouteのソースを入手する

tracerouteの仕組みを調べていたら少し興味がわいてきました。下記サイトからオリジナルのプログラムが入手できるとのことです。

https://ee.lbl.gov/

アクセスすると確かにtracerouteがあります。

ところが、筆者が使っているブラウザ(Google Chrome)だとリンクをクリックしてもファイルのダウンロードが開始されません。ftpのサポートが廃止されているようです。

ブラウザを使ってダウンロードすることはあきらめ、WinSCPを利用して接続してみます。WinSCPのインストールについては各自でお調べください。インストールできたら下記内容を保存し、ログインします。


接続できたら該当するファイルを選び、ダウンロードします。

めでたしめでたし。

参考

マスタリングTCP/IP入門編 第5版(オーム社)P197
https://www.st.ryukoku.ac.jp/services/anonymous-ftp.html

Windows で tinyrenderer を動かしてみる

はじめに


ライブラリに依存しないTiny(小さい)Rendererです。tinyrendererの存在意義としては作者の下記の言葉がすべてかと思います。

In this series of articles, I want to show the way OpenGL works by writing its clone (a much simplified one). Surprisingly enough, I often meet people who cannot overcome the initial hurdle of learning OpenGL / DirectX. Thus, I have prepared a short series of lectures, after which my students show quite good renderers.

OpenGLとかDirectXってハードル高いから、クローンを自分で書いて理解しようというコンセプトのようです。面白そうなので自分の環境で動くのかどうか試してみます。

環境

ビルド

READMEに書いてあるとおりに実行していきます。

git clone https://github.com/ssloy/tinyrenderer.git
cd tinyrenderer
mkdir build
cd build

次にcmakeを使うのですが、筆者の環境ですと下記のとおりVisual Studioに対してビルドされてしまいます。

cmake ..

-- Building for: Visual Studio 16 2019
-- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.19044.
-- The C compiler identification is MSVC 19.28.29336.0
-- The CXX compiler identification is MSVC 19.28.29336.0
(以下省略)

この場合、buildディレクトリ配下には下記のファイルが作成されます。

CMakeFiles
ALL_BUILD.vcxproj
ALL_BUILD.vcxproj.filters
CMakeCache.txt
cmake_install.cmake
tinyrenderer.sln
tinyrenderer.vcxproj
tinyrenderer.vcxproj.filters
ZERO_CHECK.vcxproj
ZERO_CHECK.vcxproj.filters

やりたいこととは違う結果になっているのでbuild配下のファイルはいったんすべて削除します。筆者の環境ではMinGWをインストール済みなので、下記の文言を加えて実行します。

cmake -G "MinGW Makefiles" ..

-- The C compiler identification is GNU 9.2.0
-- The CXX compiler identification is GNU 9.2.0
(以下省略)

最後の仕上げです。

cmake --build . -j

[ 16%] Building CXX object CMakeFiles/tinyrenderer.dir/geometry.cpp.obj
[ 33%] Building CXX object CMakeFiles/tinyrenderer.dir/main.cpp.obj
[ 50%] Building CXX object CMakeFiles/tinyrenderer.dir/model.cpp.obj[ 66%]
Building CXX object CMakeFiles/tinyrenderer.dir/our_gl.cpp.obj
[ 83%] Building CXX object CMakeFiles/tinyrenderer.dir/tgaimage.cpp.obj
[100%] Linking CXX executable tinyrenderer.exe
[100%] Built target tinyrenderer

これで準備は整いました。最後はサンプルを動かしてみます。

./tinyrenderer ../obj/diablo3_pose/diablo3_pose.obj ../obj/floor.obj

# v# 2519 f# 5022 vt# 3263 vn# 2519
texture file ../obj/diablo3_pose/diablo3_pose_diffuse.tga loading 1024x1024/24
ok
texture file ../obj/diablo3_pose/diablo3_pose_nm_tangent.tga loading 1024x1024/24
ok
texture file ../obj/diablo3_pose/diablo3_pose_spec.tga loading 1024x1024/24
ok
# v# 4 f# 2 vt# 4 vn# 1
texture file ../obj/floor_diffuse.tga loading 600x600/32
ok
texture file ../obj/floor_nm_tangent.tga loading 512x512/24
ok
texture file ../obj/floor_spec.tga loading can't open file ../obj/floor_spec.tga
failed

最後だけfailed(失敗)と表示されています。プログラムは動いているようですが、実行結果の画像がTGA形式という珍しいデータなので開くのに失敗しているようです。筆者の環境だと LibreOffice というソフトウェアでかろうじてTGAファイルを開くことができました。githubwiki には Lesson がたくさんあるようなので、勉強にはちょうどよさそうです。

【Ubuntu】【C++】Boostをダウンロードして使ってみた

ダウンロード

現時点(2022/08/27)での最新版である1.80.0をダウンロードします。
https://www.boost.org/users/history/version_1_80_0.html
ダウンロードが終わったらディレクトリを指定して解凍します。

tar --bzip2 -xf /path/to/boost_1_80_0.tar.bz2

サンプル

解凍が終わったらビルドなどは置いておいて、とりあえずサンプルプログラムを動かしていきます。

サンプル1:lambda

プログラム

受け取った数字を三倍して表示するプログラムです。

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

int main(){
  using namespace boost::lambda;
  typedef std::istream_iterator<int> in;

  std::for_each(in(std::cin),
                in(),
                std::cout << (_1 * 3) <<" ");
}
実行結果
$ c++ -I path/to/boost_1_80_0 example.cpp -o example
$ echo 1 2 3 | ./example
3 6 9

サンプル2:regex

正規表現を用いてメールの件名を抽出するプログラムです。

プログラム
#include <boost/regex.hpp>
#include <iostream>
#include <string>

int main(){
  std::string line;
  boost::regex pat("^Subject: (Re: |Aw: )*(.*)");

  while(std::cin){
    std::getline(std::cin,line);
    boost::smatch matches;
    if(boost::regex_match(line, matches, pat))
      std::cout << matches[2] << std::endl;
  }
}
使用データ:email.txt

以下のようなテキトーなデータを準備しました。

Subject: Hello,Mike!
I am riverta.
This is Subject: .
Subject: Goodbye Mike!
実行結果
$ c++ -I path/to/boost_1_80_0 example.cpp -o example
$ cat email.txt | ./example
Hello,Mike!
Goodbye Mike!

サンプル3:all_of

predicate を各要素に適用し、すべての要素について成り立つかどうか判定するプログラムです。元のサンプルを多少編集しております。

プログラム
#include <iostream>
#include <vector>
#include <boost/algorithm/cxx11/all_of.hpp>

bool isOdd(int i){ return i%2==1; }
bool lessThan10(int i){ return i<10; }
template<class T>
void print(const T& value){std::cout << value << std::endl;}

int main(){
  using namespace boost::algorithm;
  std::vector<int> c = {0,1,2,3,14,15};
  print(all_of(c, isOdd));
  print(all_of(c.begin(), c.end(), lessThan10));
}
実行結果

どちらも False なので数字の 0 が表示されます。

$ c++ -I path/to/boost_1_80_0 example.cpp -o example
$./example
0
0

openFrameworks による Langton's loop


openFrameworks と C++ の勉強として、以前作成した Langton's loop の C++ 版を作成しました。openFrameworks 0.11.2 にて動作を確認しています。

プログラム

main.cpp

#include "ofMain.h"
#include "ofApp.h"

//========================================================================
int main( ){
	ofSetupOpenGL(1024,768,OF_WINDOW);			// <-------- setup the GL context
	ofRunApp(new ofApp());

}

ofApp.cpp

#include "ofApp.h"
#include <vector>
#include <map>
#include <string>
#include <types/ofColor.h>

std::vector<std::vector<int>> ofApp::loop{
		{0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0},
		{2, 1, 7, 0, 1, 4, 0, 1, 4, 2, 0, 0, 0, 0, 0},
		{2, 0, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0},
		{2, 7, 2, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0},
		{2, 1, 2, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0},
		{2, 0, 2, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0},
		{2, 7, 2, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0},
		{2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 0},
		{2, 0, 7, 1, 0, 7, 1, 0, 7, 1, 1, 1, 1, 1, 2},
		{0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0} };

// black, blue, red, green, yellow, magenta, white, cyan
std::vector<int> ofApp::colors{0x000000,0x0000FF,0xFF0000,0x008000,0xFFFF00,0xFF00FF,0xFFFFFF,0x00FFFF};

void ofApp::initField() {
	for (int i = 0; i < n_rows; i++) {
		std::vector<int> v;
		for (int j = 0; j < n_cols; j++) {
			v.push_back(0);
		}
		field.push_back(v);
		next_field.push_back(v);
	}

	int offset_x = (int)((n_rows - loop.size()) / 2);
	int offset_y = (int)((n_cols - loop[0].size()) / 2);

	for (int y = 0; y < loop.size(); y++) {
		for (int x = 0; x < loop[0].size(); x++) {
			field[y + offset_y][x + offset_x - 10] = loop[y][x];
		}
	}
}

void ofApp::loadRule() {
	ofFile file;
	file.open(ofToDataPath("rule.txt"), ofFile::ReadWrite, false);
	ofBuffer buff = file.readToBuffer();

	for (auto line : buff.getLines()) {
		std::string c = line.substr(0, 1); // center
		std::string n = line.substr(1, 1); // north
		std::string e = line.substr(2, 1); // east
		std::string s = line.substr(3, 1); // south
		std::string w = line.substr(4, 1); // west
		std::string next_c = line.substr(5, 1);
		rules[c + n + e + s + w] = next_c;
		rules[c + w + n + e + s] = next_c;
		rules[c + s + w + n + e] = next_c;
		rules[c + e + s + w + n] = next_c;
	}
}

//--------------------------------------------------------------
void ofApp::setup(){
	stop = false;
	cell_size = 10;
	n_rows = (int)(ofGetWindowHeight() / cell_size);
	n_cols = (int)(ofGetWindowWidth() / cell_size);
	initField();
	loadRule();
	ofSetBackgroundColor(ofColor::black);
}

//--------------------------------------------------------------
void ofApp::update(){
	if (stop) {
		return;
	}
	for (int y = 1; y < n_rows - 1; y++) {
		for (int x = 1; x < n_cols - 1; x++) {
			std::string c = std::to_string(field[y][x]);
			std::string n = std::to_string(field[y - 1][x]);
			std::string e = std::to_string(field[y][x + 1]);
			std::string s = std::to_string(field[y + 1][x]);
			std::string w = std::to_string(field[y][x - 1]);
			decltype(rules)::iterator itr = rules.find(c + n + e + s + w);
			if (itr == rules.end()) {
				next_field[y][x] = field[y][x];
			}
			else {
				next_field[y][x] = stoi(rules[c + n + e + s + w]);
			}
		}
	}
	// copy
	for (int y = 1; y < n_rows; y++) {
		for (int x = 1; x < n_cols; x++) {
			field[y][x] = next_field[y][x];
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
	ofSetColor(ofColor::white);
	ofDrawBitmapString("press s to stop / start", 30, 60);
	
	for (int y = 0; y < n_rows; y++) {
		for (int x = 0; x < n_cols; x++) {
			int state = field[y][x];
			if (state!=0) {
				ofSetColor(ofColor::fromHex(colors[state]));
				ofDrawRectangle(x * cell_size, y * cell_size, cell_size, cell_size);
			}
		}
	}
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
	if (key=='s') {
		stop = !stop;
	}
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){ 

}

ofApp.h

#pragma once
#include "ofMain.h"

class ofApp : public ofBaseApp{

	public:
		void setup();
		void update();
		void draw();

		void keyPressed(int key);
		void keyReleased(int key);
		void mouseMoved(int x, int y );
		void mouseDragged(int x, int y, int button);
		void mousePressed(int x, int y, int button);
		void mouseReleased(int x, int y, int button);
		void mouseEntered(int x, int y);
		void mouseExited(int x, int y);
		void windowResized(int w, int h);
		void dragEvent(ofDragInfo dragInfo);
		void gotMessage(ofMessage msg);
		
		int cell_size;
		int n_rows;
		int n_cols;
		bool stop;
		static std::vector<int> colors;
		std::vector<std::vector<int>> next_field;
		std::vector<std::vector<int>> field;
		std::map<std::string, std::string> rules;
		static std::vector<std::vector<int>> loop;
		void initField();
		void loadRule();
};

bin/data/rule.txt

bin/data 配下にセルの変換規則に関するファイルを置いておきます。

000000
000012
000020
000030
000050
000063
000071
000112
000122
000132
000212
000220
000230
000262
000272
000320
000525
000622
000722
001022
001120
002020
002030
002050
002125
002220
002322
005222
012321
012421
012525
012621
012721
012751
014221
014321
014421
014721
016251
017221
017255
017521
017621
017721
025271
100011
100061
100077
100111
100121
100211
100244
100277
100511
101011
101111
101244
101277
102026
102121
102211
102244
102263
102277
102327
102424
102626
102644
102677
102710
102727
105427
111121
111221
111244
111251
111261
111277
111522
112121
112221
112244
112251
112277
112321
112424
112621
112727
113221
122244
122277
122434
122547
123244
123277
124255
124267
125275
200012
200022
200042
200071
200122
200152
200212
200222
200232
200242
200250
200262
200272
200326
200423
200517
200522
200575
200722
201022
201122
201222
201422
201722
202022
202032
202052
202073
202122
202152
202212
202222
202272
202321
202422
202452
202520
202552
202622
202722
203122
203216
203226
203422
204222
205122
205212
205222
205521
205725
206222
206722
207122
207222
207422
207722
211222
211261
212222
212242
212262
212272
214222
215222
216222
217222
222272
222442
222462
222762
222772
300013
300022
300041
300076
300123
300421
300622
301021
301220
302511
401120
401220
401250
402120
402221
402326
402520
403221
500022
500215
500225
500232
500272
500520
502022
502122
502152
502220
502244
502722
512122
512220
512422
512722
600011
600021
602120
612125
612131
612225
700077
701120
701220
701250
702120
702221
702251
702321
702525
702720

実行結果

openFrameworks で画像を読み込む

1. はじめに


インストールから1年弱経ちました。インストール満足野郎にならないよう気をつけます。今回は openFrameworks で画像を読み込んだり、画像の位置を動かしたります。

環境

OS : Windows 10
openFrameworks : 0.11.2
IDE : Visual Studio 2019

projectGenerator

まずは projectGenerator を起動し、プロジェクト名とパスを決めたら Generate ボタンを押します。これで ofMain.cpp / ofApp.cpp / ofApp.h という3つのプログラムが作成されます。

使用する画像

画像処理で著名なLennaの画像を使います。プロジェクト配下には bin/data というフォルダがありますので、ここに画像を置いておきます。

2. プログラム

今回のプログラムがやることは下記のとおりです。

  • 普通に画像を読み込んで描画する
  • 画像位置を counter 変数に基づいて動かす
  • キーボードで画像表示を切り替える
    • キー「s」を押下すると上下反転
    • キー「d」を押下すると左右反転

ofMain.cpp

#include "ofMain.h"
#include "ofApp.h"

int main( ){
	ofSetupOpenGL(640,480,OF_WINDOW);
	ofRunApp(new ofApp());
}

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
	ofSetWindowTitle("Load image file");
	ofBackground(ofColor::white);
	myImg.load("Lenna.jpg");
	iw = myImg.getWidth();
	ih = myImg.getHeight();
	counter = 0;
}

//--------------------------------------------------------------
void ofApp::update(){
	counter = (counter % ofGetHeight()) + 1;
}

//--------------------------------------------------------------
void ofApp::draw(){
	ofSetColor(ofColor::white);

	// image 1
	myImg.draw(0, 0);

	// image 2
	myImg.draw(iw, counter);
	int sh = ofGetHeight();
	if (ih+counter > sh) {
		myImg.drawSubsection(iw,0,iw,ih+counter-sh,
			0,sh-counter,iw,ih+counter-sh);
	}

	ofSetColor(ofColor::black);
	ofDrawBitmapString("press s to reflects the pixels across the vertial axis",20,ih+50);
	ofDrawBitmapString("press d to reflacts the pixels across the horizontal axis",20,ih+70);
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
	if (key == 's') {
		myImg.mirror(true,false);
	}else if(key == 'd') {
		myImg.mirror(false,true);
	}

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){ 

}

myImg.load("Lenna.jpg")で目的の画像をロードできます。bin/data に置いているのでパスを指定する必要はありません。draw関数の一行目は

	ofSetColor(ofColor::white);

としました。こうしないと文字色に引っ張られて画像自体が真っ黒になってしまいます。いい方法あったら教えてください。

ofApp.h

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

	public:
		void setup();
		void update();
		void draw();

		void keyPressed(int key);
		void keyReleased(int key);
		void mouseMoved(int x, int y );
		void mouseDragged(int x, int y, int button);
		void mousePressed(int x, int y, int button);
		void mouseReleased(int x, int y, int button);
		void mouseEntered(int x, int y);
		void mouseExited(int x, int y);
		void windowResized(int w, int h);
		void dragEvent(ofDragInfo dragInfo);
		void gotMessage(ofMessage msg);
		
		int counter;
		int iw, ih;
		ofImage myImg;
};

3. 実行結果

プログラムを実行すると下記のようなウィンドウが立ち上がります。

こーゆーインタラクティブなプログラムがさらっと作れるのが openFrameworks の魅力ですね。今回は以上です。

【Python】【Windows】mecab をインストールした

はじめに

python から mecab を使いたかったので pip でインストールします。

環境

OS : Windows 10
Python version 3.7.6

インストール

$ pip install mecab-python3
(省略)
Installing collected packages: mecab-python3
Successfully installed mecab-python3-1.0.5

unidic辞書もインストールしておきます。

$ pip install unidic
(省略)
Successfully built unidic
Installing collected packages: wasabi, plac, unidic
Successfully installed plac-1.3.5 unidic-1.1.0 wasabi-0.10.1

同時にインストールされた plac はオプション解析モジュール、wasabi は coloring や formatting を行うユーティリティのようです。

実行結果

python を対話モードで起動します。

>>> import MeCab
>>> import unidic
>>> tagger = MeCab.Tagger()
Traceback (most recent call last):
    super(Tagger, self).__init__(args)
RuntimeError

The above exception was the direct cause of the following exception:
  File "<stdin>", line 1, in <module>
  File "C:\Users\user\anaconda3\envs\py376\lib\site-packages\MeCab\__init__.py", line 135, in __init__
    raise RuntimeError(error_info(rawargs)) from ee
RuntimeError:

RuntimeErrorをくらいました。どうも辞書データがダウンロードされていないようです。下記でダウンロードを行います。

$ python -m unidic download

参考:https://atmarkit.itmedia.co.jp/ait/articles/2102/05/news027.html

改めて tagger を宣言します。例文として「すもももももももものうち」を使います。

>>> tagger = MeCab.Tagger()
>>> print(tagger.parse('すもももももももものうち'))
すもも  名詞,普通名詞,一般,,,,スモモ,李,すもも,スモモ,すもも,スモモ,和,"","","","","","",体,スモモ,スモモ,スモモ,スモモ,"0","C2","",15660352771596800,56972
も      助詞,係助詞,,,,,モ,も,も,モ,も,モ,和,"","","","","","",係助,モ,モ,モ,モ,"","動詞%F2@-1,形容詞%F4@-2,名詞%F1","",10324972564259328,37562
もも    名詞,普通名詞,一般,,,,モモ,桃,もも,モモ,もも,モモ,和,"","","","","","",体,モモ,モモ,モモ,モモ,"0","C3","",10425303000293888,37927
も      助詞,係助詞,,,,,モ,も,も,モ,も,モ,和,"","","","","","",係助,モ,モ,モ,モ,"","動詞%F2@-1,形容詞%F4@-2,名詞%F1","",10324972564259328,37562
もも    名詞,普通名詞,一般,,,,モモ,桃,もも,モモ,もも,モモ,和,"","","","","","",体,モモ,モモ,モモ,モモ,"0","C3","",10425303000293888,37927
の      助詞,格助詞,,,,,ノ,の,の,ノ,の,ノ,和,"","","","","","",格助,ノ,ノ,ノ,ノ,"","名詞%F1","",7968444268028416,28989
うち    名詞,普通名詞,副詞可能,,,,ウチ,内,うち,ウチ,うち,ウチ,和,"","","","","","",体,ウチ,ウチ,ウチ,ウチ,"0","C3","",881267193291264,3206
EOS

うまくいきました。

【Sage】Hopf fibration 系の話題でよく見かける図を再現してみる

タイトル通りです。

基本となる式は


\|z_0\|^2+\|z_1\|^2=1

です。これを満たす z_0,z_1\in C^2 は下記のように表せます。


z_0=\exp(i\frac{u+v}{2})\sin(\eta)\\
z_1=\exp(i\frac{u-v}{2})\cos(\eta)

また、複素数なので下記のように表すこともできます。


z_0=w+ix\\
z_1=y+iz

このとき w,x,y,z は以下のとおりです。


w=\cos(\frac{u+v}{2})\sin(\eta)\\
x= \sin(\frac{u+v}{2})\sin(\eta)\\
y= \cos(\frac{u-v}{2})\cos(\eta)\\
z=\sin(\frac{u-v}{2})\cos(\eta)

下記の操作によって三次元空間での様子を可視化します。


p(u,v,\eta)=(\frac{x}{1-w}, \frac{y}{1-w}, \frac{z}{1-w})

検証⓪ \eta が固定 u,v が連続の場合

\eta=\frac{\pi}{10} とします。

プログラム
eta = pi/10
u,v=var('u,v')
parametric_plot3d((lambda u,v:sin((u+v)/2)*sin(eta)/(1-cos((u+v)/2)*sin(eta)), 
                   lambda u,v:cos((u-v)/2)*cos(eta)/(1-cos((u+v)/2)*sin(eta)), 
                   lambda u,v:sin((u-v)/2)*cos(eta)/(1-cos((u+v)/2)*sin(eta))),
                   (u, 0, 4*pi),
                   (v, 0, 2*pi))
実行結果


検証① u が連続 v が離散値をとる場合

検証⓪と同様に \eta=\frac{\pi}{10} とします。

プログラム
eta = pi/10
vs = [pi*i/36 for i in range(72)]
p = [parametric_plot3d((lambda u:sin((u+v)/2)*sin(eta)/(1-cos((u+v)/2)*sin(eta)), 
                   lambda u:cos((u-v)/2)*cos(eta)/(1-cos((u+v)/2)*sin(eta)), 
                   lambda u:sin((u-v)/2)*cos(eta)/(1-cos((u+v)/2)*sin(eta))),
                   (u, 0, 4*pi)) for v in vs]
sum(p)
実行結果


検証② u が連続 \eta,vが離散をとる場合

重なるとわかりにくいので \eta の値で色分けします。

プログラム
p = []
n = 5
colors = ['yellow','blue','green','red','purple']
for k in range(n):
    eta = pi*k/10
    p.extend([parametric_plot3d( (lambda u:sin((u+v)/2)*sin(eta)/(1-cos((u+v)/2)*sin(eta)), 
                        lambda u:cos((u-v)/2)*cos(eta)/(1-cos((u+v)/2)*sin(eta)), 
                        lambda u:sin((u-v)/2)*cos(eta)/(1-cos((u+v)/2)*sin(eta))),
                      (u, 0, 4*pi), color=colors[k%n], plot_points=200) for v in vs])
sum(p)
実行結果

なんかそれっぽいものができます。

拡大してみると黄色の円(\eta=0)が見えます。

さて、とりあえず本稿の目標は達成しました。Hopf fibration については今後も調べて記事にしていこうと思います。