MacPortがハングする→原因はxcrunだった

MacPortsがinstall/uninstallをすると何も言わずにハングするようになってしまい、どうやって直したものかとしばらく悩んだ。

  • 一晩放置しても何も進展せずメッセージも出ない
  • Ctrl-Cで死なず、他のターミナルや電源OFFダイアログまで固まる
  • rm /opt/local/var/macports/registry/.registry.lockで解決しない
  • mv /opt/local/var/macports/ ... してMacPortをパッケージから再インストールしても状況は変わらず

諦めてHomebrewを入れたら、あっさり答えがわかった。「Error: Your xcode-select path is currently set to '/'. 」だそうな。

$ brew search scikit-learn 
Error: Your xcode-select path is currently set to '/'. 
This causes the `xcrun` tool to hang, and can render Homebrew unusable. 
If you are using Xcode, you should: 
  sudo xcode-select -switch /Applications/Xcode.app 
Otherwise, you should: 
  sudo rm -rf /usr/share/xcode-select 

sudo xcode-select -switch /Applications/Xcode.app したらMacPortもちゃんと動くようになった。

scikit-learnをインストールした

MacOSX(10.7.5)でInstalling scikit-learnを見ながらpip installしたらあっさり成功したので喜んでいたのだが、いざ使ってみるとsoを読もうとしてATLで始まるシンボルを見つけられずにエラーになる。

import sklearnが成功しただけで満足して、ちゃんと「nosetests sklearn --exe」しなかったのがいけない。動的に読み込まれるものがちゃんと動くかどうかテストすることが必要だった。

今回の問題は、振る舞いとしてはこれと同じ:python - scikit-learn fails to load - Stack Overflow

from .cd_fast import sparse_std
ImportError: sklearn/linear_model/cd_fast.so: undefined symbol: ATL_dcopy

で、こちらではワークアラウンドスクリプトが紹介されている。Linking problem with atlas on OS X · Issue #1247 · scikit-learn/scikit-learn

このスクリプトは「-L/opt/local/libが付いているコマンドを、全部-L/opt/local/libを削って再実行」というもの。しかし、あれはportでいれて、これはpipで入れて、それはソースからワークアラウンドスクリプト噛ませて入れて、というのはなるべくしたくないなぁ。

MacPortで入っているATLASが悪さをしている風だったので、まずMacPortをバッサリ削除して、そこからport install py27-scikit-learnで入れたらどうなるかを確認してみた。テストでATLAS系の問題が引っかからなくなった。めでたしめでたし。

でもテストは1個エラーになる。

======================================================================
ERROR: sklearn.cluster.bicluster.tests.test_utils.test_get_submatrix
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sklearn/cluster/bicluster/tests/test_utils.py", line 43, in test_get_submatrix
    assert_true(np.all(X != -1))
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py", line 422, in assertTrue
    if not expr:
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/sparse/base.py", line 183, in __bool__
    raise ValueError("The truth value of an array with more than one "
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().

----------------------------------------------------------------------
def test_get_submatrix():
    data = np.arange(20).reshape(5, 4)
    rows = [True, True, False, False, True]
    cols = [False, False, True, True]
    for X in (data, csr_matrix(data)):
        submatrix = get_submatrix(rows, cols, X)
        if issparse(submatrix):
            submatrix = submatrix.todense()
        assert_array_equal(submatrix, [[2, 3],
                                       [6, 7],
                                       [18, 19]])
        submatrix[:] = -1
        assert_true(np.all(X != -1))

これcsr_matrix(data)がsparse matrixを返して、X != -1でブロードキャストされてboolのsparse matrixになって、 *それがnp.allに渡されてもなぜかboolではなくsparse matrixが返る* という現象なのでsparse matrixのバグかnp.allの設計がイケてないのかじゃないかと疑っているが、まあ続きは今度気が向いたら追いかける。