Skip to content

Commit b472cf4

Browse files
committed
Accelerated C code for Markov chain
1 parent 3f30cf0 commit b472cf4

5 files changed

Lines changed: 72 additions & 35 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Package: spatstat.sparse
2-
Version: 3.1-0.003
2+
Version: 3.1-0.004
33
Date: 2026-04-11
44
Title: Sparse Three-Dimensional Arrays and Linear Algebra Utilities
55
Authors@R: c(person("Adrian", "Baddeley",

NEWS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
CHANGES IN spatstat.sparse VERSION 3.1-0.003
2+
CHANGES IN spatstat.sparse VERSION 3.1-0.004
33

44
OVERVIEW
55

inst/doc/packagesizes.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ date version nhelpfiles nobjects ndatasets Rlines srclines
1919
"2023-03-12" "3.0-1" 15 48 0 2092 740
2020
"2023-10-24" "3.0-3" 15 48 0 2092 740
2121
"2024-06-21" "3.1-0" 15 48 0 2092 740
22-
"2026-04-11" "3.1-0.003" 16 49 0 2189 907
22+
"2026-04-11" "3.1-0.004" 16 49 0 2189 944

inst/info/packagesizes.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ date version nhelpfiles nobjects ndatasets Rlines srclines
1919
"2023-03-12" "3.0-1" 15 48 0 2092 740
2020
"2023-10-24" "3.0-3" 15 48 0 2092 740
2121
"2024-06-21" "3.1-0" 15 48 0 2092 740
22-
"2026-04-11" "3.1-0.003" 16 49 0 2189 907
22+
"2026-04-11" "3.1-0.004" 16 49 0 2189 944

src/rmarkovchain.c

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,23 @@
77
rMCspMF - return final state only
88
rMCspMH - return history of chain
99
10-
Sparse matrix is required to be in row-major sparse form
11-
(class 'dgRmatrix') which can be achieved using 'as(, "RsparseMatrix")'
12-
Information passed to the C code:
10+
These C functions are called from 'sparseMarkov.R'
11+
12+
The transition matrix M is required to be in row-major sparse form
13+
(virtual class 'RsparseMatrix' which embraces 'dgRMatrix' and 'dtRMatrix')
14+
Matrices can be converted to this form using 'as(M, "RsparseMatrix")'
15+
16+
Data passed to the C code from the sparse matrix M:
1317
14-
nrows Number of rows (and columns) of matrix dim(M)[1]
15-
nsparse Number of nonzero entries in matrix length(M@x)
16-
probval Vector of nonzero entries M@x
17-
colindex Vector of column indices for nonzero entries M@j
18-
rowstart Start position in M@x, M@j of each row M@p
18+
nrows Number of rows (and columns) of matrix dim(M)[1]
19+
nsparse Number of nonzero entries in matrix length(M@x)
20+
probval Vector of nonzero entries M@x
21+
colindex Vector of column indices for nonzero entries M@j
22+
rowstart Start position in M@x, M@j of each row of matrix M@p
1923
2024
The indices in 'colindex' and 'rowstart' are zero-based.
2125
22-
$Revision: 1.4 $ $Date: 2026/04/10 08:04:44 $
26+
$Revision: 1.8 $ $Date: 2026/04/11 09:54:48 $
2327
2428
Copyright (c) Adrian Baddeley 2026
2529
GNU Public Licence (>= 2.0)
@@ -50,41 +54,59 @@ void rMCspMF(
5054
int *nsteps,
5155
/* output: final state for each point */
5256
int *endpos) {
53-
register int istep, ipoint, currentpos, thisrowstart, nextrowstart, j, k;
57+
register int steps, points, entries, currentpos, j;
58+
int thisrowstart, nextrowstart, thisrowlength;
5459
register double u;
5560
int Nrows, Nsparse, Npoints, Nsteps;
61+
register int *sp, *ep, *cp;
62+
register double *pp;
5663

5764
Nrows = *nrows;
5865
Nsparse = *nsparse;
5966
Npoints = *npoints;
6067
Nsteps = *nsteps;
6168

6269
GetRNGstate();
70+
71+
/* initialise pointers */
72+
sp = startpos;
73+
ep = endpos;
6374

64-
for(ipoint = 0; ipoint < Npoints; ipoint++) {
75+
for(points = Npoints; points > 0; --points, ++sp, ++ep) {
6576
/* initialise position */
66-
currentpos = startpos[ipoint];
77+
currentpos = *sp;
6778
/* run chain */
68-
for(istep = 0; istep < Nsteps; istep++) {
69-
/* transition probabilities from current position */
79+
for(steps = Nsteps; steps > 0; --steps) {
80+
/* nonzero transition probabilities from current position */
7081
thisrowstart = rowstart[currentpos];
7182
nextrowstart = ((currentpos+1) < Nrows) ? rowstart[currentpos+1] : Nsparse;
83+
thisrowlength = nextrowstart - thisrowstart;
7284
/* random number */
7385
u = unif_rand();
86+
/* pointers into probval[] and colindex[] for this row */
87+
pp = probval + thisrowstart;
88+
cp = colindex + thisrowstart;
89+
/* loop over nonzero entries in current row */
7490
j = -1;
75-
for(k = thisrowstart; k < nextrowstart; k++) {
76-
u -= probval[k];
91+
for(entries = thisrowlength; entries > 0; --entries, pp++, cp++) {
92+
u -= *pp;
7793
if(u <= 0.0) {
7894
/* jump */
79-
j = colindex[k];
95+
j = *cp;
8096
break;
8197
}
8298
}
83-
if(j < 0) j = colindex[nextrowstart - 1];
99+
if(j < 0) {
100+
/*
101+
Random number exceeded row sum of transition matrix.
102+
theoretically impossible -- can occur due to numerical error
103+
*/
104+
j = colindex[nextrowstart - 1];
105+
}
84106
currentpos = j;
85107
}
86108
/* save state */
87-
endpos[ipoint] = currentpos;
109+
*ep = currentpos;
88110
}
89111

90112
PutRNGstate();
@@ -111,11 +133,13 @@ void rMCspMH(
111133
int *nsteps,
112134
/* output: history for each point ( (Nsteps + 1) * Npoints ) */
113135
int *history) {
114-
register int istep, ipoint, currentpos, thisrowstart, nextrowstart, j, k;
136+
register int steps, points, entries, currentpos, j;
137+
int thisrowstart, nextrowstart, thisrowlength;
115138
register double u;
116139
int Nrows, Nsparse, Npoints, Nsteps, Nhistory;
117-
int *histp;
118-
140+
register int *sp, *cp, *histp;
141+
register double *pp;
142+
119143
Nrows = *nrows;
120144
Nsparse = *nsparse;
121145
Npoints = *npoints;
@@ -127,30 +151,43 @@ void rMCspMH(
127151

128152
/* pointer to next entry in 'history' */
129153
histp = history;
154+
/* pointer to initial state */
155+
sp = startpos;
130156

131-
for(ipoint = 0; ipoint < Npoints; ipoint++) {
157+
for(points = Npoints; points > 0; --points, ++sp) {
132158
/* initialise position */
133-
currentpos = startpos[ipoint];
159+
currentpos = *sp;
134160
/* save initial state */
135161
*histp = currentpos;
136162
++histp;
137-
/* run chain for point number 'ipoint' */
138-
for(istep = 0; istep < Nsteps; istep++, histp++) {
139-
/* transition probabilities from current position */
163+
/* run chain */
164+
for(steps = Nsteps; steps > 0; --steps, ++histp) {
165+
/* nonzero transition probabilities from current position */
140166
thisrowstart = rowstart[currentpos];
141167
nextrowstart = ((currentpos+1) < Nrows) ? rowstart[currentpos+1] : Nsparse;
168+
thisrowlength = nextrowstart - thisrowstart;
142169
/* random number */
143170
u = unif_rand();
171+
/* pointers into probval[] and colindex[] for this row */
172+
pp = probval + thisrowstart;
173+
cp = colindex + thisrowstart;
174+
/* loop over nonzero entries in current row */
144175
j = -1;
145-
for(k = thisrowstart; k < nextrowstart; k++) {
146-
u -= probval[k];
176+
for(entries = thisrowlength; entries > 0; --entries, pp++, cp++) {
177+
u -= *pp;
147178
if(u <= 0.0) {
148179
/* jump */
149-
j = colindex[k];
180+
j = *cp;
150181
break;
151182
}
152183
}
153-
if(j < 0) j = colindex[nextrowstart - 1];
184+
if(j < 0) {
185+
/*
186+
Random number exceeded row sum of transition matrix.
187+
theoretically impossible -- can occur due to numerical error
188+
*/
189+
j = colindex[nextrowstart - 1];
190+
}
154191
currentpos = j;
155192
/* save state */
156193
*histp = currentpos;

0 commit comments

Comments
 (0)