##/*****************************************************************************
## * SIENA: Simulation Investigation for Empirical Network Analysis
## *
## * Web: https://www.stats.ox.ac.uk/~snijders/siena
## *
## * File: siena07.r
## *
## * Description: This file contains the main controlling module for the
## * estimation.
## * Also contains utility functions used within siena07
## ****************************************************************************/

##@siena estimation
siena <- function(data = NULL, effects = NULL,
	control_model = NULL, control_algo = NULL, control_out = NULL,
	thetaBound = 50,
	returnDeps = FALSE,
	batch = FALSE, verbose = FALSE, silent = TRUE,
	initC = TRUE,
	nbrNodes = 1,
	clusterString = rep("localhost", nbrNodes),
	clusterType = c("PSOCK", "FORK"), cl = NULL, ...)
{
	exitfn <- function()
	{
		 if (!is.batch())
		{
		  tcltk::tkdestroy(tkvars$tt)
		}
		## close the report file
		Report(closefiles=TRUE)
		RNGkind("default")
	}
	on.exit(exitfn())

	checking <- any(grepl("_R_CHECK", names(Sys.getenv())))

	dataName <- deparse(substitute(data))
	if (dataName=="") # impossible?
	{
		dataName <- "Siena"
	}

	if (!inherits(effects, "sienaEffects"))
	{
		stop("effects should be an RSiena effects object")
	}
	if (!inherits(data, "sienadata") && !inherits(data, "siena"))
	{
		stop("data should be a siena data structure")
	}
# "siena" is added here, because in pre-1.6.0 versions
# this was the class name that now is defined as "sienadata".


	if (is.null(control_model))
	{
		control_model <- set_model_saom()
	}
	if (is.null(control_algo))
	{
		control_algo <- set_algorithm_saom()
	}
	if (is.null(control_out))
	{
		control_out <- set_output_saom()
	}
	if (is.null(control_out$outputName))
	{
		if (checking)
		{
			control_out$outputName <- tempfile("Siena")
#			cat('siena will create/use an output file',
#				paste('Siena','.txt',sep=''),'.\n')
#			cat('This is a temporary file for this R session.\n')
		}
		else
		{
			if (grepl("%>%|\\|>", dataName))
			{
				stop("For piped data, you need to give an outputName in the output control object.")
			}				
			control_out$outputName <- paste(dataName, "_out", sep="")
			cat('siena will create/use an output file',
				paste(control_out$outputName,'.txt',sep=''),'.\n')
		}
		control_out$projname <- control_out$outputName
	}
	if (control_algo$maxlike)
	{
		if (!is.null(control_model$MaxDegree))
		{
			if (control_model$MaxDegree > 0)
			{
				stop("maxlike and MaxDegree are incompatible")
			}
		}
		if (control_algo$FinDiff.method)
		{
			stop("Finite differences estimation of derivatives",
				"is not possible with maximum likelihood estimation")
		}
	}

	# If the user is passing clusters through -cl- then change the
	# useCluster to TRUE, and assign the -nbrNodes- to number of nodes
	useCluster <- ((nbrNodes >= 2) | (!is.null(cl)))
	if (!useCluster & length(cl))
	{
		useCluster <- TRUE
		nbrNodes   <- length(cl)
	}

	time0 <-  proc.time()['elapsed']
	z <- list() ## z is the object for all control information which may change.
	z$newNames <- TRUE
	z$thetaBound <- thetaBound

	if (control_algo$maxlike)
	{
		if (!is.null(control_model$MaxDegree))
		{
			stop("maxlike and MaxDegree are incompatible")
		}
		if (control_algo$FinDiff.method)
		{
			stop("Finite differences estimation of derivatives",
				"is not possible with maximum likelihood estimation")
		}
	}
	x <- c(control_model, control_algo, control_out)
# Note that, if this call of siena comes from sienaBayes,
# there will be components control_algo$fromBayes
# and control_algo$ddfra
	z$returnThetas <- control_out$returnThetas

	parallelTesting <- FALSE
	clusterIter <- !control_algo$maxlike
			# clusterIter = clustering for parallelization goes by iteration
	if (useCluster)
	{
		if (!length(cl))
		{
			clusterType <- match.arg(clusterType)
			if (.Platform$OS.type == "windows" && clusterType != "PSOCK")
			{
				stop("cannot use forking processes on Windows")
			}
		}
		if (clusterIter)
		{
			x$firstg <- control_algo$firstg * sqrt(nbrNodes)
			z$int <- nbrNodes
			z$int2 <- 1
		}
		else
		{
			z$int <- 1
			z$int2 <- nbrNodes
		}
	}
	else
	{
		z$int <- 1
		z$int2 <- 1
	}
	if (!is.null(control_algo$randomSeed))
	{
		set.seed(control_algo$randomSeed, kind="default")
		seed <- control_algo$randomSeed
	}
	else
	{
		newseed <- NULL
		seed <- NULL
	}

	x$targets <- control_algo$targets
	z$x <- x
# x is designed to be readonly. Only z is returned.

	## set the global is.batch
	batchUse <- batch
	if (!batch)
	{
		if (!requireNamespace("tcltk", quietly = TRUE))
		{
				batchUse <- TRUE
				message("Package tcltk not available, forcing use of batch mode")
		}
		else
		{
			if (.Platform$OS.type != "windows")
			{
				if (!capabilities("X11"))
				{
					batchUse <- TRUE
					message("No X11 device available, forcing use of batch mode")
				}
			}
		}
		if(nzchar(Sys.getenv("RSIENA_TESTING")))
		{
			silent <- TRUE
		}
	}
	is.batch(batchUse)
	## open the output file
	Report(openfiles=TRUE, projname=control_out$projname, verbose=verbose, silent=silent)
	z <- InitReports(z, seed, newseed)

	## reset the globals for interrupts
	NullChecks()

	## create the screen
	tt <- NULL # this is set from a keyword in siena07; here the default, NULL
	if (!is.batch())
	{
		tkvars <- siena07Gui(tt=tt)
		z$tkvars <- tkvars
		z$pb <- list(pb=tkvars$pb, pbval=0, pbmax=1)
	}
	else
	{
		z$pb <- list(pb=NULL, pbval=0, pbmax=1)
	}

	## create theta values for phase 3, if necessary
	if (is.null(control_algo$thetaValues))
	{
		z$thetaValues <- NULL
		z$thetaFromFile <- FALSE
	}
	else
	{
		z$thetaValues <- control_algo$thetaValues
		z$thetaFromFile <- TRUE
	}				   	
	z <- robmon(z, x, useCluster, nbrNodes, initC, clusterString,
		clusterIter, clusterType, cl, data=data, effects=effects,
		returnDeps=returnDeps, 
		returnChains=control_out$returnChains,
		returnDataFrame=control_out$returnDataFrame,
		returnChangeContributions=control_out$returnChangeContributions, ...)
	time1 <-  proc.time()['elapsed']
	Report(c("Total computation time", round(time1 - time0, digits=2),
			"seconds.\n"), outf)
	z$compTime <- round(time1 - time0, digits=2)

	if (useCluster)
	{
		# Only stop cluster if it wasn't provided by the user
		#	  if (!length(cl))
		#		  stopCluster(z$cl)

		## need to reset the random number type to the normal one
		assign(".Random.seed", z$oldRandomNumbers, pos=1)
	}

	class(z) <- "sienaFit"
	attr(z, "version") <- packageDescription(pkgname, fields = "Version")
	z$tkvars <- NULL
	z$pb <- NULL
	z
}


##@siena07 siena07
siena07 <- function(alg, batch = FALSE, verbose = FALSE, silent = FALSE,
	useCluster = FALSE, nbrNodes = 2,
	thetaValues = NULL,
    returnThetas = FALSE,
	thetaBound = 50,
	targets = NULL,
	initC = TRUE,
	clusterString = rep("localhost", nbrNodes), tt = NULL,
	parallelTesting = FALSE, clusterIter = !alg$maxlike,
	clusterType = c("PSOCK", "FORK"), cl = NULL, ...)
{
	exitfn <- function()
	{
		if (!is.batch())
		{
		  tcltk::tkdestroy(tkvars$tt)
		}
		## close the report file
		Report(closefiles=TRUE)
		RNGkind("default")
	}
	on.exit(exitfn())

	# If the user is passing clusters through -cl- then change the
	# useCluster to TRUE, and assign the -nbrNodes- to number of nodes
	if (!useCluster & length(cl))
	{
		useCluster <- TRUE
		nbrNodes   <- length(cl)
	}

	time0 <-  proc.time()['elapsed']
	x <- alg
	z <- NULL ## z is the object for all control information which may change.
	## x is designed to be readonly. Only z is returned.
	z$x <- x
	z$returnThetas <- returnThetas
	z$thetaBound <- thetaBound
	if (useCluster)
	{
		if (parallelTesting)
		{
			stop("cannot parallel test with multiple processes")
		}
		if (!length(cl))
		{
			clusterType <- match.arg(clusterType)
			if (.Platform$OS.type == "windows" && clusterType != "PSOCK")
			{
				stop("cannot use forking processes on Windows")
			}
		}
		# The possibility to use snow now has been dropped
		# because RSiena requires R >= 2.15.0
		# and snow is superseded.
		# if (getRversion() < "2.14.0")
		## fake this to recreate old results
		## if (TRUE)
		#{
		#	require(snow, warn.conflicts=FALSE)
		#	require(rlecuyer)
		#	clusterType <- "SOCK"
		#}
		#else
		#{
		## require(parallel)
		#}
		if (clusterIter)
		{
			x$firstg <- x$firstg * sqrt(nbrNodes)
			z$int <- nbrNodes
			z$int2 <- 1
		}
		else
		{
			z$int <- 1
			z$int2 <- nbrNodes
		}
	}
	else
	{
		z$int <- 1
		z$int2 <- 1
	}
	if (parallelTesting)
	{
		set.seed(1, kind='Wich')
		## randomseed2 is for second generator needed only for parallel testing
		randomseed2 <- .Random.seed
		## .Random.seed[2:4] <- as.integer(c(1,2,3))
		## randomseed2[2:4] <- as.integer(c(3,2,1))
		randomseed2[2:4] <- as.integer(c(1, 2, 3))
		seed <- 1
		newseed <- 1
		z$parallelTesting <- TRUE
	}
	else
	{
		randomseed2 <- NULL
		## x$randomSeed is the user seed, if any
		if (!is.null(x$randomSeed))
		{
			set.seed(x$randomSeed, kind="default")
			seed <- x$randomSeed
		}
		else
		{
			if (!nzchar(Sys.getenv("RSIENA_TESTING")))
			{
				if (exists(".Random.seed"))
				{
					rm(.Random.seed, pos=1)
				}
				newseed <- trunc(runif(1) * 1000000)
				set.seed(newseed)  ## get R to create a random number seed for me.
				seed <- NULL
			}
			else
			{
				newseed <- NULL
				seed <- NULL
			}
		}
	}
	z$randomseed2 <- randomseed2

	x$targets <- targets

	## set the global is.batch
	batchUse <- batch
	if (!batch)
	{
		if (!requireNamespace("tcltk", quietly = TRUE))
		{
				batchUse <- TRUE
				message("Package tcltk not available, forcing use of batch mode")
		}
		else
		{
			if (.Platform$OS.type != "windows")
			{
				if (!capabilities("X11"))
				{
					batchUse <- TRUE
					message("No X11 device available, forcing use of batch mode")
				}
			}
		}
		if(nzchar(Sys.getenv("RSIENA_TESTING")))
		{
			silent <- TRUE
		}
	}
	is.batch(batchUse)

	## open the output file
	Report(openfiles=TRUE, projname=x$projname, verbose=verbose, silent=silent)
	z <- InitReports(z, seed, newseed)

	## reset the globals for interrupts
	NullChecks()

	## create the screen
	if (!is.batch())
	{
		tkvars <- siena07Gui(tt=tt)
		z$tkvars <- tkvars
		z$pb <- list(pb=tkvars$pb, pbval=0, pbmax=1)
	}
	else
	{
		z$pb <- list(pb=NULL, pbval=0, pbmax=1)
	}

	## create theta values for phase 3, if necessary
	if (is.null(thetaValues))
	{
		z$thetaValues <- NULL
		z$thetaFromFile <- FALSE
	}
	else
	{
		if (!x$simOnly)
		{
			cat('The thetaValues parameter was given\n')
			cat('but simOnly was not specified in the algorithm object.\n')
			cat('This is inconsistent.\n')
			stop('Inconsistent combination simOnly - thetaValues')
		}
		if (!is.matrix(thetaValues))
		{
			stop('thetaValues should be a matrix.')
		}
		z$thetaValues <- thetaValues
		z$thetaFromFile <- TRUE
	}

	z <- robmon(z, x, useCluster, nbrNodes, initC, clusterString,
		clusterIter, clusterType, cl, ...)

	time1 <-  proc.time()['elapsed']
	Report(c("Total computation time", round(time1 - time0, digits=2),
			"seconds.\n"), outf)
	z$compTime <- round(time1 - time0, digits=2)

	if (useCluster)
	{
		# Only stop cluster if it wasn't provided by the user
		#	  if (!length(cl))
		#		  stopCluster(z$cl)

		## need to reset the random number type to the normal one
		assign(".Random.seed", z$oldRandomNumbers, pos=1)
	}

	class(z) <- "sienaFit"
	attr(z, "version") <- packageDescription(pkgname, fields = "Version")
	z$tkvars <- NULL
	z$pb <- NULL
	z
}

##@InitReports siena07 Print report
InitReports <- function(z, seed, newseed)
{
	Report("\n\n-----------------------------------\n", outf)
	Report("New Analysis started.\n", outf)
	Report(c("Date and time:", format(Sys.time(),"%d/%m/%Y %H:%M:%S")), outf)
	Report("\nNew results follow.\n", outf)
	Report("-----------------------------------\n", outf)
	version <- packageDescription(pkgname, fields = "Version")
	Report(c(paste("\n", pkgname, " version ", sep = ""), version, " (",
		format(as.Date(packageDescription(pkgname, fields = "Date")), "%d %b %y"),
		")", "\n\n"), sep = "", outf)
	if (z$x$simOnly)
	{
		Heading(1, outf, "Simulations.")
	}
	else
	{
		Heading(1, outf, "Estimation by stochastic approximation algorithm.")
	}
	if (is.null(seed))
	{
		Report("Random initialization of random number stream.\n", outf)
		if (!is.null(newseed))
		{
			Report(sprintf("Current random number seed is %d.\n", newseed), outf)
		}
	}
	else
	{
		Report(sprintf("Current random number seed is %d.\n", seed), outf)
	}
	z$version <- version
	z$startingDate <- date()
	z
}

##@AnnouncePhase siena07 Progress reporting
AnnouncePhase <- function(z, x, subphase=NULL)
{
	## require(tcltk)
	if (!is.batch())
	{
		tcltk::tkdelete(z$tkvars$phase, 0, "end")
		tcltk::tkinsert(z$tkvars$phase, 0, paste(" ", z$Phase))
		tcltk::tkdelete(z$tkvars$subphase, 0, "end")
		tcltk::tkdelete(z$tkvars$iteration, 0, "end")
		tcltk::tkinsert(z$tkvars$iteration, 0, format(0, width=6))
	}
	if (missing(subphase))
	{
		if (is.batch())
		{
			##Report(c("\nStart phase", z$Phase, "\n"), cf)
			Report(c("\nStart phase", z$Phase, "\n"))
		}
	}
	else
	{
		if (!is.batch())
		{
			tcltk::tkinsert(z$tkvars$subphase, 0, paste(" ", subphase))
		}
		else
		{
			##Report(c("\nStart phase ", z$Phase, ".", subphase, "\n"),
			##sep="", cf)
			Report(c("\nStart phase ", z$Phase, ".", subphase, "\n"), sep="")
		}
	}
	if (z$Phase == 0)
	{
		if (!is.batch())
		{
			tcltk::tkconfigure(z$tkvars$current, height=min(z$pp, 30))
			tcltk::tkconfigure(z$tkvars$deviation, height=min(z$pp, 30))
			tcltk::tkconfigure(z$tkvars$quasi, height=min(z$pp, 30))
		}
		n1pos <- z$n1 * (z$pp + 1)
		z$n2min0 <- 7 + z$pp
		z$n2min0 <- max(5, z$n2min0 / z$int)
		z$n2minimum<- rep(0, x$nsub)
		z$n2maximum<- rep(0, x$nsub)
		## 2.5198421 = 2^(4/3); this gives a gain parameter of order n^(-3/4) ##
		if (x$nsub > 0)
		{
			z$n2minimum[1] <-
				ifelse(is.null(x$n2start), trunc(z$n2min0 * 2.52), x$n2start)
			z$n2maximum[1] <- z$n2minimum[1] + 200
			if (x$nsub > 1)
			{
				for (i in 2:x$nsub)
				{
					z$n2minimum[i] <- trunc(z$n2minimum[i-1] * 2.52)
					z$n2maximum[i] <- z$n2minimum[i] + 200
				}
			}
		}
		z$n2partsum <- c(0, cumsum(z$n2maximum))
		n2sum <- sum(z$n2maximum)
		##Progress bar
		pbmax <- n1pos + n2sum + x$n3
		z$n1pos<- n1pos
		if (!x$maxlike && z$FinDiff.method)
			pbmax <- pbmax + x$n3 * z$pp
		z$pb$pbval <- 0
		z$pb <- createProgressBar(z$pb, maxvalue=pbmax)
		z$pb$pbmax <- pbmax
	}
	if (z$Phase==2)
	{
		propo <- z$n1pos + z$n2partsum[max(subphase,1)]
		if (propo> getProgressBar(z$pb))
			z$pb <-setProgressBar(z$pb,propo)
	}
	if (z$Phase ==3)
	{
		propo <- z$n1pos + z$n2partsum[x$nsub + 1]
		if (!z$AllUserFixed)
			z$pb <- setProgressBar(z$pb,propo)
		else
		{
			max <- x$n3
			z$pb <-createProgressBar(z$pb,max)
		}
	}
	z
}
##@roundfreq siena07 Prettify interval between progress reports
roundfreq <- function(w)
{
	vec1 <- c(1, 2, 3, 4, 31, 66, 101, 300, 500)
	vec2 <- c(1, 2, 3, 20, 50, 100, 200, 500)
	if (is.batch())
		w <- max(10,vec2[findInterval(w, vec1, all.inside=TRUE)])
	else
		w <- vec2[findInterval(w, vec1[1:7], all.inside=TRUE)]
	w
}

##@WriteOutTheta siena07 Progress reporting
WriteOutTheta <- function(z)
{
	if (!is.batch())
	{
		DisplayTheta(z)
	}
	else
	{
		Report(c("theta:", format(z$theta, digits=3), "\n"))
	}
	Report("Current parameter values:\n", cf)
	Report(format(z$theta), cf, fill=80)
}

##@DisplayThetaAutocor siena07 Progress reporting
DisplayThetaAutocor <- function(z)
{
	if (!is.batch())
	{
		DisplayTheta(z)
		tcltk::tkdelete(z$tkvars$quasi, "1.0", "end")
		tcltk::tkinsert(z$tkvars$quasi, "1.0", FormatString(z$pp, z$ac))
	}
	else
	{
		Report(c("theta", format(z$theta, digits=3),"\n"))
		Report(c("ac", format(z$ac, digits=3), "\n"))
	}

}
##@DisplayandWriteTheta siena07 Progress reporting
DisplayandWritetheta <- function(z)
{
	if (!is.batch())
	{
		DisplayTheta(z)
	}
	else
	{
		Report(c("theta", format(z$theta, digits=3), "\n"))
	}
}
##@DisplayTheta siena07 Progress reporting
DisplayTheta <- function(z)
{
	if (!is.batch())
	{
		tcltk::tkdelete(z$tkvars$current, "1.0", "end")
		tcltk::tkinsert(z$tkvars$current, "1.0", FormatString(z$pp, z$theta))
	}

}
##@FormatString siena07 Progress Reporting
FormatString <- function(pp, value)
{
	ppuse <- min(30, pp)
	nbrs <- format(1:ppuse)
	nch <- nchar(nbrs[1])
#	formatstr <- paste("%", nch, "d.%", (13 - nch), ".4f\n", sep="",
#		collapse="")
#	paste(sprintf(formatstr, 1:ppuse, value[1:ppuse]), collapse="")
# In version 1.4.13 changed to:
	formatstr1 <- paste("%", nch, "d.%", (13 - nch), ".4f\n", sep="",
		collapse="")
	formatstr2 <- paste("%", nch, "d.%", (13 - nch), ".4g\n", sep="",
		collapse="")
	formatstr <- ifelse(abs(value[1:ppuse]) >= 1e5, formatstr2, formatstr1)
	formatstr[is.na(formatstr)] <- formatstr1 
	paste(sprintf(formatstr, 1:ppuse, value[1:ppuse]), collapse="")	
}
##@DisplayDeviations siena07 Progress reporting
DisplayDeviations <- function(z, fra)
{
	if (!is.batch())
	{
		tcltk::tkdelete(z$tkvars$deviations, "1.0", "end")
		tcltk::tkinsert(z$tkvars$deviations, "1.0", FormatString(z$pp, fra))
	}
}
##@DisplayIteration siena07 Progress reporting
DisplayIteration <- function(z)
{
	if (!is.batch())
	{
		tcltk::tkdelete(z$tkvars$iteration, 0, "end")
		tcltk::tkinsert(z$tkvars$iteration, 0, format(z$nit, width=6))
		tcltk::tcl("update")
	}
}
##@Root siena07 Safe square root for compatibility with siena3. Probably not necessary in R.
Root<- function(x)
{
	ifelse(abs(x) > 1e-36, sqrt(abs(x)), 1e-18)
}

##@getProgressBar siena07 Progress reporting
getProgressBar <- function(pb)
{
	if (is.batch())
		val <- pb$pbval
	else
		val <- as.numeric(tcltk::tclvalue(tcltk::tkcget(pb$pb, "-value")))
	val
}

##@setProgressBarProgress siena07 reporting
setProgressBar <- function(pb, val)
{
	if (is.batch())
	{
		pb$pbval <- val
	}
	else
	{
		tcltk::tkconfigure(pb$pb, value=val)
		tcltk::tcl("update")
	}
	pb
}
##@createProgressBar siena07 Progress reporting
createProgressBar <- function(pb, maxvalue)
{
	if (is.batch())
		pb$pbmax <- maxvalue
	else
		tcltk::tkconfigure(pb$pb, maximum=maxvalue)
	pb
}
##@tkErrorMessage Miscellaneous Not used
tkErrorMessage <- function()
{
	tcltk::tkmessageBox(geterrmessage(), icon="error")
}

##@errorHandler Miscellaneous Not used
errorHandler <- function()
{
	## opts <- options()
	if (!is.batch())
	{
		options(show.error.messages=FALSE)
		options(error=tkErrorMessage)
	}
}

##@coef.sienaFit method for sienaFit
coef.sienaFit <- function(object, dropRates=TRUE, shortenNames=TRUE, ...)
{
	result <- object$theta
	if (shortenNames)
	{
		names(result) <- fromObjectToText(object$requestedEffects$effectName)
	}
	else
	{
		names(result) <- object$requestedEffects$effectName
	}	
	if (dropRates)
	{
		return(result[!object$requestedEffects$basicRate])
	}
	else
	{
		return(result)
	}
}

##@vcov.sienaFit method for sienaFit
vcov.sienaFit <- function(object, dropRates=TRUE, shortenNames=TRUE, ...)
{
	result <- object$covtheta
	if (shortenNames)
	{
		colnames(result) <- fromObjectToText(object$requestedEffects$effectName)
	}
	else
	{
		colnames(result) <- object$requestedEffects$effectName
	}	
	rownames(result) <- colnames(result)
	if (dropRates)
	{
		return(result[!object$requestedEffects$basicRate,!object$requestedEffects$basicRate])
	}
	else
	{
		return(result)
	}
}

fromObjectToText <- function(a, type='notex'){
# This is an extended version of the function in sienatable.r
	b <- as.character(a)
	if (type == 'tex')
	{
		b <- gsub('->', '$\\rightarrow$', fixed=TRUE, b)
		b <- gsub('<-', '$\\leftarrow$', fixed=TRUE, b)
		b <- gsub('<>', '$\\leftrightarrow$', fixed=TRUE, b)
		b <- gsub('=>', '$\\Rightarrow$', fixed=TRUE, b)
		b <- gsub('>=', '$\\geq$', fixed=TRUE, b)
		b <- gsub('<=', '$\\leq$', fixed=TRUE, b)
		b <- gsub('sqrt', '$\\sqrt{}$', fixed=TRUE, b)
		b <- gsub('&', '.', fixed=TRUE, b)
	}
# Note: R changes \\ to \ but still displays \\ in printing the string.
	b <- gsub(" (density)", "", fixed=TRUE, b)
	b <- gsub("ocity", "", fixed=TRUE, b)
	b <- gsub("itive", "", fixed=TRUE, b)
	b <- gsub("iated", "", fixed=TRUE, b)
	b <- gsub("basic ", "", fixed=TRUE, b)
	b <- gsub("rate constant ", "", fixed=TRUE, b)
	b <- gsub("(period ", "(per_", fixed=TRUE, b)
	b <- gsub("degree", "deg", fixed=TRUE, b)
	b <- gsub("arity", "", fixed=TRUE, b)
	b <- gsub("ativity", "", fixed=TRUE, b)
	b <- gsub("ivity", "", fixed=TRUE, b)
	b <- gsub("erence", "", fixed=TRUE, b)
	b <- gsub("tot.", "tot", fixed=TRUE, b)
	b <- gsub("av.", "av", fixed=TRUE, b)
	b <- gsub("aver.", "av", fixed=TRUE, b)
	b <- gsub(" at ", " ", fixed=TRUE, b)
	b <- gsub(" of ", " ", fixed=TRUE, b)
	b <- gsub(" by ", " ", fixed=TRUE, b)
	b <- gsub("compression", "compr", fixed=TRUE, b)
	b <- gsub("triplets", "tripl", fixed=TRUE, b)
	b <- gsub("weighted", "wght", fixed=TRUE, b)
	b <- gsub("weight", "wght", fixed=TRUE, b)
	b <- gsub("maximum", "max", fixed=TRUE, b)
	b <- gsub("minimum", "min", fixed=TRUE, b)
	b <- gsub(" -> ", ">", fixed=TRUE, b)
	b <- gsub(" <- ", "<", fixed=TRUE, b)
	b <- gsub(" <> ", "=", fixed=TRUE, b)
	b <- gsub(" - ", "-", fixed=TRUE, b)
	b <- gsub(" * ", "*", fixed=TRUE, b)
	b <- gsub(" x ", "*", fixed=TRUE, b)
	b <- gsub("ilarity", "", fixed=TRUE, b)
	b <- gsub('^(1/1)', '(1)', fixed=TRUE, b)
	b <- gsub('^(1/2)', '(sqrt)', fixed=TRUE, b)
	b <- gsub(' (', '(', fixed=TRUE, b)
	b <- gsub('^', '', fixed=TRUE, b)
	b <- gsub('_', '-', fixed=TRUE, b)
	b <- gsub('#', '.', fixed=TRUE, b)	
	if (type != 'tex')
	{
		b <- gsub(' ', '_', fixed=TRUE, b)
		b <- gsub('.', '_', fixed=TRUE, b)
		b <- gsub('__', '_', fixed=TRUE, b)
		b <- gsub('_(', '(', fixed=TRUE, b)
	}
	b
}
