ラベル windows の投稿を表示しています。 すべての投稿を表示
ラベル windows の投稿を表示しています。 すべての投稿を表示

2026年6月6日土曜日

Surface go 3を使ってみて

Windows搭載のタブレットとして、 DellのLatitude10を使っていましたが、 2018年には液晶が漏れて、 電源も入らなくなっていました。 しばらくタブレットなしでしたが、 旅行時に持ち出すPCとして surface go 3を購入して使ってきました。

Latitude10は、運用するためにいろいろ設定を行ったり手間がかかりましたが、 surface go 3は、特別なことをせずに使えて、 あえて書くようなこともありませんでした。 2026年の現在もWindows11Home(25H2)で十分安定して動いています。 4年以上使っていますので、Latitude10が不調になってきた時期程度に時間が経過しています。 それを考えると、完成度の高いタブレットだと感じています。

購入したsurface go 3のスペックは、 CPUがIntel Core i3-10100Y、 メモリ8GB、ストレージ128GBのモデルです。 ペンもキーボードカバーも合わせて購入しました。 ペンは、タブレットではあると便利でしたので購入しました。 キーボードは、ソフトウェアキーボードでは満足できないので購入しました。 Latitude10では、外部キーボードとしてポメラを使ったりしていました。

普段は別のノートPCを使用しているため、使用頻度は、高くありません。 ときどきの旅行記録を書くのに持ち出し、空港での待ち時間などに使えています。 旅行記録を書くのには、Windowsのメモ帳で十分です。 他には、Vimエディタ、Python、Libre Officeもインストールしていますが、 移動中にそれらをしっかり利用することはありません。 この用途程度なら、ポメラでも十分なのですが、 移動中にメールのチェックが必要になったり、 急遽、書類を作成しなければならなくなったりしたときに助かりました。

心配な箇所は、ストレージが128GBとちょっと少ない点です。 すでに97GB使用してしまっています。 データやポータブルなソルトウェアは micro SDに入れていますが、挿入したまま利用していて、一度、そのmicro SDが破損しました。 断片的にファイルが破損ていて、ソフトウェアは動いているのに、なにかおかしいという 状態の原因は気づきにくかったです。 別のストレージへのバックアップは大切ですね。

自立させるために、キックスタンドがついていますが、膝上で使うのには不安定なので、 テーブルのある場所が必要です。 キックスタンドは弱弱しいので、それを開くのに両手を使うため、 本体をどこかに置かなければならず、開閉に気を使います。 キックスタンドは、タブレット単体で自立させるのものとしてはよいものですが、 よくキーボードを使うのであれば、 タブレットである必要性はあまりないのかなと感じています。

そのような経験から、 10インチから11インチのクラムシェルのノートPCで、 キーボードがSurface go 3のキーボードカバーようにちゃんとしていて、 バッテリーまわりが安心できるものを探してみると、見つからないものです。 Surface go 3を大切に使っていかないとと思いました。

2017年4月15日土曜日

Dell Latitude10の最近の調子

もうすぐWindows10のCreaters Updateがくるかもしれないと思いつつ、 Latitude10はWindows10 Version 1607で使用中です。

 先日、1607用の更新プログラムKB15217が2回ほど失敗し、 3回目にしてようやくインストールされました。 ところが、再起動されないで止まってしまうということに。

電源ケーブルはつないだ状態で使っていましたが、電源ボタンを押しても、反応がありません。

電源ケーブルをはずして、電源ボタンを押すとやっと反応して、ボタン脇のLEDが一瞬点灯します。しかし、起動しません。

バッテリーを外して、少し放置してから再度バッテリーを取り付け試みましたが、LEDが一瞬点灯するだけなのは変わらず。

とうとうハードウェア故障かと覚悟しましたが、突然壊れるものなのかと、あきらめきれず。 電源ケーブルをつないで、一日放置して再度試したところなぜか無事に起動され、 KB15217インストールの再起動後のプロセスが実行され無事に成功しました。

 またしばらく使用して、電源を切り、翌日電源ボタンをいれたところ同じような症状で起動しません。 しかし、今回は電源ケーブルをはずし、数回電源ボタンを押し、LEDが一瞬点灯するのを繰り返し、 また10秒ほどまって再び押したところ起動しました。

電源ボタンの接触の問題なのかと思いますが、LEDは的確に反応しますので、別の原因でしょう。 シャットダウンして、LEDランプが消灯しますが、じつは内部ではなにかがずっと動いているのでしょうか。 ということで、考えられるのはWindowsの高速スタートアップの設定です。 コントロールパネルから電源ボタンの動作設定を見てみると、チェックがはいっています。 はずしてつかっていたつもりでしたが、現状はチェックが入った状態。

とりあえず、高速スタートアップを無効にして、シャットダウンしてみました。 LEDが消灯してから、電源ボタンを押してみると、無事に起動します。 二回ほど試したところで、これを書いていますが、無事に起動しています。

 これが原因か、まだはっきりとはしませんが、覚書として残しておきます。

追加
残念ながら、夜にまた起動できない状態に。LEDランプが一瞬点灯するけど、起動しない。
電源ケーブルをはずして、しばらく経過すると起動に成功しました。
シャットダウンしたあと、電源ケーブルを差しておいたのですが、そういえばアップデートをかけて、電源ケーブルを差して翌朝起動しないということが多い。
電源ケーブルをはずして、しばらく経過したのち電源が入ります。
なにかバッテリー関係の保護が働いているのでしょうか。
今度は、シャットダウンして電源ケーブル接続せずに放置して、どうなるか様子を見ます。





2016年11月18日金曜日

一文字飛ばしにした文字列へ変換する

ある文字列を一文字飛ばしにした文字列へ変換する関数をRubyで書くという話を見かけました。 "abcdefg"を入力したら"aceg"が帰ってくる関数です。 Pythonを使っていると、関数を書くまでもなくs[::2]としたら望みの文字列が得られます。せっかくだからRubyで書いてみました。
pythonでは、
def one_skipped(s):
    return s[::2]

print one_skipped('abcdefg') #=> 'aceg'

と関数にするまでもありません。 Juliaでも、
function one_skipped(s)
    s[1:2:length(s)]
end

print(one_skipped("abcdefg"))

のように文字列から文字列を生成できます。

Rubyでも文字列のメソッドに便利なものがあるのかと見てみましたが、 slice()では、範囲のみの指定のようです。 インデックスを指定して一文字取り出すことはできるようですので、 一つとびのインデックスさえ生成できれば、それをもとに文字列を組み立てられそうです。
def one_skipped(s)
    return (0..s.length/2).map {|i| i*2}.collect {|i| s[i]}.join()
end

Rubyはreturnを省略できるということ。i*2として一つ飛びの数に直すより、 i%2==0の判定を使って取り出したいということで、selectメソッドを使ってみます。
def one_skipped(s)
    (0..s.length).select {|i| i%2==0}.collect {|i| s[i]}.join()
end
ずらずらと記述が並びますね。関数に分けてみます。

def range(start, stop, step)
    (start .. stop).select {|i| (i-start)%step==0}
end

def chars_at_indices(s, indices)
    indices.collect {|i| s[i]}
end

def one_skipped(s)
    chars_at_indices(s, range(0, s.length, 2)).join()
end

puts 'abcdefg'
こんな感じでしょうか。関数に分けるほどでもないでしょうか。 せっかく関数に分けたので、SBCLでも書いてみます。
(defun range (start stop step)
  (loop for i from start below stop by step collect i))

(defun chars-at-indices (s indices)
  (loop for i in indices collect (elt s i)))

(defun one-skipped (s)
  (concatenate 'string (chars-at-indices s (range 0 (length s) 2))))

普段使わない言語を、ちょっと調べつつ書いてみる題材としてちょうどよいですね。

Rubyは、Windows上で、
ruby 2.1.2p95 (2014-05-08 revision 45877)
irb 0.9.6(09/06/30)
を用いました。

2016年11月11日金曜日

Gmailの下書きメモと同期するスクリプトを作ってみた

ポメラのdm200いいですね。 Gmailの下書きを利用して同期する機能があるということ。

Windowsでもそんなことやってみようと、pythonで作ってどんな感じかと試し中。 IMAPでgmailに接続して、下書きフォルダにメッセージを送るとともに、「メモ」ラベルをつけてみました。 こうすると、たんに「メモ」にメッセージを送るのとは違い、ブラウザで開いたGmailからも編集可能です。


IMAPでメッセージを削除するときは、「メモ」ラベルを消した後でないと、\Deleteフラグをstoreしても削除されませんでした。 直接「メモ」に送ったメッセージは、\Deleteフラグをstoreするだけで削除されました。 ただ、直接「メモ」に送ると、ブラウザで開いたGmailからは編集不可能でした。 「[Gmail]/下書き」にいれないと再編集できないようですね。

Windowsならファイルの同期には、Dropboxを使うので、あえてGmailに同期する必要はなさそうです。
dm200を手に入れたときには、ターゲットを変更して、便利に使えるのかもしれません。

2016年10月29日土曜日

pythonでSTL形式のデータを作ってみた

gnuplotでは、以下のようなスクリプトで球面を描画したりします。
set parametric # 媒介変数モード
set urange[0:2*pi] # uの範囲を設定
set vrange[0:2*pi] # vの範囲を設定
set ticslevel 0
set hidden3d
set isosample 50
set view equal xyz
splot cos(u/2.0)*cos(v),sin(u/2.0)*cos(v),sin(v) w l
このようなものを3Dモデルとして出力したいということで、 pythonで(u, v)の関数をSTL形式にして出力するスクリプトを書いてみました。 ほかの言語で書き換えて遊ぶのにも、ちょうどよい内容と長さかと思います。
import math

def Sphere(u, v):
    x = math.cos(u/2.0)*math.cos(v)
    y = math.sin(u/2.0)*math.cos(v)
    z = math.sin(v)
    return x, y, z

def VectorSub(v1, v2):
    return [e1-e2 for e1, e2 in zip(v1, v2)] 

def VectorDiv(v, a):
    return [e/a for e in v] 

def VectorCross(v1, v2):
    x1, y1, z1 = v1
    x2, y2, z2 = v2
    return [y1*z2-z1*y2, z1*x2-x1*z2, x1*y2-y1*x2]

def VectorAbs(v):
    return math.sqrt(sum([e**2 for e in v]))

def NormalVector(p1, p2, p3):
    v1 = VectorSub(p2, p1)
    v2 = VectorSub(p3, p2)
    vc = VectorCross(v1, v2)
    a = VectorAbs(vc)
    v = VectorDiv(vc, a) if a!=0.0 else False
    return v

def STLfacet(apolygon, inverse=False):
    if inverse:
        points = apolygon[::-1]
    else:
        points = apolygon[:]

    nv = NormalVector(*points)

    if not nv:
        return ""

    l = "facet normal %g %g %g\n" % tuple(nv)
    l = l + "outer loop\n"
    for p in points:
        l = l + "vertex %g %g %g\n" % tuple(p)
    l = l + "endloop\n"
    l = l + "endfacet\n"
    return l

def PolygonsToSTL(name, polygons, inverse=False):
    l = "solid %s\n" % name
    for p in polygons:
        l = l + STLfacet(p, inverse)
    l = l+"endsolid\n"
    return l

def Polygons_of_Function_UV(func):
    nu = 90 
    nv = 90 
    du = 2.0 * math.pi / nu
    dv = 2.0 * math.pi / nv

    u = [du * i for i in range(nu+1)]
    v = [dv * i for i in range(nv+1)]

    polygons = []
    for i in range(nu):
        for j in range(nv):
            p1 = func(u[i], v[j])
            p2 = func(u[i+1], v[j])
            p3 = func(u[i+1], v[j+1])
            p4 = func(u[i], v[j+1])
            polygons.append((p1, p2, p4))
            polygons.append((p4, p2, p3))
    return polygons

def OutputSTL(name, polygons):
    with open('%s.stl' % name, "w") as fp:
        fp.write(PolygonsToSTL(name, polygons, False))

if __name__ == '__main__':
    OutputSTL("Sphere", Polygons_of_Function_UV(Sphere))


出力されたSTLデータを見るには、GLC Playerが便利ですね。また、Windows10には、3D Builderがついているので、そのままでSTLデータを見ることができます。GLC Playerでスナップショットを取ったものが下の図です。

関数を次のものにしてみます。

def Dounut(u, v):
    x = math.cos(u)*(1+0.5*math.cos(v))
    y = math.sin(u)*(1+0.5*math.cos(v))
    z = 0.5*math.sin(v)
    return x, y, z

ドーナツの形になりました。

def Helical(u, v):
    n = 10.0
    a = 0.6
    b = 0.3
    rm = (lambda v: a*b/math.sqrt(b*b*math.cos(v)**2 + a*a*math.sin(v)**2))
    r = (lambda u, v: 1 + rm(v)*math.cos(v+n*u/2.0))
    x = r(u, v) * math.cos(u)
    y = r(u, v) * math.sin(u)
    z = rm(v) * math.sin(v + n*u/2.0)
    return x, y, z

楕円をぐるぐる回転させていくと、ねじれた形状になりました。

2016年10月20日木曜日

Windowsでファイルをドロップしてpythonスクリプトを起動する

ファイルをドラッグ&ドロップでpythonスクリプトを起動し、処理たいこともあるようで、Googleで検索してみると、二つ方法があるようですね。

一つは、レジストリを編集してPythonスクリプトにドロップハンドルを設定する方法があるようです。

もう一つは、バッチファイルを使う方法です。レジストリをいじったりしないので、こちらの方が好みですし、おすすめです。

testDragAndDrop.py (pythonスクリプトファイル)
import sys
for arg in sys.argv:
    print arg
raw_input()

testDragAndDrop.bat (バッチファイル)
python testDragAndDrop.py %*

の二つのファイルを用意して、testDragAndDrop.batにファイルをドロップするとtestDragAndDrop.pyに引数としてドロップされたファイルのパスが渡されます。非常に簡単ですね。バッチファイルのショートカットを作成して、そちらにドロップすることも可能です。

2016年10月11日火曜日

DELL Latitude10とWindows10 1607 anniversary update

DELLのLatitude10は、いつの間にかWindows10 Anniversary Updateが来たようです。1607用のセキュリティアップデートもきましたが、いまのところ順調にに動作しています。



ただしBluetoothドライバは、標準のものに戻っています。キングジムのポメラDM100をBluetoothキーボードとして利用するには問題ない(キーアサインの問題はソフトウェアで解決済み)のですが、Bluetoothを使ったファイル転送機能は、1607でも問題があるようです。

Windows10へアップグレードした時と同様に、DELLのサポートページからBluetoothドライバ(Network_Driver_4Y0Y8_WIN_12.0.6300_A06.EXE)をダウンロードしてきてインストールしたところ、ファイルのやりとりができるようになりました。

さて、新しくポメラDM200が発表されましたが、このBluetoothのファイル転送機能はなくなるということ。環境によってファイル転送できたりできなかったりとあるようなので、削除されたのでしょうか。QRコードやケーブル接続してPCリンクによるファイル転送、さらにWifiを使ってファイル転送まであるので問題なさそうです。画面が広くなったり、キーボードが新しくなったり、漢字変換も賢くなったりと楽しみな箇所がいっぱいです。

2016年3月23日水曜日

Kivy LauncherでAnimated Gif Viewer

Kivy Launcherのアップデートがあったので、せっかくなのでAnimated Gif Viewerを作ってみた。Kivyで作成して、QPythonでの動作を確認したけど、Kivy Launcherでは起動しない。GIFイメージの読み込みにPILを使っているけど、出力されたlogを見るとどうやら、GIFイメージを読むときに AttributeError: tobytes が起こっている。Pillowではtostring()が廃止予定になってtobytes()が使われるらしいとのこと。どうやらKivy Launcherが呼び出しているPILのバージョンが古いためにtobytes()メソッドがないらしい。そういうわけで、以下のようにスクリプトのあたまでtostring()を呼び出すようにtobytes()メソッドを追加してみた。

from PIL import Image as PILImage

def tobytes(pilimg, encoder_name="raw", *args):
    return pilimg.tostring(encoder_name=encoder_name)

PILImage.Image.tobytes = tobytes

無事に起動することができた。こういうところ、Pythonは便利ですね。


Next, Back, Pause, Rotate, Resume, Open, Quitとボタンをつけてみました。
GUIをwxPythonで作り直して、Windows用にもしてみた。



2015年8月25日火曜日

Windows10になったLatitude10とポメラDM100

Latitude10をWindows10にアップグレードしたので、ポメラDM100のBluetooth接続を試してみました。

ポメラDM100をBluetoothキーボードとして接続させてみると、問題なく認識しました。ところが、ファイル転送をさせようとしてもペアリングの手続きは現れますが、接続が完了しません。以前のメモでいうとステップ(5)で、ファイル転送のサービスが表示されないのです。

Windows8、8.1と使えていたので、ハードウェア上の問題はないはず。Windows10の標準のBluetoothドライバーが問題なのかと思い、DELLのサポートページからWindows8のBluetoothドライバーをダウンロードしてきてインストールしてみました。インストール中にタスクバーに表示されるアイコンは空欄になってしまい怪しかったのですが、無事にインストールできました。再度、DM100のBluetoothファイル転送を試みると、これまで同様に使えるようになりました。

これで、ポメラDM100とのBluetooth連携も問題なくできそうです。キーボードとして使うと、相変わらずキートップの表示とは異なる文字が入力されるキーがありますが、pythonで書いたスクリプトで回避しています。

ファイル転送は、PCを開いたデバイス欄にDM100アイコンが追加されるので、それを開くだけでファイル転送ができます。もちろん、ポメラはBluetoothのファイル転送状態にしておきます。フォルダが開かれたところで、ポメラのほうは接続完了状態になりました。


ファイル転送できるようになると、DM100アイコンがデバイスとドライブに追加された


DM100以下には、Main MemoryとSDカードがあり、これはMainMemoryを開いたところ



2015年8月19日水曜日

Latitude10のOSをWindows10にアップグレードした

DELLのLatitude10は、Windows8からWindows8.1にアップグレードして利用していた。Windows10への無償アップグレードが開始され、8月頭にそれを予約しておいたが、しばらくなにも起こらなかった。やっと先に進めるような通知が現れたので、さっそくアップグレードを実行してみた。

アップグレードは簡単で、指示にしたがって、ただ放置しておくだけであった。途中、何度か再起動がかかったが、そのときDELLのロゴ表示後に何も画面に表示されない長い時間が存在した。このときは、アップグレードに失敗して起動できなくなったのだろうかと不安になりつつも、電源ボタンに触るのを我慢し待ったところ、先に進みアップグレードは無事に終了した。ブラウザを起動して、とくに操作不能になるような不具合はなさそうだと思いつつ、それ以上触る時間もないので、電源を落としておいた。

問題に気づいたのは、 翌日、電源を入れてから。Windows10は起動したようだが、タッチパネルをスワイプしてもロック画面から先にすすめない。USBマウスと、キーボードを接続しログインしたところ、タッチパネルでも操作できるようになった。どうやら起動直後にタッチパネルが動いていないようである。デジタイザペンは最初認識している様子だったが、いざアプリケーションでデジタイザペンを使おうとすると、使えなくなっていた。

タブレットであるLatitude10でタッチパネルやデジタイザペンが使えないのは不便なので、使えるようにしたいところ。デバイスマネージャーを見てみると、特にエラーになっている様子はない。DELLのサポートページを見てみると、Latitude10は、Windows10ではサポートされていない様子。デジタイザ用にTABLET PC - Enhanced Tablet Driver 7.3.1-7をインストールしてみたり、デジタイザのユーザー設定を削除したりを行うと、一時的に使えるようになる。

そうこうしているうちに、デジタイザペンを使わずにある程度時間がたつと認識しなくなることが分かる。節電のためにデジタイザをオフをにするような動作だ。デバイスドライバの一覧からWacom Deviceのプロパティにある電源管理のタブを開くと、「電力節約のために、コンピュータでこのデバイスの電源をオフにできるようにする」があるので、このチェックをはずしたところ、無事にデジタイザペンを継続して使えるようになった。タッチパネルも同様かと思い、I2C HIDデバイスのプロパティから同様に設定すると、こちらも起動直後から使えるようになった。

とりあえず、入力デバイスが利用できるようになったので、一安心。Pythonで作ったGraffitiっぽい入力ができるソフトウェアキーボードも無事に動いている。 


2015年7月8日水曜日

MinGW gcc とctypesモジュールを用いてpythonからc関数を呼び出してみる 2

前に構造体を渡すような関数までやったけど、構造体の配列を渡すようなこともよくありそう。簡単な例で試してみたのでメモしておきます。
呼び出されるc関数は、以下の通り。

#include <stdio.h>

typedef struct {
 char name[20];
 int age;
} NAMEandAGE;

int sum_ages(int sz, NAMEandAGE *na)
{
 int i;
 int sum = 0;
 
 for (i=0; i<sz; i++){
  printf("%s %d\n", na[i].name, na[i].age);
  sum = sum + na[i].age;
 }
 return sum;
}
文字列と整数のフィールドをもつ、構造体NAMEandAGEの配列を渡して、 要素の値を表示し、ageの和を返す関数です。
配列は、pythonスクリプトで作成するため、その長さが分からないので、 整数szで長さを渡しています。

ソースファイルをstructures.cというファイルに保存して、

gcc -Wall -c structures.c

でコンパイルします。structures.oというオブジェクトファイルができますので、

gcc -shared -o structures.so structures.o

として、structures.soという、共有ライブラリファイルを作成します。
これを呼び出す、pythonスクリプトは、以下の通り。

import ctypes

class NAMEandAGE(ctypes.Structure):
    _fields_ = [('name', ctypes.c_char*20),
                ('age', ctypes.c_int)]

if __name__ == '__main__':
    mydll = ctypes.CDLL("structures.so")

    data = [('name1', 1), ('name2', 2)] 
    nameandages = (NAMEandAGE * len(data))()
    for n, d in zip(nameandages, data):
        n.name = d[0]
        n.age = d[1]

    result = mydll.sum_ages(ctypes.c_int(len(data)), ctypes.pointer(nameandages))
    print result

配列は、(構造体のクラス * 要素数)で構造体配列のクラスを作って、それを用いてインスタンスを生成するようです。 その後、リストdataの値で、各要素のフィールドを設定しました。
関数を呼び出すときは、ctypes.pointer()を使って、構造体配列のポインタを渡せばよいようです。

2014年7月31日木曜日

Latitude10がWindows8.1の起動に失敗

Windowsの更新を確認したところ、アップデートあったので、 いつもどおりにやったら、エラーが出て起動に失敗しました。 自動修復で、どうにか復帰。巻き戻ったので、またアップデートをかけたら、 また、再起動後にエラーが出てしまった(IRQ_NOT_LESS_OR_EQUAL)。今度は、自動修復にも失敗してしまった。

自動修復が失敗した後、詳細オプションで、選べる中に、「そのまま続ける」 というのがあったので、選んでみたがなにも反応がない。 電源を落として、再び、起動しなおし。

次に、リフレッシュを選んだところ、Windows8になって起動した。
とりあえず、 Windows8でも起動してくれたので、ほっとしたところ。
Windowsの更新をすると、ストアに8.1へのアップデートが現れたので、再び8.1へ。
と思ったら、失敗。
その後、チップセットのドライバをA07にして、 再び挑戦したところ、無事に8.1へとアップデートできた。今度は、8.1で全ての更新を適用しても、起動時にエラーが起こることはなく、使えるように復帰しました。

なにがよくて、なにが悪かったのか、はっきりせずにちょっと心配ですが、以前のように動作している様子。リフレッシュ後、元の状態に戻すのには時間がかかるので、もうやりたくないですね。



2014年7月26日土曜日

Windowsのgnuplotで、plot sin(x)をしてみた

Javaは知らないけど、便利なライブラリがあるようなので、 Clojureを触ってみようということでやってみました。

数値を得たら、プロットしてみるということはしばしばあります。 pythonだとmatplotlibを使ったりしますが、 gnuplotを呼び出すことができれば、 グラフ描画をgnuplotにまかせることもできそうです。

gnuplotは、gp463-win32-setup.exeを使ってインストールしたも のを利用しています。(ver.4.6.5でも大丈夫です) コマンドラインでgnuplotが実行できるように、インストールされたgnuplot.exeがあるディレクトリへあらかじめPathを通しておきます。

Clojureは、1.6.0をダウンロードしました。 Getting Startedにあるように、

java -cp clojure-1.6.0.jar clojure.main

で、REPLを起動して利用しています。

以下が、そのスクリプトですが、 プロセスを開始するgpstart、gnuplotのコマンドを送るgpdo、 終了するgpstopという関数を作っています。 sin(x)をプロットするのは、demo関数で行います。
(defrecord GnuplotProc [proc out in])

(defn gpstart
  "Start gnuplot process"
  []
  (let [proc (.start (doto (ProcessBuilder. '("gnuplot" "--persist"))
                       (.redirectErrorStream true)))
        out (clojure.java.io/writer (.getOutputStream proc))
        in (clojure.java.io/reader (.getInputStream proc))]
    (GnuplotProc. proc out in)))

(defn gpstop
  "Stop gnuplot process"
  [proc]
  (.destroy (get proc :proc)))

(defn gpdo
  "send command string to gnuplot process"
  [proc s]
  (let [w (get proc :out)]
       (.write w (str s))
       (.newLine w)
       (.flush w)))

(defn demo
  "Demo function"
  []
  (def p (gpstart))
  (gpdo p "set xlabel \"x\"")
  (gpdo p "set ylabel \"y\"")
  (gpdo p "plot sin(x)")
  (read)
  (gpstop p))

(demo)
clispと、pythonでも書いてみました。
(defun gpstart 
  ;Start gnuplot process
  ()
  (make-pipe-io-stream "gnuplot --persist" :buffered t))

(defun gpstop
  ;Stop gnuplot process
  (proc)
  (let ()
    (gpdo proc "quit")
    (close proc)))

(defun gpdo
  ;send command string to gnuplot process
  (proc s)
  (let ()
    (format proc "~A~%" s)
    (force-output proc)))

(defun demo
  ;demo function
  ()
  (let ((p (gpstart)))
    (gpdo p "set xlabel \"x\"")
    (gpdo p "set ylabel \"y\"")
    (gpdo p "plot sin(x)")
    (read)
    (gpstop p)))

(demo)

Pythonで書いたスクリプトは以下の通り。
import subprocess

def gpstart():
    """ Start gnuplot process """
    proc = subprocess.Popen(["gnuplot", "--persist"], 
                            stdin = subprocess.PIPE,
                            stdout = subprocess.PIPE,
                            stderr = subprocess.PIPE)
    return proc

def gpstop(proc):
    """ Stop gnuplot process """
    gpdo(proc, "quit")
    proc.kill()

def gpdo(proc, s):
    """ send command string to gnuplot process """
    proc.stdin.write(s)
    proc.stdin.write("\n")
    proc.stdin.flush()

def demo():
    """ Demo function """
    p = gpstart()
    gpdo(p, 'set xlabel "x"')
    gpdo(p, 'set ylabel "y"')
    gpdo(p, 'plot sin(x)')
    raw_input()
    gpstop(p)

if __name__ == '__main__':
    demo()
この程度なら、行数はほぼ一緒ですね。
clispやClojureを使ってもgnuplotを操作できそうなので、ひと安心です。

Rubyでもやってみました。
def gpstart
    # Start gnuplot process
    IO.popen("gnuplot --persist", "r+")
end

def gpstop(io)
    # Stop gnuplot process
    io.close
end

def gpdo(io, s)
    # send command string to gnuplot process
    io.puts(s)
end

def demo
    io = gpstart
    gpdo(io, "set xlabel \"x\"")
    gpdo(io, "set ylabel \"y\"")
    gpdo(io, "plot sin(x)")
    gets
    gpstop(io)
end

if __FILE__ == $0
    demo
end
シンプルですね。
Windows環境でirbを利用する人は少ないのかな。 ActiveScriptRuby 2.1.2-p95を利用してみたのですが、 irbのインタラクティブな環境で、Backspaceがちゃんと動作しませんでした。 検索してみたら、1.9.2での同様な症状と対処法がこちらにありました。 irbに--noreadlineオプションをつけて起動すると、正常にBackspaceできるようになりました。


2016/07/24追記
同じものをC言語で。Windows Vista 32bit MinGWのgcc-4.9.3で確認。

#include <stdio.h>

FILE *gpstart(void);
void gpstop(FILE *p);
void gpdo(FILE *p, char *s);

FILE *gpstart(void) {
    /* start gnuplot process */
    return popen("gnuplot.exe --persist", "w");
}

void gpstop(FILE *p) {
    /* stop gnuplot process */
    gpdo(p, "quit");
    pclose(p);
}

void gpdo(FILE *p, char *s) {
    /* send command string to gnuplot process */
    fprintf(p, s);
    fprintf(p, "\n");
}

void demo(void) {
    /* demo function */
    FILE *p;
    p = gpstart();
    gpdo(p, "set xlabel \"x\"");
    gpdo(p, "set ylabel \"y\"");
    gpdo(p, "plot sin(x)");
    gpstop(p);
}

void main(void) {
    demo();
}


2014年7月19日土曜日

Graffiti入力っぽいキーボードを修正した

DELLのLatitude10でしばらく使っていたGraffiti入力っぽいソフトウェアキーボードに、ショートカット機能を追加してみた。ショートカットストロークのあとに、アルファベットのストロークで、コマンドを実行するものだ。ショートカットで起動させるコマンドは、テキストファイルに書き込んでおくようにした。python+wxPythonで書かれたスクリプトを修正するのは、動作を確認しながら、少しずつ手を加えていき、30分ほどで修正が完了した。

Windowsタブレットは、あたりまえだけどWindows上で作成したスクリプトがそのまま動作するので、自作のスクリプトを動作させる環境としては、とてもよいものだと思う。操作方法も特別なことはないし。最近、8インチのWindowsタブレットが気になるところですが、Latitude10が調子よく動作しているので、しばらくはないかな。



2014年5月23日金曜日

アルファベットで入力

ハングル文字やキリル文字など、普通の日本語キーボードから入力しにくい文字があります。
そのような文字と一対一に対応したアルファベットや記号のシーケンスを利用して、入力できるようにしたら便利そうです。
そこで、アルファベットの文字列と入力したい文字をTAB区切りで並べたテキストファイルを読み込んで、それを参照して入力できるスクリプトをpythonとwxPythonを用いて書いてみました。ハングル文字は、unicode上で規則的に並んでいるようです。それを出力するスクリプトもpythonで書いて読み込むファイルを作成しました。



アルファベットの並びと文字の対応ファイルは選択できるようにしたので、ほかの文字セットの入力にも使えそうです。 シンプルなスクリプトですが、使いどころがありそうです。アルファベットで入力するような方法は、そのままのIMEを使って、特別なキー配列を覚える必要もないのがよいですよね。

アルファベットとハングル文字の対応ファイルは次のpython(2.7)スクリプトを実行して、出力をファイルにリダイレクトするとほぼ完成です。

STARTCHAR = ('g', 'kk', 'n', 'd', 'tt', 
             'r', 'm', 'b', 'pp', 's', 
             'ss', '', 'j', 'jj', 'ch', 
             'k', 't', 'p', 'h')

MIDCHAR = ('a', 'ae', 'ya', 'yae', 'eo', 
           'e', 'yeo', 'ye', 'o', 'wa', 
           'wae', 'oe', 'yo', 'u', 'wo', 
           'we', 'wi', 'yu', 'eu', 'ui', 
           'i')

PCHAR = ('', 'g', 'kk', 'gs', 'n', 
         'nj', 'nh', 'd', 'l', 'lg', 
         'lm', 'lb', 'ls', 'lt', 'lp', 
         'lh', 'm', 'b', 'bs', 's', 
         'ss', 'ng', 'j', 'ch', 'k', 
         't', 'p', 'h')

c = 0
for s in STARTCHAR:
    for m in MIDCHAR:
        for p in PCHAR:
            seq = s+m+p
            code = 0xAC00 + c
            uni_line = "%s\t%s" % (seq, unichr(code))
            utf8_line = uni_line.encode('utf-8')
            print utf8_line
            c = c+1




2014年4月8日火曜日

ちょっとしたpythonのコード片を試すエディタ

ちょっとpythonのコードを試したり、電卓代わりに使ったり、そういうときは、pythonのインタラクティブシェルをよく使います。でも、forループやちょっと関数定義してみたりしたときには、やり直すのが面倒だなと思いながらも、テキストエディタでスクリプトファイルを書いては、コマンドラインから実行していました。

そうこうしているうちに、エディタで書きつつ、その一部を実行してみたりしたいなと思ったしだいです。Mac OS 8.6を使っていたときには、pythonではないですが、そんな感じのメモ帳があってしばしば利用して便利だった覚えがありましたし、SqueakのWorkspaceで遊んでいると、あらためてエディタから、コードを実行できるといいなと思いました。
そこでpythonでも、ちょっとしたエディタを書いてみました。選択したテキストをexecや、eval()に渡すだけというものですが、使ってみると便利ですね。GUIにはいつもwxPythonを利用していますが、今回は、pythonをインストールしたら利用できるTkinterを使いました。pythonのTurtle graphicsで遊ぶときにも、こういうエディタは便利かと思います。



2014年1月31日金曜日

matplotlibのMultiCursor

matplotlibは、wxPythonと簡単に組み合わせて利用できて便利ですね。
matplotlibのグラフ上にマウスカーソルに合わせて動く十字のカーソルを表示するMultiCursorというものがありますが、 twinx()してY2軸を利用すると奇妙なことがおこりました。
カーソルは、Y軸に描画されながらも、その表示位置はY2軸上の値になるという状態です。
もちろん、カーソルを描画する対象をY2軸のほうにすると矛盾のない状態にはなります。
そもそもMultiCursorを利用する対象にY2軸を追加するような利用の仕方は、あまりなさそうです。そうはいっても、そのような要求があったため、Y2軸を追加しても、カーソル位置は、Y軸のほうで決まるようにしてみました。
マウス移動のイベントを処理するonmove()に渡されるeventからキャンバス上のx,y座標が得られるので、それを利用してグラフ軸上のデータに焼きなおすようにしました。
使い方はオリジナルのMultiCursorとほぼ同じですが、parentウィンドウを渡すようにして、そちらへ座標を通知するイベントをポストしています。parentウィンドウでそのイベントを拾えば、カーソル移動にあわせて座標位置を表示できます。

from matplotlib.widgets import MultiCursor
import wx
import wx.lib.newevent
class MyMultiCursor(MultiCursor):
    def __init__(self, parent, canvas, axes, color='r', lw=1,  
            useblit = True, horizOn=True, vertOn=True): 
        if matplotlib.__version__ >= '1.3.0':
            MultiCursor.__init__(self, canvas, axes, color=color, 
                    lw=lw, useblit=useblit, horizOn=horizOn, vertOn=vertOn)
        else:
            MultiCursor.__init__(self, canvas, axes, color=color, lw=lw, useblit=useblit)
        
        # Produce New Event for Cursor Move Notification to parent window.
        self.parent = parent
        self.CursorMoveEvent, self.EVT_CURSOR_MOVE = wx.lib.newevent.NewEvent()
        self.visible = False

    def xydata(self, x, y):
        #make new xdata, ydata
        cwidth, cheight = self.canvas.GetSize()
        target = None
        for ax in self.axes:
            #find the axes in which the mouse cursor is.
            bbox = ax.get_position()
            [[left,bottom], [right, top]] = bbox.get_points()
            xc = (x+1)/float(cwidth)
            yc = y/float(cheight) 
            if ((left < xc) and (xc < right) and 
                (bottom < yc) and (yc < top)):
                target = ax
                break
        if not target: 
            # if there is no target
            return (None, None)

        width = right-left
        height =top-bottom
        xmin, xmax = ax.get_xlim()
        ymin, ymax = ax.get_ylim()
        xdata = xmin + (xc - left) * (xmax - xmin)/width
        ydata = ymin + (yc - bottom) * (ymax - ymin)/height
        return (xdata, ydata)

    def onmove(self, event):
        event.xdata, event.ydata = self.xydata(event.x, event.y)
        MultiCursor.onmove(self, event)
        #make event data
        evt = self.CursorMoveEvent(pos = (event.xdata, event.ydata))
        #post event to parent window
        wx.PostEvent(self.parent, evt)
        self.visible = True


2014年1月24日金曜日

WindowsでGraffiti入力っぽいキーボードを修正してみた

Cの関数をPythonから呼び出す方法を使って、例のGraffitiっぽい入力のソフトウェアキーボードをgKeyを修正してみた。

ストロークの判定ルーチンをC言語で書き直して、その部分だけ置き換えてみた。判定用のモジュール内のPythonで書かれた従来関数と同じ名前でラッピングして、モジュール差し替えを行うと、ほとんどいじらずにCルーチンを利用したものができあがる。
pythonでプロトタイプを作って、徐々にCに置き換えていくような作り方もよいかもしれないですね。Cの関数のテストにPythonを使うというのもよさそうです。

ところでgKeyの使用感に違いがあったかというと、pythonのみで作ったものでも十分快適だったので、それほどでもなかった。もともと軽い処理になので、非線形最小二乗フィットほどの効果はないようですね。でも、Cで書いたらもっともっと快適かもという思いに対して、すっきりできた気分。


2014年1月17日金曜日

MinGW gcc とctypesモジュールを用いてpythonからc関数を呼び出してみる

Fortranで記述して、f2pyを使うのもよいのですが、Cで記述した関数が手元にあるもので、そちらを使いたいと思ったしだいです。
Python APIを使ったり、SWIGやCythonを利用したりと、いろいろ方法はある様子ですが、ctypesモジュールを利用して、呼び出す方法を試してみました。

コンパイラは、Visual Studioではなくて、MinGWのgccを使います。関数をコンパイルするだけなら、コンソールからちょっとコマンドを打つだけなので、こちらのほうが楽そうです。
 簡単なものから順番に試していきたいと思います。

まずは、一つの整数を渡して二倍して返す関数です。
/* doublenumber.c */
#include
int doublenumber(int n)
{
    return n * 2;
}

コンパイルします

gcc -Wall -fPIC -c doublenumber.c

windowsでは、-fPICは無視されるとの警告がでました。
どうやらデフォルトでPICオプションが適用される様子です。
オブジェクトファイルdoublenumber.oができました。

共有ライブラリを作成します。
gcc -shared -o doublenumber.so doublenumber.o
共有ライブラリdoublenumber.soファイルができました。

pythonから利用してみようと思います。

import ctypes
mydll = ctypes.CDLL('doublenumber.so')
mydll.doublenumber(5)
10
とちゃんと利用できています。
実数を引数として与えると、ctypes.ArgumentErrorが発生します。

さて、次に実数型を利用してみましょう。
C関数の引数をdouble vにして、同様に二倍した値を返すものにします。

/* doubledouble.c */
#include
double doublenumber(double v)
{
    return v * 2.0;
}

コンパイルして、共有ライブラリにします。
gcc -Wall -c doubledouble.c
gcc -shared -o doubledouble.so  doubledouble.o
 

実数を渡してもエラーが出ます。
型をc言語用に変換して、渡します。
mydll.doublenumber(ctypes.c_double(5.3))
1075131187
あれ、エラーは出ませんが、返り値がおかしいですね。
どうやらデフォルトで、関数はc_intを返すと仮定されているようです。
関数オブジェクトのrestype属性を設定するとよいようです。

mydll.doublenumber.restype = ctypes.c_double
mydll.doublenumber(ctypes.c_double(5.3))
10.6
ちゃんと値が得られました。
さて、引数でc_double指定をするのも大変です。
argtypesを設定してみます。
mydll.doublenumber.argtypes = [ctypes.c_double]
mydll.doublenumber(5.3)
10.6
簡単に5.3を渡すことができました。
整数5を渡しても、自動的に変換されるようです。

次は、文字列を渡す関数を試してみます。
/* charcount.c */
#include
int charcount(char *s)
{
    int c;
    c = 0;
    while (s[c] != '\0')
        c++;
    return c;
}
そういえばstrlen()なんて関数もありましたね。

コンパイルして共有ライブラリを作成します。
gcc -Wall -c charcount.c
gcc -shared -o charcount.so  charcount.o

テストするPythonスクリプトは以下の通り
C言語の文字列は、文字配列のポインタになります。
文字型のポインタは、ctypes.c_char_pで指定できます。
import ctypes
mydll = ctypes.CDLL("charcount.so")
mydll.charcount.argtypes = [ctypes.c_char_p]
mydll.charcount.restype = ctypes.c_int
print mydll.charcount("Hello")

実行すると文字列の長さの 5 がプリントされました。
次に、文字列を渡して、それを変更して返すような関数を作ってみます。

/* editstring.c */
#include
#include
char *editstring(char *s)
{
    char buff[1024];
    sprintf(buff, "*** %s ***", s);
    strcpy(s, buff);
    return s;
}

バッファ内で文字列を編集して、それを渡された文字列領域にコピーして、
そのポインタを返す関数です。

渡した文字列領域が編集されることになります。
Pythonの文字列は変更できないので、編集のための文字列バッファを用意するらしいです。
Pythonスクリプトは以下の通りです。

import ctypes
mydll = ctypes.CDLL("editstring.so")
mydll.editstring.argtypes = [ctypes.c_char_p]
mydll.editstring.restype = ctypes.c_char_p

s = ctypes.create_string_buffer("Hello", 1024)
result = mydll.editstring(s)
print '[%s]' % result

実行すると、
[*** Hello ***]
と表示され、編集されたのが確認できます。
返り値の型をc_char_pにして受け取ったresultは、
そのまま文字列としてプリントされますが、sはそうはいきません。
print sとすると c_char_arrayのオブジェクトであると表示されます。
その中の文字列をプリントするときは、
print '%s' % s.value
とするとよいようです。

でも、普通にbuffのポインタを返したらよいかな。
/* newstring.c */
#include
char *newstring(char *s)
{
    char buff[1024];
    sprintf(buff, "*** %s ***", s);
    return buff;
}
こちら、コンパイルすると「関数が局所変数のアドレスを返します」
と警告が出ます。それはそうですよね。

この関数を抜けると、このメモリ領域は、解放されてしまいそうですが、、、。
Pythonスクリプトは以下の通り。

import ctypes

mydll = ctypes.CDLL("newstring.so")
mydll.newstring.argtypes = [ctypes.c_char_p]
mydll.newstring.restype = ctypes.c_char_p
string =  mydll.newstring("Hello")
print string

ちゃんと*** Hello ***と出力されました。
このような書き方のほうが書きやすいですね。
直接渡した文字列をいじる必要がなければ、create_string_buffer()
は使わなくてもよいのでしょうか。
type(string)すると、となります。
でもちょっとメモリが心配。

Python側で文字列バッファを用意したほうがいいかな。

次は、複数の実数値が入った配列をPythonから渡して、その和を返すようなC関数を試してみます。

/* sumvalues.c */
#include
double sumvalues(double *v, int n)
{
    int i;
    double sum;
    sum = 0.0;
    for (i=0; i    {
        sum = sum + v[i];
        printf("%f\n", v[i]);
    }
    return sum;
}


配列の長さはCの関数から分かりませんので、その長さも渡すようにしています。

コンパイルして、共有ライブラリを作ります。
gcc -c sumvalues.c
gcc -shared -o sumvalues.so sumvalues.o

Pythonスクリプトは以下の通り

import ctypes
mydll = ctypes.CDLL("sumvalues.so")
mydll.sumvalues.restype = ctypes.c_double

n = 10
nvalues = ctypes.c_double * n
vlist = nvalues(*[1.0+i*1.0 for i in range(n)])
print vlist, len(vlist)

v = mydll.sumvalues(vlist, ctypes.c_int(n))
print v

共有ライブラリをを呼び出すところと、返り値を指定するのは同じです。
配列を使うときは、まず長さ分の型を作ります。
nvaluesという型で、長さがnのctypes.cdoubleの型を作ります。
その型でvlistというn個の実数値が配列に入ったものを作成します。

len()を用いてvlistの長さを調べることができます。
vlistは、c_double_Array_10オブジェクトになっています。
vlistは、ctypesの型になっていますので、あらためてargtypesで設定する必要もありません。長さだけ、ctypes.c_int()の型にして渡します。
1から10までの足し算をすることができました。

実際に利用するときは、Pythonの関数でラッピングするとよいかと思いました。
そのように書いたPythonスクリプトは以下の通りです。

import ctypes
mydll = ctypes.CDLL("sumvalues.so")
mydll.sumvalues.restype = ctypes.c_double

def sumvalues(vlist):
    n = len(vlist)
    nvalues = ctypes.c_double * n
    arg1 = nvalues(*vlist)
    v = mydll.sumvalues(arg1, ctypes.c_int(n))
    return v

if __name__ == '__main__':
    vlist = [1.0+i*1.0 for i in range(10)]
    v = sumvalues(vlist)
    print v

次は、複数の値を返してもらう関数を書いてみます。
関数は、基本的に一つの値しか返しません。
ですので、引数に値を入れてもらうための変数(へのポインタ)を渡すことにします。

ソースファイル
/* summean.c */
#include
int summean(double *v, int n, double *sum, double *mean)
{
    int i;
    double s;
    s = 0.0;
    for (i=0; i    {
        s = s + v[i];
    }
    *sum = s;
    *mean = s/n;
    return 0;
}

コンパイルして共有ライブラリを作成します。
gcc -c summean.c
gcc -shared -o summean.so summean.o

Pythonスクリプトは以下の通り


import ctypes
mydll = ctypes.CDLL("summean.so")

def summean(vs):
    n = len(vs)
    nvalues = ctypes.c_double * n
    vlist = nvalues(*vs)
    s = ctypes.c_double(0.0)
    m = ctypes.c_double(0.0)
    mydll.summean(vlist, ctypes.c_int(n), ctypes.pointer(s), ctypes.pointer(m))
    return (s.value, m.value)

if __name__ == '__main__':
    vs = [1.0+i*1.0 for i in range(10)]
    s, m  = summean(vs)
    print s, m

前と同様にPythonスクリプトでsummean関数としてラッピングしました。
結果を保存する変数sおよびmをc_double(0.0)で用意します。
関数summeanには、そのポインタを渡す必要があるため、ctypes.pointer()関数を利用しています。
Pythonの関数の返り値として、s.valueおよびm.valueをタプルにして返します。


つぎは、いよいよ構造体です。まずは、シンプルな構造体を渡して、その内容を参照した計算結果が返ってくる関数を作ってみたいと思います。
ここでは、四角の左、右、下、上の座標を格納する構造体です。
ソースファイル
/* squarearea.c *\
#include

typedef struct {
    double left;
    double right;
    double bottom;
    double top;
} SQUARE;

double squarearea(SQUARE sq)
{
    double area;
    double width;
    double height;
    width = sq.right - sq.left;
    height = sq.top - sq.bottom;
    area = width * height;
    return area;
}

コンパイルして、共有ライブラリを作成します。
gcc -c squarearea.c
gcc -shared -o squarearea.so squarearea.o

次に、Pythonスクリプトです。
Pythonスクリプト側で構造体を取り扱うためには、ctypes.Structureを継承したクラスを作ります。
そのクラスに、_fields_属性を設定することで、Cの構造体と一致させるということです。
_fields_属性は、フィールド名 と フィールド型 を持つ 2要素タプル のリストです。
ctypes.Structureで定義されているコンストラクタが、このフィールドを参照して、初期化するようです。

Pythonスクリプトは、以下のようになりました。
 

import ctypes
mydll = ctypes.CDLL("squarearea.so")

class SQUARE(ctypes.Structure):
    _fields_ = [('left', ctypes.c_double),
                ('right', ctypes.c_double),
                ('bottom', ctypes.c_double),
                ('top', ctypes.c_double)]

if __name__ == '__main__':
    sq = SQUARE(0.3, 0.8, 0.4, 3.4)
    mydll.squarearea.restype = ctypes.c_double
    v = mydll.squarearea(sq)
    print v

幅0.5、高さ3ですので、1.5が返ってきます。
返り値の型を設定するのを忘れないようにしましょう。


C言語で返り値として構造体を使うと、複数の値を返すことができて便利ですよね。
先ほどの関数で、高さを1/2したものを返すようにしてみましょう。

ソースファイル
/* squarehalf.c */
#include

typedef struct {
    double left;
    double right;
    double bottom;
    double top;
} SQUARE;

SQUARE squarehalf(SQUARE sq)
{
    double area;
    double width;
    double height;
    SQUARE hsq;
    hsq = sq;
    height = sq.top - sq.bottom;
    hsq.top = hsq.bottom + height/2.0;
    return hsq;
}

hsqにsqを入れて、そのtopの値を、半分の高さになるように設定しなおしています。
コンパイルして、共有ライブラリを作ります。
gcc -c squarehalf.c
gcc -shared -o squarehalf.so squarehalf.o

Pythonスクリプト
import ctypes
mydll = ctypes.CDLL("squarehalf.so")

class SQUARE(ctypes.Structure):
    _fields_ = [('left', ctypes.c_double),
                ('right', ctypes.c_double),
                ('bottom', ctypes.c_double),
                ('top', ctypes.c_double)]

if __name__ == '__main__':
    sq = SQUARE(0.3, 0.8, 0.4, 3.4)
    v = SQUARE()
    mydll.squarehalf.restype = SQUARE
    v = mydll.squarehalf(sq)
    print sq.left, sq.right, sq.bottom, sq.top
    print v.left, v.right, v.bottom, v.top

返り値をSQUAREにすることと、返り値を入れる変数vをSQUARE()クラスのインスタンスにしただけです。
0.3 0.8 0.4 3.4
0.3 0.8 0.4 1.9
と出力され、半分の高さの四角を表すデータになりました。


構造体の中に、別の構造体がある場合はどう書けるのでしょうか。
先ほど面積を求めた四角を、左下、右上の座標データPOINTで表してみます。

/* squarearea2.c */
#include

typedef struct {
    double x;
    double y;
} POINT;

typedef struct {
    POINT leftbottom;
    POINT righttop;
} SQUARE;

double squarearea(SQUARE sq)
{
    double area;
    double width;
    double height;
    width = sq.righttop.x - sq.leftbottom.x;
    height = sq.righttop.y - sq.leftbottom.y;
    area = width * height;
    return area;
}

コンパイルして共有ライブラリにします。
gcc -c squarearea2.c
gcc -shared -o squarearea2.so squarearea2.o

Pythonスクリプトは以下のようになりました。
import ctypes
mydll = ctypes.CDLL("squarearea2.so")

class POINT(ctypes.Structure):
    _fields_ = [('x', ctypes.c_double),
                ('y', ctypes.c_double)]

class SQUARE(ctypes.Structure):
    _fields_ = [('leftbottom', POINT),
                ('righttop', POINT)]

if __name__ == '__main__':
    sq = SQUARE(POINT(0.3, 0.4), POINT(0.8, 3.4))
    v = SQUARE()
    mydll.squarearea.restype = ctypes.c_double
    v = mydll.squarearea(sq)
    print v

それぞれ対応するクラスを書いただけで、意外なところはないですね。
ただ、クラス定義する順番で、POINTをSQUAREの後で行うと、
SQUAREで利用しているPOINTが定義できないというエラーが起こります。

構造体の定義では、その中に自分自身をもつものもありますね。
再帰的な構造は、中に同じ自分自身の型へのポインタを入れたりします。
不完全型と呼ばれているようです。
簡単のため、
(v1, (v2, (v3, (v4, (v5, NULL)))))
のようなリストに似た形のデータを考えてみます。

ソースファイル
/* showlist.c */
#include

struct CELL {
    int value;
    struct CELL *next;
};

int showlist(struct CELL *c, int flg)
{
    printf("(%d, ", c->value);
    if ((struct CELL *)NULL != c->next)
            showlist(c->next, 0);
    else
        printf("NULL");
   
    if (1 == flg)
        printf(")\n");
    else
        printf(")");
    return 0;
}

CELLという型の定義の中に、CELLへのポインタが含まれています。
前の例のように、typedef struct { ... } CELL; のような書き方をすると、コンパイル時にエラーがでます。使われるより前の方に、CELLというワードが入るような記述をする必要があるということです。

showlistは、再帰的に呼び出される関数で、渡されたCELLの値を出力したのちに、続くCELLの描画を行うため、showlistを呼び出します。nextに、NULLポインタが入っていれば、そこで終了です。
flgは、最初に呼び出すときに1をセットすると、それ以降とを区別することができます。

コンパイルして、共有ライブラリにします。
gcc -c showlist.c
gcc -shared -o showlist.so sholist.o

このような不完全な構造体定義の場合、Pythonスクリプトは、次のようにするようです。

import ctypes
mydll = ctypes.CDLL("showlist.so")

class CELL(ctypes.Structure):
    pass

CELL._fields_ = [('value', ctypes.c_int),
                ('next', ctypes.POINTER(CELL))]

if __name__ == '__main__':
    c = CELL(0, None)
    for i in range(5):
        c = CELL((i+1), ctypes.pointer(c))
    mydll.showlist(ctypes.pointer(c), ctypes.c_int(1))

クラスCELLの定義では、なにも行わずに、あとから改めて_fields_属性を設定するようです。

ctypes.POINTER(CELL)で、CELLへのポインタ型という指定ができます。
実際に利用するときに、CELL型のcというもののポインタは、ctypes.pointer(c)で得ます。紛らわしいですね。

Pythonスクリプトでcの値を設定していき、showlistにcへのポインタと整数1を渡すと、
(5, (4, (3, (2, (1, (0, NULL))))))
と表示されます。この表示は、C関数内で行われたものです。
 


このようにctypesを使って共有ライブラリを呼び出す方法だと、CのソースファイルにPythonで利用するという配慮をせずに、Pythonから呼び出すことができました。

Pythonスクリプト側で、ちょっと使いやすいように包んであげれば呼び出しやすくなるかと思います。

f2pyを使ってFortranプログラムで計算するのもいいのですが、すでにCの関数を作っているようなら、この方法は便利ですね。

ということで、自作のガウス分布をフィットするルーチンをPythonから呼び出してみました。速度の比較のために、Pythonスクリプトでも書いてみました。numpyを利用せずに、Cのソースをほぼ1対1に直したものです。

#--- C func ---
#1.02713    0.0241351
#4.93666    0.0580069
#-0.938185    0.023901
#2.49769    0.0360503
# time_c = 0.000507835 s
#--- Python func ---
#1.02713    0.0241351
#4.93666    0.0580069
#-0.938185    0.023901
#2.49769    0.0360503
# time_py = 0.00944325 s
#-------------------
# time_py/time_c = 18.5951
#-------------------

200点のデータをフィットしました。やっぱりCで記述されたものは早いですね。
Pythonスクリプトの方は、numpyの機能を利用して実装すると、どこまで速くなるのでしょうか。




2013年10月19日土曜日

Latitude10にWindows8.1をインストール

WindowsストアにWindows8.1のアップデートがきました。
評判はあまりよくない様子もあり、ドライバの互換性など心配もありましたが、
さっそくインストールしてみました。

念のため電源ケーブルを接続して、Latitude10を起動します。

まず、WindowsストアからWindows8.1のダウンロードを開始しました。
「ダウンロード中もほかの作業ができます」と表示されますが、そのままほっておきます。

30分ほどたった頃、「互換性をチェックしています」と表示されました。
プログレッシブバーは、半分をちょっとすぎたところです。
それから5分ほど経過し、「変更を適用しています」とのこと。
互換性チェックは、問題なかったのでしょうか。
さらに5分後、「情報を集めています」に。
そして20分ほど経過して、「再起動の準備をしています」に。
5分ほどで、再起動を促すメッセージが表示されました。
もちろん「今すぐ再起動」します。
画面が消えた後、DELLのマークが表示され、「設定しています(xx%)」という表示に。
まだ時間はかかりそう。
20分ほどで、「デバイスの準備をしています」に。こちらははやい。
画面が消えて点いて、「準備しています」に。
1分ほどで「PC設定を適用しています」が表示されました。
5分ほど後、画面が2度消えて、「その他の処理を実行しています」に。
その後8分ほどで、「準備しています」になり、すぐに、ライセンス条項が表示されました。
「同意します」で設定に進みます。
「自分で設定する」を選び、「IEの閲覧履歴をMicrosoftに送る」というものをオフにしました。
次に、アカウントのセットアップに進みます。
これまでローカルアカウントで利用していたのですが、設定が見当たりません。
「新しくアカウントを作成」を選んで、「すでにもっているアカウントを使い続ける」を選びました。
すると、次に進むことができて「アプリをインストールしています」が表示されました。
「最後の処理をしています」「PCの電源を切らないでください」と表示され、
5分ほどで、スタート画面が表示されました。
アカウントは、これまで利用していたローカルになっている様子です。
ダウンロードをはじめてから、1時間45分ほどかかりました。


インストールしているストアアプリの起動をチェックしてみます。
タスクリスト OK
Yahoo!天気 OK
NoteAnytimePremium OK
RubyReader OK
乗換NAVITIME OK
FlightAware OK
Skyscanner OK
PDF Touch OK
CamiApp OK
TuneIn Raddio OK
gMaps OK
GoogleSearch OK
Bingの検索が見当たりませんが、使っていなかったので問題ありません。
スタート画面の最後のページの下矢印で「すべてのアプリ」表示になるのですね。
こちらは以前、文字でちゃんと記述されていた方がわかりやすかったと思います。

デスクトップに移って、自分のPythonスクリプトの動作チェックをしました。
ImageViewer OK
QR Camera OK
Pomera Fix OK
gKey OK
Address Book OK
普段使っているものは問題なく動いたので安心しました。

さて、Pomera Fixの動作を確認するときに気がつきましたが、dm100のBluetooth接続は、ドライバーエラーになっています。
Bluetoothデバイスの追加を行うと、管理画面になります。
そこでドライバーエラーとなっているdm100デバイスを、いったん削除します。
その後、dm100の方から、キーボード接続を開始すると、dm100が見つかりペアリングできるようになります。
ペアリングを選んで、ペアリングコードをdm100から入力するとペアリング完了です。
これでまたdm100をBluetoothキーボードとして利用できます。

dmm100とのファイル転送も、様子が変わりました。
コントロールパネルのデバイスとプリンターの表示で、dm100デバイスにファイル転送のサービスを登録するところは、前に書いたとおりです。
その後は、デスクトップのPCを開くと、デバイスとドライブのところにdm100が表示されており、そこを開くとポメラ側の内蔵メモリやSDカードが表示されました。これはわかりやすくなりましたね。
この投稿はポメラで書いて、Win8.1にアップデートしたLatitude10へBluetoothでファイルを転送し、Dropboxを経由して、普段使いのノートPCで追加、修正して投稿しています。

デジタイザペンですが、最近WacomのタブレットPC用ドライバISD_DualTouch_712-9で、スリープ時の電源LEDの点灯問題が解決していたのですが、Windows8.1にアップデートしてから再びスリープ時にも点灯し続けています。
この問題が解決されたから、このドライバをいれたという人は注意が必要かもしれません。

ということで、大きな問題なく、利用できそうなので安心です。
でもLatitude10では、電源シャットダウンは、チャームだしてやっているので、今のところ使い勝手は変わりないかも。

2013/10/20 追記
アップデートと関係があるかわかりませんが、その後のあやしい動作。
一度、画面が点描みたいになりました。再起動したら直りました。
一度、バッテリーが認識できないという表示になった。再起動したら直りました。

BIOS A07、チップセットA06をインストールしたところ、スリープでのLED点灯不具合は解消されました。

2013/10/24 追記
Latitude10のBIOSのA08がでたので、入れてみました。
すると、Windows8.1の設定画面の文字が白く塗りつぶされて見えなくなりました。
デスクトップのIEを開いて、Windows Updateを確認したところ、
Intel(R) Corporation driver update for Intel(R) Graphics Media Accelerator
のドライバ更新がきていたので、それを適用したところ、その問題は解消されました。
BluetoohキーボードのドライバHIDデバイスがエラーになっていましたが(それでも利用できましたが)、それが解消されました。その代わり、ポメラをファイル転送で接続できなくなりました。
コントロールパネルのデバイスの表示で、DM100キーボードを右クリックでプロパティが表示されないのです。前のようにDM100のキーボードにFTPサービスを追加することができません。

しかたがないので、Bluetoothのデバイス追加画面でDM100のキーボードを削除します。そして、DM100からファイル転送をかけてみたところ、今度は、DM100をドライブとして認識しました。デスクトップのPCを開くと、DM100があります)開くと、DM100側のファイルを見ることができ、こちらへコピーしてくることができました。(DM100を開いたところで、ポメラ側が接続状態になりました。)
もちろん今度は、キーボードとして利用できません。

ということで、キーボードかファイル転送か、どちらかとしては利用できるようです。いちいちデバイスを削除するだけですが、以前のように手軽にはいきませんね。とりあえず、Latitude10で外付けキーボードを利用する機会はあまりないので、ファイル転送状態で維持しておきます。

A08で、Wacomドライバを用いても、スリープでLEDが消灯することは確認できました。
ソフトウェアで、いろいろ変わるようで、これからのアップデートも楽しみです。

2013/10/27 追記
その後、Windows Updateや、win8.1用のチップセットドライバーをインストールしたところ、以前のようにデバイス表示で、ポメラdm100を右クリックしたときのメニュー表示も出来るようになっていました。これで、サービスの追加もできるようになったと思うので、以前のようなポメラとの連携もできるかと期待してます。また試してみます。win8.1の動作も安定してきたかな。

2013/10/29 追記
ポメラとBluetooth接続してみました。以前のように、ポメラでキーボードかファイル転送かを選択するだけで、どちらの機能も利用できるようになりました。最初に、ストレージで、ペアリングしてもあとからキーボードのサービスを追加するだけでよいようです。