C++ Program
#include<iostream>
#include<fstream>
#include<cmath>
#include<list>
#include "Unode.h"
#include "Vnode.h"
using namespace std;
void computePVal(double* t, double* count, int numt, double tobs);
void getObservables(int I, int* J, int** n, int** z, double** x, double& tobs, int&
s1obs, int& s2obs, int& s3obs);
//Functions for U
void insertU(list<Unode>* theList, Unode& entry);
void printU(list<Unode>& theList);
void minFeasibleValsU(int I, int* J, int** n, int inow, int jnow, int s1obs, int
s2obs, int& s1min, int& s2min);
//Functions for V should mirror those for U
void insertV(list<Vnode>* theList, Vnode& entry);
void printU(list<Vnode>& theList);
void minFeasibleValsV(int I, int* J, int** n, int inow, int s1obs,
int s2obs, int s3obs, int& s1min, int& s2min, int& s3min);
//General function but needs a rewrite
void computeDistribution(int I, int* J, int** n, double** x, int s1obs, int s2obs,
int s3obs, double tobs);
int main(void)
{
//observed values of the sufficient statistics
double tobs = -1;
int s1obs = -1;
int s2obs = -1;
int s3obs = -1;
//the total number of primary clusters
int I = 1;
cout << "Enter the number of primary clusters: ";
cin >> I;
//arrays for the various data
int* J = new int[I]; //Vector with the number of secondary clusters in each
primary cluster
int** n = new int*[I]; //number of observations per cluster
int** z = new int*[I]; //number of successes observed per cluster
double** x = new double*[I]; //value of the covariate in each secondary cluster
//To make the algorithm efficient, these should
take values from
//a relatively small discrete set (integers,
half-integers, quarter-ints, etc)
getObservables(I, J, n, z, x, tobs, s1obs, s2obs, s3obs);
computeDistribution(I, J, n, x, s1obs, s2obs, s3obs, tobs);
return 0;
}//end main
void getObservables(int I, int* J, int** n, int** z, double** x, double& tobs, int&
s1obs, int& s2obs, int& s3obs)
{
for(int i=0; i<I; i++)
{
cout<< "How many secondary clusters are there in primary cluster " << i <<
"?"<< endl;
cin >> J[i];
n[i]=new int[J[i]];
z[i]=new int[J[i]];
x[i]=new double[J[i]];
for(int j=0; j<J[i]; j++)
{
cout << "In secondary cluster " << i << "," << j << ", enter the following"
<< endl;
cout << "n: ";
cin >> n[i][j];
cout << "z: ";
cin >> z[i][j];
cout << "x: ";
cin >> x[i][j];
}
}
tobs = 0;
s1obs = 0;
s2obs = 0;
s3obs = 0;
for(int i=0; i<I; i++)
{
int nTot = 0;
int zTot = 0;
for(int j=0; j<J[i]; j++)
{
s1obs += z[i][j];
s2obs += z[i][j]*(n[i][j]-z[i][j]);
tobs += z[i][j]*x[i][j];
nTot += n[i][j];
zTot += z[i][j];
}
s3obs += zTot*(nTot-zTot);
}
}
void computePVal(double* t, double* count, int numt, double tobs)
{
double total = 0, sum=0;
for(int ndx = 0; ndx<numt; ndx++)
{
total += count[ndx];
if(t[ndx]>=tobs)
sum+=count[ndx];
}
double pval = sum/total;
cout << "One-sided Pvalue is: " << pval << endl;
}
//***************FUNCTIONS INVOLVING JUST U.
void insertU(list<Unode>* theList, Unode& entry)
{
if((*theList).begin()==(*theList).end()) //A blank list. This case is not
tested in the demo.
{
Unode toInsert(entry);
(*theList).push_back(toInsert);
}
else
{
list<Unode>::iterator iterU;
iterU = (*theList).begin();
while(entry > *iterU && iterU != (*theList).end())
iterU++;
if(entry == *iterU)
iterU->augmentCount(entry);
else //entry belongs in front of *iterU...this works even
if iterU is the end.
{
Unode toInsert(entry);
(*theList).insert(iterU, toInsert);
}
}
}
void printU(list<Unode>& theList)
{
for(list<Unode>::iterator iterU=theList.begin(); iterU != theList.end();
++iterU)
(*iterU).print();
}
void minFeasibleValsU(int I, int* J, int** n, int inow, int jnow, int s1obs,
int s2obs, int& s1min, int& s2min)
{
int s1poss = 0, s2poss = 0;
//sum the possible values after the current one in this cluster
for(int j = jnow+1; j<J[inow]; j++)
{
s1poss += n[inow][j]; //the largest possible addition to s1 in that cluster
s2poss += (n[inow][j]*n[inow][j])/4; //the largest possible addition to s2
}
//sum the possible values in later clusters
for(int i=inow+1; i<I; i++)
{
for(int j=0; j<J[i]; j++)
{
s1poss += n[i][j]; //the largest possible addition to s1 in that cluster
s2poss += (n[i][j]*n[i][j])/4; //the largest possible addition to s2
}
}
//these are the minimum values at this stage that would make it possible
to eventually reach observeds.
s1min = s1obs - s1poss;
s2min = s2obs - s2poss;
}
//***************FUNCTIONS INVOLVING JUST V.
void insertV(list<Vnode>* theList, Vnode& entry)
{
if((*theList).begin()==(*theList).end())
{
Vnode toInsert(entry);
(*theList).push_back(toInsert);
}
else
{
list<Vnode>::iterator iterV;
iterV = (*theList).begin();
while(entry > *iterV && iterV != (*theList).end())
iterV++;
if(entry == *iterV)
(*iterV).augmentCount(entry);
else //entry belongs in front of *iterU...this works even if
iterV is the end.
{
Vnode toInsert(entry);
(*theList).insert(iterV, toInsert);
}
}
}//end insertV
void printV(list<Vnode>& theList)
{
for(list<Vnode>::iterator iterU=theList.begin(); iterU != theList.end();
++iterU)
(*iterU).print();
}
void minFeasibleValsV(int I, int* J, int** n, int inow, int s1obs,
int s2obs, int s3obs, int& s1min, int& s2min, int& s3min)
{
//note: we don't need a preliminary loop this time since we are at the end
of the primary cluster
int s1poss = 0, s2poss = 0, s3poss = 0;
//sum the possible values in later primary clusters
for(int i=inow+1; i<I; i++)
{
//Figure out the largest possible addition to s3 from primary cluster i.
int nTot = 0;
for(int j=0; j<J[i]; j++)
nTot += n[i][j];
s3poss += (nTot*nTot)/4;
//Sum the possible values for secondary clusters within the primary cluster
for(int j=0; j<J[i]; j++)
{
s1poss += n[i][j];
s2poss += (n[i][j]*n[i][j])/4;
}
}
//these are the minimum values at this stage that would make it
possible to eventually reach observeds.
s1min = s1obs - s1poss;
s2min = s2obs - s2poss;
s3min = s3obs - s3poss;
}//end getObservables
//***********************Compute Distribution.
void computeDistribution(int I, int* J, int** n, double** x, int s1obs, int
s2obs, int s3obs, double tobs)
{
//defining V lists and iterator for scanning
list<Vnode> newV;
list<Vnode> oldV;
list<Vnode>::iterator iterV;
//making a base V list before i loop.
Vnode addV;
insertV(&newV, addV);
for(int i=0; i< I; i++)
{
//making the copy of the V list for next iteration
oldV = newV;
newV = list<Vnode>();
//defining U lists and iterator for scanning
list<Unode> newU;
list<Unode> oldU;
list<Unode>::iterator iterU;
//making a base U list before j loop.
Unode addU;
insertU(&newU, addU);
for(int j=0; j<J[i]; j++)
{
//copying the U list for next iteration
oldU = newU;
newU = list<Unode>();
for(int z=0; z<=n[i][j]; z++)
{
//Creating the set of additions to suff statistics if
z[i][j]=z were true
addU = Unode(n[i][j],z,x[i][j]);
//Adding those additions to existing suff statistics
for(iterU = oldU.begin(); iterU != oldU.end(); iterU++)
{
//the new value if z[i][j]=z after adding
Unode addedU = addU + (*iterU);
//feasibility check...can't easily do minimums here,
so only check maximums
if(addedU.isFeasible(s1obs, s2obs))
insertU(&newU, addedU);
}
}//end z-loop
//releasing memory, since we have now finished with the i,j-th
second-stage cluster
oldU.clear();
}//End j loop...Unew is now complete for the ith primary cluster
/****Updating newV using oldV and newV****/
//In order to update, we need the total number of observations in
i-th primary cluster
int nTot = 0;
for(int j=0; j<J[i]; j++)
nTot += n[i][j];
//Loop, one iteration for each element of newU
for(iterU = newU.begin(); iterU != newU.end(); iterU++)
{
//create that element
Vnode Vadd(*iterU, nTot);
for(iterV = oldV.begin(); iterV != oldV.end(); iterV++)
{
Vnode addedV = *iterV + Vadd;
//feasibility check
int s1min, s2min, s3min;
minFeasibleValsV(I, J, n, i, s1obs, s2obs, s3obs, s1min, s2min, s3min);
if(addedV.isFeasible(s1obs, s2obs, s3obs, s1min, s2min, s3min))
insertV(&newV, addedV);
}
}//end iterU loop, done defining newV for the i-th primary cluster
//releasing memory for the next i loop
newU.clear();
oldV.clear();
}//end i loop...Vnew is now complete
//finding the number of terms in the conditional distribution
int numt = 0;
for(iterV = newV.begin(); iterV != newV.end(); iterV++)
{
if((*iterV).match(s1obs, s2obs, s3obs))
numt++;
}
//define vecs to hold condtnl dist...note, count can get too big for
unsigned long long
double* t = new double[numt];
double* count = new double[numt];
//filling out the conditional distribution
int ndx=0;
for(iterV = newV.begin(); iterV != newV.end(); iterV++)
{
if((*iterV).match(s1obs, s2obs, s3obs))
{
(*iterV).setDist(t[ndx],count[ndx]); //puts in the value of t,
num for that node
ndx++;
}
}
computePVal(t, count, numt, tobs);
}//end computeDistribution
#include<iostream>
#include<fstream>
#include<cmath>
#include "Unode.h"
using namespace std;
Unode::Unode(int numIn)
{
count=static_cast<double>(numIn);
t = 0;
s1=0;
s2=0;
}
Unode::Unode(double tin, int s1in, int s2in, double numIn)
{
count= numIn;
t=tin;
s1=s1in;
s2=s2in;
}
Unode::Unode(int nijk, int zijk, double xijk)
{
count = choose(nijk, zijk);
t = zijk*xijk;
s1 = zijk;
s2 = zijk*(nijk-zijk);
}
Unode::Unode(const Unode& entry)
{
count = entry.count;
t = entry.t;
s1 = entry.s1;
s2 = entry.s2;
}
bool Unode::operator>(const Unode& entry)
{
if(t>entry.t)
return true;
else if(t==entry.t && s1>entry.s1)
return true;
else if(t==entry.t && s1==entry.s1 && s2>entry.s2)
return true;
return false;
}
bool Unode::operator==(const Unode& entry)
{
return (t==entry.t && s1==entry.s1 && s2==entry.s2);
}
Unode Unode::operator+(const Unode& toAdd)
{
//Note that the correct thing to do with count is multiply, b/c count
//is counting the ways to get a particular outcome.
Unode sum(t + toAdd.t,s1 + toAdd.s1, s2 + toAdd.s2, count*toAdd.count);
return sum;
}
void Unode::print(void)
{
cout << t << " " << s1 << " " << s2 << " " << count << endl;
}
void Unode::augmentCount(const Unode& augmentor)
{
count += augmentor.count;
}
bool Unode::match(int s1obs, int s2obs)
{
return (s1==s1obs && s2==s2obs);
}
void Unode::setDist(double& tSet, double& countSet)
{
tSet = t;
countSet = count;
}
double Unode::factorial(int number)
{
double temp;
if(number <= 1) return 1;
temp = number * factorial(number - 1);
return temp;
}
double Unode::choose(int top, int bottom)
{
return (factorial(top)/(factorial(bottom)*factorial(top-bottom)));
}
bool Unode::isFeasible(int s1obs, int s2obs)
{
return (s1<=s1obs && s2<=s2obs);
}
void Unode::setVTerms(double& countIn, double& tIn, int& s1In, int& s2In, int&
s3In, int total)
{
countIn = count;
tIn = t;
s1In = s1;
s2In = s2;
s3In = s1*(total-s1); //In TeX shorthand, this is equivalent to \sum_j
z_{ij}(n_{ij}-z_{ij})
}
#include<iostream>
#include<fstream>
#include<cmath>
#include "Vnode.h"
#include "Unode.h"
using namespace std;
Vnode::Vnode(int numIn)
{
count=static_cast<double>(numIn);
t = 0;
s1=0;
s2=0;
s3=0;
}
Vnode::Vnode(double tin, int s1in, int s2in, int s3in, double numIn)
{
count= numIn;
t=tin;
s1=s1in;
s2=s2in;
s3=s3in;
}
Vnode::Vnode(const Vnode& entry)
{
count = entry.count;
t = entry.t;
s1 = entry.s1;
s2 = entry.s2;
s3 = entry.s3;
}
Vnode::Vnode(Unode parent, int total)
{
parent.setVTerms(count, t, s1, s2, s3, total);
}
bool Vnode::operator>(const Vnode& entry)
{
if(t>entry.t)
return true;
else if(t==entry.t && s1>entry.s1)
return true;
else if(t==entry.t && s1==entry.s1 && s2>entry.s2)
return true;
else if(t==entry.t && s1==entry.s1 && s2==entry.s2 && s3>entry.s3)
return true;
return false;
}
bool Vnode::operator==(const Vnode& entry)
{
return (t==entry.t && s1==entry.s1 && s2==entry.s2 && s3==entry.s3);
}
Vnode Vnode::operator+(const Vnode& toAdd)
{
//Note that the correct thing to do with count is multiply, b/c count
//is counting the ways to get a particular outcome.
Vnode sum(t + toAdd.t,s1 + toAdd.s1, s2 + toAdd.s2, s3+ toAdd.s3,
count*toAdd.count);
return sum;
}
void Vnode::print(void)
{
cout << t << " " << s1 << " " << s2 << " " << s3 << " " << count << endl;
}
void Vnode::augmentCount(const Vnode& augmentor)
{
count += augmentor.count;
}
bool Vnode::match(int s1obs, int s2obs, int s3obs)
{
return (s1==s1obs && s2==s2obs && s3==s3obs);
}
void Vnode::setDist(double& tSet, double& countSet)
{
tSet = t;
countSet = count;
}
bool Vnode::isFeasible(int s1obs, int s2obs, int s3obs, int s1min, int s2min,
int s3min)
{
return (s1min<=s1 && s1<=s1obs && s2min<=s2 && s2<=s2obs && s3min<=s3 &&
s3<=s3obs);
}
#ifndef UNODE_H
#define UNODE_H
class Unode
{
//standard variables
double count; //origninally I had this an int, but it can get too big for
unsigned long long's
double t;
int s1;
int s2;
double factorial(int number);
double choose(int top, int bottom);
public:
Unode(int numIn=1); //makes a list with all zeros except num, set to
numIn...use this to make Unew originally
Unode(double tin, int s1in, int s2in, double numIn); //direct constructor
Unode(int nijk, int zijk, double xijk); //constructor from data
Unode(const Unode& entry);
~Unode(){}
//methods for navigating lists
bool operator>(const Unode& entry);
bool operator==(const Unode& entry);
//methods for working with lists in the j-loop
Unode operator+(const Unode& toAdd);
void augmentCount(const Unode& augmentor);
bool match(int s1obs, int s2obs);
void setDist(double& tSet, double& countSet);
bool isFeasible(int s1obs, int s2obs);
//method sets terms; to be used in the V constructor. Total needs to
contain the sum of the n[i][j]'s
//for the ith primary cluster (this needs to also be passed into the
constructor).
void setVTerms(double& countIn, double& tIn, int& s1In, int& s2In, int&
s3In, int total);
void print();
};
#endif
#ifndef VNODE_H
#define VNODE_H
#include "Unode.h"
class Vnode
{
//standard variables
double count; //origninally I had this an int, but it can get too big
for unsigned long long's
double t;
int s1;
int s2;
int s3;
public:
Vnode(int numIn=1); //makes a list with all zeros except num, set to
numIn...use this to make Unew originally
Vnode(Unode parent, int total); //this takes a Unode parent--presumably
from one primary clusters, and makes Vnode
//the argument total needs to contain the sum of n's in that primary cluster.
Vnode(const Vnode& entry);
Vnode(double tin, int s1in, int s2in, int s3in, double numIn); //direct constructor
~Vnode(){}
bool operator>(const Vnode& entry);
bool operator==(const Vnode& entry);
Vnode operator+(const Vnode& toAdd);
void augmentCount(const Vnode& augmentor);
bool match(int s1obs, int s2obs, int s3obs);
void setDist(double& tSet, double& countSet);
bool isFeasible(int s1obs, int s2obs, int s3obs, int s1min, int s2min,
int s3min);
void print();
};
#endif