S-PLUS中使用CONNECT/C++模块与C++进行交互

 

介绍

CONNECT/C++是一个使用S语言和C++交互的接口工具。它为使用C++的程序员提供了把SPLUS引擎集成在其中的便利,同时,它也可以整合C++代码到SPLUS环境中去。

 

为了容许在GUISPLUS间通讯,在SPLUS7中,CONNECT/C++被开发用来提供了这样一个框架(基于S语句版本4)。事实上,SPLUS7 GUI提供了使用CONNECT/C++集成SPLUS引擎和C++应用更全面的例子。同样的,C++开发者也可以使用同样的技术来和SPLUS交互

 

CONNECT/C++是一个C++类库,使用这些类和它们的成员可以创建和处理大多数的本地S对象

 

为在C++程序和模块中计算S表达式,CONNECT/C++提供了一个灵活多变的机制,在SPLUS7.X中提供了许多使用这些类库的例子,其中有些例子提供了执行相同任务的等价的SC++函数,其中C++函数大多数运行时间都要快于S代码,当然这也依赖于代码的复杂度和数据的尺寸。这些例子你可以在SHOME/sconnect目录中找到,其中SHOME为你的SPLUS的安装目录。

 

资源                 

更多关于CONNECT/C++的信息,请参见SPLUS7.0 CONNECT/C++库帮助,如果你再UNIX上,请查看SHOME/connect/help/ConnectC++ .Class.library.htm文件。这个HTML文件是一个CONNECT/C++类库的C++开发者指南。它仔细讨论了如何连接到SPLUS引擎,如何建立数据对象、调用SPLUS函数和执行SPLUS语法

 

 

 

 

 

简单的例子:一个简单应用的执行流程

 

 

 

CONNECT/C++主要用于实现这2个目标:建立一个能访问SPLUS功能的C++应用;建立一个能被SPLUS调用的C++函数,下面我们开始一个简单的应用

 

 


建立一个简单的应用


这个例子是一个控制台程序,用来在应用中建立2SPLUS向量,然后使用SPLUS来建立关于这2个向量的线性模型。

 

这个代码开始行包含了一个sconnect.h文件,这是必须的,所有CONECT/C++代码必须引用这个文件。然后定义一个全局的SPLUS连接对象,这个类的名字为CSPengineConnect, 它必须在主调函数之前定义,这个CSPengineConnect类会在客户应用和SPLUS间生成一个连接,这将允许你建立SPLUS对象,并且当数据库被附加或者被卸载到客户的时候发出通知,而且还可以执行S语言表达式等。代码看起来像下面所示:

 

#include  "sconnect.h"

 

 

//  A  global  connection  object

CSPengineConnect  g_engineConnect;

 

 

int  main(int  argc,  char*  argv[])

{

 

主函数的第一步是建立一个实际的连接对象(连接到SPLUS

 

//  Create  the  connection  to  S-PLUS

g_engineConnect.Create(  argc,  argv);

 

然后我们建立变量X,Y,这个CSPnumeric用于存储数字型向量。这个类是CONNECT/C++中的一个类,被使用在C++中用来表示SPLUS中的对象,同样,也还有很多C++类对应了SPLUS中的原子对象(见表71);接下来通过使用create方法建立这个类的一个实例,通过Assign方法赋值这个类到SPLUS数据库,如下


 

 

//  Create  S  object  with  name  "x"  in  the  current  database.

//  Same  as  x<-1:10  at  the  command  line. CSPnumeric  sx;

sx.Create("1:10","x");

 

 

//  Squaring  sx,  which  is  the  same  as  S  expression

//  sy  <-  x*x  in  a  local  frame,  but  here  we  set  it  to  local

//  C++  variable  sy. CSPnumeric  sy  =  sx  *  sx;

//  Assign  the  result  as  S  object  with  name  "y"  in  the

//  current  database. sy.Assign("y");

 

最后,我们准备合适的线性模型,通过CONNECT/C++方法在适当的时候调用SPLUS执行,如下

 

//  Evaluate  z<-lm(y~x)

g_engineConnect.SyncParseEval("z<-lm(y~x)");

 

 

return  1;

}

 

这个例子的完整代码在SHOME/samples/spllmWIN下),UNIX下这个目录在SHOM E/sconnect/samples/splm.

 

要运行这个应用,打开一个命令提示或者MS-DOS窗口(WIN)或者编译(UNIX

1.   改变当前目录到包含代码的目录

 

cd  SHOME/samples/spllm

 

(WIN)

 

cd  /sconnect/samples/splm

 

(UNIX,假设当前路径为SHOME)

 

 

 

2.   编译程序

 

msdev  spllm.dsp  /make

 

(WIN)

 

Splus7  CHAPTER  -sconnectapp  *.cxx

Splus7  make

 

(UNIX)

 

3.   如果你在WIN下,检查环境变量PATH确认它包含了%SHOM E%/cmd,如果没有,你应该在运行下面的步骤前把它加上去。

 

4.   运行程序

 

spllm.exe  S_PROJ=.

 

WIN

 

Splus7  EXEC  S.app

 

UNIX

 

要验证运行结果,在相同目录下启动SPLUS控制台(WIN)或者启动SPLUSUNIX

 

sqpe.exe  S_PROJ=.

 

WIN平台上,SPLUS将返回下面信息

 

S-PLUS  :  Copyright  (c)  1988,  2005  Insightful  Corp. Version  7.0  Release  1  for  Microsoft  Windows  :  2005

Working  data  will  be  in  E:/programs/splus7.0/users/rich

 

或者输入

 

Splus7

 

UNXI上,将返回下面信息:

 

S-PLUS  :  Copyright  (c)  1988,  2005  Insightful  Corp. Version  7.0  Release  1  for  Sun  SPARC,  SunOS  5.8  :  2005

Working  data  will  be  in  .Data

 

然后查看对象X,YZ

 

[1]

1

2

3

4

>  y

 

 

 

 

[1]

1

4

9

16

 

>    x

5     6     7     8     9     10

 

 

25    36     49     64     81     100

 

 

 

>  z

Call:

lm(formula  =  y  ~  x)

 

 

Coefficients:

(Intercept)     x

-22  11

 

 

Degrees  of  freedom:  10  total;  8  residual

Residual  standard  error:  8.124038

 

 


通过CALL调用C函数的例子


 Gauss-Seidel是一个熟悉的技术,主用于线性回归系统的解决。这个算法在SPLUS中是很容易简单明了的实现,如下

 

gaussSeidel<-

#  gaussSeidel  solves  a  linear  system  using  Gauss-Seidel

#  iterative  method.

#  REQUIRED  ARGUMENTS:

#              A  and  b  are  numeric  matrix  and  vector  respectively.

#  VALUE:

#              a  vector  x,  solution  of  A  x  =  b

#

#  Usage:

#     A<-matrix(rnorm(100),nrow=10)

#     diag(A)<-seq(ncol(A),ncol(A))  #Make  it  diagonally

#                                                                             #  dominant

#     b<-rnorm(ncol(A))

#     sys.time({x1<-gaussSeidel(A,b)})

function(A,b)

{


#  Hard-coded  relative  tolerance  and  max  iterations tol<-1.0e-4

maxItr<-1e4

 

 

#  Validating

A  <-  as.matrix(A)

b  <-  as.numeric(b)

if(nrow(A)!=ncol(A)  ||  ncol(A)!=length(b))

stop("nrow(A)!=ncol(A)  ||  ncol(A)!=length(b)")

 

 

 

 

 

 

#  Begin  Gauss-Seidel  step

x<-b

for(k  in  1:maxItr)

{

xOld<-x

for(i  in  1:nrow(A))

{

s<-  A[i,i]*x[i]

for(j  in  1:ncol(A))

s  <-  s  -  A[i,j]*x[j]

x[i]  <-  (b[i]+s)/A[i,i]

}

#  Check  convergence;  continue  if  necessary if(max(abs((x-xOld)/x))  <  tol)

return(x);

}

warning("Solution  does  not  converge/n")

return(x)

}

 

这个代码中,包含了一个嵌套的循环,也许可以写成更加有效率的代码,但我们这只是一个演示。通过使用CONNECT/C++的类和方法,下面的这些代码实现了上面类似的功能

 

这些代码开始处包含了sconnect.h头文件,这样我们就可以访问SCONNECT/C++库,下一步,它包含了一个实现Gauss-Seidel的头文件

 

#  include  "sconnect.h"

#  include  "gausssdl.h"

当我们定义gaussSeidel对象作为s_object类的一个对象时,它请求通过CALL交互

 

s_object*  gaussSeidel(s_object*  ps_A,  s_object*  ps_b)

 

作为一个典型的代码,我们定义了S_EVALUATOR.然后嵌入了我们的实现代码在try-catch块中,try 块里,可能发生的错误是可以捕抓的。如下代码

 

 

 

{

S_EVALUATOR

try

{

//  Hard-coded  relative  tolerance  and  max  iterations double  tol  =1e-4;

long  maxItr  =  1000;

 

 

//  Constructing  and  validating  C++  objects

CSPnumericMatrix  A(ps_A); CSPnumeric  b(ps_b);

if(A.nrow()!=A.ncol()  ||  A.ncol()!=b.length())

PROBLEM  "A.nrow()!=A.ncol()  ||  A.ncol()!=b.length()" ERROR;

 

实际的Gauss-Seidel步骤如下:

 

//  Begin  Gauss-Seidel  step

CSPnumeric  x=b;

for(long  k  =1;  k<=  maxItr;  k++)

{

CSPnumeric  xOld  =  x;

for(long  i=  1;  i  <=  A.nrow();  i++)

{

double  s  =  A(i,i)  *  x(i);

for(long  j  =  1;  j  <=  A.ncol();  j++)

s     =  s  -  A(i,j)  *  x(j);

x(i)  =  (b(i)+s)/A(i,i);

}

//  Check  convergence;  continue  if  necessary if(Max(abs((x-xOld)/x))  <  tol)

return(x);

}

PROBLEM  "Solution  does  not  converge"  WARN;

return(x);

}

catch(...)

{

}

return(blt_in_NULL);  //  return  the  built-in  NULL  object

}

 

 

 


UNXI上编译和执行C++


这个例子代码在SHOM E/ sconnect/samples/gausssdl下,C++代码在gausssdl.cxx

 

编译和执行C++代码

 

1.   改变当前目录到包含代码的目录

 

cd  SHOME/sconnect/samples/gausssdl

 

2.   编译共享库

 

Splus7  CHAPTER  -sconnectlib  *.cxx

Splus7  make

 

3.   运行SPLUS

 

Splus7

 

通过CHAPTER生成makefile,编译的代码只是需要在SPLUS后加上MAKE命令,如步骤2

 

MAKE前可以适当的设置环境变量

 

make工具执行了必要的命令编译和连接C++代码到共享对象S.so

.注意:-sconnectlib是被请求包含CONNECT/C++

 

通过CALL调用CONNECT/C++要比SPLUS代码快,下面是一个比较,运行在奔腾3 512内存,WIN平台,矩阵A100100

 

>  A<-matrix(rnorm(10000),nrow=100);  diag(A)<-seq(ncol(A),

+  ncol(A))  #  Make  it  diagonally  dominant

>  b<-rnorm(100);

>  sys.time({x1<-gaussSeidel(A,b)})

[1]  19.328  19.354

 

下面是一个运行在Solaris机器上的一个比较,矩阵也是100100

 

[1]  37.00  39.35

 

 

>  sys.time({x2<-.Call('gaussSeidel',A,b)})


我们比较(通过sys.time 在不同平台的输出的时间:

 

 

 

[1]  0.07  0.07

 

WIN

 

[1]  0.04  0.04

 

UNIXt.

 

可以看出,相同的CONNECT/C++版本比WIN上快250次,比纯SPLUS版本快大约1000

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值