Conteúdo


Integre código do MATLAB no InfoSphere Streams

Compile funções do MATLAB em bibliotecas C++ e importe no SPL para execução em aplicativos do Streams

Comments

Visão geral

Este artigo descreve como executar funções do MATLAB dentro de aplicativos do InfoSphere Streams. O MATLAB é uma linguagem e plataforma de computação científica. Devido ao seu forte suporte para manipulação de matriz e sua grande coleção de bibliotecas de modelagem matemática, ele tornou-se uma escolha de implementação popular para diversos ativos analíticos. A reimplementação desses ativos analíticos em outras linguagens é frequentemente trabalhosa devido à necessidade de encontrar bibliotecas externas que forneçam a funcionalidade já incorporada no MATLAB. Isso cria uma forte motivação para integrar funções escritas no MATLAB em aplicativos do InfoSphere Streams sem reescrever a lógica de função em C++ ou Java™, que são as linguagens de primeira classe suportadas pelo Streams.

O MATLAB oferece suporte à compilação de funções escritas na linguagem de programação do MATLAB (em arquivos .m) em bibliotecas compartilhadas C++. Ele também fornece APIs para escrever código C++ que interaja com a biblioteca gerada, assim como classes de utilitários que fornecem tipos de dados de matriz. Além disso, o MATLAB também fornece uma biblioteca de tempo de execução para fazer links, para aplicativos que usam as rotinas do MATLAB compiladas em C++. A abordagem geral da integração de funções do MATLAB no Streams é a seguinte:

  1. Desenvolva sua(s) função(ões) do MATLAB.
  2. Use o compilador do MATLAB para criar uma biblioteca compartilhada C++.
  3. Crie uma função nativa em SPL que encapsule a biblioteca compartilhada C++.
  4. Escreva um aplicativo do SPL que use as funções ativas.

Essas etapas são ilustradas pela amostra a seguir.

Desenvolva sua função do MATLAB

Você escreverá uma função simples do MATLAB que executa a inversão de matriz.

Crie um diretório chamado Matlab_inv e coloque nele um arquivo chamado ml_inv.m , com o seguinte conteúdo:

  function out = ml_inv(in)
  % ML_INV Matrix inverse
  % Invert a given matrix
  out = inv(in);

Seu objetivo é ser capaz de usar essa função inversa de matriz no código SPL. Segue uma amostra de função SPL que utiliza a função inversa de matriz ml::inv que encapsula a função ml_inv do MATLAB. No restante deste artigo, você observará as etapas necessárias para criar o ml::inv .

  void foo() 
  {   // Sample SPL code that uses the matrix inverse
      list<list<float64>> inM = [[1.0,3.0],[2.0,4.0]];
      mutable list<list<float64>> outM = [];
      ml::inv(outM, inM); // ml::inv is the wrapper for ml_inv
  }

Use o compilador do MATLAB para criar uma biblioteca compartilhada C++.

Você usará o compilador do MATLAB para criar uma biblioteca compartilhada C++ que conterá a função de inversão de matriz.

  1. Na linha de comando do MATLAB, digite deploytool.
  2. Siga a interface gráfica para criar um projeto de implementação chamado libMatlab_inv no diretório Matlab_inv .
  3. Clique no botão Add File para incluir o arquivo ml_inv.m no projeto.
  4. Clique no botão Build para criar a biblioteca compartilhada.

Os seguintes arquivos de resultado serão gerados no diretório Matlab_inv/libMatlab_inv/distrib .

  • libMatlab_inv.h: este é o arquivo de interface que declara as funções C++ geradas a partir do código do MATLAB.
  • libMatlab_inv.so: esta é a biblioteca compartilhada que contém as implementações de função C++ geradas a partir do código do MATLAB.
  • libMatlab_inv.exports: este é um arquivo de texto que relaciona o nome das funções exportadas pela biblioteca. Este arquivo não é obrigatório para a operação da biblioteca.
  • libMatlab_inv.ctf e libMatlab_inv_mcr: o primeiro é um archive, a partir do qual o segundo diretório é criado pelo compilador do MATLAB. Estes contêm bibliotecas de suporte adicionais. Elas devem estar localizadas no mesmo local da biblioteca compartilhada .so .

Experimente a biblioteca compartilhada em um aplicativo C++ independente

Antes de usar a biblioteca compartilhada em um aplicativo do Streams, você a experimentará em um aplicativo C++ independente.

Crie um diretório chamado sample_c++ no mesmo nível do Matlab_inv. Dentro desse diretório, crie um arquivo chamado sample.cpp e preencha-o da seguinte forma:

  #include "libMatlab_inv.h"
  int main()
  {
      libMatlab_invInitialize();
      double data[] = {1.0, 2.0, 3.0, 4.0};
      mwArray in(2,2,mxDOUBLE_CLASS);
      mwArray out(2,2,mxDOUBLE_CLASS);
      in.SetData(data, 4);
      ml_inv(1, out, in);
      std::cerr << "[" << out(1,1) << ", " << out(1,2) << "; "
                       << out(2,1) << ", " << out(2,2) << "]\n";
      libMatlab_invTerminate();
      return 0;
  }

No código acima, a função libMatlab_invInitialize é chamada para inicializar o tempo de execução do MATLAB. Essa é uma das funções geradas para você pelo compilador do MATLAB. Você então cria estas duas matrizes: in e out. O mwArray é uma classe C++ fornecida pelas APIs C++ do MATLAB para trabalhar com matrizes. É possível usar a função ml_inv para tomar o inverso da matriz in e atribuí-lo à matriz out . Essa é a função principal gerada para você pelo compilador do MATLAB, com base na função do MATLAB com o mesmo nome a partir do arquivo ml_inv.m . Finalmente, a função libMatlab_invTerminate é chamada para finalizar o tempo de execução do MATLAB. Novamente, essa é uma função gerada para você pelo compilador MATLAB.

Para compilar esse programa, crie um Makefile da seguinte forma:

.PHONY: all clean
MATLAB_LIBRARY_LOCATION := /nfs/hny/apps01/matlab/bin/glnxa64/
MATLAB_INCLUDE_LOCATION := /nfs/hny/apps01/matlab/extern/include/
all: 
	g++ -o sample sample.cpp                           \
            -I ../Matlab_inv/libMatlab_inv/distrib         \
            -I $(MATLAB_INCLUDE_LOCATION)                  \
            -L ../Matlab_inv/libMatlab_inv/distrib         \
	    -Wl,-rpath,../Matlab_inv/libMatlab_inv/distrib \
            -L $(MATLAB_LIBRARY_LOCATION)                  \
	    -Wl,-rpath,/nfs/hny/apps01/matlab/bin/glnxa64/ \
            -lMatlab_inv -lmwmclmcrrt 

clean:
	rm sample

Seguem abaixo alguns pontos que você deve observar:

  • O caminho de inclusão -I ../Matlab_inv/libMatlab_inv/distrib é usado para especificar o local do arquivo de interface (libMatlab_inv.h) gerado pelo compilador do MATLAB.
  • O caminho de inclusão -I $(MATLAB_INCLUDE_LOCATION) é usado para especificar o local dos arquivos de interface para as APIs C++ do MATLAB. Esse local será específico ao seu ambiente e dependerá do local da instalação do MATLAB. A variável $(MATLAB_INCLUDE_LOCATION) deve ser definida apropriadamente.
  • O caminho da biblioteca -L ../Matlab_inv/libMatlab_inv/distrib é usado para especificar o local da biblioteca libMatlab_inv.so) gerada pelo compilador do MATLAB. Um RPATH é especificado usando o mesmo caminho para o local do tempo de execução da biblioteca.
  • O caminho da biblioteca -L $(MATLAB_LIBRARY_LOCATION) é usado para especificar o local das bibliotecas de tempo de execução do MATLAB. Esse local será específico ao seu ambiente e depende do local da instalação do MATLAB e da arquitetura do seu sistema. A variável $(MATLAB_LIBRARY_LOCATION) deve ser definida apropriadamente.
  • A biblioteca -lMatlab_inv deve ser usada para especificar o nome da biblioteca gerada pelo compilador do MATLAB (libMatlab_inv.so).
  • A biblioteca -lmwmclmcrrt é usada para especificar o nome da biblioteca de tempo de execução do MATLAB (libmwmclmcrrt.so).

Simplesmente digite make para desenvolver a biblioteca e ./sample para executá-la. A seguinte saída deve ser produzida: [-2, 1.5000; 1, -0.5000].

Crie uma função nativa no SPL que encapsule a biblioteca compartilhada C++

Você criará funções nativas no SPL que fazem uso das funções geradas pelo compilador do MATLAB. Isso pode ser feito de duas maneiras. É possível criar um kit de ferramentas que encapsula todas as funções nativas, ou inclui funções nativas diretamente em um aplicativo. A primeira opção é mais apropriada se houver aplicativos que usarão as funções. Para concisão, use esta segunda abordagem.

  1. Crie um diretório chamado sample_spl no mesmo nível que Matlab_inv e sample_c++. Esse será seu diretório de aplicativos.
  2. Crie um subdiretório chamado ml. Esse será seu diretório de espaço de nome.
  3. Em ml, crie um subdiretório chamado native.function, que manterá o modelo de função.
  4. Nesse diretório, inclua o arquivo de modelo de função chamado function.xml, que contém o seguinte conteúdo.
<functionModel
   xmlns="http://www.ibm.com/xmlns/prod/streams/spl/function"
   xmlns:cmn="http://www.ibm.com/xmlns/prod/streams/spl/common"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.ibm.com/xmlns/prod/streams/spl/function 
                       functionModel.xsd">
  <functionSet>
    <headerFileName>spl_ml_inv.h</headerFileName>
    <functions>
      <function>
        <description>Take inverse of a matrix</description>
        <prototype><![CDATA[ public void inv(mutable list<list<float64>> r,
                             list<list<float64>> s) ]]></prototype>
      </function>
      <function>
        <description>Initialize Matlab runtime</description>
        <prototype><![CDATA[ public void initialize() ]]></prototype>
      </function>
      <function>
        <description>Finalize Matlab runtime</description>
        <prototype><![CDATA[ public void terminate() ]]></prototype>
      </function>
    </functions>
    <dependencies>
      <library>
        <cmn:description>Matrix inverse</cmn:description>
        <cmn:managedLibrary>
          <cmn:lib>Matlab_inv</cmn:lib>
          <cmn:lib>mwmclmcrrt</cmn:lib>
          <cmn:libPath>../../impl/lib</cmn:libPath>
          <cmn:libPath>/nfs/hny/apps01/matlab/bin/glnxa64/</cmn:libPath>
          <cmn:includePath>../../impl/include</cmn:includePath>
          <cmn:includePath>/nfs/hny/apps01/matlab/extern/include/</cmn:includePath>
        </cmn:managedLibrary>
      </library>
    </dependencies>
  </functionSet>
</functionModel>

No arquivo de modelo de função acima, há algumas coisas a serem observadas:

  • O arquivo spl_ml_inv.h é o arquivo de cabeçalho que contém as funções C++ que encapsularão as funções geradas pelo MATLAB.
  • As três funções nativas do SPL inv, initialize e terminate correspondem às três funções ml_inv, libMatlab_invInitialize e libMatlab_invTerminate geradas pelo compilador do MATLAB. Observe que a função inv usa listas aninhadas do SPL para representar matrizes, já que não há tipos de matriz no SPL. Como você verá, a função inv também executará a conversão entre tipos C++ do SPL e tipos C++ do MATLAB.
  • As bibliotecas Matlab_inv e mwmclmcrrt são especificadas como dependências, incluindo seus caminhos de biblioteca e caminhos de inclusão. Observe que os caminhos de inclusão e de biblioteca para as bibliotecas Matlab_inv são especificados relativos ao arquivo de modelo.

Agora, copie os arquivos relevantes para o subdiretório impl ,no diretório do aplicativo sample_spl , para tornar o aplicativo independente.

  1. Crie um diretório impl no diretório de aplicativo sample_spl.
  2. Crie dois subdiretórios em impl: include e lib. Copie o arquivo libMatlab_inv.h do diretório Matlab_inv/libMatlab_inv/distrib para o diretório include .
  3. Agora copie os arquivos libMatlab_inv.so e libMatlab_inv.ctf , assim como o diretório libMatlab_inv_mcr , para o diretório lib .
  4. Finalmente, crie o arquivo de cabeçalho de wrapper spl_ml_inv.h no diretório include , com o seguinte conteúdo.
  #include "libMatlab_inv.h"
  namespace ml {
      void initialize() {
          libMatlab_invInitialize();
      }
      void terminate() {
          libMatlab_invTerminate();
      }
      void inv(SPL::list<SPL::list<SPL::float64> > & lhs,
               SPL::list<SPL::list<SPL::float64> > const & rhs)
      {
          size_t nr = rhs.size(), nc = rhs[0].size();
          mwArray in(nr, nc, mxDOUBLE_CLASS);
          mwArray out(nr, nc, mxDOUBLE_CLASS);
          for(size_t r=0; r<nr; ++r)
              for(size_t c=0; c<nc; ++c)
                  in(r+1,c+1) = rhs[r][c];
          ml_inv(1, out, in);
          lhs.resize(nr);
          for(size_t r=0; r<nr; ++r) {
              lhs[r].resize(nc);
              for(size_t c=0; c<nc; ++c)
                  lhs[r][c] = out(r+1,c+1);  
          }      
      }
  }

No código anterior, a função inv executa transformações entre os tipos de list do SPL e os tipos de mwArray do MATLAB para encapsular a função ml_inv gerada pelo compilador do MATLAB. Observe que todas as funções de wrapper são colocadas no espaço de nome ml, já que seu diretório native.function está no diretório de espaço de nome ml.

Escreva um aplicativo do SPL que use as funções nativas.

Escreva um aplicativo do SPL que usa as funções nativas para encapsular as funções geradas pelo compilador do MATLAB.

Crie um arquivo chamado Main.spl no diretório sample_spl junto com o seguinte conteúdo:

  composite Main {
      graph
          stream<int8 dummy> Beat = Beacon() { 
              param iterations : 1u; 
          }
          () as Sink = Custom(Beat) {
              logic
                  onTuple Beat: {
                      ml::initialize();
                      list<list<float64>> inM = [[1.0,3.0],[2.0,4.0]];
                      mutable list<list<float64>> outM = [];
                      ml::inv(outM, inM);
                      println(outM);
                      ml::terminate();
                  }
          }
  }

Este é um aplicativo de amostra do SPL que inicializa o tempo de execução do MATLAB, executa uma inversão de matriz por meio da função ml::inv e finaliza o tempo de execução do MATLAB.

  1. Digite sc -m -M Main no diretório sample_spl para criar um Makefile para este aplicativo.
  2. Então, digite make standalone para compilá-lo.
  3. É possível que alguns avisos sejam exibidos. Ignore os avisos supérfluos (versões futuras do Streams podem incluir suporte para suprimir esses avisos) e digite ./output/bin/standalone para executar o aplicativo. Deve-se encontrar o seguinte resultado: [[-2,1.5],[1,-0.5]].

Conclusão

Neste artigo, você viu como integrar funções do MATLAB em aplicativos do Streams sem reescrever a lógica das funções em uma linguagem diferente. A abordagem utiliza o compilador do MATLAB para converter o código do MATLAB em bibliotecas compartilhadas C++, escrevendo uma função C++ nativa que encapsula essa biblioteca compartilhada e importando a função de wrapper para o SPL usando um modelo de função. O código de origem para o exemplo dado em nossa discussão é fornecido neste artigo.


Recursos para download


Temas relacionados

  • Saiba mais sobre "IBM InfoSphere Streams" (Maio de 2011) é a página de produto do Streams.
  • Leia sobre o "MathWorks MATLAB Compiler" (Maio de 2011) é a página de produto do MATLAB Compiler.
  • Crie seu próximo projeto de desenvolvimento com a versão de teste do software IBM, disponível para download diretamente no developerWorks, ou dedique algumas horas à SOA Sandbox aprendendo como implementar Arquitetura Orientada a Serviços de forma eficiente.

Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Information Management
ArticleID=697383
ArticleTitle=Integre código do MATLAB no InfoSphere Streams
publish-date=07052011