Introduction

The goal of this document is to introduce the main steps distilling a CPDnA like simulator as dicrete event engine.

The first step will be focused on defining the the structure of the netkork. Main hypothesis are: * The network topology is fixed. * The process KPI per node uses one time step. (output kpis at time t will be based on input kpi until t-1 * Different reporting wavelenghts are enabled. * Output times for nodes will be the maximum of their input kpis

Definition of the topology

It will be stored in a csv file, having * Label ID for the KPI (link) * Source Node ID * Sink Node ID * Wavelength of the reporting (0 when the link is internal) * The KPI will vary between 0 and 1 (normalized status), therefore it is defined if the optimal status is growing (+1) or decreasing (-1)

#
lnk=read.csv(file="links.csv",sep=",",header = TRUE,
             stringsAsFactors = FALSE)

Node definition

Every node has its own transference funtion, which fits into the expression: G(z)=exp(-kz) when the UPD is 1 or G(z)=1-exp(-kz) when UPD=-1 as it is normalized between 0 and 1 k(t+1) = sum(intg(kpi(i,t)))*w(i,t) i=1,…,Nj when j are the total links enering into the node j w(i,j) will represent the way of weighting and i can depend on t intg(kpi(i,t)) will represent how to proceed when several samples are reported (average, last, max(range), etc.) the value of the KPI. It is stored the node ID, the ID for coming KPI, the ID for the exiting KPI, the w expression and the operating function over the KPI

nod=read.csv(file="nodes.csv",sep=",",header = TRUE,
             stringsAsFactors = FALSE)
# Let's update the updating freq for inner cpdna
updf=function(rowcp,links,nodes) {
  if (rowcp[4]==0) {
    idcp=rowcp[1]
    idnod = unique(nodes[nodes[,4]==idcp,2])
    if (length(idnod) > 1) {
      cat(paste("Error ",idcp, "cpdna outputs more than one node:",idnod,sep=""))
      exit;
    } else {
      idjcp = unique(nodes[(nodes[,2]==idnod & nodes[,4]==idcp),3])
      valid = min(links[links$ID %in% idjcp,4])
      res = max(links[links$ID %in% idjcp,4])
      if (valid == 0 ) { # Not all the inner cpdna are already calculates
        res = 0
      }
    }
  } else {
    res=rowcp[4]
  }
  return(res)
}
#
wij=function(t,txt){
  res=eval(parse(text=txt))
  if (res > 1 ) {
    res = 1
  }
  if (res < 0) {
    res = 0
  }
  return(res)
}
kpi=function(vkpi,txt){
  res=eval(parse(text=txt))
  if (res > 1 ) {
    res = 1
  }
  if (res < 0) {
    res = 0
  }
  return(res)  
}
#
lnk[,6]=lnk[,4]
colnames(lnk)[6]="OldFrq"
iter = 0
crit = sum(lnk[,4]==0)
while (crit > 0 ) {
  lnk[,4] = apply(lnk,1,updf,lnk,nod)
  crit=sum(lnk[,4]==0)  
  iter = iter + 1
}

Learning capability

Because of the time being, each PO should behave better and better. This effect will be implemented by controlling the z factor of the G function

#
defz=function(t,T) {
  z=t/T/3
  if(z>1) {
    z=1+log(z)
  }
  return(z)
}

Node evaluation

Let’s define the function evaluating the CPDnA being outcome for the node I at time t+1 when input CPDnA at time t are available

#
e_cpdna=function(idcpdna,t,T,arr_cpdna=acpdna,links=lnk,nodes=nod) {
  ni=links[links$ID==idcpdna,2]
  vcpin = links[links[,3]==ni,1]
  ff = links[idcpdna,4]
  sgn= links[idcpdna,5]
  if ( t %% ff != 0 ){ # It is not the right time to calculate
    return(NA)
  }
  if ( sum(is.na(arr_cpdna[vcpin,t])) > 0 ) {
    return(NA)
  }
  vt = 0
  for (j in vcpin) {
    nstps = floor(ff/links[j,4])
    vkpi  = as.double(arr_cpdna[j,((t-nstps+1):t)])
    txtw  = nodes[(nodes[,2]==ni & nodes[,3]==j & nodes[,4]==idcpdna),5]
    txtkpi= nodes[(nodes[,2]==ni & nodes[,3]==j & nodes[,4]==idcpdna),6]
    w     = wij(t,txtw)
    mkp   = kpi(vkpi,txtkpi)
    z     = defz(t,T)
    vt    = vt + mkp*w
  }
  Gz = exp(-1/vt)
  if ( sgn > 0 ) {
    Gz = 1 - Gz
  }
  if (Gz > 1 ) {
    Gz = 1
  }
  if (Gz < 0 ) {
    Gz = 0
  }
  return(Gz)
}
#
t_cpdna=function(t,T,arr_cpdna=acpdna,links=lnk,nodes=nod) {
  idx=t%%links[,4]==0
  still = sum(is.na(arr_cpdna[idx,t]))
  while (still > 0) {
    jdx=(1:nrow(links))[is.na(arr_cpdna[,t]) & idx]
    for (j in jdx) {
      arr_cpdna[j,t]=e_cpdna(j,t,T,arr_cpdna,links,nodes)
    }
    still = sum(is.na(arr_cpdna[idx,t]))
  }
  return(arr_cpdna[,t])
}
#
random=function(i,T,a,b){
  return(runif(T,a,b))
}
#

Simulate the network behavior

Basic Configuration

Starting with the feed-in cpdna (freq > 0 in links[,6]) we will run several times per time-step looking to fulfill the pending CPDnA values.

#
T=1000
results = as.data.frame(matrix(rep(NA,nrow(lnk)*T),nrow=nrow(lnk),ncol=T),
                     stringsAsFactors=FALSE,row.names=1:nrow(lnk),
                     col.names=1:T)
vecin = as.data.frame(lnk[lnk[,6]>0,1])
matrdm= t(apply(vecin,1,random,T,0,0.15))
results[as.vector(unlist(vecin)),]=matrdm
# Random Pick setup
npick = sample(1:nrow(vecin),1)
vpick = sample(1:2*nrow(lnk),npick,replace=TRUE)
for (i in 1:length(vpick)) {
  matrdm[i,vpick[i]]=1
}
#

Step by step simulation

When all the parameters are setup, it’s time to run the simulation

#
ini = results
for (i in 1:T) {
  results[,i]=t_cpdna(i,T,results,lnk,nod)
}
plot(seq(lnk[12,4],T,lnk[12,4]),as.double(
      results[12,seq(lnk[12,4],T,lnk[12,4])]),
      ylim=c(0,1),type="l")

#