您的位置:首页 > 编程语言 > C语言/C++

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

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

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

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

为在C++程序和模块中计算S表达式,CONNECT/C++提供了一个灵活多变的机制,在SPLUS7.X中提供了许多使用这些类库的例子,其中有些例子提供了执行相同任务的等价的S和C++函数,其中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++函数,下面我们开始一个简单的应用

建立一个简单的应用

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

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

#include"sconnect.h"

//Aglobalconnectionobject
CSPengineConnectg_engineConnect;

intmain(intargc,char*argv[])
{

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

//CreatetheconnectiontoS-PLUS
g_engineConnect.Create(argc,argv);

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

//CreateSobjectwithname"x"inthecurrentdatabase.
//Sameasx<-1:10atthecommandline.CSPnumericsx;
sx.Create("1:10","x");

//Squaringsx,whichisthesameasSexpression
//sy<-x*xinalocalframe,butherewesetittolocal
//C++variablesy.CSPnumericsy=sx*sx;
//AssigntheresultasSobjectwithname"y"inthe
//currentdatabase.sy.Assign("y");

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

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

return1;
}

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

要运行这个应用,打开一个命令提示或者MS-DOS窗口(WIN)或者编译(UNIX)
1. 改变当前目录到包含代码的目录

cdSHOME/samples/spllm

(WIN)

cd/sconnect/samples/splm

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

2. 编译程序

msdevspllm.dsp/make

(WIN)

Splus7CHAPTER-sconnectapp*.cxx
Splus7make

(UNIX)

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

4. 运行程序

spllm.exeS_PROJ=.

(WIN)

Splus7EXECS.app

(UNIX)

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

sqpe.exeS_PROJ=.

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

S-PLUS:Copyright(c)1988,2005InsightfulCorp.Version7.0Release1forMicrosoftWindows:2005
WorkingdatawillbeinE:/programs/splus7.0/users/rich

或者输入

Splus7

在UNXI上,将返回下面信息:

S-PLUS:Copyright(c)1988,2005InsightfulCorp.Version7.0Release1forSunSPARC,SunOS5.8:2005
Workingdatawillbein.Data

然后查看对象X,Y和Z:

[1]
1
2
3
4
>y
[1]
1
4
9
16
>x
5678910

2536496481100

>z
Call:
lm(formula=y~x)

Coefficients:
(Intercept)x
-2211

Degreesoffreedom:10total;8residual
Residualstandarderror:8.124038

通过CALL调用C函数的例子

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

gaussSeidel<-
#gaussSeidelsolvesalinearsystemusingGauss-Seidel
#iterativemethod.
#REQUIREDARGUMENTS:
#Aandbarenumericmatrixandvectorrespectively.
#VALUE:
#avectorx,solutionofAx=b
#
#Usage:
#A<-matrix(rnorm(100),nrow=10)
#diag(A)<-seq(ncol(A),ncol(A))#Makeitdiagonally
##dominant
#b<-rnorm(ncol(A))
#sys.time({x1<-gaussSeidel(A,b)})
function(A,b)
{

#Hard-codedrelativetoleranceandmaxiterationstol<-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)")

#BeginGauss-Seidelstep
x<-b
for(kin1:maxItr)
{
xOld<-x
for(iin1:nrow(A))
{
s<-A[i,i]*x[i]
for(jin1:ncol(A))
s<-s-A[i,j]*x[j]
x[i]<-(b[i]+s)/A[i,i]
}
#Checkconvergence;continueifnecessaryif(max(abs((x-xOld)/x))<tol)
return(x);
}
warning("Solutiondoesnotconverge/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-codedrelativetoleranceandmaxiterationsdoubletol=1e-4;
longmaxItr=1000;

//ConstructingandvalidatingC++objects
CSPnumericMatrixA(ps_A);CSPnumericb(ps_b);
if(A.nrow()!=A.ncol()||A.ncol()!=b.length())
PROBLEM"A.nrow()!=A.ncol()||A.ncol()!=b.length()"ERROR;

实际的Gauss-Seidel步骤如下:

//BeginGauss-Seidelstep
CSPnumericx=b;
for(longk=1;k<=maxItr;k++)
{
CSPnumericxOld=x;
for(longi=1;i<=A.nrow();i++)
{
doubles=A(i,i)*x(i);
for(longj=1;j<=A.ncol();j++)
s=s-A(i,j)*x(j);
x(i)=(b(i)+s)/A(i,i);
}
//Checkconvergence;continueifnecessaryif(Max(abs((x-xOld)/x))<tol)
return(x);
}
PROBLEM"Solutiondoesnotconverge"WARN;
return(x);
}
catch(...)
{
}
return(blt_in_NULL);//returnthebuilt-inNULLobject
}

UNXI上编译和执行C++

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

编译和执行C++代码

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

cdSHOME/sconnect/samples/gausssdl

2. 编译共享库

Splus7CHAPTER-sconnectlib*.cxx
Splus7make

3. 运行SPLUS

Splus7

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

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

make工具执行了必要的命令编译和连接C++代码到共享对象S.so
.注意:-sconnectlib是被请求包含CONNECT/C++库

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

>A<-matrix(rnorm(10000),nrow=100);diag(A)<-seq(ncol(A),
+ncol(A))#Makeitdiagonallydominant
>b<-rnorm(100);
>sys.time({x1<-gaussSeidel(A,b)})
[1]19.32819.354

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

[1]37.0039.35

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

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

[1]0.070.07

在WIN上

[1]0.040.04

在UNIX上t.

可以看出,相同的CONNECT/C++版本比WIN上快250次,比纯SPLUS版本快大约1000次
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息