Hatena::ブログ(Diary)

arupaka-_-arupakaの日記

2013-07-04

scalaで配列のランダムシャッフル c++の関数の利用

JNAを使ってc++シャッフル関数と連携.

c_shuff_test.scala


import com.sun.jna.Library;
import com.sun.jna.Native;

import com.sun.jna.NativeLibrary;


object c_shuff_test{



        def main(args: Array[String]): Unit={

                val lib=NativeLibrary.getInstance("shuffle.dll");
                val func=lib.getFunction("shuff_array");
                var a=Array(1.0,2.0,3.0);

 
                var f12=func.invoke(Array(a,a.length.asInstanceOf[java.lang.Integer]));
                a.foreach{println;}


        }





}


shuffle.cpp

#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

class Random
{
public:
  
        Random()
        {
               // 初期化しすぎるとおかしくなる 1秒に一度しかシードかわらないので
               // srand( static_cast<unsigned int>( time(NULL) ) );
        }


        unsigned int operator()(unsigned int max)
        {
                double tmp = static_cast<double>( rand() ) / static_cast<double>( RAND_MAX );
                return static_cast<unsigned int>( tmp * max );
        }
};

extern "C" void* shuff_array(double* v,int n)
{      
        int i;

        Random r;
        random_shuffle(&v[0],  &v[n], r );  // ランダムシャッフル

};



shuffle.h

#ifndef shuffle
#define shuffle


#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <stdio.h>
using namespace std;

        extern "C" void shuff_array(double* v,int n);


#endif
compile.sh

コンパイルスクリプトc++

filename=$1;
filename=`basename $filename .cpp`
filename2=`basename $2 .cpp`

echo $filename;
echo $filename2;

x86_64-w64-mingw32-g++ -c $filename.cpp -static-libstdc++ -static-libgcc
echo "test"
x86_64-w64-mingw32-g++ -shared -o $filename.dll $filename.o -static-libstdc++ -static-libgcc

echo "test2";
x86_64-w64-mingw32-g++ $filename2.cpp -o $filename2.out -L. -l$filename -static-libstdc++ -static-libgcc

コンパイル c++

sh compile.sh shuffle.cpp random_shuffle.cpp

コンパイル scala

scalac -cp jna.jar c_shuff_test.scala

実行 (コンソールで)

scala c_shuff_test

実行結果

2.0

3.0

1.0


メルセンヌツイタ版 mainの部分は実験用,消す。

また,mt19937ar.cのメインの部分も消しておく

wget http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c

#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <time.h>
#include "mt19937ar.c"

using namespace std;

class Random
{
public:
        // コンストラクタ
        Random()
        {
//              srand((unsigned)( time(NULL) ) );
//              init_genrand((unsigned)time(NULL));
//              printf("%ld\n",(unsigned)(time(NULL)));
//              cout << time(NULL) << "\n";
        }

        // 関数オブジェクト
        unsigned int operator()(unsigned int max)
        {
//              double tmp = static_cast<double>( rand() ) / static_cast<double>( RAND_MAX );
//              printf("%d\n",max);
//
                double tmp = static_cast<double>( genrand_real2() );
                return static_cast<unsigned int>( tmp * max );
        }
};

extern "C" void* shuff_array(double* v,int n)
{       //int n;
        int i;

        Random r;
        random_shuffle(&v[0],  &v[n], r );  // ランダムシャッフル

//      random_shuffle(&v[0],  &v[n] );  // ランダムシャッフル
//      double *a= &nums[0];
};

int main(){
        double a[4]={1.0,2.0,3.0,4.0};
        int i;
        int t;
        for(t=0;t<=10000;t++){

//              srand( static_cast<unsigned int>( time(NULL) ) );
                a[0]=1.0;
                a[1]=2.0;
                a[2]=3.0;
                a[3]=4.0;
                shuff_array(a,4);
                for(i=0;i<4;i++){
                        cout << a[i] <<"," ;
                }

                cout<<"\n";
        }
        return 0;
}

scalaからc++関数を使う

scalaからjnaでc++関数を使う。

少しはまった.

ポイントは関数にextern "C" をつけること.

C++では、関数オーバーロード(多重定義)などが原因で

関数名で関数が特定できない(識別子がつくらしい)。

そこで、C方式の関数名として宣言しておく.

http://www.geocities.jp/ky_webid/cpp/language/038.html

http://ja.softuses.com/112083

また,コンパイルオプションがCの場合と少し違う

ライブラリがないといわれるので、staticオプションをつけてライブラリとリンクしとく

http://convenient.blog106.fc2.com/blog-entry-764.html




cpp_test.scala

import com.sun.jna.Library;
import com.sun.jna.Native;

import com.sun.jna.NativeLibrary;


object cpp_test2{


        def main(args: Array[String]): Unit={


                val lib=NativeLibrary.getInstance("cpp_test2.dll");
                val func=lib.getFunction("test1");
                func.invokeVoid(Array(a,a.length.asInstanceOf[java.lang.Integer]))



        }





}

cpp_test2.cpp

#include<iostream>
using namespace std;

extern "C" void test1(){

        cout << "hello22\n";

}

cpp_test2.h

#ifndef cpp_test2
#define cpp_test2
#include<iostream>
using namespace std;

extern "C" void test1();

#endif

コンパイル dll

filename=$1;
filename=`basename $filename .cpp`
#filename2=`basename $2 .cpp`

echo $filename;
#echo $filename2;

x86_64-w64-mingw32-g++ -c $filename.cpp -static-libstdc++ -static-libgcc
echo "test"
x86_64-w64-mingw32-g++ -shared -o $filename.dll $filename.o -static-libstdc++ -static-libgcc

#echo "test2";
#x86_64-w64-mingw32-g++ $filename2.cpp -o $filename2.out -L. -l$filename -static-libstdc++ -static-libgcc

実行結果

hello22

scalaとC言語で配列の値の1をたす,ポインタ渡しの例

cpp_test.scala

import com.sun.jna.Library;
import com.sun.jna.Native;

import com.sun.jna.NativeLibrary;


object cpp_test{


        def main(args: Array[String]): Unit={


                var a=Array(1.0,2.0,3.0);

                println("Input");
                a.foreach{println}
                val lib=NativeLibrary.getInstance("cpp_test.dll");
                val func=lib.getFunction("test2");
        func.invokeVoid(Array(a,a.length.asInstanceOf[java.lang.Integer]));

                println("Output");
                a.foreach{println}



        }





}

cpp_test.c

#include<stdio.h>

void test2(double r1[],int n){

        int i;

        for(i=0;i<n;i++){
                r1[i]=r1[i]+1;

        }

}

cpp_test.h

#ifndef cpp_test
#define cpp_test
#include<stdio.h>
void test2(double *r ,int n);
#endif

出力例:

Input

1.0

2.0

3.0

Output

2.0

3.0

4.0

参考 ライブラリファイル作成用のスクリプト

filename=$1;
filename=`basename $filename .c`
#filename2=`basename $2 .c`

echo $filename;
echo $filename2;

x86_64-w64-mingw32-gcc -c $filename.c
echo "test"
x86_64-w64-mingw32-gcc -shared -o $filename.dll $filename.o

echo "test2";
#x86_64-w64-mingw32-gcc $filename2.c -o $filename2.out -L. -l$filename

2013-07-02

scalaとcで内積

scalaからcの関数をよび内積を計算

loop.c

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include"loop.h"

int loop2(double* v1, double* v2,int n){
        double tmp=0;
        int i;
        for(i=0;i<n;i++){
                tmp=tmp+v1[i]*v2[i];

        }
        return tmp;

}

loop.h

#ifndef loop
#define loop

#ifdef _cplusplus
extern "C" {
#endif
        int loop2(double* v1, double* v2, int n);
#ifdef _cplusplus
}
#endif
#endif

c_test3.scala

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;

object c_test3{

        def main(args: Array[String]): Unit={

                val lib=NativeLibrary.getInstance("loop.dll");
                val func=lib.getFunction("loop2");
                val k=func.invokeDouble(Array(Array(1.0,2.0,3.0),Array(2.0,3.0,4.0),3.asInstanceOf[java.lang.Integer]));

                println(k);

        }


}

コンパイル

x86_64-w64-mingw32-gcc -c loop.c

x86_64-w64-mingw32-gcc -shared -o loop.dll loop.o

scalac -cp jna.jar c_test3.scala

コマンドプロンプト

scala c_test3.scala

出力

20.0

2013-07-01

scalaからCのプログラムを読みだす

(1)まず準備。

C言語のダイナミックリンクライブラリ(dll)を作る

 #include<stdio.h>
  
   void test_hello(char* v){
  
           printf(v);
  
  }

dll化する

gcc -c test_hello.c

gcc -shared -o test_hello.dll test_hello.o

実行用プログラム

void main(){
        test_hello("This is test");

}

コンパイル

gcc test_dll.c -o test_dll.out -L./ -ltest_hello

実行

./test_dll.out

This is test

関数名とdll名が同じじゃなきゃだめだ。

以下のようにmain関数で定義すれば大丈夫

   void test2();
   void test1(char* v);

   void main(){
          test1("This is test");
          test2();
  }

上記のdllのソース

#include<stdio.h>

void test1(char* v){

        printf(v);
        printf("\n");

}

void test2(){

        printf("hello\n");
}

ちゃんと.hを使って重複を抑えると



test_hello.h

void test1(char* v);
void test2();

test_hello.c

#include<stdio.h>
#include"test_hello.h"

void test1(char* v){

        printf(v);
        printf("\n");

}

void test2(){

        printf("hello\n");
}

main

#include<stdio.h>
#include"test_hello.h"


void main(){
        test1("This is test");
        test2();
}

http://www.sixnine.net/cygwin/translation/cygwin-ug-net/dll.html

http://www.nslabs.jp/cygwin-dll.rhtml

http://exlight.net/devel/windows/dll/windll.html

(2)次にJNA関数Javaに取り込む

http://www.brainsellers.com/blog/inastream/2011/04/introjna.html

JNAをとってくる

wget https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna/3.5.2/jna-3.5.2.jar … --no-check-certificate

http://d.hatena.ne.jp/mrgoofy33/20110204/1296829185

適当にリネーム

mv jna-3.5.2.jar jna.jar

コンパイル

javac c_test.java -classpath jna-3.5.2.jar

http://d.hatena.ne.jp/ujiujise/20091202/p1 がわかりやすい感じ。。

プログラム

test_hello.h

#ifndef test_hello
#define test_hello

#ifdef _cplusplus
extern "C" {
#endif
        void test1(char* v);
        void test2();
#ifdef _cplusplus
}
#endif
#endif

#ifdef _cplusplus

#endif

c++ のときにif endif内のコードを実行するという意味

extern "C" はC言語関数を表す


import com.sun.jna.Library;
import com.sun.jna.Native;

public class c_test{



        public interface test_hello extends Library{


                test_hello INSTANCE=(test_hello) Native.loadLibrary("test_hello",test_hello.class);


                void test1(String format);



        }

        public static void main(String[] args){
                test_hello.INSTANCE.test1("Hello World\n");

        }

}

コンパイル

javac c_test -classpath jna.jar

jnaはcygwinに対応していないので,windowsとしてコンパイルする.

mingwを使う


javaWindowsjavaか確認

/cygdrive/c/Windows/system32/java

mingwインストール

apt-cyg install mingw64-x86_64-gcc-core

コンパイル

x86_64-w64-mingw32-gcc -c test_hello.c

x86_64-w64-mingw32-gcc -shared -o test_hello.dll test_hello.o

x86_64-w64-mingw32-gcc test_dll.c -o test_dll.out -L. -ltest_hello

これでもcygwinでは実行できないので,コマンドプロンプで以下のコマンドで実行

java c_test

アドバイスを受けた人の話だとコンパイラの基礎とかわかってると

色々わかるらしい。

また

jar tf jna.jar 

でどのOSに対応しているか探ることができる

http://choni-waniwani.blogspot.jp/2013/05/playframework211scalajnac.html

scalaで導入

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;

object c_test2{

        def main(args: Array[String]): Unit={

                val lib=NativeLibrary.getInstance("test_hello.dll");
                val func=lib.getFunction("test1");
                func.invokeVoid(Array("test_hello".asInstanceOf[java.lang.String]));


                val func2=lib.getFunction("test2");
                func2.invokeVoid(null);
                //val func2=lib.getFunction("test3");
                //func2.invokeVoid(Array(10.asInstanceOf[java.lang.Integer]));

        }


}

コンパイル

scalac -cp jna.jar c_test2.scala

実行

scala c_test2.scala

結果

test_hello

hello

http://saekiyoshiyasu.org/pblog/programming/java/jna-2009-05-24-22-32.html

2013-06-24

特定の値をすべてほかの値で置き換える

20を4に置き換える。

match が b match であり,b.match でないことに注意

scala> a
res9: Array[Int] = Array(1, 20, 20, 30, 40, 50)

scala> a.map{i=> i match{case 20 => 4;case _ => i;}};
res10: Array[Int] = Array(1, 4, 4, 30, 40, 50)

scalaで内積

var a=List(1,2,3,4);
var v=List(2,3,4,5);
a.zip(v).map{i=> i._1*i._2;}.sum
res15: Int = 40