diff --git a/.github/workflows/R-CMD-check-ubuntu.yml b/.github/workflows/R-CMD-check-ubuntu.yml index 645396120..9fe81de99 100644 --- a/.github/workflows/R-CMD-check-ubuntu.yml +++ b/.github/workflows/R-CMD-check-ubuntu.yml @@ -22,8 +22,8 @@ jobs: config: - {os: ubuntu-latest, r: 'devel'} - {os: ubuntu-latest, r: 'release'} - - {os: ubuntu-18.04, r: 'devel'} - - {os: ubuntu-18.04, r: 'release'} + - {os: ubuntu-20.04, r: 'devel'} + - {os: ubuntu-20.04, r: 'release'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true diff --git a/R-proj/R/RcppExports.R b/R-proj/R/RcppExports.R index 5713d11a3..c3f192aee 100644 --- a/R-proj/R/RcppExports.R +++ b/R-proj/R/RcppExports.R @@ -361,11 +361,6 @@ sample_points <- function(P, n, random_walk = NULL, distribution = NULL, seed = .Call(`_volesti_sample_points`, P, n, random_walk, distribution, seed) } -#' @export -sample_spectra <- function(file = NULL, N = NULL, walk_length = NULL) { - .Call(`_volesti_sample_spectra`, file, N, walk_length) -} - #' Write a SDPA format file #' #' Outputs a spectrahedron (the matrices defining a linear matrix inequality) and a vector (the objective function) diff --git a/R-proj/examples/Dirichlet/dirichlet_crhmc.R b/R-proj/examples/Dirichlet/dirichlet_crhmc.R new file mode 100644 index 000000000..e6d211ec7 --- /dev/null +++ b/R-proj/examples/Dirichlet/dirichlet_crhmc.R @@ -0,0 +1,42 @@ +# VolEsti (volume computation and sampling library) + +# Copyright (c) 2012-2023 Vissarion Fisikopoulos +# Copyright (c) 2018-2023 Apostolos Chalkis +# Copyright (c) 2020-2023 Elias Tsigaridas + +# Licensed under GNU LGPL.3, see LICENCE file + +# Example script for sampling from the Dirichlet distribution with CRHMC + +# Import required libraries +library(volesti) +library(Matrix) + +Aeq = matrix(c(1, 1, 1), ncol=3, nrow=1, byrow=TRUE) +Aeq = as( Aeq, 'dgCMatrix' ) +beq = matrix(c(1), ncol=1, nrow=1, byrow=TRUE) +Aineq = matrix(, ncol=3, nrow=0, byrow=TRUE) +Aineq = as( Aineq, 'dgCMatrix' ) +bineq = matrix(, ncol=0, nrow=0, byrow=TRUE) +lb = c(0,0,0) +ub = c(1, 1 ,1) + +# Create domain of truncation +P <- volesti::sparse_constraint_problem$new(Aineq, bineq, Aeq, beq, lb, ub) + +a_vec = c(2,3,4) +# Negative log-probability oracle +f <- function(x) (-((a_vec-1)%*%log(x))[1]) + +# Negative log-probability gradient oracle +grad_f <- function(x) (-(a_vec-1)/x) + +n_samples <- 5000 +n_burns <- n_samples / 2 +pts <- sample_points(P, n = n_samples, + random_walk = list("walk" = "CRHMC", + "nburns" = n_burns, "walk_length" = 1, + "solver" = "implicit_midpoint"), + distribution = list("density" = "logconcave", + "negative_logprob" = f, + "negative_logprob_gradient" = grad_f)) \ No newline at end of file diff --git a/R-proj/examples/Dirichlet/dirichlet_ellipsoid_nuts.R b/R-proj/examples/Dirichlet/dirichlet_ellipsoid_nuts.R new file mode 100644 index 000000000..3a72f0a2c --- /dev/null +++ b/R-proj/examples/Dirichlet/dirichlet_ellipsoid_nuts.R @@ -0,0 +1,88 @@ +# VolEsti (volume computation and sampling library) + +# Copyright (c) 2012-2023 Vissarion Fisikopoulos +# Copyright (c) 2018-2023 Apostolos Chalkis +# Copyright (c) 2020-2023 Elias Tsigaridas + +# Licensed under GNU LGPL.3, see LICENCE file + +# Example script for sampling from the Dirichlet distribution with CRHMC + +# Import required libraries +library(volesti) +library(Matrix) + +n = 3 +Aeq = matrix(rep(1,n), ncol=n, nrow=1, byrow=TRUE) +beq = c(1) +A = -diag(n) +b = rep(0, n) + +# ellipsoid x'Ex <= 1 +E = matrix(c(7.8791, 3.6018, -6.9191, 3.6018, 2.2995, + -4.4496, -6.9191, -4.4496, 11.7993), + nrow = 3, ncol = 3, byrow = TRUE) + +x0 = c(0.2455, 0.4287, 0.3258) #interior point + +# Projecting everything onto the null space of Aeq +N_trans = pracma::nullspace(Aeq) +N_shift = x0 + +b = b - A %*% N_shift +A = A %*% N_trans +p0 = rep(0, n-1) #interior point of the projected point + +#the new matrix of the projected ellipsoid +Et = t(N_trans) %*% E %*% N_trans +#the new center of the projected ellipsoid +center = -MASS::ginv(Et) %*% (t(N_trans) %*% E) %*% N_shift +#the new offset of the projeced ellipsoid +R = 1 + t(center)%*%Et%*%center - t(N_shift)%*%E%*%N_shift +R = R[1] +#normalizing the offset +Et = Et / R + +#we shift by the ellipsoid's center so that it is given by x'Etx <= 1 +b = b - A %*% center # shift ellipsoid's center to origin +# interior point in the projected body +p0 = p0 - center + +#now, from a point y, in the projected body, we get +#the point oin the initial body as follows: x = N_trans%*%(y+center) + x0 + +# Create domain of truncation +P <- volesti::PolytopeIntersectEllipsoid$new(A, b, Et) + +a_vec = c(2,3,4) +# Transformed negative log-probability oracle +f <- function(y) (-((a_vec-1)%*%log(N_trans%*%(y+center) + x0))[1]) + +# Transformed negative log-probability gradient oracle +grad_f <- function(y) (-(a_vec-1)/(N_trans%*%(y+center) + x0)) + +n_samples <- 5000 +n_burns <- n_samples / 2 +samples <- volesti::sample_points(P, n = n_samples, + random_walk = list("walk" = "NUTS", "solver" = "leapfrog", + "starting_point" = p0), + distribution = list("density" = "logconcave", "negative_logprob" = f, + "negative_logprob_gradient" = grad_f)) + +M = dim(samples)[2] +# samples in the initial body following Dirichlet distribution +random_portfolios = N_trans %*% (samples + kronecker(matrix(1, 1, M), matrix(center, ncol = 1))) + + kronecker(matrix(1, 1, M), matrix(N_shift, ncol = 1)) + +###################### +## UNIFORM SAMPLING ## +###################### +# it's better to use Billiard walk instead of a dirichlet with ones + +samples <- volesti::sample_points(P, n = n_samples, + random_walk = list("walk" = "aBiW", "starting_point" = p0)) + +M = dim(samples)[2] +# samples in the initial body following uniform distribution +random_portfolios = N_trans %*% (samples + kronecker(matrix(1, 1, M), matrix(center, ncol = 1))) + + kronecker(matrix(1, 1, M), matrix(N_shift, ncol = 1)) diff --git a/R-proj/examples/logconcave/nuts_poly_intersect_ellipsoid.R b/R-proj/examples/logconcave/nuts_poly_intersect_ellipsoid.R new file mode 100644 index 000000000..33dd0b452 --- /dev/null +++ b/R-proj/examples/logconcave/nuts_poly_intersect_ellipsoid.R @@ -0,0 +1,47 @@ +# VolEsti (volume computation and sampling library) + +# Copyright (c) 2012-2020 Vissarion Fisikopoulos +# Copyright (c) 2018-2020 Apostolos Chalkis +# Copyright (c) 2020-223 Elias Tsigaridas + +# Licensed under GNU LGPL.3, see LICENCE file + +# Example script for using the logconcave sampling methods + +# Import required libraries +library(ggplot2) +library(volesti) + +# Sampling from logconcave density example + +# Helper function +norm_vec <- function(x) sqrt(sum(x^2)) + +# Negative log-probability oracle +f <- function(x) (norm_vec(x)^2 + sum(x)) + +# Negative log-probability gradient oracle +grad_f <- function(x) (2 * x + 1) + +# Create domain of truncation +A = matrix(c(1,0,0,1,-1,0,0,-1), nrow=4, ncol=2, byrow=TRUE) +b = rep(1,4) +E = matrix(c(0.25, 0.75, 0.75, 3.25), nrow=2, ncol=2, byrow=TRUE) +EP = PolytopeIntersectEllipsoid$new(A, b, E) +dim = 2 + +x0 = rep(0, dim) + +# Sample points +n_samples = 2000 + +samples = sample_points(EP, n = n_samples, random_walk = list("walk" = "NUTS", "solver" = "leapfrog", "starting_point" = x0), + distribution = list("density" = "logconcave", "negative_logprob" = f, "negative_logprob_gradient" = grad_f)) + +# Plot histogram +hist(samples[1,], probability=TRUE, breaks = 100) + +psrfs = psrf_univariate(samples) +n_ess = ess(samples) + + diff --git a/R-proj/examples/logconcave/nuts_rand_poly.R b/R-proj/examples/logconcave/nuts_rand_poly.R new file mode 100644 index 000000000..00400ba72 --- /dev/null +++ b/R-proj/examples/logconcave/nuts_rand_poly.R @@ -0,0 +1,55 @@ +# VolEsti (volume computation and sampling library) + +# Copyright (c) 2012-2020 Vissarion Fisikopoulos +# Copyright (c) 2018-2020 Apostolos Chalkis +# Copyright (c) 2020-2020 Marios Papachristou + +# Contributed and/or modified by Marios Papachristou, as part of Google Summer of Code 2020 program. + +# Licensed under GNU LGPL.3, see LICENCE file + +# Example script for using the logconcave sampling methods + +# Import required libraries +library(ggplot2) +library(volesti) + +# Sampling from logconcave density example + +# Helper function +norm_vec <- function(x) sqrt(sum(x^2)) + +# Negative log-probability oracle +f <- function(x) (norm_vec(x)^2 + sum(x)) + +# Negative log-probability gradient oracle +grad_f <- function(x) (2 * x + 1) + +dimension <- 50 +facets <- 200 + +# Create domain of truncation +H <- gen_rand_hpoly(dimension, facets, seed = 15) + +# Rounding +Tr <- rounding(H, seed = 127) + +P <- Hpolytope$new(A = Tr$Mat[1:nrow(Tr$Mat), 2:ncol(Tr$Mat)], b = Tr$Mat[,1]) + +x_min = matrix(0, dimension, 1) + +# Warm start point from truncated Gaussian +warm_start <- sample_points(P, n = 1, random_walk = list("nburns" = 5000), distribution = list("density" = "gaussian", "variance" = 1/2, "mode" = x_min)) + +# Sample points +n_samples <- 20000 + +samples <- sample_points(P, n = n_samples, random_walk = list("walk" = "NUTS", "solver" = "leapfrog", "starting_point" = warm_start[,1]), + distribution = list("density" = "logconcave", "negative_logprob" = f, "negative_logprob_gradient" = grad_f)) + +# Plot histogram +hist(samples[1,], probability=TRUE, breaks = 100) + +psrfs <- psrf_univariate(samples) +n_ess <- ess(samples) + diff --git a/R-proj/examples/logconcave/simple_crhmc.R b/R-proj/examples/logconcave/simple_crhmc.R new file mode 100644 index 000000000..5fee2b8b8 --- /dev/null +++ b/R-proj/examples/logconcave/simple_crhmc.R @@ -0,0 +1,49 @@ +# VolEsti (volume computation and sampling library) + +# Copyright (c) 2012-2020 Vissarion Fisikopoulos +# Copyright (c) 2018-2020 Apostolos Chalkis +# Copyright (c) 2020-2020 Marios Papachristou +# Copyright (c) 2022-2022 Ioannis Iakovidis + +# Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of Code 2022 program. + +# Licensed under GNU LGPL.3, see LICENCE file + +# Example script for using the logconcave sampling methods + +# Import required libraries +library(volesti) + +# Sampling from uniform density example + +logconcave_sample<- function(P,distribution, n_samples ,n_burns){ + if (distribution == "uniform"){ + f <- function(x) (0) + grad_f <- function(x) (0) + L=1 + m=1 + pts <- sample_points(P, n = n_samples, random_walk = list("walk" = "CRHMC", "nburns" = n_burns, "walk_length" = 1, "solver" = "implicit_midpoint"), distribution = list("density" = "logconcave", "negative_logprob" = f, "negative_logprob_gradient" = grad_f, "L_" = L, "m" = m)) + return(max(psrf_univariate(pts, "interval"))) + } + else if(distribution == "gaussian"){ + pts <- sample_points(P, n = n_samples, random_walk = list("walk" = "CRHMC", "nburns" = n_burns, "walk_length" = 1, "solver" = "implicit_midpoint"), distribution = list("density" = "logconcave", "variance"=8)) + return(max(psrf_univariate(pts, "interval"))) + } +} + +for (i in 1:2) { + + if (i==1) { + distribution = 'gaussian' + cat("Gaussian ") + } else { + distribution = 'uniform' + cat("Uniform ") + } + + P = gen_simplex(10, 'H') + psrf = logconcave_sample(P,distribution,5000,2000) + cat("psrf = ") + cat(psrf) + cat("\n") +} diff --git a/R-proj/examples/logconcave/simple_hmc_rand_poly.R b/R-proj/examples/logconcave/simple_hmc_rand_poly.R index 9f785aaa8..b352c9a16 100644 --- a/R-proj/examples/logconcave/simple_hmc_rand_poly.R +++ b/R-proj/examples/logconcave/simple_hmc_rand_poly.R @@ -29,10 +29,10 @@ dimension <- 50 facets <- 200 # Create domain of truncation -H <- gen_rand_hpoly(dimension, facets) +H <- gen_rand_hpoly(dimension, facets, seed = 15) # Rounding -Tr <- rounding(H) +Tr <- rounding(H, seed = 127) P <- Hpolytope$new(A = Tr$Mat[1:nrow(Tr$Mat), 2:ncol(Tr$Mat)], b = Tr$Mat[,1]) diff --git a/R-proj/examples/logconcave/sparse_crhmc.R b/R-proj/examples/logconcave/sparse_crhmc.R new file mode 100644 index 000000000..373371986 --- /dev/null +++ b/R-proj/examples/logconcave/sparse_crhmc.R @@ -0,0 +1,98 @@ +# VolEsti (volume computation and sampling library) + +# Copyright (c) 2012-2020 Vissarion Fisikopoulos +# Copyright (c) 2018-2020 Apostolos Chalkis +# Copyright (c) 2020-2020 Marios Papachristou +# Copyright (c) 2022-2022 Ioannis Iakovidis + +# Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of Code 2022 program. + +# Licensed under GNU LGPL.3, see LICENCE file + +# Example script for using the logconcave sampling methods + +# Import required libraries +library(ggplot2) +library(volesti) + +# Sampling from logconcave density example + +# Helper function +norm_vec <- function(x) sqrt(sum(x^2)) + +# Negative log-probability oracle +f <- function(x) (norm_vec(x)^2 + sum(x)) + +# Negative log-probability gradient oracle +grad_f <- function(x) (2 * x + 1) + +# Interval [-1, 1] +A = matrix(c(1, -1), ncol=1, nrow=2, byrow=TRUE) +b = c(2,1) + +# Create domain of truncation +P <- volesti::Hpolytope$new(A, b) + +# Mode of logconcave density +x_min <- c(-0.5) + +# Smoothness and strong-convexity +L <- 2 +m <- 2 + +# Sample points +n_samples <- 80000 +n_burns <- n_samples / 2 +cat("---Sampling without hessian\n") +pts <- sample_points(P, n = n_samples, random_walk = list("walk" = "CRHMC", "step_size" = 0.3, "nburns" = n_burns, "walk_length" = 1, "solver" = "implicit_midpoint"), distribution = list("density" = "logconcave", "negative_logprob" = f, "negative_logprob_gradient" = grad_f, "L_" = L, "m" = m)) +jpeg("histogram_without_hessian.jpg") +# Plot histogram +hist(pts, probability=TRUE, breaks = 100) + +cat("Sample mean is: ") +sample_mean <- mean(pts) +cat(sample_mean) +cat("\n") +cat("Sample variance is: ") +sample_variance <- mean((pts - sample_mean)^2) +cat(sample_variance) +cat("\n") +invisible(capture.output(dev.off())) + +# Negative log-probability hessian oracle +hess_f <- function(x) (2) +cat("---Sampling with hessian\n") +pts <- sample_points(P, n = n_samples, random_walk = list("walk" = "CRHMC", "step_size" = 0.3, "nburns" = n_burns, "walk_length" = 1, "solver" = "implicit_midpoint"), distribution = list("density" = "logconcave", "negative_logprob" = f, "negative_logprob_gradient" = grad_f,"negative_logprob_hessian" = hess_f, "L_" = L, "m" = m)) +jpeg("histogram_with_hessian.jpg") +# Plot histogram +hist(pts, probability=TRUE, breaks = 100) + +cat("Sample mean is: ") +sample_mean <- mean(pts) +cat(sample_mean) +cat("\n") +cat("Sample variance is: ") +sample_variance <- mean((pts - sample_mean)^2) +cat(sample_variance) +cat("\n") +invisible(capture.output(dev.off())) + +walk="CRHMC" +library(Matrix) +bineq=matrix(c(10,10,10,10,10), nrow=5, ncol=1, byrow=TRUE) +Aineq = matrix(c(1,0,-0.25,-1,2.5,1,0.4,-1,-0.9,0.5), nrow=5, ncol=2, byrow = TRUE) +Aineq = as( Aineq, 'dgCMatrix' ) +beq=matrix(,nrow=0, ncol=1, byrow=TRUE) +Aeq = matrix(, nrow=0, ncol=2, byrow = TRUE) +Aeq=as( Aeq, 'dgCMatrix' ) +lb=-100000*c(1,1); +ub=100000*c(1,1); +cat("---Sampling the normal distribution in a pentagon\n") +P <- volesti::sparse_constraint_problem$new(Aineq, bineq,Aeq, beq, lb, ub) +points <- sample_points(P, n = n_samples, random_walk = list("walk" = "CRHMC", "step_size" = 0.3, "nburns" = n_burns, "walk_length" = 1, "solver" = "implicit_midpoint"), distribution = list("density" = "logconcave", "variance" = 8)) +jpeg("pentagon.jpg") +plot(ggplot(data.frame( x=points[1,], y=points[2,] )) + +geom_point( aes(x=x, y=y, color=walk)) + coord_fixed(xlim = c(-15,15), +ylim = c(-15,15)) + ggtitle(sprintf("Sampling a random pentagon with walk %s", walk))) +invisible(capture.output(dev.off())) +write.table(points, file="pentagon.txt", row.names=FALSE, col.names=FALSE) diff --git a/R-proj/man/PolytopeIntersectEllipsoid.Rd b/R-proj/man/PolytopeIntersectEllipsoid.Rd new file mode 100644 index 000000000..bd96097bb --- /dev/null +++ b/R-proj/man/PolytopeIntersectEllipsoid.Rd @@ -0,0 +1,22 @@ +\name{PolytopeIntersectEllipsoid} +\alias{PolytopeIntersectEllipsoid} +\title{An exposed class to represent an intersection between an H-polytope and an ellipsoid.} + +\description{ +An intersection between of an H-polytope, defined by a set of linear inequalities, or a matrix A and an \eqn{m}-dimensional vector b s.t., \eqn{x, Ax\leq b}, and an ellipsoid defined by a positive definite matrix E s.t., \eqn{x, x^TEx \leq 1}. +} +\section{Fields}{ +\itemize{ +\item{\code{A} }{ \eqn{m \times d} matrix A} + +\item{\code{b} }{ \eqn{m}-dimensional vector b} + +\item{\code{E} }{ \eqn{d \times d} positive definite matrix E} + +\item{\code{type} }{ An integer that declares the representation of the convex body. For the intersection between an H-polytope and an ellipsoid the default value is 6. It has not be given to the constructor.} + +\item{\code{dimension} }{ An integer that declares the dimension of the convex body. It has not be given to the constructor.} + +\item{\code{volume} }{ The volume of the convex body, if it is known.} +}} + diff --git a/R-proj/man/Rcpp_PolytopeIntersectEllipsoid.Rd b/R-proj/man/Rcpp_PolytopeIntersectEllipsoid.Rd new file mode 100644 index 000000000..cf025bc03 --- /dev/null +++ b/R-proj/man/Rcpp_PolytopeIntersectEllipsoid.Rd @@ -0,0 +1,31 @@ +\docType{class} +\name{Rcpp_PolytopeIntersectEllipsoid} +\alias{Rcpp_PolytopeIntersectEllipsoid-class} +\alias{[,Rcpp_PolytopeIntersectEllipsoid-method} +\alias{[,Rcpp_PolytopeIntersectEllipsoid,ANY,ANY,ANY-method} +\alias{$<-,Rcpp_PolytopeIntersectEllipsoid-method} +\alias{$,Rcpp_PolytopeIntersectEllipsoid-method} +\alias{filepaths<-,Rcpp_PolytopeIntersectEllipsoid-method} +\title{ +An \code{Rcpp} class to represent an intersection between an H-polytope and an ellipsoid, exposed to \code{R} via modules. +} +\description{ +An intersection between of an H-polytope, defined by a set of linear inequalities, or a matrix A and an \eqn{m}-dimensional vector b s.t., \eqn{x, Ax\leq b}, and an ellipsoid defined by a positive definite matrix E s.t., \eqn{x, x^TEx \leq 1}. +} +\details{ +\describe{ +\item{\code{A} }{ \eqn{m \times d} matrix A} + +\item{\code{b} }{ \eqn{m}-dimensional vector b} + +\item{\code{E} }{ \eqn{d \times d} positive definite matrix E} + +\item{\code{type} }{ An integer that declares the representation of the convex body. For the intersection between an H-polytope and an ellipsoid the default value is 6. It has not be given to the constructor.} + +\item{\code{dimension} }{ An integer that declares the dimension of the convex body. It has not be given to the constructor.} + +\item{\code{volume} }{ The volume of the convex body, if it is known.} + } +} +\keyword{internal} + diff --git a/R-proj/man/Rcpp_sparse_constraint_problem.Rd b/R-proj/man/Rcpp_sparse_constraint_problem.Rd new file mode 100644 index 000000000..82f81f6c9 --- /dev/null +++ b/R-proj/man/Rcpp_sparse_constraint_problem.Rd @@ -0,0 +1,34 @@ +\docType{class} +\name{Rcpp_sparse_constraint_problem} +\alias{Rcpp_sparse_constraint_problem-class} +\alias{[,Rcpp_sparse_constraint_problem-method} +\alias{[,Rcpp_sparse_constraint_problem,ANY,ANY,ANY-method} +\alias{$<-,Rcpp_sparse_constraint_problem-method} +\alias{$,Rcpp_sparse_constraint_problem-method} +\alias{filepaths<-,Rcpp_sparse_constraint_problem-method} +\title{ +An \code{Rcpp} class to represent sparse_constraint_problems, exposed to \code{R} via modules. +} +\description{ +A constraint problem is defined by a set of linear inequalities and equalities or equivalently a \eqn{d}-dimensional constraint problem is defined by a \eqn{mineq\times d} matrix Aineq and a \eqn{mineq}-dimensional vector bineq, s.t.: \eqn{Aineqx\leq bineq}, a \eqn{meq\times d} matrix Aeq and a \eqn{meq}-dimensional vector beq, s.t.: \eqn{Aeqx= beq} and two \eqn{d} vectors lb, ub such that \eqn{lb\leq x \leq ub}.} +\details{ +\describe{ +\item{\code{Aineq} }{\eqn{mineq\times d} sparse matrix Aineq} + +\item{\code{bineq} }{\eqn{mineq}-dimensional vector bineq} + +\item{\code{Aeq} }{\eqn{meq\times d} sparse matrix Aeq} + +\item{\code{beq} }{\eqn{meq}-dimensional vector beq} + +\item{\code{lb} }{\eqn{d}-dimensional vector bineq} + +\item{\code{ub} }{\eqn{d}-dimensional vector bineq} + +\item{\code{type} }{An integer that declares the representation of the polytope. For sparse_constraint_problem the default value is 5.} + +\item{\code{dimension} }{The dimension of the polytope.} + + } +} +\keyword{internal} diff --git a/R-proj/man/sample_points.Rd b/R-proj/man/sample_points.Rd index f5ea6f2bf..e969e557d 100644 --- a/R-proj/man/sample_points.Rd +++ b/R-proj/man/sample_points.Rd @@ -7,13 +7,13 @@ sample_points(P, n, random_walk = NULL, distribution = NULL, seed = NULL) } \arguments{ -\item{P}{A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope or (d) VpolytopeIntersection.} +\item{P}{A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope or (d) VpolytopeIntersection or (e) sparse_constraint_problem.} \item{n}{The number of points that the function is going to sample from the convex polytope.} \item{random_walk}{Optional. A list that declares the random walk and some related parameters as follows: \itemize{ -\item{\code{walk} }{ A string to declare the random walk: i) \code{'CDHR'} for Coordinate Directions Hit-and-Run, ii) \code{'RDHR'} for Random Directions Hit-and-Run, iii) \code{'BaW'} for Ball Walk, iv) \code{'BiW'} for Billiard walk, v) \code{'dikin'} for dikin walk, vi) \code{'vaidya'} for vaidya walk, vii) \code{'john'} for john walk, viii) \code{'BCDHR'} boundary sampling by keeping the extreme points of CDHR or ix) \code{'BRDHR'} boundary sampling by keeping the extreme points of RDHR x) \code{'HMC'} for Hamiltonian Monte Carlo (logconcave) xi) \code{'ULD'} for Underdamped Langevin Dynamics using the Randomized Midpoint Method. The default walk is \code{'aBiW'} for the uniform distribution or \code{'CDHR'} for the Gaussian distribution and H-polytopes and \code{'BiW'} or \code{'RDHR'} for the same distributions and V-polytopes and zonotopes.} +\item{\code{walk} }{ A string to declare the random walk: i) \code{'CDHR'} for Coordinate Directions Hit-and-Run, ii) \code{'RDHR'} for Random Directions Hit-and-Run, iii) \code{'BaW'} for Ball Walk, iv) \code{'BiW'} for Billiard walk, v) \code{'dikin'} for dikin walk, vi) \code{'vaidya'} for vaidya walk, vii) \code{'john'} for john walk, viii) \code{'BCDHR'} boundary sampling by keeping the extreme points of CDHR or ix) \code{'BRDHR'} boundary sampling by keeping the extreme points of RDHR, x) \code{'NUTS'} for NUTS Hamiltonian Monte Carlo sampler (logconcave densities), xi) \code{'HMC'} for Hamiltonian Monte Carlo (logconcave densities), xii) CRHMC for Riemannian HMC with H-polytope constraints (uniform and general logconcave densities), xiii) \code{'ULD'} for Underdamped Langevin Dynamics using the Randomized Midpoint Method (logconcave densities), xiii) \code{'ExactHMC'} for exact Hamiltonian Monte Carlo with reflections (spherical Gaussian or exponential distribution). The default walk is \code{'aBiW'} for the uniform distribution, \code{'CDHR'} for the Gaussian distribution and H-polytopes and \code{'BiW'} or \code{'RDHR'} for the same distributions and V-polytopes and zonotopes. \code{'NUTS'} is the default sampler for logconcave densities and \code{'CRHMC'} for logconcave densities with H-polytope and sparse constrainted problems.} \item{\code{walk_length} }{ The number of the steps per generated point for the random walk. The default value is \eqn{1}.} \item{\code{nburns} }{ The number of points to burn before start sampling. The default value is \eqn{1}.} \item{\code{starting_point} }{ A \eqn{d}-dimensional numerical vector that declares a starting point in the interior of the polytope for the random walk. The default choice is the center of the ball as that one computed by the function \code{inner_ball()}.} @@ -25,13 +25,14 @@ sample_points(P, n, random_walk = NULL, distribution = NULL, seed = NULL) \item{distribution}{Optional. A list that declares the target density and some related parameters as follows: \itemize{ -\item{\code{density} }{ A string: (a) \code{'uniform'} for the uniform distribution or b) \code{'gaussian'} for the multidimensional spherical distribution. The default target distribution is uniform. c) Logconcave with form proportional to exp(-f(x)) where f(x) is L-smooth and m-strongly-convex. } -\item{\code{variance} }{ The variance of the multidimensional spherical gaussian. The default value is 1.} +\item{\code{density} }{ A string: (a) \code{'uniform'} for the uniform distribution or b) \code{'gaussian'} for the multidimensional spherical distribution c) \code{logconcave} with form proportional to exp(-f(x)) where f(x) is L-smooth and m-strongly-convex d) \code{'exponential'} for the exponential distribution. The default target distribution is the uniform distribution.} +\item{\code{variance} }{ The variance of the multidimensional spherical gaussian or the exponential distribution. The default value is 1.} \item{\code{mode} }{ A \eqn{d}-dimensional numerical vector that declares the mode of the Gaussian distribution. The default choice is the center of the as that one computed by the function \code{inner_ball()}.} -\item{\code{L_}} { Smoothness constant (for logconcave). } -\item{\code{m}} { Strong-convexity constant (for logconcave). } -\item{\code{negative_logprob}} { Negative log-probability (for logconcave). } -\item{\code{negative_logprob_gradient}} { Negative log-probability gradient (for logconcave). } +\item{\code{bias} }{ The bias vector for the exponential distribution. The default vector is \eqn{c_1 = 1} and \eqn{c_i = 0} for \eqn{i \neq 1}.} +\item{\code{L_} }{ Smoothness constant (for logconcave). } +\item{\code{m} }{ Strong-convexity constant (for logconcave). } +\item{\code{negative_logprob} }{ Negative log-probability (for logconcave). } +\item{\code{negative_logprob_gradient} }{ Negative log-probability gradient (for logconcave). } }} \item{seed}{Optional. A fixed seed for the number generator.} @@ -75,4 +76,7 @@ points = sample_points(P, n = 100, random_walk = list("walk" = "BRDHR")) \cite{Shen, Ruoqi, and Yin Tat Lee, \dQuote{"The randomized midpoint method for log-concave sampling.",} \emph{Advances in Neural Information Processing Systems}, 2019.} + +\cite{Augustin Chevallier, Sylvain Pion, Frederic Cazals, +\dQuote{"Hamiltonian Monte Carlo with boundary reflections, and application to polytope volume calculations,"} \emph{Research Report preprint hal-01919855}, 2018.} } diff --git a/R-proj/man/sparse_constraint_problem.Rd b/R-proj/man/sparse_constraint_problem.Rd new file mode 100644 index 000000000..535dc8426 --- /dev/null +++ b/R-proj/man/sparse_constraint_problem.Rd @@ -0,0 +1,26 @@ +\name{sparse_constraint_problem} +\alias{sparse_constraint_problem} +\title{An \code{R} class to represent sparse constraint problems.} + +\description{ +A constraint problem is defined by a set of linear inequalities and equalities or equivalently a \eqn{d}-dimensional constraint problem is defined by a \eqn{mineq\times d} matrix Aineq and a \eqn{mineq}-dimensional vector bineq, s.t.: \eqn{Aineqx\leq bineq}, a \eqn{meq\times d} matrix Aeq and a \eqn{meq}-dimensional vector beq, s.t.: \eqn{Aeqx\eq beq} and two \eqn{d} vectors lb, ub such that \eqn{lb\leq x \leq ub}. +} +\section{Fields}{ +\itemize{ +\item{\code{Aineq} }{\eqn{mineq\times d} sparse matrix Aineq} + +\item{\code{bineq} }{\eqn{mineq}-dimensional vector bineq} + +\item{\code{Aeq} }{\eqn{meq\times d} sparse matrix Aeq} + +\item{\code{beq} }{\eqn{meq}-dimensional vector beq} + +\item{\code{lb} }{\eqn{d}-dimensional vector bineq} + +\item{\code{ub} }{\eqn{d}-dimensional vector bineq} + +\item{\code{type} }{An integer that declares the representation of the polytope. For sparse_constraint_problem the default value is 5.} + +\item{\code{dimension} }{The dimension of the polytope.} + +}} diff --git a/R-proj/src/Makevars b/R-proj/src/Makevars index 8f401249e..b642e2fbe 100644 --- a/R-proj/src/Makevars +++ b/R-proj/src/Makevars @@ -4,11 +4,16 @@ PKG_CXXFLAGS= -Wno-deprecated-declarations -lm -ldl -Wno-ignored-attributes -DBO CXX_STD = CXX11 -PKG_LIBS=-LRproj_externals/lp_solve -llp_solve $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) +PKG_LIBS=-LRproj_externals/lp_solve -llp_solve -L../../external/PackedCSparse/qd -lqd $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) -$(SHLIB): Rproj_externals/lp_solve/liblp_solve.a +$(SHLIB): Rproj_externals/lp_solve/liblp_solve.a ../../external/PackedCSparse/qd/libqd.a Rproj_externals/lp_solve/liblp_solve.a: @(cd Rproj_externals/lp_solve && $(MAKE) liblp_solve.a \ CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ CPICFLAGS="$(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)") + +../../external/PackedCSparse/qd/libqd.a: + @(cd ../../PackedCSparse/qd && $(MAKE) libqd.a \ + CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ + CPICFLAGS="$(CPICFLAGS)" AR="$(AR)") diff --git a/R-proj/src/Makevars.win b/R-proj/src/Makevars.win index 867308b75..17d28e206 100644 --- a/R-proj/src/Makevars.win +++ b/R-proj/src/Makevars.win @@ -2,12 +2,17 @@ PKG_CPPFLAGS=-I../../external/boost -I../../external/LPsolve_src/run_headers -I. PKG_CXXFLAGS= -Wno-deprecated-declarations -lm -ldl -Wno-ignored-attributes -DBOOST_NO_AUTO_PTR -DDISABLE_NLP_ORACLES CXX_STD = CXX11 -PKG_LIBS=-LRproj_externals/lp_solve -llp_solve $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) +PKG_LIBS=-LRproj_externals/lp_solve -llp_solve -L../../external/PackedCSparse/qd -lqd $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) -$(SHLIB): Rproj_externals/lp_solve/liblp_solve.a +$(SHLIB): Rproj_externals/lp_solve/liblp_solve.a ../../external/PackedCSparse/qd/libqd.a Rproj_externals/lp_solve/liblp_solve.a: @(cd Rproj_externals/lp_solve && $(MAKE) liblp_solve.a \ CC="$(CC)" CPPFLAGS="$(CPPFLAGS) -DUSRDLL -DINLINE=static" \ CFLAGS="$(CFLAGS)" CPICFLAGS="$(CPICFLAGS)" AR="$(AR)" \ RANLIB="$(RANLIB)") + +../../external/PackedCSparse/qd/libqd.a: + @(cd ../../PackedCSparse/qd && $(MAKE) libqd.a \ + CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ + CPICFLAGS="$(CPICFLAGS)" AR="$(AR)") diff --git a/R-proj/src/oracle_functors_rcpp.h b/R-proj/src/oracle_functors_rcpp.h index 558ac1b07..6929540ca 100644 --- a/R-proj/src/oracle_functors_rcpp.h +++ b/R-proj/src/oracle_functors_rcpp.h @@ -17,7 +17,8 @@ enum ode_solvers { euler, runge_kutta, richardson, - collocation + collocation, + implicit_midpoint }; // Holds Oracle Functor that wraps an R function via RCpp @@ -91,6 +92,17 @@ struct RcppFunctor { } } + Point operator() (Point const& x) const { + VT y = Rcpp::as(neg_grad_f(Rcpp::wrap(x.getCoefficients()))); + + Point z(y); + + if (negate) z = (-1.0) * z; + + // Return result as Point + return z; + } + }; // Negative log-probability functor @@ -118,6 +130,31 @@ struct RcppFunctor { }; + // Log-probability hessian functor + template + < + typename Point + > + struct HessianFunctor { + typedef typename Point::FT NT; + typedef typename Point::Coeff VT; + + parameters params; + Rcpp::Function hessian; // Negative hessian as an Rcpp::Function + + HessianFunctor( + parameters params_, + Rcpp::Function hessian_) : + params(params_), + hessian(hessian_) + {}; + + Point operator() (Point const& x) const { + VT y= Rcpp::as(hessian(Rcpp::wrap(x.getCoefficients()))); + return Point(y); + } + + }; }; #endif diff --git a/R-proj/src/polytopes_modules.cpp b/R-proj/src/polytopes_modules.cpp index 88c036988..82cdcacdd 100644 --- a/R-proj/src/polytopes_modules.cpp +++ b/R-proj/src/polytopes_modules.cpp @@ -11,11 +11,11 @@ class Hpolytope { Hpolytope() {} Hpolytope(Rcpp::NumericMatrix _A, Rcpp::NumericVector _b) : A(_A), b(_b), Aeq(Rcpp::NumericMatrix(0,0)), beq(Rcpp::NumericVector(0)), vol(std::numeric_limits::signaling_NaN()), dimension(_A.ncol()), type(1) {} - Hpolytope(Rcpp::NumericMatrix _A, Rcpp::NumericVector _b, Rcpp::NumericMatrix _Aeq, Rcpp::NumericVector _beq) : + Hpolytope(Rcpp::NumericMatrix _A, Rcpp::NumericVector _b, Rcpp::NumericMatrix _Aeq, Rcpp::NumericVector _beq) : A(_A), b(_b), Aeq(_Aeq), beq(_beq), vol(std::numeric_limits::signaling_NaN()), dimension(_A.ncol()), type(1) {} Hpolytope(Rcpp::NumericMatrix _A, Rcpp::NumericVector _b, double volume) : A(_A), b(_b), Aeq(Rcpp::NumericMatrix(0,0)), beq(Rcpp::NumericVector(0)), vol(volume), dimension(_A.ncol()), type(1) {} - Hpolytope(Rcpp::NumericMatrix _A, Rcpp::NumericVector _b, Rcpp::NumericMatrix _Aeq, Rcpp::NumericVector _beq, + Hpolytope(Rcpp::NumericMatrix _A, Rcpp::NumericVector _b, Rcpp::NumericMatrix _Aeq, Rcpp::NumericVector _beq, double volume) : A(_A), b(_b), Aeq(_Aeq), beq(_beq), vol(volume), dimension(_A.ncol()), type(1) {} Rcpp::NumericMatrix A; Rcpp::NumericVector b; @@ -60,6 +60,41 @@ class VPinterVP { int type; }; +class PolytopeIntersectEllipsoid { +public: + PolytopeIntersectEllipsoid() {} + PolytopeIntersectEllipsoid(Rcpp::NumericMatrix _A, Rcpp::NumericVector _b, Rcpp::NumericMatrix _E) : A(_A), b(_b), E(_E), vol(std::numeric_limits::signaling_NaN()), dimension(_A.ncol()), type(6) {} + PolytopeIntersectEllipsoid(Rcpp::NumericMatrix _A, Rcpp::NumericVector _b, Rcpp::NumericMatrix _E, double volume) : A(_A), b(_b), E(_E), vol(volume), dimension(_A.ncol()), type(6) {} + Rcpp::NumericMatrix A; + Rcpp::NumericVector b; + Rcpp::NumericMatrix E; + double vol; + unsigned int dimension; + int type; +}; + +#include +using SpMat=Eigen::SparseMatrix ; +class sparse_constraint_problem { +public: + sparse_constraint_problem() {} + sparse_constraint_problem(SpMat _Aineq, Rcpp::NumericVector _bineq, SpMat _Aeq, Rcpp::NumericVector _beq) : Aineq(_Aineq), bineq(_bineq), Aeq(_Aeq), beq(_beq), + lb(Rcpp::NumericVector(_Aineq.cols(),-1e9)), ub(Rcpp::NumericMatrix(_Aineq.cols(),1e9)), dimension(_Aineq.cols()), type(5) {} + sparse_constraint_problem(SpMat _Aineq, Rcpp::NumericVector _bineq, SpMat _Aeq, Rcpp::NumericVector _beq, + Rcpp::NumericVector _lb, Rcpp::NumericVector _ub) : Aineq(_Aineq), bineq(_bineq), Aeq(_Aeq), beq(_beq), + lb(_lb), ub(_ub), dimension(_Aineq.cols()), type(5) {} + sparse_constraint_problem(SpMat _Aeq, Rcpp::NumericVector _beq) : Aineq(SpMat(0, _Aeq.cols())), bineq(Rcpp::NumericVector(0)), Aeq(_Aeq), beq(_beq), + lb(Rcpp::NumericVector(_Aeq.cols(),-1e9)), ub(Rcpp::NumericMatrix(_Aeq.cols(),1e9)), dimension(_Aeq.cols()), type(5) {} + SpMat Aineq; + Rcpp::NumericVector bineq; + SpMat Aeq; + Rcpp::NumericVector beq; + Rcpp::NumericVector lb; + Rcpp::NumericVector ub; + unsigned int dimension; + int type; +}; + RCPP_MODULE(polytopes){ using namespace Rcpp ; @@ -174,6 +209,78 @@ RCPP_MODULE(polytopes){ .field( "volume", &VPinterVP::vol ) .field( "dimension", &VPinterVP::dimension ) .field( "type", &VPinterVP::type ); + + //' An exposed class to represent an intersection between an H-polytope and an ellipsoid. + //' + //' @description An intersection between of an H-polytope, defined by a set of linear inequalities, or a matrix A and an \eqn{m}-dimensional vector b s.t., \eqn{x, Ax\leq b}, and an ellipsoid defined by a positive definite matrix E s.t., \eqn{x, x^TEx \leq 1}. + //' + //' @field A \eqn{m \times d} matrix A + //' @field b \eqn{m}-dimensional vector b + //' @field E \eqn{d \times d} positive definite matrix E + //' @field volume The volume of the convex body, if it is known. + //' @field dimension An integer that declares the dimension of the convex body. It has not be given to the constructor. + //' @field type An integer that declares the representation of the convex body. For the intersection between an H-polytope and an ellipsoid the default value is 6. It has not be given to the constructor. + //' + //' @example + //' # create a 2-d intersection + //' A = matrix(c(1,0,0,1,-1,0,0,-1), nrow=4, ncol=2, byrow=TRUE) + //' b = rep(1,4) + //' E = matrix(c(0.25, 0.75, 0.75, 3.25), nrow=2, ncol=2, byrow=TRUE) + //' EP = PolytopeIntersectEllipsoid$new(A, b, E) + //' @export + class_("PolytopeIntersectEllipsoid") + // expose the default constructor + .constructor() + .constructor() + .constructor() + + .field( "A", &PolytopeIntersectEllipsoid::A ) + .field( "b", &PolytopeIntersectEllipsoid::b ) + .field( "E", &PolytopeIntersectEllipsoid::E ) + .field( "volume", &PolytopeIntersectEllipsoid::vol ) + .field( "dimension", &PolytopeIntersectEllipsoid::dimension ) + .field( "type", &PolytopeIntersectEllipsoid::type ); + + //' An exposed class to represent a sparse constraint problem + //' + //' @description A constraint problem is defined by a set of linear inequalities and equalities or equivalently a \eqn{d}-dimensional constraint problem is defined by a \eqn{mineq\times d} matrix Aineq and a \eqn{mineq}-dimensional vector bineq, s.t.: \eqn{Aineqx\leq bineq}, a \eqn{meq\times d} matrix Aeq and a \eqn{meq}-dimensional vector beq, s.t.: \eqn{Aeqx\eq beq} and two \eqn{d} vectors lb, ub such that \eqn{lb\leq x \leq ub}. + //' + //' @field Aineq \eqn{mineq\times d} sparse matrix Aineq + //' @field bineq \eqn{mineq}-dimensional vector bineq + //' @field Aeq \eqn{meq\times d} sparse matrix Aeq + //' @field beq \eqn{meq}-dimensional vector beq + //' @field lb \eqn{d}-dimensional vector lb + //' @field ub \eqn{d}-dimensional vector ub + //' @field dimension An integer that declares the dimension of the polytope. It has not be given to the constructor. + //' @field type An integer that declares the representation of the polytope. For sparse_constraint_problem the default value is 5. It has not be given to the constructor. + //' + //' @example + //' # create a 2-d unit simplex + //' Aineq = matrix(, nrow=0, ncol=2, byrow = TRUE) + //' Aineq = as( Aineq, 'dgCMatrix' ) + //' bineq= matrix(,nrow=0, ncol=1, byrow=TRUE) + //' Aeq = matrix(c(1,1), ncol=2, nrow=1, byrow=TRUE) + //' Aeq = as( Aeq, 'dgCMatrix' ) + //' beq = c(1) + //' lb = c(0,0) + //' ub = c(1,1) + //' P = sparse_constraint_problem$new(Aineq, bineq, Aeq, beq, lb, ub) + //' @export + class_("sparse_constraint_problem") + // expose the default constructor + .constructor() + .constructor() + .constructor() + .constructor() + + .field( "Aineq", &sparse_constraint_problem::Aineq ) + .field( "bineq", &sparse_constraint_problem::bineq ) + .field( "Aeq", &sparse_constraint_problem::Aeq ) + .field( "beq", &sparse_constraint_problem::beq ) + .field( "lb", &sparse_constraint_problem::lb ) + .field( "ub", &sparse_constraint_problem::ub ) + .field( "dimension", &sparse_constraint_problem::dimension ) + .field( "type", &sparse_constraint_problem::type ); } extern SEXP _rcpp_module_boot_polytopes(void); diff --git a/R-proj/src/sample_points.cpp b/R-proj/src/sample_points.cpp index d03c9b33f..5fd82bc51 100644 --- a/R-proj/src/sample_points.cpp +++ b/R-proj/src/sample_points.cpp @@ -23,7 +23,7 @@ #include "sampling/sampling.hpp" #include "ode_solvers/ode_solvers.hpp" #include "oracle_functors_rcpp.h" - +#include "preprocess/crhmc/constraint_problem.h" enum random_walks { ball_walk, rdhr, @@ -36,9 +36,11 @@ enum random_walks { brdhr, bcdhr, hmc, + nuts, gaussian_hmc, exponential_hmc, - uld + uld, + crhmc }; template < @@ -48,7 +50,8 @@ template < typename NT, typename Point, typename NegativeGradientFunctor, - typename NegativeLogprobFunctor + typename NegativeLogprobFunctor, + typename HessianFunctor > void sample_from_polytope(Polytope &P, int type, RNGType &rng, PointList &randPoints, unsigned int const& walkL, unsigned int const& numpoints, @@ -56,7 +59,7 @@ void sample_from_polytope(Polytope &P, int type, RNGType &rng, PointList &randPo Point const& StartingPoint, unsigned int const& nburns, bool const& set_L, NT const& eta, random_walks walk, NegativeGradientFunctor *F=NULL, NegativeLogprobFunctor *f=NULL, - ode_solvers solver_type = no_solver) + HessianFunctor *h=NULL, ode_solvers solver_type = no_solver) { switch (walk) { @@ -213,6 +216,30 @@ void sample_from_polytope(Polytope &P, int type, RNGType &rng, PointList &randPo } break; + case crhmc:{ + execute_crhmc(P, rng, randPoints, walkL, numpoints, nburns, F, f, h); + break; + } + case nuts: + + logconcave_sampling < + PointList, + Polytope, + RNGType, + NutsHamiltonianMonteCarloWalk, + NT, + Point, + NegativeGradientFunctor, + NegativeLogprobFunctor, + LeapfrogODESolver < + Point, + NT, + Polytope, + NegativeGradientFunctor + > + >(randPoints, P, rng, walkL, numpoints, StartingPoint, nburns, *F, *f); + + break; case uld: logconcave_sampling < @@ -240,11 +267,21 @@ void sample_from_polytope(Polytope &P, int type, RNGType &rng, PointList &randPo //' Sample uniformly, normally distributed, or logconcave distributed points from a convex Polytope (H-polytope, V-polytope, zonotope or intersection of two V-polytopes). //' -//' @param P A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope or (d) VpolytopeIntersection. +//' @param P A convex polytope. It is an object from class (a) Hpolytope or (b) Vpolytope or (c) Zonotope, (d) VpolytopeIntersection, or (e) Intersection between an Hpolytope and an ellipsoid. //' @param n The number of points that the function is going to sample from the convex polytope. //' @param random_walk Optional. A list that declares the random walk and some related parameters as follows: //' \itemize{ -//' \item{\code{walk} }{ A string to declare the random walk: i) \code{'CDHR'} for Coordinate Directions Hit-and-Run, ii) \code{'RDHR'} for Random Directions Hit-and-Run, iii) \code{'BaW'} for Ball Walk, iv) \code{'BiW'} for Billiard walk, v) \code{'dikin'} for dikin walk, vi) \code{'vaidya'} for vaidya walk, vii) \code{'john'} for john walk, viii) \code{'BCDHR'} boundary sampling by keeping the extreme points of CDHR or ix) \code{'BRDHR'} boundary sampling by keeping the extreme points of RDHR x) \code{'HMC'} for Hamiltonian Monte Carlo (logconcave densities) xi) \code{'ULD'} for Underdamped Langevin Dynamics using the Randomized Midpoint Method xii) \code{'ExactHMC'} for exact Hamiltonian Monte Carlo with reflections (spherical Gaussian or exponential distribution). The default walk is \code{'aBiW'} for the uniform distribution or \code{'CDHR'} for the Gaussian distribution and H-polytopes and \code{'BiW'} or \code{'RDHR'} for the same distributions and V-polytopes and zonotopes.} +//' \item{\code{walk} }{ A string to declare the random walk: i) \code{'CDHR'} for Coordinate Directions Hit-and-Run, +//' ii) \code{'RDHR'} for Random Directions Hit-and-Run, iii) \code{'BaW'} for Ball Walk, iv) \code{'BiW'} for Billiard walk, +//' v) \code{'dikin'} for dikin walk, vi) \code{'vaidya'} for vaidya walk, vii) \code{'john'} for john walk, +//' viii) \code{'BCDHR'} boundary sampling by keeping the extreme points of CDHR or ix) \code{'BRDHR'} boundary sampling by keeping the extreme points of RDHR, +//' x) \code{'NUTS'} for NUTS Hamiltonian Monte Carlo sampler (logconcave densities), xi) \code{'HMC'} for Hamiltonian Monte Carlo (logconcave densities), +//' xii) CRHMC for Riemannian HMC with H-polytope constraints (uniform and general logconcave densities), +//' xiii) \code{'ULD'} for Underdamped Langevin Dynamics using the Randomized Midpoint Method (logconcave densities), +//' xiii) \code{'ExactHMC'} for exact Hamiltonian Monte Carlo with reflections (spherical Gaussian or exponential distribution). +//' The default walk is \code{'aBiW'} for the uniform distribution, \code{'CDHR'} for the Gaussian distribution and H-polytopes and +//' \code{'BiW'} or \code{'RDHR'} for the same distributions and V-polytopes and zonotopes. \code{'NUTS'} is the default sampler for logconcave densities and \code{'CRHMC'} +//' for logconcave densities with H-polytope and sparse constrainted problems.} //' \item{\code{walk_length} }{ The number of the steps per generated point for the random walk. The default value is \eqn{1}.} //' \item{\code{nburns} }{ The number of points to burn before start sampling. The default value is \eqn{1}.} //' \item{\code{starting_point} }{ A \eqn{d}-dimensional numerical vector that declares a starting point in the interior of the polytope for the random walk. The default choice is the center of the ball as that one computed by the function \code{inner_ball()}.} @@ -255,7 +292,7 @@ void sample_from_polytope(Polytope &P, int type, RNGType &rng, PointList &randPo //' } //' @param distribution Optional. A list that declares the target density and some related parameters as follows: //' \itemize{ -//' \item{\code{density} }{ A string: (a) \code{'uniform'} for the uniform distribution or b) \code{'gaussian'} for the multidimensional spherical distribution c) \code{logconcave} with form proportional to exp(-f(x)) where f(x) is L-smooth and m-strongly-convex d) \code{'exponential'} for the exponential distribution. The default target distribution is the uniform distribution.} +//' \item{\code{density} }{ A string: (a) \code{'uniform'} for the uniform distribution, b) \code{'gaussian'} for the multidimensional spherical distribution, c) \code{logconcave} with form proportional to exp(-f(x)) where f(x) is L-smooth and m-strongly-convex, d) \code{'exponential'} for the exponential distribution. The default target distribution is the uniform distribution.} //' \item{\code{variance} }{ The variance of the multidimensional spherical gaussian or the exponential distribution. The default value is 1.} //' \item{\code{mode} }{ A \eqn{d}-dimensional numerical vector that declares the mode of the Gaussian distribution. The default choice is the center of the as that one computed by the function \code{inner_ball()}.} //' \item{\code{bias} }{ The bias vector for the exponential distribution. The default vector is \eqn{c_1 = 1} and \eqn{c_i = 0} for \eqn{i \neq 1}.} @@ -315,19 +352,27 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, typedef BoostRandomNumberGenerator RNGType; typedef typename Kernel::Point Point; typedef HPolytope Hpolytope; - typedef VPolytope Vpolytope; + typedef VPolytope Vpolytope; typedef Zonotope zonotope; typedef IntersectionOfVpoly InterVP; + typedef Ellipsoid Ellipse; + typedef EllipsoidIntersectPolytope EllipsoidIntPolytope; typedef Eigen::Matrix VT; typedef Eigen::Matrix MT; + typedef Eigen::SparseMatrix SpMat; + typedef constraint_problem sparse_problem; unsigned int type = Rcpp::as(P).field("type"), dim = Rcpp::as(P).field("dimension"), walkL = 1, numpoints, nburns = 0; RcppFunctor::GradientFunctor *F = NULL; RcppFunctor::FunctionFunctor *f = NULL; + RcppFunctor::HessianFunctor *h = NULL; + GaussianFunctor::GradientFunctor *G = NULL; GaussianFunctor::FunctionFunctor *g = NULL; + GaussianFunctor::HessianFunctor *hess_g = NULL; + bool functor_defined = true; @@ -341,12 +386,12 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, NT radius = 1.0, L; bool set_mode = false, gaussian = false, logconcave = false, exponential = false, - set_starting_point = false, set_L = false; + set_starting_point = false, set_L = false; random_walks walk; ode_solvers solver; // Used only for logconcave sampling - NT eta; + NT eta = 1; std::list randPoints; std::pair InnerBall; Point mode(dim); @@ -410,18 +455,24 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, Rcpp::Function negative_logprob = Rcpp::as(distribution)["negative_logprob"]; Rcpp::Function negative_logprob_gradient = Rcpp::as(distribution)["negative_logprob_gradient"]; - NT L_, m, eta; + NT L_ = 1, m = 1; if (Rcpp::as(distribution).containsElementNamed("L_")) { L_ = Rcpp::as(Rcpp::as(distribution)["L_"]); + if (L_ <= NT(0)) { + throw Rcpp::exception("The smoothness constant must be positive"); + } } else { - throw Rcpp::exception("The smoothness constant is absent"); + L_ = -1; } if (Rcpp::as(distribution).containsElementNamed("m")) { m = Rcpp::as(Rcpp::as(distribution)["m"]); + if (m <= NT(0)) { + throw Rcpp::exception("The strong-convexity constant must be positive"); + } } else { - throw Rcpp::exception("The strong-convexity constant is absent"); + m = -1; } if (Rcpp::as(random_walk).containsElementNamed("step_size")) { @@ -439,19 +490,22 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, solver = leapfrog; } else if (solver_str == "euler") { solver = euler; + } else if (solver_str == "implicit_midpoint"){ + solver = implicit_midpoint; } else { throw Rcpp::exception("Invalid ODE solver specified. Aborting."); } } else { - Rcpp::warning("Solver set to leapfrog."); solver = leapfrog; } - // Create functors RcppFunctor::parameters rcpp_functor_params(L_, m, eta, 2); F = new RcppFunctor::GradientFunctor(rcpp_functor_params, negative_logprob_gradient); f = new RcppFunctor::FunctionFunctor(rcpp_functor_params, negative_logprob); - + if(Rcpp::as(distribution).containsElementNamed("negative_logprob_hessian")){ + Rcpp::Function negative_logprob_hessian = Rcpp::as(distribution)["negative_logprob_hessian"]; + h = new RcppFunctor::HessianFunctor(rcpp_functor_params, negative_logprob_hessian); + } } else if (logconcave && !Rcpp::as(distribution).containsElementNamed("negative_logprob") && @@ -459,8 +513,6 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, functor_defined = false; - NT eta; - if (Rcpp::as(random_walk).containsElementNamed("step_size")) { eta = NT(Rcpp::as(Rcpp::as(random_walk)["step_size"])); if (eta <= NT(0)) { @@ -476,6 +528,8 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, solver = leapfrog; } else if (solver_str == "euler") { solver = euler; + } else if (solver_str == "implicit_midpoint"){ + solver = implicit_midpoint; } else { throw Rcpp::exception("Invalid ODE solver specified. Aborting."); } @@ -483,12 +537,11 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, Rcpp::warning("Solver set to leapfrog."); solver = leapfrog; } - // Create functors - GaussianFunctor::parameters gaussian_functor_params(mode, a, eta); - G = new GaussianFunctor::GradientFunctor(gaussian_functor_params); - g = new GaussianFunctor::FunctionFunctor(gaussian_functor_params); - + GaussianFunctor::parameters* gaussian_functor_params=new GaussianFunctor::parameters(mode, a, eta); + G = new GaussianFunctor::GradientFunctor(*gaussian_functor_params); + g = new GaussianFunctor::FunctionFunctor(*gaussian_functor_params); + hess_g = new GaussianFunctor::HessianFunctor(*gaussian_functor_params); } if (!random_walk.isNotNull() || !Rcpp::as(random_walk).containsElementNamed("walk")) { @@ -497,18 +550,12 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, throw Rcpp::exception("Exponential sampling is supported only for H-polytopes"); } walk = exponential_hmc; + } else if (logconcave) { + walk = (type == 5) ? crhmc : nuts; } else if (gaussian) { - if (type == 1) { - walk = cdhr; - } else { - walk = rdhr; - } + walk = (type == 1) ? cdhr : rdhr; } else { - if (type == 1) { - walk = accelarated_billiard; - } else { - walk = billiard; - } + walk = (type == 1) ? accelarated_billiard : billiard; } } else if (Rcpp::as(Rcpp::as(random_walk)["walk"]).compare(std::string("CDHR")) == 0) { walk = cdhr; @@ -573,10 +620,25 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, } } else if (Rcpp::as(Rcpp::as(random_walk)["walk"]).compare(std::string("HMC")) == 0) { if (!logconcave) throw Rcpp::exception("HMC is not supported for non first-order sampling"); + if (F->params.L < 0) throw Rcpp::exception("The smoothness constant is absent"); + if (F->params.m < 0) throw Rcpp::exception("The strong-convexity constant is absent"); walk = hmc; + } else if (Rcpp::as(Rcpp::as(random_walk)["walk"]).compare(std::string("NUTS")) == 0) { + if (!logconcave) throw Rcpp::exception("NUTS is not supported for non first-order sampling"); + walk = nuts; } else if (Rcpp::as(Rcpp::as(random_walk)["walk"]).compare(std::string("ULD")) == 0) { if (!logconcave) throw Rcpp::exception("ULD is not supported for non first-order sampling"); walk = uld; + } else if(Rcpp::as(Rcpp::as(random_walk)["walk"]).compare(std::string("CRHMC")) == 0){ + if (!logconcave) throw Rcpp::exception("CRHMC is used for logconcave sampling"); + if (type !=1 && type !=5 ) { + throw Rcpp::exception("CRHMC sampling is supported only for H-polytopes and Sparse Problems."); + } + walk =crhmc; + if(solver!=implicit_midpoint){ + Rcpp::warning("Solver set to implicit midpoint."); + } + solver = implicit_midpoint; } else { throw Rcpp::exception("Unknown walk type!"); } @@ -627,11 +689,11 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, } if (functor_defined) { sample_from_polytope(HP, type, rng, randPoints, walkL, numpoints, gaussian, a, L, c, - StartingPoint, nburns, set_L, eta, walk, F, f, solver); + StartingPoint, nburns, set_L, eta, walk, F, f, h, solver); } else { sample_from_polytope(HP, type, rng, randPoints, walkL, numpoints, gaussian, a, L, c, - StartingPoint, nburns, set_L, eta, walk, G, g, solver); + StartingPoint, nburns, set_L, eta, walk, G, g, hess_g, solver); } break; } @@ -653,7 +715,7 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, VP.shift(mode.getCoefficients()); } sample_from_polytope(VP, type, rng, randPoints, walkL, numpoints, gaussian, a, L, c, - StartingPoint, nburns, set_L, eta, walk, F, f, solver); + StartingPoint, nburns, set_L, eta, walk, F, f, h, solver); break; } case 3: { @@ -674,7 +736,7 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, ZP.shift(mode.getCoefficients()); } sample_from_polytope(ZP, type, rng, randPoints, walkL, numpoints, gaussian, a, L, c, - StartingPoint, nburns, set_L, eta, walk, F, f, solver); + StartingPoint, nburns, set_L, eta, walk, F, f, h, solver); break; } case 4: { @@ -697,15 +759,55 @@ Rcpp::NumericMatrix sample_points(Rcpp::Nullable P, VPcVP.shift(mode.getCoefficients()); } sample_from_polytope(VPcVP, type, rng, randPoints, walkL, numpoints, gaussian, a, L, c, - StartingPoint, nburns, set_L, eta, walk, F, f, solver); + StartingPoint, nburns, set_L, eta, walk, F, f, h, solver); break; } + case 5: { + // Sparse constraint_problem + SpMat Aeq = Rcpp::as(Rcpp::as(P).field("Aeq")); + VT beq= Rcpp::as(Rcpp::as(P).field("beq")); + SpMat Aineq = Rcpp::as(Rcpp::as(P).field("Aineq")); + VT bineq= Rcpp::as(Rcpp::as(P).field("bineq")); + VT lb= Rcpp::as(Rcpp::as(P).field("lb")); + VT ub= Rcpp::as(Rcpp::as(P).field("ub")); + sparse_problem problem(dim, Aeq, beq, Aineq, bineq, lb, ub); + if(walk!=crhmc){throw Rcpp::exception("Sparse problems are supported only by the CRHMC walk.");} + if (functor_defined) { + execute_crhmc, RcppFunctor::GradientFunctor,RcppFunctor::FunctionFunctor, RcppFunctor::HessianFunctor, CRHMCWalk, 8>(problem, rng, randPoints, walkL, numpoints, nburns, F, f, h); + } + else { + execute_crhmc, GaussianFunctor::GradientFunctor,GaussianFunctor::FunctionFunctor, GaussianFunctor::HessianFunctor, CRHMCWalk, 8>(problem, rng, randPoints, walkL, numpoints, nburns, G, g, hess_g); + } + break; + } + case 6: { + // Intersection between an H-polytope and an ellipsoid + if (random_walk.isNotNull()) { + if (Rcpp::as(Rcpp::as(random_walk)["walk"]).compare(std::string("ExactHMC")) == 0) { + throw Rcpp::exception("Exact HMC does not support intersection of an H-polytope with an ellipsoid."); + } + } + if (!set_starting_point) {throw Rcpp::exception("An internal point must be given in the case of an intersection between an H-polytope and an ellipsoid.");} + Hpolytope HP(dim, Rcpp::as(Rcpp::as(P).field("A")), + Rcpp::as(Rcpp::as(P).field("b"))); + Ellipse ell(Rcpp::as(Rcpp::as(P).field("E"))); + EllipsoidIntPolytope EP(HP, ell); + if (walk==crhmc){throw Rcpp::exception("Intersection between an H-polytope and an ellipsoid is not supported by the CRHMC walk.");} + if (functor_defined) { + sample_from_polytope(EP, type, rng, randPoints, walkL, numpoints, gaussian, a, L, c, + StartingPoint, nburns, set_L, eta, walk, F, f, h, solver); + } + else { + sample_from_polytope(EP, type, rng, randPoints, walkL, numpoints, gaussian, a, L, c, + StartingPoint, nburns, set_L, eta, walk, G, g, hess_g, solver); + } + } } if (numpoints % 2 == 1 && (walk == brdhr || walk == bcdhr)) numpoints--; MT RetMat(dim, numpoints); unsigned int jj = 0; - + for (typename std::list::iterator rpit = randPoints.begin(); rpit!=randPoints.end(); rpit++, jj++) { if (gaussian) { RetMat.col(jj) = (*rpit).getCoefficients() + mode.getCoefficients(); diff --git a/R-proj/tests/testthat/test_sampling.R b/R-proj/tests/testthat/test_sampling.R index 1950eda07..d051dc70e 100644 --- a/R-proj/tests/testthat/test_sampling.R +++ b/R-proj/tests/testthat/test_sampling.R @@ -14,59 +14,74 @@ runsample <- function(P, name_string, dist){ res = 1 } return(res) - + +} + +logconcave_sample<- function(P,distribution, n_samples ,n_burns){ + if (distribution == "uniform"){ + f <- function(x) (0) + grad_f <- function(x) (0) + L=1 + m=1 + pts <- sample_points(P, n = n_samples, random_walk = list("walk" = "CRHMC", "nburns" = n_burns, "walk_length" = 1, "solver" = "implicit_midpoint"), distribution = list("density" = "logconcave", "negative_logprob" = f, "negative_logprob_gradient" = grad_f, "L_" = L, "m" = m)) + return(max(psrf_univariate(pts, "interval"))) + } + else if(distribution == "gaussian"){ + pts <- sample_points(P, n = n_samples, random_walk = list("walk" = "CRHMC", "nburns" = n_burns, "walk_length" = 1, "solver" = "implicit_midpoint"), distribution = list("density" = "logconcave", "variance"=8)) + return(max(psrf_univariate(pts, "interval"))) + } } for (i in 1:2) { - + if (i==1) { distribution = 'gaussian' } else { distribution = 'uniform' } - + test_that("Sampling test", { P= gen_cube(10, 'H') res = runsample(P, 'H-cube10', distribution) expect_equal(res, 1) }) - + test_that("Sampling test", { P = gen_cross(10, 'H') res = runsample(P, 'H-cross10', distribution) expect_equal(res, 1) }) - + test_that("Sampling test", { P = gen_prod_simplex(5) res = runsample(P, 'H-prod_simplex_5_5', distribution) expect_equal(res, 1) }) - + test_that("Sampling test", { P = gen_prod_simplex(10) res = runsample(P, 'H-prod_simplex_10_10', distribution) expect_equal(res, 1) }) - + test_that("Sampling test", { P = gen_simplex(10, 'H') res = runsample(P, 'H-prod_simplex10', distribution) expect_equal(res, 1) }) - + test_that("Sampling test", { P = gen_skinny_cube(10) res = runsample(P, 'H-skinny_cube10', distribution) expect_equal(res, 1) }) - + test_that("Sampling test", { P = gen_skinny_cube(20) res = runsample(P, 'H-skinny_cube20', distribution) expect_equal(res, 1) }) - + test_that("Sampling test", { Z = gen_rand_zonotope(4, 8) res = runsample(Z, 'zonotope_4_8', distribution) diff --git a/cran_gen/Makevars b/cran_gen/Makevars index a609d3dac..28c42dcad 100644 --- a/cran_gen/Makevars +++ b/cran_gen/Makevars @@ -2,11 +2,16 @@ PKG_CPPFLAGS=-Iexternal -Iexternal/lpsolve/headers/run_headers -Iexternal/minimu PKG_CXXFLAGS= -DBOOST_NO_AUTO_PTR -DDISABLE_NLP_ORACLES CXX_STD = CXX11 -PKG_LIBS=-Lexternal/lpsolve/build/lp_solve -llp_solve $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) +PKG_LIBS=-Lexternal/lpsolve/build/lp_solve -llp_solve -Lexternal/PackedCSparse/qd -lqd $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) -$(SHLIB): external/lpsolve/build/lp_solve/liblp_solve.a +$(SHLIB): external/lpsolve/build/lp_solve/liblp_solve.a external/PackedCSparse/qd/libqd.a external/lpsolve/build/lp_solve/liblp_solve.a: @(cd external/lpsolve/build/lp_solve && $(MAKE) liblp_solve.a \ CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ CPICFLAGS="$(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)") + +external/PackedCSparse/qd/libqd.a: + @(cd external/PackedCSparse/qd/ && $(MAKE) libqd.a \ + CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ + CPICFLAGS="$(CPICFLAGS)" AR="$(AR)") diff --git a/cran_gen/Makevars.win b/cran_gen/Makevars.win index 70005148e..b93299131 100644 --- a/cran_gen/Makevars.win +++ b/cran_gen/Makevars.win @@ -2,12 +2,17 @@ PKG_CPPFLAGS=-Iexternal -Iexternal/lpsolve/headers/run_headers -Iexternal/minimu PKG_CXXFLAGS= -lm -ldl -DBOOST_NO_AUTO_PTR -DDISABLE_NLP_ORACLES CXX_STD = CXX11 -PKG_LIBS=-Lexternal/lpsolve/build/lp_solve -llp_solve $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) +PKG_LIBS=-Lexternal/lpsolve/build/lp_solve -llp_solve -Lexternal/PackedCSparse/qd -lqd $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) -$(SHLIB): external/lpsolve/build/lp_solve/liblp_solve.a +$(SHLIB): external/lpsolve/build/lp_solve/liblp_solve.a external/PackedCSparse/qd/libqd.a external/lpsolve/build/lp_solve/liblp_solve.a: @(cd external/lpsolve/build/lp_solve && $(MAKE) liblp_solve.a \ CC="$(CC)" CPPFLAGS="$(CPPFLAGS) -DUSRDLL -DINLINE=static" \ CFLAGS="$(CFLAGS)" CPICFLAGS="$(CPICFLAGS)" AR="$(AR)" \ RANLIB="$(RANLIB)") + +external/PackedCSparse/qd/libqd.a: + @(cd external/PackedCSparse/qd/ && $(MAKE) libqd.a \ + CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \ + CPICFLAGS="$(CPICFLAGS)" AR="$(AR)") diff --git a/cran_gen/genCRANpkg.R b/cran_gen/genCRANpkg.R index f12905f06..abf51d88a 100644 --- a/cran_gen/genCRANpkg.R +++ b/cran_gen/genCRANpkg.R @@ -17,17 +17,17 @@ file.copy(dir_lp, lp_dist, recursive=TRUE) # fix ftime deprecation, taken from: https://github.com/GeomScale/volesti/pull/89/files library(xfun) gsub_file( - paste0(path,"/R-proj/src/Rproj_externals/lp_solve/commonlib.c"), - "struct timeb buf;", "", + paste0(path,"/R-proj/src/Rproj_externals/lp_solve/commonlib.c"), + "struct timeb buf;", "", fixed=TRUE) gsub_file( - paste0(path,"/R-proj/src/Rproj_externals/lp_solve/commonlib.c"), - "ftime(&buf);", "", + paste0(path,"/R-proj/src/Rproj_externals/lp_solve/commonlib.c"), + "ftime(&buf);", "", fixed=TRUE) gsub_file( - paste0(path,"/R-proj/src/Rproj_externals/lp_solve/commonlib.c"), - "return((double)buf.time+((double) buf.millitm)/1000.0);", - "return((double)0);", + paste0(path,"/R-proj/src/Rproj_externals/lp_solve/commonlib.c"), + "return((double)buf.time+((double) buf.millitm)/1000.0);", + "return((double)0);", fixed=TRUE) # add lpsolve header files in external @@ -42,6 +42,8 @@ dir_lp = paste0(path,"/lpSolveAPI/inst/include") h_files = dir(dir_lp, "*.h", ignore.case = TRUE, all.files = TRUE) lp_dist = paste0(path,"/external/LPsolve_src/include") file.copy(file.path(dir_lp, h_files), lp_dist, recursive=TRUE, overwrite=TRUE) +# replace the lpsolve header file that issues a warning in mac's cran test +file.copy(paste0(path,"/external/cmake-files/lpsolve_modified_header_files/lp_rlp.h"), lp_dist, recursive=TRUE, overwrite=TRUE) dir_lp = paste0(path,"/lpSolve/src") h_files = dir(dir_lp, "*.h", ignore.case = TRUE, all.files = TRUE) lp_dist = paste0(path,"/external/LPsolve_src/run_headers") @@ -164,6 +166,8 @@ makefile_dir = paste0(path,'/cran_gen/Makefile') makefile_dist = paste0(path, '/cran_gen/cran_package/src/external/lpsolve/build/lp_solve') file.copy(makefile_dir, makefile_dist, recursive=TRUE) + + # set new cran package folder as wrking directory setwd(paste0(path,'/cran_gen/cran_package')) # enable devtools and Rcpp libraries diff --git a/examples/crhmc_prepare/CMakeLists.txt b/examples/crhmc_prepare/CMakeLists.txt index 6bdf831b2..35c31e9e1 100644 --- a/examples/crhmc_prepare/CMakeLists.txt +++ b/examples/crhmc_prepare/CMakeLists.txt @@ -121,7 +121,7 @@ else () add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") - add_executable (crhmc_prepare crhmc_prepare.cpp) - TARGET_LINK_LIBRARIES(crhmc_prepare ${QD_LIB} ${MKL_LINK} ${LP_SOLVE}) + add_executable (crhmc_prepare crhmc_prepare.cpp ) + TARGET_LINK_LIBRARIES(crhmc_prepare QD_LIB ${MKL_LINK} ${LP_SOLVE}) endif() diff --git a/examples/crhmc_sampling/.gitignore b/examples/crhmc_sampling/.gitignore index 5ba563ce6..60b43389a 100644 --- a/examples/crhmc_sampling/.gitignore +++ b/examples/crhmc_sampling/.gitignore @@ -1,3 +1,7 @@ crhmc_sampling +crhmc_sample_sparse samples.txt +CRHMC_SIMD_* +sampling_functions +simple_crhmc libQD_LIB.a diff --git a/examples/crhmc_sampling/CMakeLists.txt b/examples/crhmc_sampling/CMakeLists.txt index bb206ea49..8bd8d958e 100644 --- a/examples/crhmc_sampling/CMakeLists.txt +++ b/examples/crhmc_sampling/CMakeLists.txt @@ -114,15 +114,18 @@ else () add_definitions(${CMAKE_CXX_FLAGS} "-std=c++11") # enable C++11 standard - #add_definitions(${CMAKE_CXX_FLAGS} "-g") # enable debuger set(ADDITIONAL_FLAGS "-march=native -DSIMD_LEN=0 -DTIME_KEEPING") - add_definitions(${CMAKE_CXX_FLAGS} "-O3 " ${ADDITIONAL_FLAGS}) # optimization of the compiler + add_definitions(${CMAKE_CXX_FLAGS} "-O3 -DTIME_KEEPING" ${ADDITIONAL_FLAGS}) # optimization of the compiler #add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lgsl") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-lm") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-ldl") add_definitions(${CXX_COVERAGE_COMPILE_FLAGS} "-DBOOST_NO_AUTO_PTR") - add_executable (crhmc_sampling crhmc_sampling.cpp) - TARGET_LINK_LIBRARIES(crhmc_sampling ${QD_LIB} ${MKL_LINK} ${LP_SOLVE}) + add_executable (sampling_functions sampling_functions.cpp) + TARGET_LINK_LIBRARIES(sampling_functions QD_LIB ${MKL_LINK} ${LP_SOLVE}) + add_executable (simple_crhmc simple_crhmc.cpp) + TARGET_LINK_LIBRARIES(simple_crhmc QD_LIB ${MKL_LINK} ${LP_SOLVE}) + add_executable (dirichlet_sampling dirichlet_sampling.cpp) + TARGET_LINK_LIBRARIES(dirichlet_sampling QD_LIB ${MKL_LINK} ${LP_SOLVE}) endif() diff --git a/examples/crhmc_sampling/README.md b/examples/crhmc_sampling/README.md index 38070b2d3..e70ada760 100644 --- a/examples/crhmc_sampling/README.md +++ b/examples/crhmc_sampling/README.md @@ -11,11 +11,16 @@ Build the example by running the following commands in this directory. cmake . -DLP_SOLVE=_PATH_TO_LIB_FILE make ``` -You have to specify the path to liblpsolve55.so/dll/dylib. +You have to specify the path to liblpsolve55.so. For example: -DLP_SOLVE=/usr/lib/lpsolve/liblpsolve55.so ## Running: ```bash - ./crhmc_sampling >samples.txt - python3 ../python_utilities/plot_samples.py -#include -#include -#include -#include -#include -#include - -#include "Eigen/Eigen" -#include "cartesian_geom/cartesian_kernel.h" -#include "diagnostics/multivariate_psrf.hpp" -#include "ode_solvers/ode_solvers.hpp" -#include "preprocess/crhmc/crhmc_input.h" -#include "preprocess/crhmc/crhmc_problem.h" -#include "random.hpp" -#include "random/normal_distribution.hpp" -#include "random/uniform_int.hpp" -#include "random/uniform_real_distribution.hpp" -#include "random_walks/random_walks.hpp" -#include "ode_solvers/oracle_functors.hpp" - -template -void run_main(int n_samples = 10000, int n_burns = -1, int dimension = 2, - int walk_length = 1, int burn_steps = 1) { - using Kernel = Cartesian; - using Point = typename Kernel::Point; - using MT = Eigen::Matrix; - using VT = Eigen::Matrix; - using RandomNumberGenerator = BoostRandomNumberGenerator; - using Func = GaussianFunctor::FunctionFunctor; - using Grad = GaussianFunctor::GradientFunctor; - using Hess = GaussianFunctor::HessianFunctor; - using func_params = GaussianFunctor::parameters; - using Input = crhmc_input; - using CrhmcProblem = crhmc_problem; - using Solver = ImplicitMidpointODESolver; - using Opts = opts; - using Hpolytope = HPolytope; - - func_params params = func_params(Point(dimension), 4, 1); - Func f(params); - Grad g(params); - Hess h(params); - if (n_burns == -1) { - n_burns = n_samples / 2; - } - RandomNumberGenerator rng(1); - unsigned int dim = dimension; - Opts options; - - CRHMCWalk::parameters crhmc_params(g, dim, options); - Input input = Input(dim, f, g, h); - input.lb = -VT::Ones(dim); - input.ub = VT::Ones(dim); - CrhmcProblem P = CrhmcProblem(input, options); - P.print(); - Point x0 = Point(P.center); - crhmc_params.eta = 0.2; - crhmc_params.momentum = 0.8; - CRHMCWalk::Walk - crhmc(P, x0, g, f, crhmc_params); - MT samples = MT(dim, n_samples - n_burns); -#ifdef TIME_KEEPING - std::chrono::time_point start, end; - start = std::chrono::high_resolution_clock::now(); -#endif -#ifdef TIME_KEEPING - std::chrono::time_point start_file, - end_file; - std::chrono::duration total_time_file = - std::chrono::duration::zero(); -#endif - int j = 0; - for (int i = 0; i < n_samples; i++) { - if (i % 1000 == 0) { - std::cerr << i << " out of " << n_samples << "\n"; - } - for (int k = 0; k < burn_steps; k++) { - crhmc.apply(rng, walk_length, true); - } -#ifdef TIME_KEEPING - start_file = std::chrono::high_resolution_clock::now(); -#endif - if (i >= n_burns) { - VT sample = crhmc.getPoint().getCoefficients(); - samples.col(j) = VT(sample); - j++; - } -#ifdef TIME_KEEPING - end_file = std::chrono::high_resolution_clock::now(); - total_time_file += end_file - start_file; -#endif - } - std::cerr << "\n"; -#ifdef TIME_KEEPING - end = std::chrono::high_resolution_clock::now(); - std::chrono::duration total_time = end - start; - std::cerr << "Total time: " << total_time.count() << "\n"; - crhmc.print_timing_information(); -#endif - - std::cerr << "Step size (final): " << crhmc.solver->eta << std::endl; - std::cerr << "Discard Ratio: " << crhmc.discard_ratio << std::endl; - std::cerr << "Average Acceptance Probability: " - << crhmc.average_acceptance_prob << std::endl; - std::cerr << "PSRF: " << multivariate_psrf(samples) << std::endl; -#ifdef TIME_KEEPING - start_file = std::chrono::high_resolution_clock::now(); -#endif - std::cerr << "Writing samples in a file \n"; - std::cout << samples.transpose() << std::endl; -#ifdef TIME_KEEPING - end_file = std::chrono::high_resolution_clock::now(); - total_time_file += end_file - start_file; - std::cerr << "Time for writing the file: " << total_time_file.count() << "\n"; -#endif -} - -int main(int argc, char *argv[]) { - std::cerr << "Example Usage: ./crhmc_sampling n_sample initial_burns " - "dimension ode_steps steps_bettween_samples\n"; - std::cerr << "Example Usage: ./crhmc_sampling 10000 5000 " - "2 1 1\n"; - if (argc == 1) - run_main(); - else if (argc == 2) - run_main(atoi(argv[1])); - else if (argc == 3) - run_main(atoi(argv[1]), atoi(argv[2])); - else if (argc == 4) - run_main(atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); - else if (argc == 5) - run_main(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), - atoi(argv[4])); - return 0; -} diff --git a/examples/crhmc_sampling/data/afiro.mm b/examples/crhmc_sampling/data/afiro.mm new file mode 100644 index 000000000..28d2ef31c --- /dev/null +++ b/examples/crhmc_sampling/data/afiro.mm @@ -0,0 +1,112 @@ +%%MatrixMarket matrix coordinate real general +% Generated 25-Sep-2022 +27 52 109 +3 1 1 +4 2 1 +7 3 1 +8 4 1 +9 5 1 +10 6 1 +13 7 1 +14 8 1 +17 9 1 +18 10 1 +19 11 1 +20 12 1 +21 13 1 +22 14 1 +23 15 1 +24 16 1 +25 17 1 +26 18 1 +27 19 1 +1 20 -1 +2 20 -1.06 +3 20 1 +24 20 0.301 +1 21 1 +4 21 -1 +1 22 1 +22 22 -1 +2 23 1 +26 23 1 +5 24 -1 +6 24 -1.06 +7 24 1 +25 24 0.301 +5 25 -1 +6 25 -1.06 +8 25 1 +25 25 0.313 +5 26 -1 +6 26 -0.96 +9 26 1 +25 26 0.313 +5 27 -1 +6 27 -0.86 +10 27 1 +25 27 0.326 +7 28 -1 +21 28 2.364 +8 29 -1 +21 29 2.386 +9 30 -1 +21 30 2.408 +10 31 -1 +21 31 2.429 +4 32 1.4 +5 32 1 +5 33 1 +23 33 -1 +6 34 1 +27 34 1 +11 35 -1 +12 35 -0.43 +13 35 1 +22 35 0.109 +11 36 1 +14 36 -1 +11 37 1 +24 37 -1 +11 38 1 +21 38 -1 +12 39 1 +26 39 1 +15 40 -0.43 +16 40 1 +17 40 1 +23 40 0.109 +15 41 -0.43 +16 41 1 +18 41 1 +23 41 0.108 +15 42 -0.39 +16 42 1 +19 42 1 +23 42 0.108 +15 43 -0.37 +16 43 1 +20 43 1 +23 43 0.107 +17 44 -1 +21 44 2.191 +18 45 -1 +21 45 2.219 +19 46 -1 +21 46 2.249 +20 47 -1 +21 47 2.279 +14 48 1.4 +16 48 -1 +16 49 1 +25 49 -1 +15 50 1 +27 50 1 +16 51 1 +3 52 80 +7 52 80 +13 52 500 +16 52 44 +17 52 500 +26 52 310 +27 52 300 diff --git a/examples/crhmc_sampling/data/afiro_bounds.mm b/examples/crhmc_sampling/data/afiro_bounds.mm new file mode 100644 index 000000000..7041a15ef --- /dev/null +++ b/examples/crhmc_sampling/data/afiro_bounds.mm @@ -0,0 +1,54 @@ +%%MatrixMarket matrix coordinate real general +% Generated 25-Sep-2022 +51 2 51 +1 2 1000000000 +2 2 1000000000 +3 2 1000000000 +4 2 1000000000 +5 2 1000000000 +6 2 1000000000 +7 2 1000000000 +8 2 1000000000 +9 2 1000000000 +10 2 1000000000 +11 2 1000000000 +12 2 1000000000 +13 2 1000000000 +14 2 1000000000 +15 2 1000000000 +16 2 1000000000 +17 2 1000000000 +18 2 1000000000 +19 2 1000000000 +20 2 1000000000 +21 2 1000000000 +22 2 1000000000 +23 2 1000000000 +24 2 1000000000 +25 2 1000000000 +26 2 1000000000 +27 2 1000000000 +28 2 1000000000 +29 2 1000000000 +30 2 1000000000 +31 2 1000000000 +32 2 1000000000 +33 2 1000000000 +34 2 1000000000 +35 2 1000000000 +36 2 1000000000 +37 2 1000000000 +38 2 1000000000 +39 2 1000000000 +40 2 1000000000 +41 2 1000000000 +42 2 1000000000 +43 2 1000000000 +44 2 1000000000 +45 2 1000000000 +46 2 1000000000 +47 2 1000000000 +48 2 1000000000 +49 2 1000000000 +50 2 1000000000 +51 2 1000000000 diff --git a/examples/crhmc_sampling/data/cube2d.jpg b/examples/crhmc_sampling/data/cube2d.jpg new file mode 100644 index 000000000..63e7c2b7b Binary files /dev/null and b/examples/crhmc_sampling/data/cube2d.jpg differ diff --git a/examples/crhmc_sampling/data/simplex2d.jpg b/examples/crhmc_sampling/data/simplex2d.jpg new file mode 100644 index 000000000..6bc2eaefb Binary files /dev/null and b/examples/crhmc_sampling/data/simplex2d.jpg differ diff --git a/examples/crhmc_sampling/data/simplex3.mm b/examples/crhmc_sampling/data/simplex3.mm new file mode 100644 index 000000000..ef342e474 --- /dev/null +++ b/examples/crhmc_sampling/data/simplex3.mm @@ -0,0 +1,7 @@ +%%MatrixMarket matrix coordinate real general +% Generated 28-Sep-2022 +1 4 4 +1 1 1 +1 2 1 +1 3 1 +1 4 1 diff --git a/examples/crhmc_sampling/data/simplex3_bounds.mm b/examples/crhmc_sampling/data/simplex3_bounds.mm new file mode 100644 index 000000000..2438aa676 --- /dev/null +++ b/examples/crhmc_sampling/data/simplex3_bounds.mm @@ -0,0 +1,6 @@ +%%MatrixMarket matrix coordinate real general +% Generated 28-Sep-2022 +3 2 3 +1 2 1000000000 +2 2 1000000000 +3 2 1000000000 diff --git a/examples/crhmc_sampling/dirichlet_sampling.cpp b/examples/crhmc_sampling/dirichlet_sampling.cpp new file mode 100644 index 000000000..5fba587a6 --- /dev/null +++ b/examples/crhmc_sampling/dirichlet_sampling.cpp @@ -0,0 +1,104 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2023 Vissarion Fisikopoulos +// Copyright (c) 2018-2023 Apostolos Chalkis +// Copyright (c) 2020-2023 Elias Tsigaridas + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "volume/sampling_policies.hpp" +#include "ode_solvers/ode_solvers.hpp" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include "sampling/random_point_generators.hpp" +#include "sampling/sampling.hpp" +#include "misc/misc.h" +#include "random.hpp" +#include +#include "random_walks/random_walks.hpp" +#include "generators/known_polytope_generators.h" +#include "helper_functions.hpp" +using NT = double; +using Kernel = Cartesian; +using Point = typename Kernel::Point; +using Func = DirichletFunctor::FunctionFunctor; +using Grad = DirichletFunctor::GradientFunctor; +using Hess = GaussianFunctor::HessianFunctor; +using PolytopeType = HPolytope; +using MT = PolytopeType::MT; +using VT = Eigen::Matrix; +using func_params = DirichletFunctor::parameters; +using RNG = BoostRandomNumberGenerator; + +template +void sample_dirichlet(int n_samples = 80000, + int n_burns = 20000){ + using SpMat = Eigen::SparseMatrix; + using ConstraintProblem =constraint_problem; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using Solver = + ImplicitMidpointODESolver; + + int dim = 3; + RNG rng(dim); + SpMat Aeq(1,3); + Aeq.coeffRef(0,0) = NT(1); + Aeq.coeffRef(0,1) = NT(1); + Aeq.coeffRef(0,2) = NT(1); + VT beq = VT::Ones(1), lb = VT::Zero(dim), ub = VT::Ones(dim); + + VT a_vec(dim); + //a_vec << 2.0, 3.0, 4.0; + a_vec << 2.0, 3.0, 4.0; + + std::string problem_name("dirichlet"); + ConstraintProblem problem = ConstraintProblem(dim); + problem.set_equality_constraints(Aeq, beq); + problem.set_bounds(lb, ub); + func_params params = func_params(a_vec); + Func *f = new Func(params); + Grad *g = new Grad(params); + Hess *h = NULL; + std::list PointList; + //crhmc_sampling, ConstraintProblem, RNG, CRHMCWalk, NT, Point, Grad, Func, Hess, Solver>( + // PointList, problem, rng, 1, n_samples, n_burns, g, f, h, simdLen); + execute_crhmc, Grad, Func, Hess, CRHMCWalk, simdLen> + (problem, rng, PointList, 1, n_samples, n_burns, g, f, h); + MT samples = MT(dim, PointList.size()); + int i=0; + for (std::list::iterator it = PointList.begin(); it != PointList.end(); ++it){ + samples.col(i) = (*it).getCoefficients(); + i++; + } + std::ofstream diagnostics_stream; + diagnostics_stream.open("CRHMC_SIMD_" + std::to_string(simdLen) + "_" + + problem_name + "_diagnostics.txt"); + diagnose(samples, diagnostics_stream); + std::ofstream samples_stream; + samples_stream.open("CRHMC_SIMD_" + std::to_string(simdLen) + "_" + + problem_name + "_samples.txt"); + samples_stream << samples.transpose() << std::endl; +} + +int main() { + int n_samples = 5000; + int n_burns = 2000; + + std::cerr<<"Sampling Dirichlet\n"; + sample_dirichlet<1>(n_samples, n_burns); + sample_dirichlet<4>(n_samples, n_burns); + sample_dirichlet<8>(n_samples, n_burns); + sample_dirichlet<16>(n_samples, n_burns); + + return 0; +} diff --git a/examples/crhmc_sampling/helper_functions.hpp b/examples/crhmc_sampling/helper_functions.hpp new file mode 100644 index 000000000..7f92f925e --- /dev/null +++ b/examples/crhmc_sampling/helper_functions.hpp @@ -0,0 +1,61 @@ +#ifndef HELPER_FUNCTIONS_HPP +#define HELPER_FUNCTIONS_HPP +#include "diagnostics/diagnostics.hpp" +#include + +inline bool exists_check(const std::string &name) { + std::ifstream f(name.c_str()); + return f.good(); +} +/*Problem on the form X=[A|b] bounds=[lb|ub] */ +template< typename SpMat, typename VT> +void load_crhmc_problem(SpMat &A, VT &b, VT &lb, VT &ub, int &dimension, + std::string problem_name) { + { + std::string fileName("./data/"); + fileName.append(problem_name); + fileName.append(".mm"); + if(!exists_check(fileName)){ + std::cerr<<"Problem does not exist.\n"; + exit(1);} + SpMat X; + loadMarket(X, fileName); + int m = X.rows(); + dimension = X.cols() - 1; + A = X.leftCols(dimension); + b = VT(X.col(dimension)); + } + { + std::string fileName("./data/"); + fileName.append(problem_name); + fileName.append("_bounds.mm"); + if(!exists_check(fileName)){ + std::cerr<<"Problem does not exist.\n"; + exit(1);} + SpMat bounds; + loadMarket(bounds, fileName); + lb = VT(bounds.col(0)); + ub = VT(bounds.col(1)); + } +} +template +NT max_interval_psrf(MT &samples) { + NT max_psrf = NT(0); + VT intv_psrf = interval_psrf(samples); + unsigned int d = intv_psrf.rows(); + for (unsigned int i = 0; i < d; i++) { + if (intv_psrf(i) > max_psrf) + max_psrf = intv_psrf(i); + } + return max_psrf; +} +template +void diagnose(MT &samples, StreamType &stream) { + unsigned int min_ess = 0; + print_diagnostics(samples, min_ess, stream); + NT max_psrf = max_interval_psrf(samples); + stream << "max_psrf: " << max_psrf << std::endl; + stream << "min ess " << min_ess << std::endl; +} + +#endif diff --git a/examples/crhmc_sampling/sampling_functions.cpp b/examples/crhmc_sampling/sampling_functions.cpp new file mode 100644 index 000000000..18b83d32e --- /dev/null +++ b/examples/crhmc_sampling/sampling_functions.cpp @@ -0,0 +1,144 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2023 Vissarion Fisikopoulos +// Copyright (c) 2018-2023 Apostolos Chalkis +// Copyright (c) 2020-2023 Elias Tsigaridas +// Copyright (c) 2022-2023 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "volume/sampling_policies.hpp" +#include "ode_solvers/ode_solvers.hpp" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include "sampling/random_point_generators.hpp" +#include "sampling/sampling.hpp" +#include "misc/misc.h" +#include "random.hpp" +#include +#include "random_walks/random_walks.hpp" +#include "generators/known_polytope_generators.h" +#include "helper_functions.hpp" +using NT = double; +using Kernel = Cartesian; +using Point = typename Kernel::Point; +using Func = GaussianFunctor::FunctionFunctor; +using Grad = GaussianFunctor::GradientFunctor; +using Hess = GaussianFunctor::HessianFunctor; +using PolytopeType = HPolytope; +using MT = PolytopeType::MT; +using VT = Eigen::Matrix; +using func_params = GaussianFunctor::parameters; +using RNG = BoostRandomNumberGenerator; +template +void sample_hpoly(int n_samples = 80000, + int n_burns = 20000) { + std::string problem_name("simplex"); + std::cerr << "CRHMC on " << problem_name << "\n"; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using Solver = + ImplicitMidpointODESolver; + RNG rng(1); + PolytopeType HP=generate_simplex(2,false); + int dimension = HP.dimension(); + func_params params = func_params(Point(dimension), 0.5, 1); + Func f(params); + Grad g(params); + Hess h(params); + std::list PointList; + crhmc_sampling, PolytopeType, RNG, CRHMCWalk, NT, Point, Grad, Func, Hess, Solver>( + PointList, HP, rng, 1, n_samples, n_burns, g, f, h, simdLen); + MT samples = MT(dimension, PointList.size()); + int i=0; + for (std::list::iterator it = PointList.begin(); it != PointList.end(); ++it){ + samples.col(i) = (*it).getCoefficients(); + i++; + } + std::ofstream diagnostics_stream; + diagnostics_stream.open("CRHMC_SIMD_" + std::to_string(simdLen) + "_" + + problem_name + "_diagnostics.txt"); + diagnose(samples, diagnostics_stream); + std::ofstream samples_stream; + samples_stream.open("CRHMC_SIMD_" + std::to_string(simdLen) + "_" + + problem_name + "_samples.txt"); + samples_stream << samples.transpose() << std::endl; +} + +template +void sample_sparse_problem(int n_samples = 80000, + int n_burns = 20000){ + using SpMat = Eigen::SparseMatrix; + using ConstraintProblem =constraint_problem; + std::string problem_name("simplex3"); + std::cerr << "CRHMC on " << problem_name << "\n"; + using Input = crhmc_input; + using CrhmcProblem = crhmc_problem; + using Solver = + ImplicitMidpointODESolver; + + RNG rng(1); + SpMat A; + VT b, lb, ub; + int dimension; + load_crhmc_problem(A, b, lb, ub, dimension, problem_name); + ConstraintProblem problem = ConstraintProblem(dimension); + problem.set_equality_constraints(A, b); + problem.set_bounds(lb, ub); + func_params params = func_params(Point(dimension), 0.5, 1); + Func f(params); + Grad g(params); + Hess h(params); + std::list PointList; + crhmc_sampling, ConstraintProblem, RNG, CRHMCWalk, NT, Point, Grad, Func, Hess, Solver>( + PointList, problem, rng, 1, n_samples, n_burns, g, f, h, simdLen); + MT samples = MT(dimension, PointList.size()); + int i=0; + for (std::list::iterator it = PointList.begin(); it != PointList.end(); ++it){ + samples.col(i) = (*it).getCoefficients(); + i++; + } + std::ofstream diagnostics_stream; + diagnostics_stream.open("CRHMC_SIMD_" + std::to_string(simdLen) + "_" + + problem_name + "_diagnostics.txt"); + diagnose(samples, diagnostics_stream); + std::ofstream samples_stream; + samples_stream.open("CRHMC_SIMD_" + std::to_string(simdLen) + "_" + + problem_name + "_samples.txt"); + samples_stream << samples.transpose() << std::endl; +} +template +void run_main(int n_samples = 80000, + int n_burns = 20000){ + std::cerr<<"Sampling HPolytope\n"; + sample_hpoly(n_samples, n_burns); + std::cerr<<"Sampling Sparse Problem\n"; + sample_sparse_problem(n_samples, n_burns); +} +int main(int argc, char *argv[]) { + if (argc != 4) { + std::cerr << "Example Usage: ./crhmc_sample_sparse " + "[simdLen] [n_samples] [n_burns]\n"; + std::cerr << "i.e.: ./crhmc_sample_ 4 1000 500\n"; + exit(1); + } + if (atoi(argv[1]) == 1) { + run_main<1>(atoi(argv[2]), atoi(argv[3])); + } else if (atoi(argv[1]) == 4) { + run_main<4>(atoi(argv[2]), atoi(argv[3])); + } else if (atoi(argv[1]) == 8) { + run_main<8>(atoi(argv[2]), atoi(argv[3])); + } else if (atoi(argv[1]) == 16) { + run_main<16>(atoi(argv[2]), atoi(argv[3])); + } + return 0; +} diff --git a/examples/crhmc_sampling/simple_crhmc.cpp b/examples/crhmc_sampling/simple_crhmc.cpp new file mode 100644 index 000000000..8f07065b0 --- /dev/null +++ b/examples/crhmc_sampling/simple_crhmc.cpp @@ -0,0 +1,94 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Yunbum Kook, Yin Tat Lee, Ruoqi Shen, Santosh S. Vempala. "Sampling with +// Riemannian Hamiltonian +// Monte Carlo in a Constrained Space" +#include "Eigen/Eigen" +#include "cartesian_geom/cartesian_kernel.h" +#include "volume/sampling_policies.hpp" +#include "ode_solvers/ode_solvers.hpp" +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include "sampling/random_point_generators.hpp" +#include "sampling/sampling.hpp" +#include "misc/misc.h" +#include "random.hpp" +#include +#include "random_walks/random_walks.hpp" +#include "generators/known_polytope_generators.h" +#include "helper_functions.hpp" + +template +void sample_hpoly(int n_samples = 80000, + int n_burns = 20000, int dim = 2) { + using NT = double; + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using Func = ZeroScalarFunctor; + using Grad = ZeroFunctor; + using Hess = ZeroFunctor; + using PolytopeType = HPolytope; + using VT = Eigen::Matrix; + using MT = PolytopeType::MT; + using RNG = BoostRandomNumberGenerator; + std::string problem_name("simplex"); + std::cerr << "CRHMC on " << problem_name << "\n"; + RNG rng(1); + PolytopeType HP=generate_simplex(dim,false); + int dimension = HP.dimension(); + Func * f = new Func; + Grad * g = new Grad; + std::list PointList; + execute_crhmc< PolytopeType, RNG, std::list, Grad, Func, Hess, CRHMCWalk, simdLen>( + HP, rng, PointList, 1, n_samples, n_burns, g, f); + MT samples = MT(dimension, PointList.size()); + int i=0; + for (std::list::iterator it = PointList.begin(); it != PointList.end(); ++it){ + samples.col(i) = (*it).getCoefficients(); + i++; + } + std::cerr<<"max_psrf: "<< max_interval_psrf(samples)<<"\n"; + std::ofstream samples_stream; + samples_stream.open("CRHMC_SIMD_" + std::to_string(simdLen) + "_" + + problem_name + "_samples.txt"); + samples_stream << samples.transpose() << std::endl; + delete f; + delete g; +} + +template +void run_main(int n_samples = 80000, + int n_burns = 20000, + int dimension = 2){ + std::cerr<<"Sampling HPolytope\n"; + sample_hpoly(n_samples, n_burns, dimension); +} +int main(int argc, char *argv[]) { + if (argc != 5) { + std::cerr << "Example Usage: ./simple_crhmc " + "[simdLen] [n_samples] [n_burns] [dimension]\n"; + std::cerr << "i.e.: ./simple_crhmc 4 1000 500 2\n"; + exit(1); + } + std::cerr << "To plot: python3 ../python_utilities/plot_samples.py (atoi(argv[2]), atoi(argv[3]), atoi(argv[4])); + } else if (atoi(argv[1]) == 4) { + run_main<4>(atoi(argv[2]), atoi(argv[3]), atoi(argv[4])); + } else if (atoi(argv[1]) == 8) { + run_main<8>(atoi(argv[2]), atoi(argv[3]), atoi(argv[4])); + } else if (atoi(argv[1]) == 16) { + run_main<16>(atoi(argv[2]), atoi(argv[3]), atoi(argv[4])); + } + return 0; +} diff --git a/examples/ellipsoid-sampling/ellipsoid2d-sampling.cpp b/examples/ellipsoid-sampling/ellipsoid2d-sampling.cpp index 4a021bf1f..20d3271d3 100644 --- a/examples/ellipsoid-sampling/ellipsoid2d-sampling.cpp +++ b/examples/ellipsoid-sampling/ellipsoid2d-sampling.cpp @@ -3,30 +3,227 @@ #include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" #include "ellipsoid.h" +#include "ellipsoidintersectconvex.h" #include "sampling/ellipsoid.hpp" #include "random_walks/random_walks.hpp" -typedef double NT; -typedef Cartesian Kernel; -typedef typename Kernel::Point Point; -typedef Eigen::Matrix MT; -typedef Eigen::Matrix VT; -typedef BoostRandomNumberGenerator RNGType; - -int main(int argc, char const *argv[]) { +template +int run_ellipsoid_sampling() { + typedef Cartesian Kernel; + typedef BoostRandomNumberGenerator RNGType; + typedef typename Kernel::Point Point; + typedef Eigen::Matrix VT; + typedef Eigen::Matrix MT; unsigned int dim = 2; MT A(2, 2); A << 0.25, 0.75, 0.75, 3.25; Ellipsoid ell(A); // origin centered ellipsoid - int num_points = 1000; + int num_points = 5000; Point p(dim); RNGType rng(dim); + std::cout << "Sampling from ellipsoid..." << std::endl; + for (int i=0; i::apply(dim, ell, rng); p.print(); } + + std::cout << "Sampling from ellipsoid completed." << std::endl; + + return 0; +} + +template +int run_ellipsoid_polytope_sampling() { + typedef Cartesian Kernel; + typedef BoostRandomNumberGenerator RNGType; + typedef typename Kernel::Point Point; + typedef HPolytope Hpolytope; + typedef Ellipsoid CEllipsoid; + typedef EllipsoidIntersectPolytope EllipsoidIntPolytope; + typedef Eigen::Matrix VT; + typedef Eigen::Matrix MT; + typedef AcceleratedBilliardWalk::template Walk AcceleratedBilliardWalkType; + + PushBackWalkPolicy push_back_policy; + unsigned int dim = 2; + MT E(2, 2); + E << 0.25, 0.75, + 0.75, 3.25; + + Ellipsoid ell(E); // origin centered ellipsoid + + MT A(4,2); + A << 1.0, 0.0, + 0.0, 1.0, + -1.0, 0.0, + 0.0, -1.0; + VT b = VT::Ones(4); + Hpolytope P(dim, A, b); + + EllipsoidIntPolytope EP(P, ell); + + int num_points = 5000; + RNGType rng(dim); + Point p(dim); + + std::cout << "Sampling from the intersection between ellipsoid and polytope..." << std::endl; + + typedef RandomPointGenerator Generator; + std::vector randPoints; + Point q = Point(VT::Zero(dim)); // origin + Generator::apply(EP, q, num_points, 1, + randPoints, push_back_policy, rng); + + for (int i=0; i + struct parameters { + unsigned int order; + NT L; // Lipschitz constant for gradient + NT m; // Strong convexity constant + NT kappa; // Condition number + + parameters() : order(2), L(2), m(2), kappa(1) {}; + + parameters(unsigned int order_) : + order(order), + L(2), + m(2), + kappa(1) + {} + }; + + template + < + typename Point + > + struct GradientFunctor { + typedef typename Point::FT NT; + typedef std::vector pts; + + parameters params; + + GradientFunctor() {}; + + // The index i represents the state vector index + Point operator() (unsigned int const& i, pts const& xs, NT const& t) const { + if (i == params.order - 1) { + Point y = (-1.0) * Point::all_ones(xs[0].dimension()); + y = y + (-2.0) * xs[0]; + return y; + } else { + return xs[i + 1]; // returns derivative + } + } + + }; + + template + < + typename Point + > + struct FunctionFunctor { + typedef typename Point::FT NT; + + parameters params; + + FunctionFunctor() {}; + + // The index i represents the state vector index + NT operator() (Point const& x) const { + return x.dot(x) + x.sum(); + } + + }; + +}; + + +template +int run_ellipsoid_polytope_nuts_sampling() { + typedef Cartesian Kernel; + typedef BoostRandomNumberGenerator RNGType; + typedef typename Kernel::Point Point; + typedef BoostRandomNumberGenerator RandomNumberGenerator; + typedef HPolytope Hpolytope; + typedef Ellipsoid CEllipsoid; + typedef EllipsoidIntersectPolytope EllipsoidIntPolytope; + typedef Eigen::Matrix VT; + typedef Eigen::Matrix MT; + typedef CustomFunctor::GradientFunctor NegativeGradientFunctor; + typedef CustomFunctor::FunctionFunctor NegativeLogprobFunctor; + typedef LeapfrogODESolver Solver; + + + PushBackWalkPolicy push_back_policy; + unsigned int dim = 2; + MT E(2, 2); + E << 0.25, 0.75, + 0.75, 3.25; + + Ellipsoid ell(E); // origin centered ellipsoid + + MT A(4,2); + A << 1.0, 0.0, + 0.0, 1.0, + -1.0, 0.0, + 0.0, -1.0; + VT b = VT::Ones(4); + + Hpolytope P(dim, A, b); + EllipsoidIntPolytope EP(P, ell); + + NegativeGradientFunctor F; + NegativeLogprobFunctor f; + NutsHamiltonianMonteCarloWalk::parameters hmc_params(F, dim); + + std::cout << "Starting NUTS example" << std::endl; + std::cout << "eta0 before burnin: " << hmc_params.eta << std::endl; + + int num_points = 5000; + bool automatic_burnin = false; + RNGType rng(dim); + Point p(dim), q(dim); + + NutsHamiltonianMonteCarloWalk::Walk + hmc(&EP, p, F, f, hmc_params, automatic_burnin); + hmc.burnin(rng); + + std::cout << "eta after burnin: " << hmc.get_eta_solver() << std::endl; + std::cout << "Sampling with NUTS from the intersection between ellipsoid and polytope..." << std::endl; + + for (int i = 0; i < num_points; i++) { + hmc.apply(rng); + q = hmc.x.getCoefficients(); + q.print(); + } + + std::cout << "Sampling with NUTS from the intersection completed." << std::endl; + return 0; } + + +int main() { + run_ellipsoid_sampling(); + run_ellipsoid_polytope_sampling(); + run_ellipsoid_polytope_nuts_sampling(); + return 0; +} diff --git a/examples/logconcave/CMakeLists.txt b/examples/logconcave/CMakeLists.txt index 0448ce3e3..33725d0c9 100644 --- a/examples/logconcave/CMakeLists.txt +++ b/examples/logconcave/CMakeLists.txt @@ -20,7 +20,7 @@ endif(COMMAND cmake_policy) option(DISABLE_NLP_ORACLES "Disable non-linear oracles (used in collocation)" ON) option(BUILTIN_EIGEN "Use eigen from ../external" OFF) -option(USE_MKL "Use MKL library to build eigen" ON) +option(USE_MKL "Use MKL library to build eigen" OFF) if(DISABLE_NLP_ORACLES) add_definitions(-DDISABLE_NLP_ORACLES) @@ -73,16 +73,24 @@ else () include_directories(BEFORE /usr/include/eigen3) endif(BUILTIN_EIGEN) +find_library(BLAS NAMES libblas.so libblas.dylib PATHS /usr/local/Cellar/lapack/3.9.1_1/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu /usr/local/Cellar/openblas/0.3.15_1/lib /usr/lib) + if (USE_MKL) - find_library(BLAS NAME libblas.so PATHS /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu) + find_library(BLAS NAMES libblas.so libblas.dylib PATHS /usr/local/Cellar/lapack/3.9.1_1/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu /usr/local/Cellar/openblas/0.3.15_1/lib /usr/lib) + find_library(GFORTRAN NAME libgfortran.dylib PATHS /usr/local/Cellar/gcc/10.2.0_4/lib/gcc/10) + find_library(LAPACK NAME liblapack.dylib PATHS /usr/lib) + find_library(OPENMP NAME libiomp5.dylib PATHS /opt/intel/oneapi/compiler/2021.1.1/mac/compiler/lib) + include_directories (BEFORE ${MKLROOT}/include) - set(PROJECT_LIBS ${BLAS_LIBRARIES}) + set(PROJECT_LIBS ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${GFORTRAN_LIBRARIES}) set(MKL_LINK "-L${MKLROOT}/lib -Wl,-rpath,${MKLROOT}/lib -lmkl_intel_ilp64 -lmkl_sequential -lmkl_core -lpthread -lm -ldl") add_definitions(-DEIGEN_USE_MKL_ALL) +else() + set(MKL_LINK "") endif(USE_MKL) # Find lpsolve library -find_library(LP_SOLVE NAMES liblpsolve55.so PATHS /usr/lib/lp_solve) +find_library(LP_SOLVE NAMES liblpsolve55.so liblpsolve55.dylib PATHS /usr/lib/lp_solve /usr/local/lib) if (NOT LP_SOLVE) message(FATAL_ERROR "This program requires the lp_solve library, and will not be compiled.") @@ -145,6 +153,6 @@ else () TARGET_LINK_LIBRARIES(simple_hmc ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) TARGET_LINK_LIBRARIES(exponential_exact_hmc ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) TARGET_LINK_LIBRARIES(gaussian_exact_hmc ${LP_SOLVE} ${BLAS} ${MKL_LINK} ) - + endif() diff --git a/examples/optimization_spectrahedra/readWriteSdpaFile.cpp b/examples/optimization_spectrahedra/readWriteSdpaFile.cpp deleted file mode 100644 index c734ccac5..000000000 --- a/examples/optimization_spectrahedra/readWriteSdpaFile.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// VolEsti (volume computation and sampling library) - -// Copyright (c) 2012-2018 Vissarion Fisikopoulos -// Copyright (c) 2018 Apostolos Chalkis - -//Contributed and/or modified by Repouskos Panagiotis, as part of Google Summer of Code 2019 program. - -// Licensed under GNU LGPL.3, see LICENCE file - -// This examples illustrates how to read and write SDPA format files. -// It will read a semidefinite program from data/sdp_n2m3.txt, print it and then write it to a new file - -#define VOLESTI_DEBUG -#include "Eigen/Eigen" -#include "vector" -#include -#include "cartesian_geom/cartesian_kernel.h" -#include "random.hpp" -#include "spectrahedron.h" -#include "SDPAFormatManager.h" -#include "string" -#include "iostream" - -typedef double NT; -typedef Eigen::Matrix VT; -typedef Eigen::Matrix MT; -typedef Cartesian Kernel; -typedef typename Kernel::Point Point; -typedef Spectrahedron SPECTRAHEDRON; - - -int main(int argc, char* argv[]) { - std::string fileName("data/sdp_n2m3.txt"); - std::string outputFile("new_sdp_n2m3.txt"); - - SPECTRAHEDRON spectrahedron; - Point objFunction; - - // read the semidefinite program - // and create a vector (objective function) and a spectrahedron - - // open a stream to read the input file - std::ifstream in; - in.open(fileName, std::ifstream::in); - - // read the file - SdpaFormatManager sdpaFormatManager; - sdpaFormatManager.loadSDPAFormatFile(in, spectrahedron, objFunction); - - // print the contents - std::cout << "The objective Function:\n\n"; - objFunction.print(); - std::cout << "\n\nThe matrices of the spectrahedron:\n\n"; - spectrahedron.getLMI().print(); - - // open a stream to an output file - std::filebuf fb; - fb.open(outputFile, std::ios::out); - std::ostream os(&fb); - - // write a SDPA format file using the data we read before - sdpaFormatManager.writeSDPAFormatFile(os, spectrahedron, objFunction); - - return 0; -} - diff --git a/external/PackedCSparse/PackedChol.h b/external/PackedCSparse/PackedChol.h index 57a2b9232..97d102206 100644 --- a/external/PackedCSparse/PackedChol.h +++ b/external/PackedCSparse/PackedChol.h @@ -14,7 +14,7 @@ #include "leverage.h" #include "leverageJL.h" #include "multiply.h" -#include "dd_real.h" +#include "qd/dd_real.h" #include #include using namespace PackedCSparse; diff --git a/external/PackedCSparse/qd/COPYING b/external/PackedCSparse/qd/COPYING new file mode 100644 index 000000000..a20ad70eb --- /dev/null +++ b/external/PackedCSparse/qd/COPYING @@ -0,0 +1,16 @@ +This work was supported by the Director, Office of Science, Division +of Mathematical, Information, and Computational Sciences of the +U.S. Department of Energy under contract numbers DE-AC03-76SF00098 and +DE-AC02-05CH11231. + +Copyright (c) 2003-2009, The Regents of the University of California, +through Lawrence Berkeley National Laboratory (subject to receipt of +any required approvals from U.S. Dept. of Energy) All rights reserved. + +By downloading or using this software you are agreeing to the modified +BSD license that is in file "BSD-LBNL-License.doc" in the main ARPREC +directory. If you wish to use the software for commercial purposes +please contact the Technology Transfer Department at TTD@lbl.gov or +call 510-286-6457." + + diff --git a/external/PackedCSparse/qd/Makefile b/external/PackedCSparse/qd/Makefile new file mode 100644 index 000000000..791e92b99 --- /dev/null +++ b/external/PackedCSparse/qd/Makefile @@ -0,0 +1,15 @@ +QD_CPPFLAGS=$(CPPFLAGS) -I$(R_INCLUDE_DIR) -march=native + +QD_SOURCES= bits.cc c_dd.cc c_qd.cc dd_const.cc dd_real.cc fpu.cc \ + qd_const.cc qd_real.cc util.cc + +QD_OBJECTS=$(QD_SOURCES:.cc=.o) + +libqd.a: $(QD_OBJECTS) + $(AR) rc libqd.a $(QD_OBJECTS) + +.cc.o: + $(CC) $(CFLAGS) $(CPICFLAGS) $(QD_CPPFLAGS) -c $< -o $@ + +clean: + rm -rf $(QD_OBJECTS) libqd.a diff --git a/external/PackedCSparse/qd/NEWS b/external/PackedCSparse/qd/NEWS new file mode 100644 index 000000000..f32a75751 --- /dev/null +++ b/external/PackedCSparse/qd/NEWS @@ -0,0 +1,181 @@ +Changes for 2.3.22 + Made changes suggested by Vasiliy Sotnikov + +Changes for 2.3.21 + Changed renorm in include/qd/qd_inline.h + +Changes for 2.3.20 + added #include to quadt_test.cpp + changed references to 2.3.20 from 2.3.18 + +Changes for 2.3.19 + - Updated qd_real.cpp and dd_real.cpp to fix a buffer overflow problem. + +Changes for 2.3.18 + - Updated qd_real.cpp and dd_real.cpp to fix a problem in output. + +Changes for 2.3.17 + - updated qd_real.cpp, to fix a problem with improper treatment of + negative arguments in nroot. + +Changes for 2.3.16 + - Updated dd_real.cpp, to fix a problem with inaccurate values of + tanh for small arguments. + +Changes for 2.3.15 + - Updated qd_real.cpp, to fix a problem with static definitions. + +Changes for 2.3.14 + - Updated autoconfig (replaced config.sub and config.guess) + +Changes for 2.3.7 + - Fixed bug in to_digits where digits larger than 10 + where output occasionally. + +Changes for 2.3.6 + - Added fmod (C++) and mod (Fortran) functions. + +Changes for 2.3.5 + - Fixed bug in division of qd_real by dd_real. + - Fixed bug in ddoutc (Fortran ddmod.f). + - Now compiles with g++ 4.3. + - Distribute tests/coeff.dat. + +Changes for 2.3.4 + - Fixed bug in Makefile for cygwin / mingw systems. + +Changes for 2.3.3 + - Fixed bug in atan2. + +Changes for 2.3.2 + - Fixed bug in sin / cos / sincos where too much accuracy was + lost for (moderately) large angles. + - Use fused-multiply add intrinsics on IA-64 platforms if + compiled by Intel compiler. + - Fixed bug in c_dd_write and c_qd_write. + - Fixed bug were qdext.mod was not being installed. + +Changes for 2.3.1 + - Fixed bug in sincos and cos_taylor. This affected the result + of trigonometric functions in some cases. + +Changes for 2.3.0 + This is a fairly significant change, breaking API compatibility. + - Moved C++ main entry in libqdmod.a to libqd_f_main.a. + This allows to link Fortran code using QD with custom + C++ main function. Pure Fortran code will need to be linked + with qd_f_main library in addition to qdmod and qd library. + - Constructors accepting pointers made explicit. + - Fortran routines labeled as elemental or pure, where appropriate. + - Write() is now to_string(), and now takes a single fmtflag. + - dd_real addition and multiplication made commutative. + - dd_real now represented as array of two doubles, instead of + two discrete scalars. + - New Fortran generic routines to read / write, operations with + complex and integers. + - Improved exp, sin, and cos functions. + - Removed unused constants and obscure constants only used internally + from public interface. + +Changes for 2.2.6 + - Fixed bug in mixed precision multiplication: qd_real * dd_real. + +Changes for 2.2.5 + - Bug fix in qd_real addition when --enable-ieee-add is specified. + - Debugging routines dump and dump_bits updated; + dump_components removed (just use dump). + - Fortran support for Fortran strings. Use character arrays instead. + - Return NaN under error conditions. + - Added _inf constant; exp now returns Inf when argument is too large. + - Output formatting fixes for Inf and NaNs. + - Added more real-complex mixed arithmetic routines in Fortran + interface. + +Changes for 2.2.4 + - Added random_number interface for Fortran modules. + - Use slightly more conservative values for eps. + - Avoid unnecessary overflow near overflow threshold. + - Added radix, digits, min/maxexponent, range, and precision + intrinsics to Fortran interface. + - Added safe_max (C++) and safe_huge (Fortran). + +Changes for 2.2.3 + - Fix sign function bug in Fortran modules. + +Changes for 2.2.2 + - Do not bother setting uninitialized dd_real and qd_reals to zero. + - Use clock_gettime if available for timing. + - Fortran I/O should be more consistent with C++ version. + - fpu.h is now included with dd_real.h. + +Changes for 2.2.1 + - Minor fixes when printing in scientific format. + - Change search order of C++ compilers in Apple systems to avoid + case insensitive filesystems. + +Changes for 2.2.0 + - Added F95 interface for complex types. + - Renamed dd.h and qd.h to dd_real.h and qd_real.h, respectively. + This will break older C++ code using 2.1.x library, but it was + conflicting with QuickDraw libraries on Macs. (Hence the version + bump to 2.2). + - Removed overloaded typecast operators for int and double. These + permitted *automatic* conversion of dd_real/qd_real to double or + int, which is somewhat dangerous. Instead to_int and to_double + routines are added. + +Changes for 2.1.214 + - Updated pslq_test. + - Implmented numeric_limits<>. + - Better polyroot. + - Added isnan, isfinite, isinf functions. + - Fix / improve input output functions. + - Drop Microsoft Visual C++ 6.0 support. + - More efficient dd_real::sin. + +Changes for 2.1.213 + - Support for x86_64 platforms. + - Drop libtool support for now. + +Changes for 2.1.212 + - Support for pathCC compiler. + - Added accurate and sloppy versions of add / sub / mul / div avaialble. + - Added autodetection of fma functions. + +Changes for 2.1 (2003-12-30) + - added automake scripts. + - use libtool to compile / link and build libraries. + - supports standard installation targets (make install). + - support for Intel C++ compilers (icc / ecc). + - Fortran programs are now linked by C++ compiler. + - support for building shared library. + - minor bug fixes. + +Changes for 2.0 (2003-12-08) + - all header files are in "include/qd" directory. + - added autoconf scripts. + - added config.h and qd_config.h to store configuration information. + - renamed x86_* routines to fpu_* routines. + - added separate Fortran interface (f_* routines). + - options for sloppy multiply and sloppy divison separated. + - fixed C interface to be actually in C syntax. + - updated / added README, AUTHORS, NEWS, and LICENSE files. + - minor bug fixes. + +Changes for 1.2 (2003-12-04) + - added "dist-clean" target in Makefile + - initialize dd and qd variables to zero + - increases tolerance for qd / dd tests + - changed .cc extension to .cpp + - updated README, COPYING, and NEWS files + - added ChangeLog file + - fixed bug in '-all' flag in qd_test + - minor bug fixes + +Changes for 1.1 (2002-10-22) + - added "Changes" file (this file) + - fixed to + - fixed constant (3/4) * pi + - fixed exp(x) to return zero if x is a large negative number + - removed "docs" target in Makefile + diff --git a/external/PackedCSparse/qd/README b/external/PackedCSparse/qd/README new file mode 100644 index 000000000..8a085d72c --- /dev/null +++ b/external/PackedCSparse/qd/README @@ -0,0 +1,437 @@ +Quad Double computation package +Copyright (C) 2003-2019 +================================================ + +Revision date: 26 February 2019 + +Authors: +Yozo Hida U.C. Berkeley yozo@cs.berkeley.edu +Xiaoye S. Li Lawrence Berkeley Natl Lab xiaoye@nersc.gov +David H. Bailey Lawrence Berkeley Natl Lab dhbailey@lbl.gov + +C++ usage guide: +Alex Kaiser Lawrence Berkeley Natl Lab adkaiser@lbl.gov + +This work was supported by the Director, Office of Science, Division of Mathematical, +Information, and Computational Sciences of the U.S. Department of Energy under contract +number DE-AC02-05CH11231. + +This work was supported by the Director, Office of Science, Division of Mathematical, +Information, and Computational Sciences of the U.S. Department of Energy under contract +numbers DE-AC03-76SF00098 and DE-AC02-05CH11231. + +*** IMPORTANT NOTES: + +See the file COPYING for modified BSD license information. +See the file INSTALL for installation instructions. +See the file NEWS for recent revisions. +See the file docs/qd.pdf for additional information. + +Outline: + +I. Introduction +II. Installation of package, and linking and executing user files +III. C++ Usage +IV. Fortran Usage +V. Note on x86-Based Processors (MOST systems in use today) + + +I. Introduction + +This package provides numeric types of twice the precision of IEEE double (106 mantissa +bits, or approximately 32 decimal digits) and four times the precision of IEEE double (212 +mantissa bits, or approximately 64 decimal digits). Due to features such as operator and +function overloading, these facilities can be utilized with only minor modifications to +conventional C++ and Fortran-90 programs. + +In addition to the basic arithmetic operations (add, subtract, multiply, divide, square root), +common transcendental functions such as the exponential, logarithm, trigonometric and +hyperbolic functions are also included. A detailed description of the algorithms used is +available in the docs subdirectory (see docs/qd.pdf). An abridged version of this paper, +which was presented at the ARITH-15 conference, is also available at: + +Yozo Hida, Xiaoye S. Li and David H. Bailey, "Algorithms for quad-double precision + floating point arithmetic," 15th IEEE Symposium on Computer Arithmetic, IEEE Computer + Society, 2001, pg. 155-162, available at + https://www.davidhbailey.com/dhbpapers/arith15.pdf. + + +II. Installation of package, and linking and executing user files + +A. Directories + +There are six directories and several files in the main directory of this distribution, +described below + +src This contains the source code of the quad-double and double-double + library. This source code does not include inline functions, + which are found in the header files in the include directory. + +include This directory contains the header files. + +fortran This directory contains Fortran-90 files. + +tests This directory contains some simple (not comprehensive) tests. + +docs This directory contains a technical paper describing the algorithms. + +config This directory contains various scripts used by the configure + script and the Makefile. + +Please note that all commands refer to a Unix-type environment such as Mac OSX or Ubuntu +Linux using the bash shell. + +B. Installing and building + +To build the library, first run the included configure script by typing + + ./configure + +This script automatically generates makefiles for building the library and selects compilers +and necessary flags and libraries to include. If the user wishes to specify compilers or flags +they may use the following options. + + CXX C++ compiler to use + CXXFLAGS C++ compiler flags to use + CC C compiler to use (for C demo program) + CFLAGS C compiler flags to use (for C demo program) + FC Fortran 90 compiler + FCFLAGS Fortran 90 compiler flags to use + FCLIBS Fortran 90 libraries needed to link with C++ code. + +For example, if one is using GNU compilers, configure with: + + ./configure CXX=g++ FC=gfortran + +The Fortran and C++ compilers must produce compatible binaries. On some systems +additional flags must be included to ensure that portions of the +library are not built with 32 and 64 bit object files. For example, on +64-Bit Mac OSX 10.6 (Snow Leopard) and 10.7 (Lion) the correct +configure line using GNU compilers is: + + ./configure CXX=g++ FC=gfortran FCFLAGS=-m64 + +To build the library, simply type + + make + +and the automatically generated makefiles will build the library including archive files. + +To allow for easy linking to the library, the user may also wish to +install the archive files to a standard place. To do this type: + + make install + +This will also build the library if it has not already been built. Many systems, including Mac +and Ubuntu Linux systems, require administrator privileges to install the library at such +standard places. On such systems, one may type: + + sudo make install + +instead if one has sufficient access. + +The directory "tests" contains programs for high precision quadrature and integer-relation +detection. To build such programs, type: + + make demo + +in the "tests" directory. + +C. Linking and executing user programs + +C++ source files: + +The simplest way to link to the library is to install it to a standard place as described above, and use the -l option. For example + + g++ compileExample.cpp -o compileExample -l qd + +One can also use this method to build with make. A file called "compileExample.cpp" and the +associated makefile "makeCompileExample" illustrate the process. + +A third alternative is to use a link script. If one types "make demo" in the test +directory, the output produced gives guidance as to how to build the files. By +following the structure of the compiling commands one may copy the appropriate portions, +perhaps replacing the filename with an argument that the user can include at link time. +An example of such a script is as follows: + +g++ -DHAVE_CONFIG_H -I.. -I../include -I../include -O2 -MT $1.o -MD -MP -MF +.deps/qd_test.Tpo -c -o $1.o $1.cpp +mv -f .deps/$1.Tpo .deps/$1.Po +g++ -O2 -o $1 $1.o ../src/libqd.a -lm + +To use the link script, make it executable (by typing "chmod +x link.scr) and then type: + +./link.scr compileExample + +Note that the file extension is not included because the script handles all extensions, +expecting the source file to have the extension ".cpp". + +Fortran-90 source files: + +Similarly, a script for compiling fortran programs may be constructed as follows. +In the fortran directory, type "make quadtsq". This compiles the Fortran program +tquadts.f, links with all necessary library files, and produces the executable +"quadts". As this is being done, all flags and linked libraries are displayed. +For instance, on a 2019-era Apple Macintosh system, where the library was installed +as above with g++ for C++ and gfortran for Fortran-90, the following is output: + +gfortran -m64 -ffree-form -c -o tquadtsq.o tquadtsq.f +/bin/sh ../libtool --tag=CXX --mode=link g++ -O2 -o quadtsq tquadtsq.o second.o +libqdmod.la libqd_f_main.la ../src/libqd.la +-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin16/6.3.0 +-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin16/6.3.0/../../.. +-lgfortran -lquadmath -lm -lm + +Thus a general compile-link script is the following: + +gfortran -m64 -ffree-form -c -o $1.o $1.f90 +/bin/sh ../libtool --tag=CXX --mode=link g++ -O2 -o $1 $1.o second.o \ + libqdmod.la libqd_f_main.la ../src/libqd.la \ + -L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin16/6.3.0 \ + -L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin16/6.3.0/../../.. \ + -lgfortran -lquadmath -lm -lm + +Note that if the .f90 suffix is used for Fortran-90 source files, the +-ffree-form flag may be omitted, but the first line above should end with +"$1.f90" (as shown above). After forming the script, name file, "complink.scr", +and then type "chmod +x complink.scr". To use this script compile and link a +program named "prog.f90", type "./complink.scr prog". + + +III. C++ usage + +As much as possible, operator overloading is included to make basic programming as much +like using standard typed floating-point arithmetic. Changing many codes should be as +simple as changing type statements and a few other lines. + +i. Constructors + +To create dd_real and qd_real variables calculated to the proper precision, one must use +care to use the included constructors properly. Many computations in which variables are +not explicitly typed to multiple-precision may be evaluated with double-precision +arithmetic. The user must take care to ensure that this does not cause errors. In particular, +an expression such as 1.0/3.0 will be evaluated to double precision before assignment or +further arithmetic. Upon assignment to a multi-precision variable, the value will be zero +padded. This problem is serious and potentially difficult to debug. To avoid this, use the +included constructors to force arithmetic to be performed in the full precision requested. + +For a table with descriptions, please see the documentation file qd.pdf in the docs directory. + +ii. Included functions and Constants + +Supported functions include assignment operators, comparisons, arithmetic and +assignment operators, and increments for integer types. Standard C math functions such as +exponentiation, trigonometric, logarithmic, hyperbolic, exponential and rounding functions +are included. As in assignment statements, one must be careful with implied typing of +constants when using these functions. Many codes need particular conversion for the power +function, which is frequently used with constants that must be explicitly typed for multi- +precision codes. + +Many constants are included, which are global and calculated upon initialization. The +following list of constants is calculated for both the dd_real and qd_real classes separately. +Use care to select the correct value. + +For a table with descriptions, please see the included file README.pdf + +ii. Conversion of types + +Static casts may be used to convert constants between types. One may also use constructors +to return temporary multi-precision types within expressions, but should be careful, as this +will waste memory if done repeatedly. For example: + + qd_real y ; + y = sin( qd_real(4.0) / 3.0 ) ; + +C-style casts may be used, but are not recommended. Dynamic and reinterpret casts are +not supported and should be considered unreliable. Casting between multi-precision and +standard precision types can be dangerous, and care must be taken to ensure that programs +are working properly and accuracy has not degraded by use of a misplaced type-conversion. + +D. Available precision, Control of Precision Levels, + +The library provides greatly extended accuracy when compared to standard double +precision. The type dd_real provides for 106 mantissa bits, or about 32 decimal digits. The +type qd_real provides for 212 mantissa bits, or about 64 decimal digits. + +Both the dd_real and qd_real values use the exponent from the highest double-precision +word for arithmetic, and as such do not extend the total range of values available. That +means that the maximum absolute value for either data type is the same as that of double- +precision, or approximately 10^308. The precision near this range, however, is greatly +increased. + +E. I/O + +The standard I/O stream routines have been overloaded to be fully compatible with all +included data types. One may need to manually reset the precision of the stream to obtain +full output. For example, if 60 digits are desired, use: + +cout.precision(60) ; + +When reading values using cin, each input numerical value must start on a separate +line. Two formats are acceptable: + + 1. Write the full constant + 3. Mantissa e exponent + +Here are three valid examples: + + 1.1 + 3.14159 26535 89793 + 123.123123e50 + +When read using cin, these constants will be converted using full multi-precision accuracy. + + +IV. Fortran-90 Usage + +NEW (2007-01-10): The Fortran translation modules now support the complex datatypes +"dd_complex" and "qd_complex". + +Since the quad-double library is written in C++, it must be linked in with a C++ compiler (so +that C++ specific things such as static initializations are correctly handled). Thus the main +program must be written in C/C++ and call the Fortran 90 subroutine. The Fortran 90 +subroutine should be called f_main. + +Here is a sample Fortran-90 program, equivalent to the above C++ program: + + subroutine f_main + use qdmodule + implicit none + type (qd_real) a, b + a = 1.d0 + b = cos(a)**2 + sin(a)**2 - 1.d0 + call qdwrite(6, b) + stop + end subroutine + +This verifies that cos^2(1) + sin^2(1) = 1 to 64 digit accuracy. + +Most operators and generic function references, including many mixed-mode type +combinations with double-precision (ie real*8), have been overloaded (extended) to work +with double-double and quad-double data. It is important, however, that users keep in +mind the fact that expressions are evaluated strictly according to conventional Fortran +operator precedence rules. Thus some subexpressions may be evaluated only to 15-digit +accuracy. For example, with the code + + real*8 d1 + type (dd_real) t1, t2 + ... + t1 = cos (t2) + d1/3.d0 + +the expression d1/3.d0 is computed to real*8 accuracy only (about 15 digits), since both d1 +and 3.d0 have type real*8. This result is then converted to dd_real by zero extension before +being added to cos(t2). So, for example, if d1 held the value 1.d0, then the quotient d1/3.d0 +would only be accurate to 15 digits. If a fully accurate double-double quotient is required, +this should be written: + + real*8 d1 + type (dd_real) t1, t2 + ... + t1 = cos (t2) + ddreal (d1) / 3.d0 + +which forces all operations to be performed with double-double arithmetic. + +Along this line, a constant such as 1.1 appearing in an expression is evaluated only to real*4 +accuracy, and a constant such as 1.1d0 is evaluated only to real*8 accuracy (this is +according to standard Fortran conventions). If full quad-double accuracy is required, for +instance, one should write + + type (qd_real) t1 + ... + t1 = '1.1' + +The quotes enclosing 1.1 specify to the compiler that the constant is to be converted to +binary using quad-double arithmetic, before assignment to t1. Quoted constants may only +appear in assignment statements such as this. + +To link a Fortran-90 program with the C++ qd library, it is recommended to link with the +C++ compiler used to generate the library. The Fortran 90 interface (along with a C-style +main function calling f_main) is found in qdmod library. The qd-config script installed +during "make install" can be used to determine which flags to pass to compile and link your +programs: + + "qd-config --fcflags" displays compiler flags needed to compile your Fortran files. + "qd-config --fclibs" displays linker flags needed by the C++ linker to link in all the +necessary libraries. + +A sample Makefile that can be used as a template for compiling Fortran programs using +quad-double library is found in fortran/Makefile.sample. + +F90 functions defined with dd_real arguments: + Arithmetic: + - * / ** + Comparison tests: == < > <= >= /= + Others: abs, acos, aint, anint, asin, atan, atan2, cos, cosh, dble, erf, + erfc, exp, int, log, log10, max, min, mod, ddcsshf (cosh and sinh), + ddcssnf (cos and sin), ddranf (random number generator in (0,1)), + ddnrtf (n-th root), sign, sin, sinh, sqr, sqrt, tan, tanh + +Similar functions are provided for qd_real arguments with function names qdcsshf, +qdcssnf, qdranf and qdnrtf instead of the names in the list above. + +Input and output of double-double and quad-double data is done using the special +subroutines ddread, ddwrite, qdread and qdwrite. The first argument of these subroutines +is the Fortran I/O unit number, while additional arguments (as many as needed, up to 9 +arguments) are scalar variables or array elements of the appropriate type. Example: + + integer n + type (qd_real) qda, qdb, qdc(n) + ... + call qdwrite (6, qda, qdb) + do j = 1, n + call qdwrite (6, qdc(j)) + enddo + +Each input values must be on a separate line, and may include D or E exponents. Double- +double and quad-double constants may also be specified in assignment statements by +enclosing them in quotes, as in + + ... + type (qd_real) pi + ... + pi = +"3.14159265358979323846264338327950288419716939937510582097494459230" + ... + +Sample Fortran-90 programs illustrating some of these features are provided in the f90 +subdirectory. + + +V. Note on x86-Based Processors (MOST systems in use today) + +The algorithms in this library assume IEEE double precision floating point arithmetic. Since +Intel x86 processors have extended (80-bit) floating point registers, some compilers, +albeit a declining number, may generate commands for the 80-bit instructions. The QD +library does NOT work correctly with 80-bit instructions, so if one's code does not operate +correctly, this may be the reason. To avoid such problems, the round-to-double flag must be +enabled in the control word of the FPU for this library to function properly. The following +functions contains appropriate code to facilitate manipulation of this flag. For non-x86 +systems these functions do nothing (but still exist). + +fpu_fix_start This turns on the round-to-double bit in the control word. +fpu_fix_end This restores the control flag. + +These functions must be called by the main program, as follows: + + int main() { + unsigned int old_cw; + fpu_fix_start(&old_cw); + + ... user code using quad-double library ... + + fpu_fix_end(&old_cw); + } + +A Fortran-90 example is the following: + + subroutine f_main + use qdmodule + implicit none + integer*4 old_cw + + call f_fpu_fix_start(old_cw) + + ... user code using quad-double library ... + + call f_fpu_fix_end(old_cw) + end subroutine + diff --git a/external/PackedCSparse/qd/bits.cc b/external/PackedCSparse/qd/bits.cc new file mode 100644 index 000000000..4eaf9a265 --- /dev/null +++ b/external/PackedCSparse/qd/bits.cc @@ -0,0 +1,85 @@ +/* + * src/bits.cc + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Defines various routines to get / set bits of a IEEE floating point + * number. This used by the library for debugging purposes. + */ + +#include +#include +#include +#include + +#include "qd_config.h" +#include "inline.h" +#include "bits.h" + +#ifdef HAVE_IEEEFP_H +#include +#endif + +using std::setw; + +int get_double_expn(double x) { + if (x == 0.0) + return INT_MIN; + if (QD_ISINF(x) || QD_ISNAN(x)) + return INT_MAX; + + double y = std::abs(x); + int i = 0; + if (y < 1.0) { + while (y < 1.0) { + y *= 2.0; + i++; + } + return -i; + } else if (y >= 2.0) { + while (y >= 2.0) { + y *= 0.5; + i++; + } + return i; + } + return 0; +} + +void print_double_info(std::ostream &os, double x) { + std::streamsize old_prec = os.precision(19); + std::ios_base::fmtflags old_flags = os.flags(); + os << std::scientific; + + os << setw(27) << x << ' '; + if (QD_ISNAN(x) || QD_ISINF(x) || (x == 0.0)) { + os << " "; + } else { + + x = std::abs(x); + int expn = get_double_expn(x); + double d = std::ldexp(1.0, expn); + os << setw(5) << expn << " "; + for (int i = 0; i < 53; i++) { + if (x >= d) { + x -= d; + os << '1'; + } else + os << '0'; + d *= 0.5; + } + + if (x != 0.0) { + // should not happen + os << " +trailing stuff"; + } + } + + os.precision(old_prec); + os.flags(old_flags); +} + diff --git a/external/PackedCSparse/qd/bits.h b/external/PackedCSparse/qd/bits.h new file mode 100644 index 000000000..58570aac5 --- /dev/null +++ b/external/PackedCSparse/qd/bits.h @@ -0,0 +1,32 @@ +/* + * include/bits.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * This file defines various routines to get / set bits of a IEEE floating + * point number. This is used by the library for debugging purposes. + */ + +#ifndef _QD_BITS_H +#define _QD_BITS_H + +#include +#include "qd_config.h" + +/* Returns the exponent of the double precision number. + Returns INT_MIN is x is zero, and INT_MAX if x is INF or NaN. */ +int get_double_expn(double x); + +/* Prints + SIGN EXPN MANTISSA + of the given double. If x is NaN, INF, or Zero, this + prints out the strings NaN, +/- INF, and 0. */ +void print_double_info(std::ostream &os, double x); + + +#endif /* _QD_BITS_H */ + diff --git a/external/PackedCSparse/qd/c_dd.cc b/external/PackedCSparse/qd/c_dd.cc new file mode 100644 index 000000000..0a7c12ac2 --- /dev/null +++ b/external/PackedCSparse/qd/c_dd.cc @@ -0,0 +1,314 @@ +/* + * src/c_dd.cc + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Contains the C wrapper functions for double-double precision arithmetic. + * This can be used from Fortran code. + */ +#include + +#include "qd_config.h" +#include "dd_real.h" +#include "c_dd.h" + +#define TO_DOUBLE_PTR(a, ptr) ptr[0] = a.x[0]; ptr[1] = a.x[1]; + +extern "C" { + +/* add */ +void c_dd_add(const double *a, const double *b, double *c) { + dd_real cc; + cc = dd_real(a) + dd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_dd_add_dd_d(const double *a, double b, double *c) { + dd_real cc; + cc = dd_real(a) + b; + TO_DOUBLE_PTR(cc, c); +} +void c_dd_add_d_dd(double a, const double *b, double *c) { + dd_real cc; + cc = a + dd_real(b); + TO_DOUBLE_PTR(cc, c); +} + + +/* sub */ +void c_dd_sub(const double *a, const double *b, double *c) { + dd_real cc; + cc = dd_real(a) - dd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_dd_sub_dd_d(const double *a, double b, double *c) { + dd_real cc; + cc = dd_real(a) - b; + TO_DOUBLE_PTR(cc, c); +} +void c_dd_sub_d_dd(double a, const double *b, double *c) { + dd_real cc; + cc = a - dd_real(b); + TO_DOUBLE_PTR(cc, c); +} + + +/* mul */ +void c_dd_mul(const double *a, const double *b, double *c) { + dd_real cc; + cc = dd_real(a) * dd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_dd_mul_dd_d(const double *a, double b, double *c) { + dd_real cc; + cc = dd_real(a) * b; + TO_DOUBLE_PTR(cc, c); +} +void c_dd_mul_d_dd(double a, const double *b, double *c) { + dd_real cc; + cc = a * dd_real(b); + TO_DOUBLE_PTR(cc, c); +} + + +/* div */ +void c_dd_div(const double *a, const double *b, double *c) { + dd_real cc; + cc = dd_real(a) / dd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_dd_div_dd_d(const double *a, double b, double *c) { + dd_real cc; + cc = dd_real(a) / b; + TO_DOUBLE_PTR(cc, c); +} +void c_dd_div_d_dd(double a, const double *b, double *c) { + dd_real cc; + cc = a / dd_real(b); + TO_DOUBLE_PTR(cc, c); +} + + +/* copy */ +void c_dd_copy(const double *a, double *b) { + b[0] = a[0]; + b[1] = a[1]; +} +void c_dd_copy_d(double a, double *b) { + b[0] = a; + b[1] = 0.0; +} + + +void c_dd_sqrt(const double *a, double *b) { + dd_real bb; + bb = sqrt(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_sqr(const double *a, double *b) { + dd_real bb; + bb = sqr(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_abs(const double *a, double *b) { + dd_real bb; + bb = abs(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_npwr(const double *a, int n, double *b) { + dd_real bb; + bb = npwr(dd_real(a), n); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_nroot(const double *a, int n, double *b) { + dd_real bb; + bb = nroot(dd_real(a), n); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_nint(const double *a, double *b) { + dd_real bb; + bb = nint(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_aint(const double *a, double *b) { + dd_real bb; + bb = aint(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_floor(const double *a, double *b) { + dd_real bb; + bb = floor(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_ceil(const double *a, double *b) { + dd_real bb; + bb = ceil(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_log(const double *a, double *b) { + dd_real bb; + bb = log(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_log10(const double *a, double *b) { + dd_real bb; + bb = log10(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_exp(const double *a, double *b) { + dd_real bb; + bb = exp(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_sin(const double *a, double *b) { + dd_real bb; + bb = sin(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_cos(const double *a, double *b) { + dd_real bb; + bb = cos(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_tan(const double *a, double *b) { + dd_real bb; + bb = tan(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_asin(const double *a, double *b) { + dd_real bb; + bb = asin(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_acos(const double *a, double *b) { + dd_real bb; + bb = acos(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_atan(const double *a, double *b) { + dd_real bb; + bb = atan(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_atan2(const double *a, const double *b, double *c) { + dd_real cc; + cc = atan2(dd_real(a), dd_real(b)); + TO_DOUBLE_PTR(cc, c); +} + +void c_dd_sinh(const double *a, double *b) { + dd_real bb; + bb = sinh(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_cosh(const double *a, double *b) { + dd_real bb; + bb = cosh(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_tanh(const double *a, double *b) { + dd_real bb; + bb = tanh(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_asinh(const double *a, double *b) { + dd_real bb; + bb = asinh(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_acosh(const double *a, double *b) { + dd_real bb; + bb = acosh(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_dd_atanh(const double *a, double *b) { + dd_real bb; + bb = atanh(dd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_dd_sincos(const double *a, double *s, double *c) { + dd_real ss, cc; + sincos(dd_real(a), ss, cc); + TO_DOUBLE_PTR(ss, s); + TO_DOUBLE_PTR(cc, c); +} + +void c_dd_sincosh(const double *a, double *s, double *c) { + dd_real ss, cc; + sincosh(dd_real(a), ss, cc); + TO_DOUBLE_PTR(ss, s); + TO_DOUBLE_PTR(cc, c); +} + +void c_dd_read(const char *s, double *a) { + dd_real aa(s); + TO_DOUBLE_PTR(aa, a); +} + +void c_dd_swrite(const double *a, int precision, char *s, int len) { + dd_real(a).write(s, len, precision); +} + +void c_dd_write(const double *a) { + std::cout << dd_real(a).to_string(dd_real::_ndigits) << std::endl; +} + +void c_dd_neg(const double *a, double *b) { + b[0] = -a[0]; + b[1] = -a[1]; +} + +void c_dd_rand(double *a) { + dd_real aa; + aa = ddrand(); + TO_DOUBLE_PTR(aa, a); +} + +void c_dd_comp(const double *a, const double *b, int *result) { + dd_real aa(a), bb(b); + if (aa < bb) + *result = -1; + else if (aa > bb) + *result = 1; + else + *result = 0; +} + +void c_dd_comp_dd_d(const double *a, double b, int *result) { + dd_real aa(a), bb(b); + if (aa < bb) + *result = -1; + else if (aa > bb) + *result = 1; + else + *result = 0; +} + +void c_dd_comp_d_dd(double a, const double *b, int *result) { + dd_real aa(a), bb(b); + if (aa < bb) + *result = -1; + else if (aa > bb) + *result = 1; + else + *result = 0; +} + +void c_dd_pi(double *a) { + TO_DOUBLE_PTR(dd_real::_pi, a); +} + +} diff --git a/external/PackedCSparse/qd/c_dd.h b/external/PackedCSparse/qd/c_dd.h new file mode 100644 index 000000000..310162edc --- /dev/null +++ b/external/PackedCSparse/qd/c_dd.h @@ -0,0 +1,98 @@ +/* + * include/c_dd.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Contains C wrapper function prototypes for double-double precision + * arithmetic. This can also be used from fortran code. + */ +#ifndef _QD_C_DD_H +#define _QD_C_DD_H + +#include "qd_config.h" +#include "fpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* add */ +void c_dd_add(const double *a, const double *b, double *c); +void c_dd_add_d_dd(double a, const double *b, double *c); +void c_dd_add_dd_d(const double *a, double b, double *c); + +/* sub */ +void c_dd_sub(const double *a, const double *b, double *c); +void c_dd_sub_d_dd(double a, const double *b, double *c); +void c_dd_sub_dd_d(const double *a, double b, double *c); + +/* mul */ +void c_dd_mul(const double *a, const double *b, double *c); +void c_dd_mul_d_dd(double a, const double *b, double *c); +void c_dd_mul_dd_d(const double *a, double b, double *c); + +/* div */ +void c_dd_div(const double *a, const double *b, double *c); +void c_dd_div_d_dd(double a, const double *b, double *c); +void c_dd_div_dd_d(const double *a, double b, double *c); + +/* copy */ +void c_dd_copy(const double *a, double *b); +void c_dd_copy_d(double a, double *b); + +void c_dd_sqrt(const double *a, double *b); +void c_dd_sqr(const double *a, double *b); + +void c_dd_abs(const double *a, double *b); + +void c_dd_npwr(const double *a, int b, double *c); +void c_dd_nroot(const double *a, int b, double *c); + +void c_dd_nint(const double *a, double *b); +void c_dd_aint(const double *a, double *b); +void c_dd_floor(const double *a, double *b); +void c_dd_ceil(const double *a, double *b); + +void c_dd_exp(const double *a, double *b); +void c_dd_log(const double *a, double *b); +void c_dd_log10(const double *a, double *b); + +void c_dd_sin(const double *a, double *b); +void c_dd_cos(const double *a, double *b); +void c_dd_tan(const double *a, double *b); + +void c_dd_asin(const double *a, double *b); +void c_dd_acos(const double *a, double *b); +void c_dd_atan(const double *a, double *b); +void c_dd_atan2(const double *a, const double *b, double *c); + +void c_dd_sinh(const double *a, double *b); +void c_dd_cosh(const double *a, double *b); +void c_dd_tanh(const double *a, double *b); + +void c_dd_asinh(const double *a, double *b); +void c_dd_acosh(const double *a, double *b); +void c_dd_atanh(const double *a, double *b); + +void c_dd_sincos(const double *a, double *s, double *c); +void c_dd_sincosh(const double *a, double *s, double *c); + +void c_dd_read(const char *s, double *a); +void c_dd_swrite(const double *a, int precision, char *s, int len); +void c_dd_write(const double *a); +void c_dd_neg(const double *a, double *b); +void c_dd_rand(double *a); +void c_dd_comp(const double *a, const double *b, int *result); +void c_dd_comp_dd_d(const double *a, double b, int *result); +void c_dd_comp_d_dd(double a, const double *b, int *result); +void c_dd_pi(double *a); + +#ifdef __cplusplus +} +#endif + +#endif /* _QD_C_DD_H */ diff --git a/external/PackedCSparse/qd/c_qd.cc b/external/PackedCSparse/qd/c_qd.cc new file mode 100644 index 000000000..fd50e9228 --- /dev/null +++ b/external/PackedCSparse/qd/c_qd.cc @@ -0,0 +1,450 @@ +/* + * src/c_qd.cc + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Contains C wrapper function for quad-double precision arithmetic. + * This can be used from fortran code. + */ +#include + +#include "qd_config.h" +#include "qd_real.h" +#include "c_qd.h" + +#define TO_DOUBLE_PTR(a, ptr) ptr[0] = a.x[0]; ptr[1] = a.x[1]; \ + ptr[2] = a.x[2]; ptr[3] = a.x[3]; + +extern "C" { + + + +/* add */ +void c_qd_add(const double *a, const double *b, double *c) { + qd_real cc; + cc = qd_real(a) + qd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_add_qd_dd(const double *a, const double *b, double *c) { + qd_real cc; + cc = qd_real(a) + dd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_add_dd_qd(const double *a, const double *b, double *c) { + qd_real cc; + cc = dd_real(a) + qd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_add_qd_d(const double *a, double b, double *c) { + qd_real cc; + cc = qd_real(a) + b; + TO_DOUBLE_PTR(cc, c); +} +void c_qd_add_d_qd(double a, const double *b, double *c) { + qd_real cc; + cc = a + qd_real(b); + TO_DOUBLE_PTR(cc, c); +} + + + +/* sub */ +void c_qd_sub(const double *a, const double *b, double *c) { + qd_real cc; + cc = qd_real(a) - qd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_sub_qd_dd(const double *a, const double *b, double *c) { + qd_real cc; + cc = qd_real(a) - dd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_sub_dd_qd(const double *a, const double *b, double *c) { + qd_real cc; + cc = dd_real(a) - qd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_sub_qd_d(const double *a, double b, double *c) { + qd_real cc; + cc = qd_real(a) - b; + TO_DOUBLE_PTR(cc, c); +} +void c_qd_sub_d_qd(double a, const double *b, double *c) { + qd_real cc; + cc = a - qd_real(b); + TO_DOUBLE_PTR(cc, c); +} + + + +/* mul */ +void c_qd_mul(const double *a, const double *b, double *c) { + qd_real cc; + cc = qd_real(a) * qd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_mul_qd_dd(const double *a, const double *b, double *c) { + qd_real cc; + cc = qd_real(a) * dd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_mul_dd_qd(const double *a, const double *b, double *c) { + qd_real cc; + cc = dd_real(a) * qd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_mul_qd_d(const double *a, double b, double *c) { + qd_real cc; + cc = qd_real(a) * b; + TO_DOUBLE_PTR(cc, c); +} +void c_qd_mul_d_qd(double a, const double *b, double *c) { + qd_real cc; + cc = a * qd_real(b); + TO_DOUBLE_PTR(cc, c); +} + + + +/* div */ +void c_qd_div(const double *a, const double *b, double *c) { + qd_real cc; + cc = qd_real(a) / qd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_div_qd_dd(const double *a, const double *b, double *c) { + qd_real cc; + cc = qd_real(a) / dd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_div_dd_qd(const double *a, const double *b, double *c) { + qd_real cc; + cc = dd_real(a) / qd_real(b); + TO_DOUBLE_PTR(cc, c); +} +void c_qd_div_qd_d(const double *a, double b, double *c) { + qd_real cc; + cc = qd_real(a) / b; + TO_DOUBLE_PTR(cc, c); +} +void c_qd_div_d_qd(double a, const double *b, double *c) { + qd_real cc; + cc = a / qd_real(b); + TO_DOUBLE_PTR(cc, c); +} + + + + +/* selfadd */ +void c_qd_selfadd(const double *a, double *b) { + qd_real bb(b); + bb += qd_real(a); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_selfadd_dd(const double *a, double *b) { + qd_real bb(b); + bb += dd_real(a); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_selfadd_d(double a, double *b) { + qd_real bb(b); + bb += a; + TO_DOUBLE_PTR(bb, b); +} + + + +/* selfsub */ +void c_qd_selfsub(const double *a, double *b) { + qd_real bb(b); + bb -= qd_real(a); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_selfsub_dd(const double *a, double *b) { + qd_real bb(b); + bb -= dd_real(a); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_selfsub_d(double a, double *b) { + qd_real bb(b); + bb -= a; + TO_DOUBLE_PTR(bb, b); +} + + + +/* selfmul */ +void c_qd_selfmul(const double *a, double *b) { + qd_real bb(b); + bb *= qd_real(a); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_selfmul_dd(const double *a, double *b) { + qd_real bb(b); + bb *= dd_real(a); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_selfmul_d(double a, double *b) { + qd_real bb(b); + bb *= a; + TO_DOUBLE_PTR(bb, b); +} + + + +/* selfdiv */ +void c_qd_selfdiv(const double *a, double *b) { + qd_real bb(b); + bb /= qd_real(a); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_selfdiv_dd(const double *a, double *b) { + qd_real bb(b); + bb /= dd_real(a); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_selfdiv_d(double a, double *b) { + qd_real bb(b); + bb /= a; + TO_DOUBLE_PTR(bb, b); +} + + + +/* copy */ +void c_qd_copy(const double *a, double *b) { + b[0] = a[0]; + b[1] = a[1]; + b[2] = a[2]; + b[3] = a[3]; +} +void c_qd_copy_dd(const double *a, double *b) { + b[0] = a[0]; + b[1] = a[1]; + b[2] = 0.0; + b[3] = 0.0; +} +void c_qd_copy_d(double a, double *b) { + b[0] = a; + b[1] = 0.0; + b[2] = 0.0; + b[3] = 0.0; +} + + +void c_qd_sqrt(const double *a, double *b) { + qd_real bb; + bb = sqrt(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_sqr(const double *a, double *b) { + qd_real bb; + bb = sqr(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_abs(const double *a, double *b) { + qd_real bb; + bb = abs(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_npwr(const double *a, int n, double *b) { + qd_real bb; + bb = npwr(qd_real(a), n); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_nroot(const double *a, int n, double *b) { + qd_real bb; + bb = nroot(qd_real(a), n); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_nint(const double *a, double *b) { + qd_real bb; + bb = nint(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_aint(const double *a, double *b) { + qd_real bb; + bb = aint(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_floor(const double *a, double *b) { + qd_real bb; + bb = floor(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_ceil(const double *a, double *b) { + qd_real bb; + bb = ceil(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_log(const double *a, double *b) { + qd_real bb; + bb = log(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_log10(const double *a, double *b) { + qd_real bb; + bb = log10(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_exp(const double *a, double *b) { + qd_real bb; + bb = exp(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_sin(const double *a, double *b) { + qd_real bb; + bb = sin(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_cos(const double *a, double *b) { + qd_real bb; + bb = cos(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_tan(const double *a, double *b) { + qd_real bb; + bb = tan(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_asin(const double *a, double *b) { + qd_real bb; + bb = asin(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_acos(const double *a, double *b) { + qd_real bb; + bb = acos(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_atan(const double *a, double *b) { + qd_real bb; + bb = atan(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_atan2(const double *a, const double *b, double *c) { + qd_real cc; + cc = atan2(qd_real(a), qd_real(b)); + TO_DOUBLE_PTR(cc, c); +} + +void c_qd_sinh(const double *a, double *b) { + qd_real bb; + bb = sinh(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_cosh(const double *a, double *b) { + qd_real bb; + bb = cosh(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_tanh(const double *a, double *b) { + qd_real bb; + bb = tanh(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_asinh(const double *a, double *b) { + qd_real bb; + bb = asinh(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_acosh(const double *a, double *b) { + qd_real bb; + bb = acosh(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} +void c_qd_atanh(const double *a, double *b) { + qd_real bb; + bb = atanh(qd_real(a)); + TO_DOUBLE_PTR(bb, b); +} + +void c_qd_sincos(const double *a, double *s, double *c) { + qd_real ss, cc; + sincos(qd_real(a), ss, cc); + TO_DOUBLE_PTR(cc, c); + TO_DOUBLE_PTR(ss, s); +} + +void c_qd_sincosh(const double *a, double *s, double *c) { + qd_real ss, cc; + sincosh(qd_real(a), ss, cc); + TO_DOUBLE_PTR(cc, c); + TO_DOUBLE_PTR(ss, s); +} + +void c_qd_read(const char *s, double *a) { + qd_real aa(s); + TO_DOUBLE_PTR(aa, a); +} + +void c_qd_swrite(const double *a, int precision, char *s, int len) { + qd_real(a).write(s, len, precision); +} + +void c_qd_write(const double *a) { + std::cout << qd_real(a).to_string(qd_real::_ndigits) << std::endl; +} + +void c_qd_neg(const double *a, double *b) { + b[0] = -a[0]; + b[1] = -a[1]; + b[2] = -a[2]; + b[3] = -a[3]; +} + +void c_qd_rand(double *a) { + qd_real aa; + aa = qdrand(); + TO_DOUBLE_PTR(aa, a); +} + +void c_qd_comp(const double *a, const double *b, int *result) { + qd_real aa(a), bb(b); + if (aa < bb) + *result = -1; + else if (aa > bb) + *result = 1; + else + *result = 0; +} + +void c_qd_comp_qd_d(const double *a, double b, int *result) { + qd_real aa(a); + if (aa < b) + *result = -1; + else if (aa > b) + *result = 1; + else + *result = 0; +} + +void c_qd_comp_d_qd(double a, const double *b, int *result) { + qd_real bb(b); + if (a < bb) + *result = -1; + else if (a > bb) + *result = 1; + else + *result = 0; +} + +void c_qd_pi(double *a) { + TO_DOUBLE_PTR(qd_real::_pi, a); +} + +} diff --git a/external/PackedCSparse/qd/c_qd.h b/external/PackedCSparse/qd/c_qd.h new file mode 100644 index 000000000..d11a7ff17 --- /dev/null +++ b/external/PackedCSparse/qd/c_qd.h @@ -0,0 +1,119 @@ +/* + * include/c_qd.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Contains C wrapper function prototypes for quad-double precision + * arithmetic. This can also be used from fortran code. + */ +#ifndef _QD_C_QD_H +#define _QD_C_QD_H + +#include "c_dd.h" +#include "qd_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* add */ +void c_qd_add(const double *a, const double *b, double *c); +void c_qd_add_dd_qd(const double *a, const double *b, double *c); +void c_qd_add_qd_dd(const double *a, const double *b, double *c); +void c_qd_add_d_qd(double a, const double *b, double *c); +void c_qd_add_qd_d(const double *a, double b, double *c); +void c_qd_selfadd(const double *a, double *b); +void c_qd_selfadd_dd(const double *a, double *b); +void c_qd_selfadd_d(double a, double *b); + +/* sub */ +void c_qd_sub(const double *a, const double *b, double *c); +void c_qd_sub_dd_qd(const double *a, const double *b, double *c); +void c_qd_sub_qd_dd(const double *a, const double *b, double *c); +void c_qd_sub_d_qd(double a, const double *b, double *c); +void c_qd_sub_qd_d(const double *a, double b, double *c); +void c_qd_selfsub(const double *a, double *b); +void c_qd_selfsub_dd(const double *a, double *b); +void c_qd_selfsub_d(double a, double *b); + +/* mul */ +void c_qd_mul(const double *a, const double *b, double *c); +void c_qd_mul_dd_qd(const double *a, const double *b, double *c); +void c_qd_mul_qd_dd(const double *a, const double *b, double *c); +void c_qd_mul_d_qd(double a, const double *b, double *c); +void c_qd_mul_qd_d(const double *a, double b, double *c); +void c_qd_selfmul(const double *a, double *b); +void c_qd_selfmul_dd(const double *a, double *b); +void c_qd_selfmul_d(double a, double *b); + +/* div */ +void c_qd_div(const double *a, const double *b, double *c); +void c_qd_div_dd_qd(const double *a, const double *b, double *c); +void c_qd_div_qd_dd(const double *a, const double *b, double *c); +void c_qd_div_d_qd(double a, const double *b, double *c); +void c_qd_div_qd_d(const double *a, double b, double *c); +void c_qd_selfdiv(const double *a, double *b); +void c_qd_selfdiv_dd(const double *a, double *b); +void c_qd_selfdiv_d(double a, double *b); + +/* copy */ +void c_qd_copy(const double *a, double *b); +void c_qd_copy_dd(const double *a, double *b); +void c_qd_copy_d(double a, double *b); + +void c_qd_sqrt(const double *a, double *b); +void c_qd_sqr(const double *a, double *b); + +void c_qd_abs(const double *a, double *b); + +void c_qd_npwr(const double *a, int b, double *c); +void c_qd_nroot(const double *a, int b, double *c); + +void c_qd_nint(const double *a, double *b); +void c_qd_aint(const double *a, double *b); +void c_qd_floor(const double *a, double *b); +void c_qd_ceil(const double *a, double *b); + +void c_qd_exp(const double *a, double *b); +void c_qd_log(const double *a, double *b); +void c_qd_log10(const double *a, double *b); + +void c_qd_sin(const double *a, double *b); +void c_qd_cos(const double *a, double *b); +void c_qd_tan(const double *a, double *b); + +void c_qd_asin(const double *a, double *b); +void c_qd_acos(const double *a, double *b); +void c_qd_atan(const double *a, double *b); +void c_qd_atan2(const double *a, const double *b, double *c); + +void c_qd_sinh(const double *a, double *b); +void c_qd_cosh(const double *a, double *b); +void c_qd_tanh(const double *a, double *b); + +void c_qd_asinh(const double *a, double *b); +void c_qd_acosh(const double *a, double *b); +void c_qd_atanh(const double *a, double *b); + +void c_qd_sincos(const double *a, double *s, double *c); +void c_qd_sincosh(const double *a, double *s, double *c); + +void c_qd_read(const char *s, double *a); +void c_qd_swrite(const double *a, int precision, char *s, int len); +void c_qd_write(const double *a); +void c_qd_neg(const double *a, double *b); +void c_qd_rand(double *a); +void c_qd_comp(const double *a, const double *b, int *result); +void c_qd_comp_qd_d(const double *a, double b, int *result); +void c_qd_comp_d_qd(double a, const double *b, int *result); +void c_qd_pi(double *a); + +#ifdef __cplusplus +} +#endif + +#endif /* _QD_C_QD_H */ diff --git a/external/PackedCSparse/qd/dd_const.cc b/external/PackedCSparse/qd/dd_const.cc new file mode 100644 index 000000000..38b7b5ae6 --- /dev/null +++ b/external/PackedCSparse/qd/dd_const.cc @@ -0,0 +1,40 @@ +/* + * src/dd_const.cc + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2007 + */ +#include "qd_config.h" +#include "dd_real.h" + +const dd_real dd_real::_2pi = dd_real(6.283185307179586232e+00, + 2.449293598294706414e-16); +const dd_real dd_real::_pi = dd_real(3.141592653589793116e+00, + 1.224646799147353207e-16); +const dd_real dd_real::_pi2 = dd_real(1.570796326794896558e+00, + 6.123233995736766036e-17); +const dd_real dd_real::_pi4 = dd_real(7.853981633974482790e-01, + 3.061616997868383018e-17); +const dd_real dd_real::_3pi4 = dd_real(2.356194490192344837e+00, + 9.1848509936051484375e-17); +const dd_real dd_real::_e = dd_real(2.718281828459045091e+00, + 1.445646891729250158e-16); +const dd_real dd_real::_log2 = dd_real(6.931471805599452862e-01, + 2.319046813846299558e-17); +const dd_real dd_real::_log10 = dd_real(2.302585092994045901e+00, + -2.170756223382249351e-16); +const dd_real dd_real::_nan = dd_real(qd::_d_nan, qd::_d_nan); +const dd_real dd_real::_inf = dd_real(qd::_d_inf, qd::_d_inf); + +const double dd_real::_eps = 4.93038065763132e-32; // 2^-104 +const double dd_real::_min_normalized = 2.0041683600089728e-292; // = 2^(-1022 + 53) +const dd_real dd_real::_max = + dd_real(1.79769313486231570815e+308, 9.97920154767359795037e+291); +const dd_real dd_real::_safe_max = + dd_real(1.7976931080746007281e+308, 9.97920154767359795037e+291); +const int dd_real::_ndigits = 31; + + diff --git a/external/PackedCSparse/qd/dd_inline.h b/external/PackedCSparse/qd/dd_inline.h new file mode 100644 index 000000000..89bc24f2a --- /dev/null +++ b/external/PackedCSparse/qd/dd_inline.h @@ -0,0 +1,621 @@ +/* + * include/dd_inline.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Contains small functions (suitable for inlining) in the double-double + * arithmetic package. + */ +#ifndef _QD_DD_INLINE_H +#define _QD_DD_INLINE_H + +#include +#include "inline.h" + +#ifndef QD_INLINE +#define inline +#endif + + +/*********** Additions ************/ +/* double-double = double + double */ +inline dd_real dd_real::add(double a, double b) { + double s, e; + s = qd::two_sum(a, b, e); + return dd_real(s, e); +} + +/* double-double + double */ +inline dd_real operator+(const dd_real &a, double b) { + double s1, s2; + s1 = qd::two_sum(a.x[0], b, s2); + s2 += a.x[1]; + s1 = qd::quick_two_sum(s1, s2, s2); + return dd_real(s1, s2); +} + +/* double-double + double-double */ +inline dd_real dd_real::ieee_add(const dd_real &a, const dd_real &b) { + /* This one satisfies IEEE style error bound, + due to K. Briggs and W. Kahan. */ + double s1, s2, t1, t2; + + s1 = qd::two_sum(a.x[0], b.x[0], s2); + t1 = qd::two_sum(a.x[1], b.x[1], t2); + s2 += t1; + s1 = qd::quick_two_sum(s1, s2, s2); + s2 += t2; + s1 = qd::quick_two_sum(s1, s2, s2); + return dd_real(s1, s2); +} + +inline dd_real dd_real::sloppy_add(const dd_real &a, const dd_real &b) { + /* This is the less accurate version ... obeys Cray-style + error bound. */ + double s, e; + + s = qd::two_sum(a.x[0], b.x[0], e); + e += (a.x[1] + b.x[1]); + s = qd::quick_two_sum(s, e, e); + return dd_real(s, e); +} + +inline dd_real operator+(const dd_real &a, const dd_real &b) { +#ifndef QD_IEEE_ADD + return dd_real::sloppy_add(a, b); +#else + return dd_real::ieee_add(a, b); +#endif +} + +/* double + double-double */ +inline dd_real operator+(double a, const dd_real &b) { + return (b + a); +} + + +/*********** Self-Additions ************/ +/* double-double += double */ +inline dd_real &dd_real::operator+=(double a) { + double s1, s2; + s1 = qd::two_sum(x[0], a, s2); + s2 += x[1]; + x[0] = qd::quick_two_sum(s1, s2, x[1]); + return *this; +} + +/* double-double += double-double */ +inline dd_real &dd_real::operator+=(const dd_real &a) { +#ifndef QD_IEEE_ADD + double s, e; + s = qd::two_sum(x[0], a.x[0], e); + e += x[1]; + e += a.x[1]; + x[0] = qd::quick_two_sum(s, e, x[1]); + return *this; +#else + double s1, s2, t1, t2; + s1 = qd::two_sum(x[0], a.x[0], s2); + t1 = qd::two_sum(x[1], a.x[1], t2); + s2 += t1; + s1 = qd::quick_two_sum(s1, s2, s2); + s2 += t2; + x[0] = qd::quick_two_sum(s1, s2, x[1]); + return *this; +#endif +} + +/*********** Subtractions ************/ +/* double-double = double - double */ +inline dd_real dd_real::sub(double a, double b) { + double s, e; + s = qd::two_diff(a, b, e); + return dd_real(s, e); +} + +/* double-double - double */ +inline dd_real operator-(const dd_real &a, double b) { + double s1, s2; + s1 = qd::two_diff(a.x[0], b, s2); + s2 += a.x[1]; + s1 = qd::quick_two_sum(s1, s2, s2); + return dd_real(s1, s2); +} + +/* double-double - double-double */ +inline dd_real operator-(const dd_real &a, const dd_real &b) { +#ifndef QD_IEEE_ADD + double s, e; + s = qd::two_diff(a.x[0], b.x[0], e); + e += a.x[1]; + e -= b.x[1]; + s = qd::quick_two_sum(s, e, e); + return dd_real(s, e); +#else + double s1, s2, t1, t2; + s1 = qd::two_diff(a.x[0], b.x[0], s2); + t1 = qd::two_diff(a.x[1], b.x[1], t2); + s2 += t1; + s1 = qd::quick_two_sum(s1, s2, s2); + s2 += t2; + s1 = qd::quick_two_sum(s1, s2, s2); + return dd_real(s1, s2); +#endif +} + +/* double - double-double */ +inline dd_real operator-(double a, const dd_real &b) { + double s1, s2; + s1 = qd::two_diff(a, b.x[0], s2); + s2 -= b.x[1]; + s1 = qd::quick_two_sum(s1, s2, s2); + return dd_real(s1, s2); +} + +/*********** Self-Subtractions ************/ +/* double-double -= double */ +inline dd_real &dd_real::operator-=(double a) { + double s1, s2; + s1 = qd::two_diff(x[0], a, s2); + s2 += x[1]; + x[0] = qd::quick_two_sum(s1, s2, x[1]); + return *this; +} + +/* double-double -= double-double */ +inline dd_real &dd_real::operator-=(const dd_real &a) { +#ifndef QD_IEEE_ADD + double s, e; + s = qd::two_diff(x[0], a.x[0], e); + e += x[1]; + e -= a.x[1]; + x[0] = qd::quick_two_sum(s, e, x[1]); + return *this; +#else + double s1, s2, t1, t2; + s1 = qd::two_diff(x[0], a.x[0], s2); + t1 = qd::two_diff(x[1], a.x[1], t2); + s2 += t1; + s1 = qd::quick_two_sum(s1, s2, s2); + s2 += t2; + x[0] = qd::quick_two_sum(s1, s2, x[1]); + return *this; +#endif +} + +/*********** Unary Minus ***********/ +inline dd_real dd_real::operator-() const { + return dd_real(-x[0], -x[1]); +} + +/*********** Multiplications ************/ +/* double-double = double * double */ +inline dd_real dd_real::mul(double a, double b) { + double p, e; + p = qd::two_prod(a, b, e); + return dd_real(p, e); +} + +/* double-double * (2.0 ^ exp) */ +inline dd_real ldexp(const dd_real &a, int exp) { + return dd_real(std::ldexp(a.x[0], exp), std::ldexp(a.x[1], exp)); +} + +/* double-double * double, where double is a power of 2. */ +inline dd_real mul_pwr2(const dd_real &a, double b) { + return dd_real(a.x[0] * b, a.x[1] * b); +} + +/* double-double * double */ +inline dd_real operator*(const dd_real &a, double b) { + double p1, p2; + + p1 = qd::two_prod(a.x[0], b, p2); + p2 += (a.x[1] * b); + p1 = qd::quick_two_sum(p1, p2, p2); + return dd_real(p1, p2); +} + +/* double-double * double-double */ +inline dd_real operator*(const dd_real &a, const dd_real &b) { + double p1, p2; + + p1 = qd::two_prod(a.x[0], b.x[0], p2); + p2 += (a.x[0] * b.x[1] + a.x[1] * b.x[0]); + p1 = qd::quick_two_sum(p1, p2, p2); + return dd_real(p1, p2); +} + +/* double * double-double */ +inline dd_real operator*(double a, const dd_real &b) { + return (b * a); +} + +/*********** Self-Multiplications ************/ +/* double-double *= double */ +inline dd_real &dd_real::operator*=(double a) { + double p1, p2; + p1 = qd::two_prod(x[0], a, p2); + p2 += x[1] * a; + x[0] = qd::quick_two_sum(p1, p2, x[1]); + return *this; +} + +/* double-double *= double-double */ +inline dd_real &dd_real::operator*=(const dd_real &a) { + double p1, p2; + p1 = qd::two_prod(x[0], a.x[0], p2); + p2 += a.x[1] * x[0]; + p2 += a.x[0] * x[1]; + x[0] = qd::quick_two_sum(p1, p2, x[1]); + return *this; +} + +/*********** Divisions ************/ +inline dd_real dd_real::div(double a, double b) { + double q1, q2; + double p1, p2; + double s, e; + + q1 = a / b; + + /* Compute a - q1 * b */ + p1 = qd::two_prod(q1, b, p2); + s = qd::two_diff(a, p1, e); + e -= p2; + + /* get next approximation */ + q2 = (s + e) / b; + + s = qd::quick_two_sum(q1, q2, e); + + return dd_real(s, e); +} + +/* double-double / double */ +inline dd_real operator/(const dd_real &a, double b) { + + double q1, q2; + double p1, p2; + double s, e; + dd_real r; + + q1 = a.x[0] / b; /* approximate quotient. */ + + /* Compute this - q1 * d */ + p1 = qd::two_prod(q1, b, p2); + s = qd::two_diff(a.x[0], p1, e); + e += a.x[1]; + e -= p2; + + /* get next approximation. */ + q2 = (s + e) / b; + + /* renormalize */ + r.x[0] = qd::quick_two_sum(q1, q2, r.x[1]); + + return r; +} + +inline dd_real dd_real::sloppy_div(const dd_real &a, const dd_real &b) { + double s1, s2; + double q1, q2; + dd_real r; + + q1 = a.x[0] / b.x[0]; /* approximate quotient */ + + /* compute this - q1 * dd */ + r = b * q1; + s1 = qd::two_diff(a.x[0], r.x[0], s2); + s2 -= r.x[1]; + s2 += a.x[1]; + + /* get next approximation */ + q2 = (s1 + s2) / b.x[0]; + + /* renormalize */ + r.x[0] = qd::quick_two_sum(q1, q2, r.x[1]); + return r; +} + +inline dd_real dd_real::accurate_div(const dd_real &a, const dd_real &b) { + double q1, q2, q3; + dd_real r; + + q1 = a.x[0] / b.x[0]; /* approximate quotient */ + + r = a - q1 * b; + + q2 = r.x[0] / b.x[0]; + r -= (q2 * b); + + q3 = r.x[0] / b.x[0]; + + q1 = qd::quick_two_sum(q1, q2, q2); + r = dd_real(q1, q2) + q3; + return r; +} + +/* double-double / double-double */ +inline dd_real operator/(const dd_real &a, const dd_real &b) { +#ifdef QD_SLOPPY_DIV + return dd_real::sloppy_div(a, b); +#else + return dd_real::accurate_div(a, b); +#endif +} + +/* double / double-double */ +inline dd_real operator/(double a, const dd_real &b) { + return dd_real(a) / b; +} + +inline dd_real inv(const dd_real &a) { + return 1.0 / a; +} + +/*********** Self-Divisions ************/ +/* double-double /= double */ +inline dd_real &dd_real::operator/=(double a) { + *this = *this / a; + return *this; +} + +/* double-double /= double-double */ +inline dd_real &dd_real::operator/=(const dd_real &a) { + *this = *this / a; + return *this; +} + +/********** Remainder **********/ +inline dd_real drem(const dd_real &a, const dd_real &b) { + dd_real n = nint(a / b); + return (a - n * b); +} + +inline dd_real divrem(const dd_real &a, const dd_real &b, dd_real &r) { + dd_real n = nint(a / b); + r = a - n * b; + return n; +} + +/*********** Squaring **********/ +inline dd_real sqr(const dd_real &a) { + double p1, p2; + double s1, s2; + p1 = qd::two_sqr(a.x[0], p2); + p2 += 2.0 * a.x[0] * a.x[1]; + p2 += a.x[1] * a.x[1]; + s1 = qd::quick_two_sum(p1, p2, s2); + return dd_real(s1, s2); +} + +inline dd_real dd_real::sqr(double a) { + double p1, p2; + p1 = qd::two_sqr(a, p2); + return dd_real(p1, p2); +} + + +/********** Exponentiation **********/ +inline dd_real dd_real::operator^(int n) { + return npwr(*this, n); +} + + +/*********** Assignments ************/ +/* double-double = double */ +inline dd_real &dd_real::operator=(double a) { + x[0] = a; + x[1] = 0.0; + return *this; +} + +/*********** Equality Comparisons ************/ +/* double-double == double */ +inline bool operator==(const dd_real &a, double b) { + return (a.x[0] == b && a.x[1] == 0.0); +} + +/* double-double == double-double */ +inline bool operator==(const dd_real &a, const dd_real &b) { + return (a.x[0] == b.x[0] && a.x[1] == b.x[1]); +} + +/* double == double-double */ +inline bool operator==(double a, const dd_real &b) { + return (a == b.x[0] && b.x[1] == 0.0); +} + +/*********** Greater-Than Comparisons ************/ +/* double-double > double */ +inline bool operator>(const dd_real &a, double b) { + return (a.x[0] > b || (a.x[0] == b && a.x[1] > 0.0)); +} + +/* double-double > double-double */ +inline bool operator>(const dd_real &a, const dd_real &b) { + return (a.x[0] > b.x[0] || (a.x[0] == b.x[0] && a.x[1] > b.x[1])); +} + +/* double > double-double */ +inline bool operator>(double a, const dd_real &b) { + return (a > b.x[0] || (a == b.x[0] && b.x[1] < 0.0)); +} + +/*********** Less-Than Comparisons ************/ +/* double-double < double */ +inline bool operator<(const dd_real &a, double b) { + return (a.x[0] < b || (a.x[0] == b && a.x[1] < 0.0)); +} + +/* double-double < double-double */ +inline bool operator<(const dd_real &a, const dd_real &b) { + return (a.x[0] < b.x[0] || (a.x[0] == b.x[0] && a.x[1] < b.x[1])); +} + +/* double < double-double */ +inline bool operator<(double a, const dd_real &b) { + return (a < b.x[0] || (a == b.x[0] && b.x[1] > 0.0)); +} + +/*********** Greater-Than-Or-Equal-To Comparisons ************/ +/* double-double >= double */ +inline bool operator>=(const dd_real &a, double b) { + return (a.x[0] > b || (a.x[0] == b && a.x[1] >= 0.0)); +} + +/* double-double >= double-double */ +inline bool operator>=(const dd_real &a, const dd_real &b) { + return (a.x[0] > b.x[0] || (a.x[0] == b.x[0] && a.x[1] >= b.x[1])); +} + +/* double >= double-double */ +inline bool operator>=(double a, const dd_real &b) { + return (b <= a); +} + +/*********** Less-Than-Or-Equal-To Comparisons ************/ +/* double-double <= double */ +inline bool operator<=(const dd_real &a, double b) { + return (a.x[0] < b || (a.x[0] == b && a.x[1] <= 0.0)); +} + +/* double-double <= double-double */ +inline bool operator<=(const dd_real &a, const dd_real &b) { + return (a.x[0] < b.x[0] || (a.x[0] == b.x[0] && a.x[1] <= b.x[1])); +} + +/* double <= double-double */ +inline bool operator<=(double a, const dd_real &b) { + return (b >= a); +} + +/*********** Not-Equal-To Comparisons ************/ +/* double-double != double */ +inline bool operator!=(const dd_real &a, double b) { + return (a.x[0] != b || a.x[1] != 0.0); +} + +/* double-double != double-double */ +inline bool operator!=(const dd_real &a, const dd_real &b) { + return (a.x[0] != b.x[0] || a.x[1] != b.x[1]); +} + +/* double != double-double */ +inline bool operator!=(double a, const dd_real &b) { + return (a != b.x[0] || b.x[1] != 0.0); +} + +/*********** Micellaneous ************/ +/* this == 0 */ +inline bool dd_real::is_zero() const { + return (x[0] == 0.0); +} + +/* this == 1 */ +inline bool dd_real::is_one() const { + return (x[0] == 1.0 && x[1] == 0.0); +} + +/* this > 0 */ +inline bool dd_real::is_positive() const { + return (x[0] > 0.0); +} + +/* this < 0 */ +inline bool dd_real::is_negative() const { + return (x[0] < 0.0); +} + +inline dd_real::operator bool() const { + return (x[0] != 0.0); +} + +inline dd_real::operator double() const { + return to_double(*this); +} + +/* Absolute value */ +inline dd_real abs(const dd_real &a) { + return (a.x[0] < 0.0) ? -a : a; +} + +inline dd_real fabs(const dd_real &a) { + return abs(a); +} + +/* Round to Nearest integer */ +inline dd_real nint(const dd_real &a) { + double hi = qd::nint(a.x[0]); + double lo; + + if (hi == a.x[0]) { + /* High word is an integer already. Round the low word.*/ + lo = qd::nint(a.x[1]); + + /* Renormalize. This is needed if x[0] = some integer, x[1] = 1/2.*/ + hi = qd::quick_two_sum(hi, lo, lo); + } else { + /* High word is not an integer. */ + lo = 0.0; + if (std::abs(hi-a.x[0]) == 0.5 && a.x[1] < 0.0) { + /* There is a tie in the high word, consult the low word + to break the tie. */ + hi -= 1.0; /* NOTE: This does not cause INEXACT. */ + } + } + + return dd_real(hi, lo); +} + +inline dd_real floor(const dd_real &a) { + double hi = std::floor(a.x[0]); + double lo = 0.0; + + if (hi == a.x[0]) { + /* High word is integer already. Round the low word. */ + lo = std::floor(a.x[1]); + hi = qd::quick_two_sum(hi, lo, lo); + } + + return dd_real(hi, lo); +} + +inline dd_real ceil(const dd_real &a) { + double hi = std::ceil(a.x[0]); + double lo = 0.0; + + if (hi == a.x[0]) { + /* High word is integer already. Round the low word. */ + lo = std::ceil(a.x[1]); + hi = qd::quick_two_sum(hi, lo, lo); + } + + return dd_real(hi, lo); +} + +inline dd_real aint(const dd_real &a) { + return (a.x[0] >= 0.0) ? floor(a) : ceil(a); +} + +/* Cast to double. */ +inline double to_double(const dd_real &a) { + return a.x[0]; +} + +/* Cast to int. */ +inline int to_int(const dd_real &a) { + return static_cast(a.x[0]); +} + +/* Random number generator */ +inline dd_real dd_real::rand() { + return ddrand(); +} + +#endif /* _QD_DD_INLINE_H */ diff --git a/external/PackedCSparse/qd/dd_real.cc b/external/PackedCSparse/qd/dd_real.cc new file mode 100644 index 000000000..ff4d52231 --- /dev/null +++ b/external/PackedCSparse/qd/dd_real.cc @@ -0,0 +1,1303 @@ +/* + * src/dd_real.cc + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2007 + * + * Contains implementation of non-inlined functions of double-double + * package. Inlined functions are found in dd_inline.h (in include directory). + */ +#include +#include +#include +#include +#include +#include +#include + +#include "qd_config.h" +#include "dd_real.h" +#include "util.h" + +#include "bits.h" + +#ifndef QD_INLINE +#include "dd_inline.h" +#endif + +using std::cout; +using std::cerr; +using std::endl; +using std::ostream; +using std::istream; +using std::ios_base; +using std::string; +using std::setw; + +/* This routine is called whenever a fatal error occurs. */ +void dd_real::error(const char *msg) { + //if (msg) { cerr << "ERROR " << msg << endl; } +} + +/* Computes the square root of the double-double number dd. + NOTE: dd must be a non-negative number. */ +QD_API dd_real sqrt(const dd_real &a) { + /* Strategy: Use Karp's trick: if x is an approximation + to sqrt(a), then + + sqrt(a) = a*x + [a - (a*x)^2] * x / 2 (approx) + + The approximation is accurate to twice the accuracy of x. + Also, the multiplication (a*x) and [-]*x can be done with + only half the precision. + */ + + if (a.is_zero()) + return 0.0; + + if (a.is_negative()) { + dd_real::error("(dd_real::sqrt): Negative argument."); + return dd_real::_nan; + } + + double x = 1.0 / std::sqrt(a.x[0]); + double ax = a.x[0] * x; + return dd_real::add(ax, (a - dd_real::sqr(ax)).x[0] * (x * 0.5)); +} + +/* Computes the square root of a double in double-double precision. + NOTE: d must not be negative. */ +dd_real dd_real::sqrt(double d) { + return ::sqrt(dd_real(d)); +} + +/* Computes the n-th root of the double-double number a. + NOTE: n must be a positive integer. + NOTE: If n is even, then a must not be negative. */ +dd_real nroot(const dd_real &a, int n) { + /* Strategy: Use Newton iteration for the function + + f(x) = x^(-n) - a + + to find its root a^{-1/n}. The iteration is thus + + x' = x + x * (1 - a * x^n) / n + + which converges quadratically. We can then find + a^{1/n} by taking the reciprocal. + */ + + if (n <= 0) { + dd_real::error("(dd_real::nroot): N must be positive."); + return dd_real::_nan; + } + + if (n%2 == 0 && a.is_negative()) { + dd_real::error("(dd_real::nroot): Negative argument."); + return dd_real::_nan; + } + + if (n == 1) { + return a; + } + if (n == 2) { + return sqrt(a); + } + + if (a.is_zero()) + return 0.0; + + /* Note a^{-1/n} = exp(-log(a)/n) */ + dd_real r = abs(a); + dd_real x = std::exp(-std::log(r.x[0]) / n); + + /* Perform Newton's iteration. */ + x += x * (1.0 - r * npwr(x, n)) / static_cast(n); + if (a.x[0] < 0.0) + x = -x; + return 1.0/x; +} + +/* Computes the n-th power of a double-double number. + NOTE: 0^0 causes an error. */ +dd_real npwr(const dd_real &a, int n) { + + if (n == 0) { + if (a.is_zero()) { + dd_real::error("(dd_real::npwr): Invalid argument."); + return dd_real::_nan; + } + return 1.0; + } + + dd_real r = a; + dd_real s = 1.0; + int N = std::abs(n); + + if (N > 1) { + /* Use binary exponentiation */ + while (N > 0) { + if (N % 2 == 1) { + s *= r; + } + N /= 2; + if (N > 0) + r = sqr(r); + } + } else { + s = r; + } + + /* Compute the reciprocal if n is negative. */ + if (n < 0) + return (1.0 / s); + + return s; +} + +dd_real pow(const dd_real &a, int n) { + return npwr(a, n); +} + +dd_real pow(const dd_real &a, const dd_real &b) { + return exp(b * log(a)); +} + +static const int n_inv_fact = 15; +static const double inv_fact[n_inv_fact][2] = { + { 1.66666666666666657e-01, 9.25185853854297066e-18}, + { 4.16666666666666644e-02, 2.31296463463574266e-18}, + { 8.33333333333333322e-03, 1.15648231731787138e-19}, + { 1.38888888888888894e-03, -5.30054395437357706e-20}, + { 1.98412698412698413e-04, 1.72095582934207053e-22}, + { 2.48015873015873016e-05, 2.15119478667758816e-23}, + { 2.75573192239858925e-06, -1.85839327404647208e-22}, + { 2.75573192239858883e-07, 2.37677146222502973e-23}, + { 2.50521083854417202e-08, -1.44881407093591197e-24}, + { 2.08767569878681002e-09, -1.20734505911325997e-25}, + { 1.60590438368216133e-10, 1.25852945887520981e-26}, + { 1.14707455977297245e-11, 2.06555127528307454e-28}, + { 7.64716373181981641e-13, 7.03872877733453001e-30}, + { 4.77947733238738525e-14, 4.39920548583408126e-31}, + { 2.81145725434552060e-15, 1.65088427308614326e-31} +}; + +/* Exponential. Computes exp(x) in double-double precision. */ +dd_real exp(const dd_real &a) { + /* Strategy: We first reduce the size of x by noting that + + exp(kr + m * log(2)) = 2^m * exp(r)^k + + where m and k are integers. By choosing m appropriately + we can make |kr| <= log(2) / 2 = 0.347. Then exp(r) is + evaluated using the familiar Taylor series. Reducing the + argument substantially speeds up the convergence. */ + + const double k = 512.0; + const double inv_k = 1.0 / k; + + if (a.x[0] <= -709.0) + return 0.0; + + if (a.x[0] >= 709.0) + return dd_real::_inf; + + if (a.is_zero()) + return 1.0; + + if (a.is_one()) + return dd_real::_e; + + double m = std::floor(a.x[0] / dd_real::_log2.x[0] + 0.5); + dd_real r = mul_pwr2(a - dd_real::_log2 * m, inv_k); + dd_real s, t, p; + + p = sqr(r); + s = r + mul_pwr2(p, 0.5); + p *= r; + t = p * dd_real(inv_fact[0][0], inv_fact[0][1]); + int i = 0; + do { + s += t; + p *= r; + ++i; + t = p * dd_real(inv_fact[i][0], inv_fact[i][1]); + } while (std::abs(to_double(t)) > inv_k * dd_real::_eps && i < 5); + + s += t; + + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s += 1.0; + + return ldexp(s, static_cast(m)); +} + +/* Logarithm. Computes log(x) in double-double precision. + This is a natural logarithm (i.e., base e). */ +dd_real log(const dd_real &a) { + /* Strategy. The Taylor series for log converges much more + slowly than that of exp, due to the lack of the factorial + term in the denominator. Hence this routine instead tries + to determine the root of the function + + f(x) = exp(x) - a + + using Newton iteration. The iteration is given by + + x' = x - f(x)/f'(x) + = x - (1 - a * exp(-x)) + = x + a * exp(-x) - 1. + + Only one iteration is needed, since Newton's iteration + approximately doubles the number of digits per iteration. */ + + if (a.is_one()) { + return 0.0; + } + + if (a.x[0] <= 0.0) { + dd_real::error("(dd_real::log): Non-positive argument."); + return dd_real::_nan; + } + + dd_real x = std::log(a.x[0]); /* Initial approximation */ + + x = x + a * exp(-x) - 1.0; + return x; +} + +dd_real log10(const dd_real &a) { + return log(a) / dd_real::_log10; +} + +static const dd_real _pi16 = dd_real(1.963495408493620697e-01, + 7.654042494670957545e-18); + +/* Table of sin(k * pi/16) and cos(k * pi/16). */ +static const double sin_table [4][2] = { + {1.950903220161282758e-01, -7.991079068461731263e-18}, + {3.826834323650897818e-01, -1.005077269646158761e-17}, + {5.555702330196021776e-01, 4.709410940561676821e-17}, + {7.071067811865475727e-01, -4.833646656726456726e-17} +}; + +static const double cos_table [4][2] = { + {9.807852804032304306e-01, 1.854693999782500573e-17}, + {9.238795325112867385e-01, 1.764504708433667706e-17}, + {8.314696123025452357e-01, 1.407385698472802389e-18}, + {7.071067811865475727e-01, -4.833646656726456726e-17} +}; + +/* Computes sin(a) using Taylor series. + Assumes |a| <= pi/32. */ +static dd_real sin_taylor(const dd_real &a) { + const double thresh = 0.5 * std::abs(to_double(a)) * dd_real::_eps; + dd_real r, s, t, x; + + if (a.is_zero()) { + return 0.0; + } + + int i = 0; + x = -sqr(a); + s = a; + r = a; + do { + r *= x; + t = r * dd_real(inv_fact[i][0], inv_fact[i][1]); + s += t; + i += 2; + } while (i < n_inv_fact && std::abs(to_double(t)) > thresh); + + return s; +} + +static dd_real cos_taylor(const dd_real &a) { + const double thresh = 0.5 * dd_real::_eps; + dd_real r, s, t, x; + + if (a.is_zero()) { + return 1.0; + } + + x = -sqr(a); + r = x; + s = 1.0 + mul_pwr2(r, 0.5); + int i = 1; + do { + r *= x; + t = r * dd_real(inv_fact[i][0], inv_fact[i][1]); + s += t; + i += 2; + } while (i < n_inv_fact && std::abs(to_double(t)) > thresh); + + return s; +} + +static void sincos_taylor(const dd_real &a, + dd_real &sin_a, dd_real &cos_a) { + if (a.is_zero()) { + sin_a = 0.0; + cos_a = 1.0; + return; + } + + sin_a = sin_taylor(a); + cos_a = sqrt(1.0 - sqr(sin_a)); +} + + +dd_real sin(const dd_real &a) { + + /* Strategy. To compute sin(x), we choose integers a, b so that + + x = s + a * (pi/2) + b * (pi/16) + + and |s| <= pi/32. Using the fact that + + sin(pi/16) = 0.5 * sqrt(2 - sqrt(2 + sqrt(2))) + + we can compute sin(x) from sin(s), cos(s). This greatly + increases the convergence of the sine Taylor series. */ + + if (a.is_zero()) { + return 0.0; + } + + // approximately reduce modulo 2*pi + dd_real z = nint(a / dd_real::_2pi); + dd_real r = a - dd_real::_2pi * z; + + // approximately reduce modulo pi/2 and then modulo pi/16. + dd_real t; + double q = std::floor(r.x[0] / dd_real::_pi2.x[0] + 0.5); + t = r - dd_real::_pi2 * q; + int j = static_cast(q); + q = std::floor(t.x[0] / _pi16.x[0] + 0.5); + t -= _pi16 * q; + int k = static_cast(q); + int abs_k = std::abs(k); + + if (j < -2 || j > 2) { + dd_real::error("(dd_real::sin): Cannot reduce modulo pi/2."); + return dd_real::_nan; + } + + if (abs_k > 4) { + dd_real::error("(dd_real::sin): Cannot reduce modulo pi/16."); + return dd_real::_nan; + } + + if (k == 0) { + switch (j) { + case 0: + return sin_taylor(t); + case 1: + return cos_taylor(t); + case -1: + return -cos_taylor(t); + default: + return -sin_taylor(t); + } + } + + dd_real u(cos_table[abs_k-1][0], cos_table[abs_k-1][1]); + dd_real v(sin_table[abs_k-1][0], sin_table[abs_k-1][1]); + dd_real sin_t, cos_t; + sincos_taylor(t, sin_t, cos_t); + if (j == 0) { + if (k > 0) { + r = u * sin_t + v * cos_t; + } else { + r = u * sin_t - v * cos_t; + } + } else if (j == 1) { + if (k > 0) { + r = u * cos_t - v * sin_t; + } else { + r = u * cos_t + v * sin_t; + } + } else if (j == -1) { + if (k > 0) { + r = v * sin_t - u * cos_t; + } else if (k < 0) { + r = -u * cos_t - v * sin_t; + } + } else { + if (k > 0) { + r = -u * sin_t - v * cos_t; + } else { + r = v * cos_t - u * sin_t; + } + } + + return r; +} + +dd_real cos(const dd_real &a) { + + if (a.is_zero()) { + return 1.0; + } + + // approximately reduce modulo 2*pi + dd_real z = nint(a / dd_real::_2pi); + dd_real r = a - z * dd_real::_2pi; + + // approximately reduce modulo pi/2 and then modulo pi/16 + dd_real t; + double q = std::floor(r.x[0] / dd_real::_pi2.x[0] + 0.5); + t = r - dd_real::_pi2 * q; + int j = static_cast(q); + q = std::floor(t.x[0] / _pi16.x[0] + 0.5); + t -= _pi16 * q; + int k = static_cast(q); + int abs_k = std::abs(k); + + if (j < -2 || j > 2) { + dd_real::error("(dd_real::cos): Cannot reduce modulo pi/2."); + return dd_real::_nan; + } + + if (abs_k > 4) { + dd_real::error("(dd_real::cos): Cannot reduce modulo pi/16."); + return dd_real::_nan; + } + + if (k == 0) { + switch (j) { + case 0: + return cos_taylor(t); + case 1: + return -sin_taylor(t); + case -1: + return sin_taylor(t); + default: + return -cos_taylor(t); + } + } + + dd_real sin_t, cos_t; + sincos_taylor(t, sin_t, cos_t); + dd_real u(cos_table[abs_k-1][0], cos_table[abs_k-1][1]); + dd_real v(sin_table[abs_k-1][0], sin_table[abs_k-1][1]); + + if (j == 0) { + if (k > 0) { + r = u * cos_t - v * sin_t; + } else { + r = u * cos_t + v * sin_t; + } + } else if (j == 1) { + if (k > 0) { + r = - u * sin_t - v * cos_t; + } else { + r = v * cos_t - u * sin_t; + } + } else if (j == -1) { + if (k > 0) { + r = u * sin_t + v * cos_t; + } else { + r = u * sin_t - v * cos_t; + } + } else { + if (k > 0) { + r = v * sin_t - u * cos_t; + } else { + r = - u * cos_t - v * sin_t; + } + } + + return r; +} + +void sincos(const dd_real &a, dd_real &sin_a, dd_real &cos_a) { + + if (a.is_zero()) { + sin_a = 0.0; + cos_a = 1.0; + return; + } + + // approximately reduce modulo 2*pi + dd_real z = nint(a / dd_real::_2pi); + dd_real r = a - dd_real::_2pi * z; + + // approximately reduce module pi/2 and pi/16 + dd_real t; + double q = std::floor(r.x[0] / dd_real::_pi2.x[0] + 0.5); + t = r - dd_real::_pi2 * q; + int j = static_cast(q); + int abs_j = std::abs(j); + q = std::floor(t.x[0] / _pi16.x[0] + 0.5); + t -= _pi16 * q; + int k = static_cast(q); + int abs_k = std::abs(k); + + if (abs_j > 2) { + dd_real::error("(dd_real::sincos): Cannot reduce modulo pi/2."); + cos_a = sin_a = dd_real::_nan; + return; + } + + if (abs_k > 4) { + dd_real::error("(dd_real::sincos): Cannot reduce modulo pi/16."); + cos_a = sin_a = dd_real::_nan; + return; + } + + dd_real sin_t, cos_t; + dd_real s, c; + + sincos_taylor(t, sin_t, cos_t); + + if (abs_k == 0) { + s = sin_t; + c = cos_t; + } else { + dd_real u(cos_table[abs_k-1][0], cos_table[abs_k-1][1]); + dd_real v(sin_table[abs_k-1][0], sin_table[abs_k-1][1]); + + if (k > 0) { + s = u * sin_t + v * cos_t; + c = u * cos_t - v * sin_t; + } else { + s = u * sin_t - v * cos_t; + c = u * cos_t + v * sin_t; + } + } + + if (abs_j == 0) { + sin_a = s; + cos_a = c; + } else if (j == 1) { + sin_a = c; + cos_a = -s; + } else if (j == -1) { + sin_a = -c; + cos_a = s; + } else { + sin_a = -s; + cos_a = -c; + } + +} + +dd_real atan(const dd_real &a) { + return atan2(a, dd_real(1.0)); +} + +dd_real atan2(const dd_real &y, const dd_real &x) { + /* Strategy: Instead of using Taylor series to compute + arctan, we instead use Newton's iteration to solve + the equation + + sin(z) = y/r or cos(z) = x/r + + where r = sqrt(x^2 + y^2). + The iteration is given by + + z' = z + (y - sin(z)) / cos(z) (for equation 1) + z' = z - (x - cos(z)) / sin(z) (for equation 2) + + Here, x and y are normalized so that x^2 + y^2 = 1. + If |x| > |y|, then first iteration is used since the + denominator is larger. Otherwise, the second is used. + */ + + if (x.is_zero()) { + + if (y.is_zero()) { + /* Both x and y is zero. */ + dd_real::error("(dd_real::atan2): Both arguments zero."); + return dd_real::_nan; + } + + return (y.is_positive()) ? dd_real::_pi2 : -dd_real::_pi2; + } else if (y.is_zero()) { + return (x.is_positive()) ? dd_real(0.0) : dd_real::_pi; + } + + if (x == y) { + return (y.is_positive()) ? dd_real::_pi4 : -dd_real::_3pi4; + } + + if (x == -y) { + return (y.is_positive()) ? dd_real::_3pi4 : -dd_real::_pi4; + } + + dd_real r = sqrt(sqr(x) + sqr(y)); + dd_real xx = x / r; + dd_real yy = y / r; + + /* Compute double precision approximation to atan. */ + dd_real z = std::atan2(to_double(y), to_double(x)); + dd_real sin_z, cos_z; + + if (std::abs(xx.x[0]) > std::abs(yy.x[0])) { + /* Use Newton iteration 1. z' = z + (y - sin(z)) / cos(z) */ + sincos(z, sin_z, cos_z); + z += (yy - sin_z) / cos_z; + } else { + /* Use Newton iteration 2. z' = z - (x - cos(z)) / sin(z) */ + sincos(z, sin_z, cos_z); + z -= (xx - cos_z) / sin_z; + } + + return z; +} + +dd_real tan(const dd_real &a) { + dd_real s, c; + sincos(a, s, c); + return s/c; +} + +dd_real asin(const dd_real &a) { + dd_real abs_a = abs(a); + + if (abs_a > 1.0) { + dd_real::error("(dd_real::asin): Argument out of domain."); + return dd_real::_nan; + } + + if (abs_a.is_one()) { + return (a.is_positive()) ? dd_real::_pi2 : -dd_real::_pi2; + } + + return atan2(a, sqrt(1.0 - sqr(a))); +} + +dd_real acos(const dd_real &a) { + dd_real abs_a = abs(a); + + if (abs_a > 1.0) { + dd_real::error("(dd_real::acos): Argument out of domain."); + return dd_real::_nan; + } + + if (abs_a.is_one()) { + return (a.is_positive()) ? dd_real(0.0) : dd_real::_pi; + } + + return atan2(sqrt(1.0 - sqr(a)), a); +} + +dd_real sinh(const dd_real &a) { + if (a.is_zero()) { + return 0.0; + } + + if (abs(a) > 0.05) { + dd_real ea = exp(a); + return mul_pwr2(ea - inv(ea), 0.5); + } + + /* since a is small, using the above formula gives + a lot of cancellation. So use Taylor series. */ + dd_real s = a; + dd_real t = a; + dd_real r = sqr(t); + double m = 1.0; + double thresh = std::abs((to_double(a)) * dd_real::_eps); + + do { + m += 2.0; + t *= r; + t /= (m-1) * m; + + s += t; + } while (abs(t) > thresh); + + return s; + +} + +dd_real cosh(const dd_real &a) { + if (a.is_zero()) { + return 1.0; + } + + dd_real ea = exp(a); + return mul_pwr2(ea + inv(ea), 0.5); +} + +dd_real tanh(const dd_real &a) { + if (a.is_zero()) { + return 0.0; + } + + if (std::abs(to_double(a)) > 0.05) { + dd_real ea = exp(a); + dd_real inv_ea = inv(ea); + return (ea - inv_ea) / (ea + inv_ea); + } else { + dd_real s, c; + s = sinh(a); + c = sqrt(1.0 + sqr(s)); + return s / c; + } +} + +void sincosh(const dd_real &a, dd_real &s, dd_real &c) { + if (std::abs(to_double(a)) <= 0.05) { + s = sinh(a); + c = sqrt(1.0 + sqr(s)); + } else { + dd_real ea = exp(a); + dd_real inv_ea = inv(ea); + s = mul_pwr2(ea - inv_ea, 0.5); + c = mul_pwr2(ea + inv_ea, 0.5); + } +} + +dd_real asinh(const dd_real &a) { + return log(a + sqrt(sqr(a) + 1.0)); +} + +dd_real acosh(const dd_real &a) { + if (a < 1.0) { + dd_real::error("(dd_real::acosh): Argument out of domain."); + return dd_real::_nan; + } + + return log(a + sqrt(sqr(a) - 1.0)); +} + +dd_real atanh(const dd_real &a) { + if (abs(a) >= 1.0) { + dd_real::error("(dd_real::atanh): Argument out of domain."); + return dd_real::_nan; + } + + return mul_pwr2(log((1.0 + a) / (1.0 - a)), 0.5); +} + +QD_API dd_real fmod(const dd_real &a, const dd_real &b) { + dd_real n = aint(a / b); + return (a - b * n); +} + +QD_API dd_real ddrand() { + static const double m_const = 4.6566128730773926e-10; /* = 2^{-31} */ + double m = m_const; + dd_real r = 0.0; + double d; + + /* Strategy: Generate 31 bits at a time, using lrand48 + random number generator. Shift the bits, and reapeat + 4 times. */ + + for (int i = 0; i < 4; i++, m *= m_const) { +// d = lrand48() * m; + d = std::rand() * m; + r += d; + } + + return r; +} + +/* polyeval(c, n, x) + Evaluates the given n-th degree polynomial at x. + The polynomial is given by the array of (n+1) coefficients. */ +dd_real polyeval(const dd_real *c, int n, const dd_real &x) { + /* Just use Horner's method of polynomial evaluation. */ + dd_real r = c[n]; + + for (int i = n-1; i >= 0; i--) { + r *= x; + r += c[i]; + } + + return r; +} + +/* polyroot(c, n, x0) + Given an n-th degree polynomial, finds a root close to + the given guess x0. Note that this uses simple Newton + iteration scheme, and does not work for multiple roots. */ +QD_API dd_real polyroot(const dd_real *c, int n, + const dd_real &x0, int max_iter, double thresh) { + dd_real x = x0; + dd_real f; + dd_real *d = new dd_real[n]; + bool conv = false; + int i; + double max_c = std::abs(to_double(c[0])); + double v; + + if (thresh == 0.0) thresh = dd_real::_eps; + + /* Compute the coefficients of the derivatives. */ + for (i = 1; i <= n; i++) { + v = std::abs(to_double(c[i])); + if (v > max_c) max_c = v; + d[i-1] = c[i] * static_cast(i); + } + thresh *= max_c; + + /* Newton iteration. */ + for (i = 0; i < max_iter; i++) { + f = polyeval(c, n, x); + + if (abs(f) < thresh) { + conv = true; + break; + } + x -= (f / polyeval(d, n-1, x)); + } + delete [] d; + + if (!conv) { + dd_real::error("(dd_real::polyroot): Failed to converge."); + return dd_real::_nan; + } + + return x; +} + + +/* Constructor. Reads a double-double number from the string s + and constructs a double-double number. */ +dd_real::dd_real(const char *s) { + if (dd_real::read(s, *this)) { + dd_real::error("(dd_real::dd_real): INPUT ERROR."); + *this = dd_real::_nan; + } +} + +dd_real &dd_real::operator=(const char *s) { + if (dd_real::read(s, *this)) { + dd_real::error("(dd_real::operator=): INPUT ERROR."); + *this = dd_real::_nan; + } + return *this; +} + +/* Outputs the double-double number dd. */ +ostream &operator<<(ostream &os, const dd_real &dd) { + bool showpos = (os.flags() & ios_base::showpos) != 0; + bool uppercase = (os.flags() & ios_base::uppercase) != 0; + return os << dd.to_string((int)os.precision(), (int)os.width(), os.flags(), + showpos, uppercase, os.fill()); +} + +/* Reads in the double-double number a. */ +istream &operator>>(istream &s, dd_real &a) { + char str[255]; + s >> str; + a = dd_real(str); + return s; +} + +void dd_real::to_digits(char *s, int &expn, int precision) const { + int D = precision + 1; /* number of digits to compute */ + + dd_real r = abs(*this); + int e; /* exponent */ + int i, d; + + if (x[0] == 0.0) { + /* this == 0.0 */ + expn = 0; + for (i = 0; i < precision; i++) s[i] = '0'; + return; + } + + /* First determine the (approximate) exponent. */ + e = to_int(std::floor(std::log10(std::abs(x[0])))); + + if (e < -300) { + r *= dd_real(10.0) ^ 300; + r /= dd_real(10.0) ^ (e + 300); + } else if (e > 300) { + r = ldexp(r, -53); + r /= dd_real(10.0) ^ e; + r = ldexp(r, 53); + } else { + r /= dd_real(10.0) ^ e; + } + + /* Fix exponent if we are off by one */ + if (r >= 10.0) { + r /= 10.0; + e++; + } else if (r < 1.0) { + r *= 10.0; + e--; + } + + if (r >= 10.0 || r < 1.0) { + dd_real::error("(dd_real::to_digits): can't compute exponent."); + return; + } + + /* Extract the digits */ + for (i = 0; i < D; i++) { + d = static_cast(r.x[0]); + r -= d; + r *= 10.0; + + s[i] = static_cast(d + '0'); + } + + /* Fix out of range digits. */ + for (i = D-1; i > 0; i--) { + if (s[i] < '0') { + s[i-1]--; + s[i] += 10; + } else if (s[i] > '9') { + s[i-1]++; + s[i] -= 10; + } + } + + if (s[0] <= '0') { + dd_real::error("(dd_real::to_digits): non-positive leading digit."); + return; + } + + /* Round, handle carry */ + if (s[D-1] >= '5') { + s[D-2]++; + + i = D-2; + while (i > 0 && s[i] > '9') { + s[i] -= 10; + s[--i]++; + } + } + + /* If first digit is 10, shift everything. */ + if (s[0] > '9') { + e++; + for (i = precision; i >= 2; i--) s[i] = s[i-1]; + s[0] = '1'; + s[1] = '0'; + } + + s[precision] = 0; + expn = e; +} + +/* Writes the double-double number into the character array s of length len. + The integer d specifies how many significant digits to write. + The string s must be able to hold at least (d+8) characters. + showpos indicates whether to use the + sign, and uppercase indicates + whether the E or e is to be used for the exponent. */ +void dd_real::write(char *s, int len, int precision, + bool showpos, bool uppercase) const { + string str = to_string(precision, 0, ios_base::scientific, showpos, uppercase); + std::strncpy(s, str.c_str(), len-1); + s[len-1] = 0; +} + + +void round_string(char *s, int precision, int *offset){ + /* + Input string must be all digits or errors will occur. + */ + + int i; + int D = precision ; + + /* Round, handle carry */ + if (D>0 && s[D] >= '5') { + s[D-1]++; + + i = D-1; + while (i > 0 && s[i] > '9') { + s[i] -= 10; + s[--i]++; + } + } + + /* If first digit is 10, shift everything. */ + if (s[0] > '9') { + // e++; // don't modify exponent here + for (i = precision; i >= 1; i--) s[i+1] = s[i]; + s[0] = '1'; + s[1] = '0'; + + (*offset)++ ; // now offset needs to be increased by one + precision++ ; + } + + s[precision] = 0; // add terminator for array +} + +string dd_real::to_string(int precision, int width, ios_base::fmtflags fmt, + bool showpos, bool uppercase, char fill) const { + string s; + bool fixed = (fmt & ios_base::fixed) != 0; + bool sgn = true; + int i, e = 0; + + if (isnan()) { + s = uppercase ? "NAN" : "nan"; + sgn = false; + } else { + if (*this < 0.0) + s += '-'; + else if (showpos) + s += '+'; + else + sgn = false; + + if (isinf()) { + s += uppercase ? "INF" : "inf"; + } else if (*this == 0.0) { + /* Zero case */ + s += '0'; + if (precision > 0) { + s += '.'; + s.append(precision, '0'); + } + } else { + /* Non-zero case */ + int off = (fixed ? (1 + to_int(floor(log10(abs(*this))))) : 1); + int d = precision + off; + + int d_with_extra = d; + if(fixed) + d_with_extra = std::max(60, d); // longer than the max accuracy for DD + + // highly special case - fixed mode, precision is zero, abs(*this) < 1.0 + // without this trap a number like 0.9 printed fixed with 0 precision prints as 0 + // should be rounded to 1. + if(fixed && (precision == 0) && (abs(*this) < 1.0)){ + if(abs(*this) >= 0.5) + s += '1'; + else + s += '0'; + + return s; + } + + // handle near zero to working precision (but not exactly zero) + if (fixed && d <= 0) { + s += '0'; + if (precision > 0) { + s += '.'; + s.append(precision, '0'); + } + } else { // default + + char *t; // = new char[d+1]; + int j; + + if(fixed){ + t = new char[d_with_extra+1]; + to_digits(t, e, d_with_extra); + } + else{ + t = new char[d+1]; + to_digits(t, e, d); + } + + off = e + 1; + + if (fixed) { + // fix the string if it's been computed incorrectly + // round here in the decimal string if required + round_string(t, d, &off); + + if (off > 0) { + for (i = 0; i < off; i++) s += t[i]; + if (precision > 0) { + s += '.'; + for (j = 0; j < precision; j++, i++) s += t[i]; + } + } else { + s += "0."; + if (off < 0) s.append(-off, '0'); + for (i = 0; i < d; i++) s += t[i]; + } + } else { + s += t[0]; + if (precision > 0) s += '.'; + + for (i = 1; i <= precision; i++) + s += t[i]; + + } + delete [] t; + } + } + + // trap for improper offset with large values + // without this trap, output of values of the for 10^j - 1 fail for j > 28 + // and are output with the point in the wrong place, leading to a dramatically off value + if(fixed && (precision > 0)){ + // make sure that the value isn't dramatically larger + double from_string = atof(s.c_str()); + + // if this ratio is large, then we've got problems + if( fabs( from_string / this->x[0] ) > 3.0 ){ + + // loop on the string, find the point, move it up one + // don't act on the first character + for(i=1; i < (int)s.length(); i++){ + if(s[i] == '.'){ + s[i] = s[i-1] ; + s[i-1] = '.' ; + break; + } + } + + from_string = atof(s.c_str()); + // if this ratio is large, then the string has not been fixed + if( fabs( from_string / this->x[0] ) > 3.0 ){ + dd_real::error("Re-rounding unsuccessful in large number fixed point trap.") ; + } + } + } + + + if (!fixed && !isinf()) { + /* Fill in exponent part */ + s += uppercase ? 'E' : 'e'; + append_expn(s, e); + } + } + + /* Fill in the blanks */ + int len = s.length(); + if (len < width) { + int delta = width - len; + if (fmt & ios_base::internal) { + if (sgn) + s.insert(static_cast(1), delta, fill); + else + s.insert(static_cast(0), delta, fill); + } else if (fmt & ios_base::left) { + s.append(delta, fill); + } else { + s.insert(static_cast(0), delta, fill); + } + } + + return s; +} + +/* Reads in a double-double number from the string s. */ +int dd_real::read(const char *s, dd_real &a) { + const char *p = s; + char ch; + int sign = 0; + int point = -1; + int nd = 0; + int e = 0; + bool done = false; + dd_real r = 0.0; + int nread; + + /* Skip any leading spaces */ + while (*p == ' ') + p++; + + while (!done && (ch = *p) != '\0') { + if (ch >= '0' && ch <= '9') { + int d = ch - '0'; + r *= 10.0; + r += static_cast(d); + nd++; + } else { + + switch (ch) { + + case '.': + if (point >= 0) + return -1; + point = nd; + break; + + case '-': + case '+': + if (sign != 0 || nd > 0) + return -1; + sign = (ch == '-') ? -1 : 1; + break; + + case 'E': + case 'e': + nread = std::sscanf(p+1, "%d", &e); + done = true; + if (nread != 1) + return -1; + break; + + default: + return -1; + } + } + + p++; + } + + if (point >= 0) { + e -= (nd - point); + } + + if (e != 0) { + r *= (dd_real(10.0) ^ e); + } + + a = (sign == -1) ? -r : r; + return 0; +} + +/* Debugging routines */ +void dd_real::dump(const string &name, std::ostream &os) const { + std::ios_base::fmtflags old_flags = os.flags(); + std::streamsize old_prec = os.precision(19); + os << std::scientific; + + if (name.length() > 0) os << name << " = "; + os << "[ " << setw(27) << x[0] << ", " << setw(27) << x[1] << " ]" << endl; + + os.precision(old_prec); + os.flags(old_flags); +} + +void dd_real::dump_bits(const string &name, std::ostream &os) const { + string::size_type len = name.length(); + if (len > 0) { + os << name << " = "; + len +=3; + } + os << "[ "; + len += 2; + print_double_info(os, x[0]); + os << endl; + for (string::size_type i = 0; i < len; i++) os << ' '; + print_double_info(os, x[1]); + os << " ]" << endl; +} + +dd_real dd_real::debug_rand() { + + if (std::rand() % 2 == 0) + return ddrand(); + + int expn = 0; + dd_real a = 0.0; + double d; + for (int i = 0; i < 2; i++) { + d = std::ldexp(static_cast(std::rand()) / RAND_MAX, -expn); + a += d; + expn = expn + 54 + std::rand() % 200; + } + return a; +} diff --git a/external/PackedCSparse/dd_real.h b/external/PackedCSparse/qd/dd_real.h similarity index 92% rename from external/PackedCSparse/dd_real.h rename to external/PackedCSparse/qd/dd_real.h index 5fe3491e5..e16438aa0 100644 --- a/external/PackedCSparse/dd_real.h +++ b/external/PackedCSparse/qd/dd_real.h @@ -1,12 +1,3 @@ -// VolEsti (volume computation and sampling library) - -// Copyright (c) 2012-2018 Vissarion Fisikopoulos -// Copyright (c) 2018 Apostolos Chalkis -// Copyright (c) 2022 Ioannis Iakovidis - -// This file is converted from QD library -//(https://www.davidhbailey.com/dhbsoftware) by Ioannis Iakovidis - /* * include/dd_real.h * @@ -18,14 +9,14 @@ * * Double-double precision (>= 106-bit significand) floating point * arithmetic package based on David Bailey's Fortran-90 double-double - * package, with some changes. See + * package, with some changes. See * * http://www.nersc.gov/~dhbailey/mpdist/mpdist.html - * + * * for the original Fortran-90 version. * * Overall structure is similar to that of Keith Brigg's C++ double-double - * package. See + * package. See * * http://www-epidem.plansci.cam.ac.uk/~kbriggs/doubledouble.html * @@ -42,8 +33,8 @@ #include #include #include -#include "qd/qd_config.h" -#include "qd/fpu.h" +#include "qd_config.h" +#include "fpu.h" // Some compilers define isnan, isfinite, and isinf as macros, even for // C++ codes, which cause havoc when overloading these functions. We undef @@ -70,11 +61,7 @@ struct QD_API dd_real { double x[2]; - inline operator bool() const // new - { - return (x[0] != 0.0); - } dd_real(double hi, double lo) { x[0] = hi; x[1] = lo; } dd_real() {x[0] = 0.0; x[1] = 0.0; } dd_real(double h) { x[0] = h; x[1] = 0.0; } @@ -136,7 +123,7 @@ struct QD_API dd_real { static dd_real div(double a, double b); static dd_real sloppy_div(const dd_real &a, const dd_real &b); static dd_real accurate_div(const dd_real &a, const dd_real &b); - + dd_real &operator/=(double a); dd_real &operator/=(const dd_real &a); @@ -147,26 +134,28 @@ struct QD_API dd_real { static dd_real sqr(double d); static dd_real sqrt(double a); - + bool is_zero() const; bool is_one() const; bool is_positive() const; bool is_negative() const; + explicit operator bool() const; // new + explicit operator double() const; // new static dd_real rand(void); void to_digits(char *s, int &expn, int precision = _ndigits) const; - void write(char *s, int len, int precision = _ndigits, + void write(char *s, int len, int precision = _ndigits, bool showpos = false, bool uppercase = false) const; - std::string to_string(int precision = _ndigits, int width = 0, - std::ios_base::fmtflags fmt = static_cast(0), + std::string to_string(int precision = _ndigits, int width = 0, + std::ios_base::fmtflags fmt = static_cast(0), bool showpos = false, bool uppercase = false, char fill = ' ') const; int read(const char *s, dd_real &a); /* Debugging Methods */ void dump(const std::string &name, std::ostream &os = std::cerr) const; - void dump_bits(const std::string &name, + void dump_bits(const std::string &name, std::ostream &os = std::cerr) const; static dd_real debug_rand(); @@ -190,7 +179,7 @@ QD_API dd_real ddrand(void); QD_API dd_real sqrt(const dd_real &a); QD_API dd_real polyeval(const dd_real *c, int n, const dd_real &x); -QD_API dd_real polyroot(const dd_real *c, int n, +QD_API dd_real polyroot(const dd_real *c, int n, const dd_real &x0, int max_iter = 32, double thresh = 0.0); QD_API inline bool isnan(const dd_real &a) { return a.isnan(); } @@ -282,7 +271,7 @@ QD_API dd_real atan2(const dd_real &y, const dd_real &x); QD_API dd_real sinh(const dd_real &a); QD_API dd_real cosh(const dd_real &a); QD_API dd_real tanh(const dd_real &a); -QD_API void sincosh(const dd_real &a, +QD_API void sincosh(const dd_real &a, dd_real &sinh_a, dd_real &cosh_a); QD_API dd_real asinh(const dd_real &a); @@ -297,7 +286,8 @@ QD_API dd_real fmod(const dd_real &a, const dd_real &b); QD_API std::ostream& operator<<(std::ostream &s, const dd_real &a); QD_API std::istream& operator>>(std::istream &s, dd_real &a); #ifdef QD_INLINE -#include "qd/dd_inline.h" +#include "dd_inline.h" #endif #endif /* _QD_DD_REAL_H */ + diff --git a/external/PackedCSparse/qd/fpu.cc b/external/PackedCSparse/qd/fpu.cc new file mode 100644 index 000000000..96ddc488f --- /dev/null +++ b/external/PackedCSparse/qd/fpu.cc @@ -0,0 +1,124 @@ +/* + * src/fpu.cc + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Contains functions to set and restore the round-to-double flag in the + * control word of a x86 FPU. + */ + +#include "qd_config.h" +#include "fpu.h" + +#ifdef X86 +#ifdef _WIN32 +#include +#else + +#ifdef HAVE_FPU_CONTROL_H +#include +#endif + +#ifndef _FPU_GETCW +#define _FPU_GETCW(x) asm volatile ("fnstcw %0":"=m" (x)); +#endif + +#ifndef _FPU_SETCW +#define _FPU_SETCW(x) asm volatile ("fldcw %0": :"m" (x)); +#endif + +#ifndef _FPU_EXTENDED +#define _FPU_EXTENDED 0x0300 +#endif + +#ifndef _FPU_DOUBLE +#define _FPU_DOUBLE 0x0200 +#endif + +#endif +#endif /* X86 */ + +extern "C" { + +void fpu_fix_start(unsigned int *old_cw) { +#ifdef X86 +#ifdef _WIN32 +#ifdef __BORLANDC__ + /* Win 32 Borland C */ + unsigned short cw = _control87(0, 0); + _control87(0x0200, 0x0300); + if (old_cw) { + *old_cw = cw; + } +#else + /* Win 32 MSVC */ + unsigned int cw = _control87(0, 0); + _control87(0x00010000, 0x00030000); + if (old_cw) { + *old_cw = cw; + } +#endif +#else + /* Linux */ + volatile unsigned short cw, new_cw; + _FPU_GETCW(cw); + + new_cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE; + _FPU_SETCW(new_cw); + + if (old_cw) { + *old_cw = cw; + } +#endif +#endif +} + +void fpu_fix_end(unsigned int *old_cw) { +#ifdef X86 +#ifdef _WIN32 + +#ifdef __BORLANDC__ + /* Win 32 Borland C */ + if (old_cw) { + unsigned short cw = (unsigned short) *old_cw; + _control87(cw, 0xFFFF); + } +#else + /* Win 32 MSVC */ + if (old_cw) { + _control87(*old_cw, 0xFFFFFFFF); + } +#endif + +#else + /* Linux */ + if (old_cw) { + int cw; + cw = *old_cw; + _FPU_SETCW(cw); + } +#endif +#endif +} + +#ifdef HAVE_FORTRAN + +#define f_fpu_fix_start FC_FUNC_(f_fpu_fix_start, F_FPU_FIX_START) +#define f_fpu_fix_end FC_FUNC_(f_fpu_fix_end, F_FPU_FIX_END) + +void f_fpu_fix_start(unsigned int *old_cw) { + fpu_fix_start(old_cw); +} + +void f_fpu_fix_end(unsigned int *old_cw) { + fpu_fix_end(old_cw); +} + +#endif + +} + diff --git a/external/PackedCSparse/qd/fpu.h b/external/PackedCSparse/qd/fpu.h new file mode 100644 index 000000000..35eab18cf --- /dev/null +++ b/external/PackedCSparse/qd/fpu.h @@ -0,0 +1,39 @@ +/* + * include/fpu.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2001 + * + * Contains functions to set and restore the round-to-double flag in the + * control word of a x86 FPU. The algorithms in the double-double and + * quad-double package does not function with the extended mode found in + * these FPU. + */ +#ifndef _QD_FPU_H +#define _QD_FPU_H + +#include "qd_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Set the round-to-double flag, and save the old control word in old_cw. + * If old_cw is NULL, the old control word is not saved. + */ +QD_API void fpu_fix_start(unsigned int *old_cw); + +/* + * Restore the control word. + */ +QD_API void fpu_fix_end(unsigned int *old_cw); + +#ifdef __cplusplus +} +#endif + +#endif /* _QD_FPU_H */ diff --git a/external/PackedCSparse/qd/inline.h b/external/PackedCSparse/qd/inline.h new file mode 100644 index 000000000..52425545b --- /dev/null +++ b/external/PackedCSparse/qd/inline.h @@ -0,0 +1,143 @@ +/* + * include/inline.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * This file contains the basic functions used both by double-double + * and quad-double package. These are declared as inline functions as + * they are the smallest building blocks of the double-double and + * quad-double arithmetic. + */ +#ifndef _QD_INLINE_H +#define _QD_INLINE_H + +#define _QD_SPLITTER 134217729.0 // = 2^27 + 1 +#define _QD_SPLIT_THRESH 6.69692879491417e+299 // = 2^996 + +#ifdef QD_VACPP_BUILTINS_H +/* For VisualAge C++ __fmadd */ +#include +#endif + +#include +#include + +namespace qd { + +static const double _d_nan = std::numeric_limits::quiet_NaN(); +static const double _d_inf = std::numeric_limits::infinity(); + +/*********** Basic Functions ************/ +/* Computes fl(a+b) and err(a+b). Assumes |a| >= |b|. */ +inline double quick_two_sum(double a, double b, double &err) { + double s = a + b; + err = b - (s - a); + return s; +} + +/* Computes fl(a-b) and err(a-b). Assumes |a| >= |b| */ +inline double quick_two_diff(double a, double b, double &err) { + double s = a - b; + err = (a - s) - b; + return s; +} + +/* Computes fl(a+b) and err(a+b). */ +inline double two_sum(double a, double b, double &err) { + double s = a + b; + double bb = s - a; + err = (a - (s - bb)) + (b - bb); + return s; +} + +/* Computes fl(a-b) and err(a-b). */ +inline double two_diff(double a, double b, double &err) { + double s = a - b; + double bb = s - a; + err = (a - (s - bb)) - (b + bb); + return s; +} + +#ifndef QD_FMS +/* Computes high word and lo word of a */ +inline void split(double a, double &hi, double &lo) { + double temp; + if (a > _QD_SPLIT_THRESH || a < -_QD_SPLIT_THRESH) { + a *= 3.7252902984619140625e-09; // 2^-28 + temp = _QD_SPLITTER * a; + hi = temp - (temp - a); + lo = a - hi; + hi *= 268435456.0; // 2^28 + lo *= 268435456.0; // 2^28 + } else { + temp = _QD_SPLITTER * a; + hi = temp - (temp - a); + lo = a - hi; + } +} +#endif + +/* Computes fl(a*b) and err(a*b). */ +inline double two_prod(double a, double b, double &err) { +#ifdef QD_FMS + double p = a * b; + err = QD_FMS(a, b, p); + return p; +#else + double a_hi, a_lo, b_hi, b_lo; + double p = a * b; + split(a, a_hi, a_lo); + split(b, b_hi, b_lo); + err = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo; + return p; +#endif +} + +/* Computes fl(a*a) and err(a*a). Faster than the above method. */ +inline double two_sqr(double a, double &err) { +#ifdef QD_FMS + double p = a * a; + err = QD_FMS(a, a, p); + return p; +#else + double hi, lo; + double q = a * a; + split(a, hi, lo); + err = ((hi * hi - q) + 2.0 * hi * lo) + lo * lo; + return q; +#endif +} + +/* Computes the nearest integer to d. */ +inline double nint(double d) { + if (d == std::floor(d)) + return d; + return std::floor(d + 0.5); +} + +/* Computes the truncated integer. */ +inline double aint(double d) { + return (d >= 0.0) ? std::floor(d) : std::ceil(d); +} + +/* These are provided to give consistent + interface for double with double-double and quad-double. */ +inline void sincosh(double t, double &sinh_t, double &cosh_t) { + sinh_t = std::sinh(t); + cosh_t = std::cosh(t); +} + +inline double sqr(double t) { + return t * t; +} + +inline double to_double(double a) { return a; } +inline int to_int(double a) { return static_cast(a); } + +} + +#endif /* _QD_INLINE_H */ diff --git a/external/PackedCSparse/qd/qd.pdf b/external/PackedCSparse/qd/qd.pdf new file mode 100644 index 000000000..9525b8cac Binary files /dev/null and b/external/PackedCSparse/qd/qd.pdf differ diff --git a/external/PackedCSparse/qd/qd_config.h b/external/PackedCSparse/qd/qd_config.h new file mode 100644 index 000000000..d23e33a64 --- /dev/null +++ b/external/PackedCSparse/qd/qd_config.h @@ -0,0 +1,92 @@ +#include +#include + +/* include/qd/qd_config.h. Generated from qd_config.h.in by configure. */ +#ifndef _QD_QD_CONFIG_H +#define _QD_QD_CONFIG_H 1 + +#ifndef QD_API +#define QD_API /**/ +#endif + +/* Set to 1 if using VisualAge C++ compiler for __fmadd builtin. */ +#ifndef QD_VACPP_BUILTINS_H +/* #undef QD_VACPP_BUILTINS_H */ +#endif + +/* If fused multiply-add is available, define to correct macro for + using it. It is invoked as QD_FMA(a, b, c) to compute fl(a * b + c). + If correctly rounded multiply-add is not available (or if unsure), + keep it undefined.*/ +#ifndef QD_FMA +/* #undef QD_FMA */ +#endif + +/* If fused multiply-subtract is available, define to correct macro for + using it. It is invoked as QD_FMS(a, b, c) to compute fl(a * b - c). + If correctly rounded multiply-add is not available (or if unsure), + keep it undefined.*/ +#ifndef QD_FMS +#define QD_FMS(a, b, c) std::fma(a,b,-c) +/* #undef QD_FMS */ +#endif + +/* Set the following to 1 to define commonly used function + to be inlined. This should be set to 1 unless the compiler + does not support the "inline" keyword, or if building for + debugging purposes. */ +#ifndef QD_INLINE +#define QD_INLINE 1 +#endif + +/* Set the following to 1 to use ANSI C++ standard header files + such as cmath, iostream, etc. If set to zero, it will try to + include math.h, iostream.h, etc, instead. */ +#ifndef QD_HAVE_STD +#define QD_HAVE_STD 1 +#endif + +/* Set the following to 1 to make the addition and subtraction + to satisfy the IEEE-style error bound + + fl(a + b) = (1 + d) * (a + b) + + where |d| <= eps. If set to 0, the addition and subtraction + will satisfy the weaker Cray-style error bound + + fl(a + b) = (1 + d1) * a + (1 + d2) * b + + where |d1| <= eps and |d2| eps. */ +#ifndef QD_IEEE_ADD +/* #undef QD_IEEE_ADD */ +#endif + +/* Set the following to 1 to use slightly inaccurate but faster + version of multiplication. */ +#ifndef QD_SLOPPY_MUL +#define QD_SLOPPY_MUL 1 +#endif + +/* Set the following to 1 to use slightly inaccurate but faster + version of division. */ +#ifndef QD_SLOPPY_DIV +#define QD_SLOPPY_DIV 1 +#endif + +/* Define this macro to be the isfinite(x) function. */ +#ifndef QD_ISFINITE +#define QD_ISFINITE(x) std::isfinite(x) +#endif + +/* Define this macro to be the isinf(x) function. */ +#ifndef QD_ISINF +#define QD_ISINF(x) std::isinf(x) +#endif + +/* Define this macro to be the isnan(x) function. */ +#ifndef QD_ISNAN +#define QD_ISNAN(x) std::isnan(x) +#endif + + +#endif /* _QD_QD_CONFIG_H */ diff --git a/external/PackedCSparse/qd/qd_const.cc b/external/PackedCSparse/qd/qd_const.cc new file mode 100644 index 000000000..6f4e01d2a --- /dev/null +++ b/external/PackedCSparse/qd/qd_const.cc @@ -0,0 +1,62 @@ +/* + * src/qd_const.cc + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Defines constants used in quad-double package. + */ +#include "qd_config.h" +#include "qd_real.h" + +/* Some useful constants. */ +const qd_real qd_real::_2pi = qd_real(6.283185307179586232e+00, + 2.449293598294706414e-16, + -5.989539619436679332e-33, + 2.224908441726730563e-49); +const qd_real qd_real::_pi = qd_real(3.141592653589793116e+00, + 1.224646799147353207e-16, + -2.994769809718339666e-33, + 1.112454220863365282e-49); +const qd_real qd_real::_pi2 = qd_real(1.570796326794896558e+00, + 6.123233995736766036e-17, + -1.497384904859169833e-33, + 5.562271104316826408e-50); +const qd_real qd_real::_pi4 = qd_real(7.853981633974482790e-01, + 3.061616997868383018e-17, + -7.486924524295849165e-34, + 2.781135552158413204e-50); +const qd_real qd_real::_3pi4 = qd_real(2.356194490192344837e+00, + 9.1848509936051484375e-17, + 3.9168984647504003225e-33, + -2.5867981632704860386e-49); +const qd_real qd_real::_e = qd_real(2.718281828459045091e+00, + 1.445646891729250158e-16, + -2.127717108038176765e-33, + 1.515630159841218954e-49); +const qd_real qd_real::_log2 = qd_real(6.931471805599452862e-01, + 2.319046813846299558e-17, + 5.707708438416212066e-34, + -3.582432210601811423e-50); +const qd_real qd_real::_log10 = qd_real(2.302585092994045901e+00, + -2.170756223382249351e-16, + -9.984262454465776570e-33, + -4.023357454450206379e-49); +const qd_real qd_real::_nan = qd_real(qd::_d_nan, qd::_d_nan, + qd::_d_nan, qd::_d_nan); +const qd_real qd_real::_inf = qd_real(qd::_d_inf, qd::_d_inf, + qd::_d_inf, qd::_d_inf); + +const double qd_real::_eps = 1.21543267145725e-63; // = 2^-209 +const double qd_real::_min_normalized = 1.6259745436952323e-260; // = 2^(-1022 + 3*53) +const qd_real qd_real::_max = qd_real( + 1.79769313486231570815e+308, 9.97920154767359795037e+291, + 5.53956966280111259858e+275, 3.07507889307840487279e+259); +const qd_real qd_real::_safe_max = qd_real( + 1.7976931080746007281e+308, 9.97920154767359795037e+291, + 5.53956966280111259858e+275, 3.07507889307840487279e+259); +const int qd_real::_ndigits = 62; + diff --git a/external/PackedCSparse/qd/qd_inline.h b/external/PackedCSparse/qd/qd_inline.h new file mode 100644 index 000000000..89ba275b5 --- /dev/null +++ b/external/PackedCSparse/qd/qd_inline.h @@ -0,0 +1,1047 @@ +/* + * include/qd_inline.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2001 + * + * Contains small functions (suitable for inlining) in the quad-double + * arithmetic package. + */ +#ifndef _QD_QD_INLINE_H +#define _QD_QD_INLINE_H + +#include +#include "inline.h" + +#ifndef QD_INLINE +#define inline +#endif + +/********** Constructors **********/ +inline qd_real::qd_real(double x0, double x1, double x2, double x3) { + x[0] = x0; + x[1] = x1; + x[2] = x2; + x[3] = x3; +} + +inline qd_real::qd_real(const double *xx) { + x[0] = xx[0]; + x[1] = xx[1]; + x[2] = xx[2]; + x[3] = xx[3]; +} + +inline qd_real::qd_real(double x0) { + x[0] = x0; + x[1] = x[2] = x[3] = 0.0; +} + +inline qd_real::qd_real() { + x[0] = 0.0; + x[1] = 0.0; + x[2] = 0.0; + x[3] = 0.0; +} + +inline qd_real::qd_real(const dd_real &a) { + x[0] = a._hi(); + x[1] = a._lo(); + x[2] = x[3] = 0.0; +} + +inline qd_real::qd_real(int i) { + x[0] = static_cast(i); + x[1] = x[2] = x[3] = 0.0; +} + +/********** Accessors **********/ +inline double qd_real::operator[](int i) const { + return x[i]; +} + +inline double &qd_real::operator[](int i) { + return x[i]; +} + +inline bool qd_real::isnan() const { + return QD_ISNAN(x[0]) || QD_ISNAN(x[1]) || QD_ISNAN(x[2]) || QD_ISNAN(x[3]); +} + +/********** Renormalization **********/ +namespace qd { +inline void quick_renorm(double &c0, double &c1, + double &c2, double &c3, double &c4) { + double t0, t1, t2, t3; + double s; + s = qd::quick_two_sum(c3, c4, t3); + s = qd::quick_two_sum(c2, s , t2); + s = qd::quick_two_sum(c1, s , t1); + c0 = qd::quick_two_sum(c0, s , t0); + + s = qd::quick_two_sum(t2, t3, t2); + s = qd::quick_two_sum(t1, s , t1); + c1 = qd::quick_two_sum(t0, s , t0); + + s = qd::quick_two_sum(t1, t2, t1); + c2 = qd::quick_two_sum(t0, s , t0); + + c3 = t0 + t1; +} + +inline void renorm(double &c0, double &c1, + double &c2, double &c3) { + double s0, s1, s2 = 0.0, s3 = 0.0; + + if (QD_ISINF(c0)) return; + + s0 = qd::quick_two_sum(c2, c3, c3); + s0 = qd::quick_two_sum(c1, s0, c2); + c0 = qd::quick_two_sum(c0, s0, c1); + + s0 = c0; + s1 = c1; + if (s1 != 0.0) { + s1 = qd::quick_two_sum(s1, c2, s2); + if (s2 != 0.0) + s2 = qd::quick_two_sum(s2, c3, s3); + else + s1 = qd::quick_two_sum(s1, c3, s2); + } else { + s0 = qd::quick_two_sum(s0, c2, s1); + if (s1 != 0.0) + s1 = qd::quick_two_sum(s1, c3, s2); + else + s0 = qd::quick_two_sum(s0, c3, s1); + } + + c0 = s0; + c1 = s1; + c2 = s2; + c3 = s3; +} + +inline void renorm(double &c0, double &c1, + double &c2, double &c3, double &c4) { + double s0, s1, s2 = 0.0, s3 = 0.0; + + if (QD_ISINF(c0)) return; + + s0 = qd::quick_two_sum(c3, c4, c4); + s0 = qd::quick_two_sum(c2, s0, c3); + s0 = qd::quick_two_sum(c1, s0, c2); + c0 = qd::quick_two_sum(c0, s0, c1); + + s0 = c0; + s1 = c1; + + if (s1 != 0.0) { + s1 = qd::quick_two_sum(s1, c2, s2); + if (s2 != 0.0) { + s2 = qd::quick_two_sum(s2, c3, s3); + if (s3 != 0.0) + s3 += c4; + else + s2 = qd::quick_two_sum(s2, c4, s3); + } else { + s1 = qd::quick_two_sum(s1, c3, s2); + if (s2 != 0.0) + s2 = qd::quick_two_sum(s2, c4, s3); + else + s1 = qd::quick_two_sum(s1, c4, s2); + } + } else { + s0 = qd::quick_two_sum(s0, c2, s1); + if (s1 != 0.0) { + s1 = qd::quick_two_sum(s1, c3, s2); + if (s2 != 0.0) + s2 = qd::quick_two_sum(s2, c4, s3); + else + s1 = qd::quick_two_sum(s1, c4, s2); + } else { + s0 = qd::quick_two_sum(s0, c3, s1); + if (s1 != 0.0) + s1 = qd::quick_two_sum(s1, c4, s2); + else + s0 = qd::quick_two_sum(s0, c4, s1); + } + } + + c0 = s0; + c1 = s1; + c2 = s2; + c3 = s3; +} +} + +inline void qd_real::renorm() { + qd::renorm(x[0], x[1], x[2], x[3]); +} + +inline void qd_real::renorm(double &e) { + qd::renorm(x[0], x[1], x[2], x[3], e); +} + + +/********** Additions ************/ +namespace qd { + +inline void three_sum(double &a, double &b, double &c) { + double t1, t2, t3; + t1 = qd::two_sum(a, b, t2); + a = qd::two_sum(c, t1, t3); + b = qd::two_sum(t2, t3, c); +} + +inline void three_sum2(double &a, double &b, double &c) { + double t1, t2, t3; + t1 = qd::two_sum(a, b, t2); + a = qd::two_sum(c, t1, t3); + b = t2 + t3; +} + +} + +/* quad-double + double */ +inline qd_real operator+(const qd_real &a, double b) { + double c0, c1, c2, c3; + double e; + + c0 = qd::two_sum(a[0], b, e); + c1 = qd::two_sum(a[1], e, e); + c2 = qd::two_sum(a[2], e, e); + c3 = qd::two_sum(a[3], e, e); + + qd::renorm(c0, c1, c2, c3, e); + + return qd_real(c0, c1, c2, c3); +} + +/* quad-double + double-double */ +inline qd_real operator+(const qd_real &a, const dd_real &b) { + + double s0, s1, s2, s3; + double t0, t1; + + s0 = qd::two_sum(a[0], b._hi(), t0); + s1 = qd::two_sum(a[1], b._lo(), t1); + + s1 = qd::two_sum(s1, t0, t0); + + s2 = a[2]; + qd::three_sum(s2, t0, t1); + + s3 = qd::two_sum(t0, a[3], t0); + t0 += t1; + + qd::renorm(s0, s1, s2, s3, t0); + return qd_real(s0, s1, s2, s3); +} + + +/* double + quad-double */ +inline qd_real operator+(double a, const qd_real &b) { + return (b + a); +} + +/* double-double + quad-double */ +inline qd_real operator+(const dd_real &a, const qd_real &b) { + return (b + a); +} + +namespace qd { + +/* s = quick_three_accum(a, b, c) adds c to the dd-pair (a, b). + * If the result does not fit in two doubles, then the sum is + * output into s and (a,b) contains the remainder. Otherwise + * s is zero and (a,b) contains the sum. */ +inline double quick_three_accum(double &a, double &b, double c) { + double s; + bool za, zb; + + s = qd::two_sum(b, c, b); + s = qd::two_sum(a, s, a); + + za = (a != 0.0); + zb = (b != 0.0); + + if (za && zb) + return s; + + if (!zb) { + b = a; + a = s; + } else { + a = s; + } + + return 0.0; +} + +} + +inline qd_real qd_real::ieee_add(const qd_real &a, const qd_real &b) { + int i, j, k; + double s, t; + double u, v; /* double-length accumulator */ + double x[4] = {0.0, 0.0, 0.0, 0.0}; + + i = j = k = 0; + if (std::abs(a[i]) > std::abs(b[j])) + u = a[i++]; + else + u = b[j++]; + if (std::abs(a[i]) > std::abs(b[j])) + v = a[i++]; + else + v = b[j++]; + + u = qd::quick_two_sum(u, v, v); + + while (k < 4) { + if (i >= 4 && j >= 4) { + x[k] = u; + if (k < 3) + x[++k] = v; + break; + } + + if (i >= 4) + t = b[j++]; + else if (j >= 4) + t = a[i++]; + else if (std::abs(a[i]) > std::abs(b[j])) { + t = a[i++]; + } else + t = b[j++]; + + s = qd::quick_three_accum(u, v, t); + + if (s != 0.0) { + x[k++] = s; + } + } + + /* add the rest. */ + for (k = i; k < 4; k++) + x[3] += a[k]; + for (k = j; k < 4; k++) + x[3] += b[k]; + + qd::renorm(x[0], x[1], x[2], x[3]); + return qd_real(x[0], x[1], x[2], x[3]); +} + +inline qd_real qd_real::sloppy_add(const qd_real &a, const qd_real &b) { + /* + double s0, s1, s2, s3; + double t0, t1, t2, t3; + + s0 = qd::two_sum(a[0], b[0], t0); + s1 = qd::two_sum(a[1], b[1], t1); + s2 = qd::two_sum(a[2], b[2], t2); + s3 = qd::two_sum(a[3], b[3], t3); + + s1 = qd::two_sum(s1, t0, t0); + qd::three_sum(s2, t0, t1); + qd::three_sum2(s3, t0, t2); + t0 = t0 + t1 + t3; + + qd::renorm(s0, s1, s2, s3, t0); + return qd_real(s0, s1, s2, s3, t0); + */ + + /* Same as above, but addition re-organized to minimize + data dependency ... unfortunately some compilers are + not very smart to do this automatically */ + double s0, s1, s2, s3; + double t0, t1, t2, t3; + + double v0, v1, v2, v3; + double u0, u1, u2, u3; + double w0, w1, w2, w3; + + s0 = a[0] + b[0]; + s1 = a[1] + b[1]; + s2 = a[2] + b[2]; + s3 = a[3] + b[3]; + + v0 = s0 - a[0]; + v1 = s1 - a[1]; + v2 = s2 - a[2]; + v3 = s3 - a[3]; + + u0 = s0 - v0; + u1 = s1 - v1; + u2 = s2 - v2; + u3 = s3 - v3; + + w0 = a[0] - u0; + w1 = a[1] - u1; + w2 = a[2] - u2; + w3 = a[3] - u3; + + u0 = b[0] - v0; + u1 = b[1] - v1; + u2 = b[2] - v2; + u3 = b[3] - v3; + + t0 = w0 + u0; + t1 = w1 + u1; + t2 = w2 + u2; + t3 = w3 + u3; + + s1 = qd::two_sum(s1, t0, t0); + qd::three_sum(s2, t0, t1); + qd::three_sum2(s3, t0, t2); + t0 = t0 + t1 + t3; + + /* renormalize */ + qd::renorm(s0, s1, s2, s3, t0); + return qd_real(s0, s1, s2, s3); +} + +/* quad-double + quad-double */ +inline qd_real operator+(const qd_real &a, const qd_real &b) { +#ifndef QD_IEEE_ADD + return qd_real::sloppy_add(a, b); +#else + return qd_real::ieee_add(a, b); +#endif +} + + + +/********** Self-Additions ************/ +/* quad-double += double */ +inline qd_real &qd_real::operator+=(double a) { + *this = *this + a; + return *this; +} + +/* quad-double += double-double */ +inline qd_real &qd_real::operator+=(const dd_real &a) { + *this = *this + a; + return *this; +} + +/* quad-double += quad-double */ +inline qd_real &qd_real::operator+=(const qd_real &a) { + *this = *this + a; + return *this; +} + +/********** Unary Minus **********/ +inline qd_real qd_real::operator-() const { + return qd_real(-x[0], -x[1], -x[2], -x[3]); +} + +/********** Subtractions **********/ +inline qd_real operator-(const qd_real &a, double b) { + return (a + (-b)); +} + +inline qd_real operator-(double a, const qd_real &b) { + return (a + (-b)); +} + +inline qd_real operator-(const qd_real &a, const dd_real &b) { + return (a + (-b)); +} + +inline qd_real operator-(const dd_real &a, const qd_real &b) { + return (a + (-b)); +} + +inline qd_real operator-(const qd_real &a, const qd_real &b) { + return (a + (-b)); +} + +/********** Self-Subtractions **********/ +inline qd_real &qd_real::operator-=(double a) { + return ((*this) += (-a)); +} + +inline qd_real &qd_real::operator-=(const dd_real &a) { + return ((*this) += (-a)); +} + +inline qd_real &qd_real::operator-=(const qd_real &a) { + return ((*this) += (-a)); +} + + +inline qd_real operator*(double a, const qd_real &b) { + return (b * a); +} + +inline qd_real operator*(const dd_real &a, const qd_real &b) { + return (b * a); +} + +inline qd_real mul_pwr2(const qd_real &a, double b) { + return qd_real(a[0] * b, a[1] * b, a[2] * b, a[3] * b); +} + +/********** Multiplications **********/ +inline qd_real operator*(const qd_real &a, double b) { + double p0, p1, p2, p3; + double q0, q1, q2; + double s0, s1, s2, s3, s4; + + p0 = qd::two_prod(a[0], b, q0); + p1 = qd::two_prod(a[1], b, q1); + p2 = qd::two_prod(a[2], b, q2); + p3 = a[3] * b; + + s0 = p0; + + s1 = qd::two_sum(q0, p1, s2); + + qd::three_sum(s2, q1, p2); + + qd::three_sum2(q1, q2, p3); + s3 = q1; + + s4 = q2 + p2; + + qd::renorm(s0, s1, s2, s3, s4); + return qd_real(s0, s1, s2, s3); + +} + +/* quad-double * double-double */ +/* a0 * b0 0 + a0 * b1 1 + a1 * b0 2 + a1 * b1 3 + a2 * b0 4 + a2 * b1 5 + a3 * b0 6 + a3 * b1 7 */ +inline qd_real operator*(const qd_real &a, const dd_real &b) { + double p0, p1, p2, p3, p4; + double q0, q1, q2, q3, q4; + double s0, s1, s2; + double t0, t1; + + p0 = qd::two_prod(a[0], b._hi(), q0); + p1 = qd::two_prod(a[0], b._lo(), q1); + p2 = qd::two_prod(a[1], b._hi(), q2); + p3 = qd::two_prod(a[1], b._lo(), q3); + p4 = qd::two_prod(a[2], b._hi(), q4); + + qd::three_sum(p1, p2, q0); + + /* Five-Three-Sum */ + qd::three_sum(p2, p3, p4); + q1 = qd::two_sum(q1, q2, q2); + s0 = qd::two_sum(p2, q1, t0); + s1 = qd::two_sum(p3, q2, t1); + s1 = qd::two_sum(s1, t0, t0); + s2 = t0 + t1 + p4; + p2 = s0; + + p3 = a[2] * b._hi() + a[3] * b._lo() + q3 + q4; + qd::three_sum2(p3, q0, s1); + p4 = q0 + s2; + + qd::renorm(p0, p1, p2, p3, p4); + return qd_real(p0, p1, p2, p3); +} + +/* quad-double * quad-double */ +/* a0 * b0 0 + a0 * b1 1 + a1 * b0 2 + a0 * b2 3 + a1 * b1 4 + a2 * b0 5 + a0 * b3 6 + a1 * b2 7 + a2 * b1 8 + a3 * b0 9 */ +inline qd_real qd_real::sloppy_mul(const qd_real &a, const qd_real &b) { + double p0, p1, p2, p3, p4, p5; + double q0, q1, q2, q3, q4, q5; + double t0, t1; + double s0, s1, s2; + + p0 = qd::two_prod(a[0], b[0], q0); + + p1 = qd::two_prod(a[0], b[1], q1); + p2 = qd::two_prod(a[1], b[0], q2); + + p3 = qd::two_prod(a[0], b[2], q3); + p4 = qd::two_prod(a[1], b[1], q4); + p5 = qd::two_prod(a[2], b[0], q5); + + /* Start Accumulation */ + qd::three_sum(p1, p2, q0); + + /* Six-Three Sum of p2, q1, q2, p3, p4, p5. */ + qd::three_sum(p2, q1, q2); + qd::three_sum(p3, p4, p5); + /* compute (s0, s1, s2) = (p2, q1, q2) + (p3, p4, p5). */ + s0 = qd::two_sum(p2, p3, t0); + s1 = qd::two_sum(q1, p4, t1); + s2 = q2 + p5; + s1 = qd::two_sum(s1, t0, t0); + s2 += (t0 + t1); + + /* O(eps^3) order terms */ + s1 += a[0]*b[3] + a[1]*b[2] + a[2]*b[1] + a[3]*b[0] + q0 + q3 + q4 + q5; + qd::renorm(p0, p1, s0, s1, s2); + return qd_real(p0, p1, s0, s1); +} + +inline qd_real qd_real::accurate_mul(const qd_real &a, const qd_real &b) { + double p0, p1, p2, p3, p4, p5; + double q0, q1, q2, q3, q4, q5; + double p6, p7, p8, p9; + double q6, q7, q8, q9; + double r0, r1; + double t0, t1; + double s0, s1, s2; + + p0 = qd::two_prod(a[0], b[0], q0); + + p1 = qd::two_prod(a[0], b[1], q1); + p2 = qd::two_prod(a[1], b[0], q2); + + p3 = qd::two_prod(a[0], b[2], q3); + p4 = qd::two_prod(a[1], b[1], q4); + p5 = qd::two_prod(a[2], b[0], q5); + + /* Start Accumulation */ + qd::three_sum(p1, p2, q0); + + /* Six-Three Sum of p2, q1, q2, p3, p4, p5. */ + qd::three_sum(p2, q1, q2); + qd::three_sum(p3, p4, p5); + /* compute (s0, s1, s2) = (p2, q1, q2) + (p3, p4, p5). */ + s0 = qd::two_sum(p2, p3, t0); + s1 = qd::two_sum(q1, p4, t1); + s2 = q2 + p5; + s1 = qd::two_sum(s1, t0, t0); + s2 += (t0 + t1); + + /* O(eps^3) order terms */ + p6 = qd::two_prod(a[0], b[3], q6); + p7 = qd::two_prod(a[1], b[2], q7); + p8 = qd::two_prod(a[2], b[1], q8); + p9 = qd::two_prod(a[3], b[0], q9); + + /* Nine-Two-Sum of q0, s1, q3, q4, q5, p6, p7, p8, p9. */ + q0 = qd::two_sum(q0, q3, q3); + q4 = qd::two_sum(q4, q5, q5); + p6 = qd::two_sum(p6, p7, p7); + p8 = qd::two_sum(p8, p9, p9); + /* Compute (t0, t1) = (q0, q3) + (q4, q5). */ + t0 = qd::two_sum(q0, q4, t1); + t1 += (q3 + q5); + /* Compute (r0, r1) = (p6, p7) + (p8, p9). */ + r0 = qd::two_sum(p6, p8, r1); + r1 += (p7 + p9); + /* Compute (q3, q4) = (t0, t1) + (r0, r1). */ + q3 = qd::two_sum(t0, r0, q4); + q4 += (t1 + r1); + /* Compute (t0, t1) = (q3, q4) + s1. */ + t0 = qd::two_sum(q3, s1, t1); + t1 += q4; + + /* O(eps^4) terms -- Nine-One-Sum */ + t1 += a[1] * b[3] + a[2] * b[2] + a[3] * b[1] + q6 + q7 + q8 + q9 + s2; + + qd::renorm(p0, p1, s0, t0, t1); + return qd_real(p0, p1, s0, t0); +} + +inline qd_real operator*(const qd_real &a, const qd_real &b) { +#ifdef QD_SLOPPY_MUL + return qd_real::sloppy_mul(a, b); +#else + return qd_real::accurate_mul(a, b); +#endif +} + +/* quad-double ^ 2 = (x0 + x1 + x2 + x3) ^ 2 + = x0 ^ 2 + 2 x0 * x1 + (2 x0 * x2 + x1 ^ 2) + + (2 x0 * x3 + 2 x1 * x2) */ +inline qd_real sqr(const qd_real &a) { + double p0, p1, p2, p3, p4, p5; + double q0, q1, q2, q3; + double s0, s1; + double t0, t1; + + p0 = qd::two_sqr(a[0], q0); + p1 = qd::two_prod(2.0 * a[0], a[1], q1); + p2 = qd::two_prod(2.0 * a[0], a[2], q2); + p3 = qd::two_sqr(a[1], q3); + + p1 = qd::two_sum(q0, p1, q0); + + q0 = qd::two_sum(q0, q1, q1); + p2 = qd::two_sum(p2, p3, p3); + + s0 = qd::two_sum(q0, p2, t0); + s1 = qd::two_sum(q1, p3, t1); + + s1 = qd::two_sum(s1, t0, t0); + t0 += t1; + + s1 = qd::quick_two_sum(s1, t0, t0); + p2 = qd::quick_two_sum(s0, s1, t1); + p3 = qd::quick_two_sum(t1, t0, q0); + + p4 = 2.0 * a[0] * a[3]; + p5 = 2.0 * a[1] * a[2]; + + p4 = qd::two_sum(p4, p5, p5); + q2 = qd::two_sum(q2, q3, q3); + + t0 = qd::two_sum(p4, q2, t1); + t1 = t1 + p5 + q3; + + p3 = qd::two_sum(p3, t0, p4); + p4 = p4 + q0 + t1; + + qd::renorm(p0, p1, p2, p3, p4); + return qd_real(p0, p1, p2, p3); + +} + +/********** Self-Multiplication **********/ +/* quad-double *= double */ +inline qd_real &qd_real::operator*=(double a) { + *this = (*this * a); + return *this; +} + +/* quad-double *= double-double */ +inline qd_real &qd_real::operator*=(const dd_real &a) { + *this = (*this * a); + return *this; +} + +/* quad-double *= quad-double */ +inline qd_real &qd_real::operator*=(const qd_real &a) { + *this = *this * a; + return *this; +} + +inline qd_real operator/ (const qd_real &a, const dd_real &b) { +#ifdef QD_SLOPPY_DIV + return qd_real::sloppy_div(a, b); +#else + return qd_real::accurate_div(a, b); +#endif +} + +inline qd_real operator/(const qd_real &a, const qd_real &b) { +#ifdef QD_SLOPPY_DIV + return qd_real::sloppy_div(a, b); +#else + return qd_real::accurate_div(a, b); +#endif +} + +/* double / quad-double */ +inline qd_real operator/(double a, const qd_real &b) { + return qd_real(a) / b; +} + +/* double-double / quad-double */ +inline qd_real operator/(const dd_real &a, const qd_real &b) { + return qd_real(a) / b; +} + +/********** Self-Divisions **********/ +/* quad-double /= double */ +inline qd_real &qd_real::operator/=(double a) { + *this = (*this / a); + return *this; +} + +/* quad-double /= double-double */ +inline qd_real &qd_real::operator/=(const dd_real &a) { + *this = (*this / a); + return *this; +} + +/* quad-double /= quad-double */ +inline qd_real &qd_real::operator/=(const qd_real &a) { + *this = (*this / a); + return *this; +} + + +/********** Exponentiation **********/ +inline qd_real qd_real::operator^(int n) const { + return pow(*this, n); +} + +/********** Miscellaneous **********/ +inline qd_real abs(const qd_real &a) { + return (a[0] < 0.0) ? -a : a; +} + +inline qd_real fabs(const qd_real &a) { + return abs(a); +} + +/* Quick version. May be off by one when qd is very close + to the middle of two integers. */ +inline qd_real quick_nint(const qd_real &a) { + qd_real r = qd_real(qd::nint(a[0]), qd::nint(a[1]), + qd::nint(a[2]), qd::nint(a[3])); + r.renorm(); + return r; +} + +/*********** Assignments ************/ +/* quad-double = double */ +inline qd_real &qd_real::operator=(double a) { + x[0] = a; + x[1] = x[2] = x[3] = 0.0; + return *this; +} + +/* quad-double = double-double */ +inline qd_real &qd_real::operator=(const dd_real &a) { + x[0] = a._hi(); + x[1] = a._lo(); + x[2] = x[3] = 0.0; + return *this; +} + +/********** Equality Comparison **********/ +inline bool operator==(const qd_real &a, double b) { + return (a[0] == b && a[1] == 0.0 && a[2] == 0.0 && a[3] == 0.0); +} + +inline bool operator==(double a, const qd_real &b) { + return (b == a); +} + +inline bool operator==(const qd_real &a, const dd_real &b) { + return (a[0] == b._hi() && a[1] == b._lo() && + a[2] == 0.0 && a[3] == 0.0); +} + +inline bool operator==(const dd_real &a, const qd_real &b) { + return (b == a); +} + +inline bool operator==(const qd_real &a, const qd_real &b) { + return (a[0] == b[0] && a[1] == b[1] && + a[2] == b[2] && a[3] == b[3]); +} + + +/********** Less-Than Comparison ***********/ +inline bool operator<(const qd_real &a, double b) { + return (a[0] < b || (a[0] == b && a[1] < 0.0)); +} + +inline bool operator<(double a, const qd_real &b) { + return (b > a); +} + +inline bool operator<(const qd_real &a, const dd_real &b) { + return (a[0] < b._hi() || + (a[0] == b._hi() && (a[1] < b._lo() || + (a[1] == b._lo() && a[2] < 0.0)))); +} + +inline bool operator<(const dd_real &a, const qd_real &b) { + return (b > a); +} + +inline bool operator<(const qd_real &a, const qd_real &b) { + return (a[0] < b[0] || + (a[0] == b[0] && (a[1] < b[1] || + (a[1] == b[1] && (a[2] < b[2] || + (a[2] == b[2] && a[3] < b[3])))))); +} + +/********** Greater-Than Comparison ***********/ +inline bool operator>(const qd_real &a, double b) { + return (a[0] > b || (a[0] == b && a[1] > 0.0)); +} + +inline bool operator>(double a, const qd_real &b) { + return (b < a); +} + +inline bool operator>(const qd_real &a, const dd_real &b) { + return (a[0] > b._hi() || + (a[0] == b._hi() && (a[1] > b._lo() || + (a[1] == b._lo() && a[2] > 0.0)))); +} + +inline bool operator>(const dd_real &a, const qd_real &b) { + return (b < a); +} + +inline bool operator>(const qd_real &a, const qd_real &b) { + return (a[0] > b[0] || + (a[0] == b[0] && (a[1] > b[1] || + (a[1] == b[1] && (a[2] > b[2] || + (a[2] == b[2] && a[3] > b[3])))))); +} + + +/********** Less-Than-Or-Equal-To Comparison **********/ +inline bool operator<=(const qd_real &a, double b) { + return (a[0] < b || (a[0] == b && a[1] <= 0.0)); +} + +inline bool operator<=(double a, const qd_real &b) { + return (b >= a); +} + +inline bool operator<=(const qd_real &a, const dd_real &b) { + return (a[0] < b._hi() || + (a[0] == b._hi() && (a[1] < b._lo() || + (a[1] == b._lo() && a[2] <= 0.0)))); +} + +inline bool operator<=(const dd_real &a, const qd_real &b) { + return (b >= a); +} + +inline bool operator<=(const qd_real &a, const qd_real &b) { + return (a[0] < b[0] || + (a[0] == b[0] && (a[1] < b[1] || + (a[1] == b[1] && (a[2] < b[2] || + (a[2] == b[2] && a[3] <= b[3])))))); +} + +/********** Greater-Than-Or-Equal-To Comparison **********/ +inline bool operator>=(const qd_real &a, double b) { + return (a[0] > b || (a[0] == b && a[1] >= 0.0)); +} + +inline bool operator>=(double a, const qd_real &b) { + return (b <= a); +} + +inline bool operator>=(const qd_real &a, const dd_real &b) { + return (a[0] > b._hi() || + (a[0] == b._hi() && (a[1] > b._lo() || + (a[1] == b._lo() && a[2] >= 0.0)))); +} + +inline bool operator>=(const dd_real &a, const qd_real &b) { + return (b <= a); +} + +inline bool operator>=(const qd_real &a, const qd_real &b) { + return (a[0] > b[0] || + (a[0] == b[0] && (a[1] > b[1] || + (a[1] == b[1] && (a[2] > b[2] || + (a[2] == b[2] && a[3] >= b[3])))))); +} + + + +/********** Not-Equal-To Comparison **********/ +inline bool operator!=(const qd_real &a, double b) { + return !(a == b); +} + +inline bool operator!=(double a, const qd_real &b) { + return !(a == b); +} + +inline bool operator!=(const qd_real &a, const dd_real &b) { + return !(a == b); +} + +inline bool operator!=(const dd_real &a, const qd_real &b) { + return !(a == b); +} + +inline bool operator!=(const qd_real &a, const qd_real &b) { + return !(a == b); +} + + + +inline qd_real aint(const qd_real &a) { + return (a[0] >= 0) ? floor(a) : ceil(a); +} + +inline bool qd_real::is_zero() const { + return (x[0] == 0.0); +} + +inline bool qd_real::is_one() const { + return (x[0] == 1.0 && x[1] == 0.0 && x[2] == 0.0 && x[3] == 0.0); +} + +inline bool qd_real::is_positive() const { + return (x[0] > 0.0); +} + +inline bool qd_real::is_negative() const { + return (x[0] < 0.0); +} + +inline qd_real::operator bool() const { + return (x[0] != 0.0); +} + +inline qd_real::operator double() const { + return to_double(*this); +} + +inline dd_real to_dd_real(const qd_real &a) { + return dd_real(a[0], a[1]); +} + +inline double to_double(const qd_real &a) { + return a[0]; +} + +inline int to_int(const qd_real &a) { + return static_cast(a[0]); +} + +inline qd_real inv(const qd_real &qd) { + return 1.0 / qd; +} + +inline qd_real max(const qd_real &a, const qd_real &b) { + return (a > b) ? a : b; +} + +inline qd_real max(const qd_real &a, const qd_real &b, + const qd_real &c) { + return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); +} + +inline qd_real min(const qd_real &a, const qd_real &b) { + return (a < b) ? a : b; +} + +inline qd_real min(const qd_real &a, const qd_real &b, + const qd_real &c) { + return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c); +} + +/* Random number generator */ +inline qd_real qd_real::rand() { + return qdrand(); +} + +inline qd_real ldexp(const qd_real &a, int n) { + return qd_real(std::ldexp(a[0], n), std::ldexp(a[1], n), + std::ldexp(a[2], n), std::ldexp(a[3], n)); +} + +#endif /* _QD_QD_INLINE_H */ diff --git a/external/PackedCSparse/qd/qd_real.cc b/external/PackedCSparse/qd/qd_real.cc new file mode 100644 index 000000000..02cb7aa3b --- /dev/null +++ b/external/PackedCSparse/qd/qd_real.cc @@ -0,0 +1,2624 @@ +/* + * src/qd_real.cc + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2007 + * + * Contains implementation of non-inlined functions of quad-double + * package. Inlined functions are found in qd_inline.h (in include directory). + */ +#include +#include +#include +#include +#include +#include +#include + +#include "qd_config.h" +#include "qd_real.h" +#include "util.h" + +#include "bits.h" + +#ifndef QD_INLINE +#include "qd_inline.h" +#endif + +using std::cout; +using std::cerr; +using std::endl; +using std::istream; +using std::ostream; +using std::ios_base; +using std::string; +using std::setw; + +using namespace qd; + +void qd_real::error(const char *msg) { + //if (msg) { cerr << "ERROR " << msg << endl; } +} + +/********** Multiplications **********/ + +qd_real nint(const qd_real &a) { + double x0, x1, x2, x3; + + x0 = nint(a[0]); + x1 = x2 = x3 = 0.0; + + if (x0 == a[0]) { + /* First double is already an integer. */ + x1 = nint(a[1]); + + if (x1 == a[1]) { + /* Second double is already an integer. */ + x2 = nint(a[2]); + + if (x2 == a[2]) { + /* Third double is already an integer. */ + x3 = nint(a[3]); + } else { + if (std::abs(x2 - a[2]) == 0.5 && a[3] < 0.0) { + x2 -= 1.0; + } + } + + } else { + if (std::abs(x1 - a[1]) == 0.5 && a[2] < 0.0) { + x1 -= 1.0; + } + } + + } else { + /* First double is not an integer. */ + if (std::abs(x0 - a[0]) == 0.5 && a[1] < 0.0) { + x0 -= 1.0; + } + } + + renorm(x0, x1, x2, x3); + return qd_real(x0, x1, x2, x3); +} + +qd_real floor(const qd_real &a) { + double x0, x1, x2, x3; + x1 = x2 = x3 = 0.0; + x0 = std::floor(a[0]); + + if (x0 == a[0]) { + x1 = std::floor(a[1]); + + if (x1 == a[1]) { + x2 = std::floor(a[2]); + + if (x2 == a[2]) { + x3 = std::floor(a[3]); + } + } + + renorm(x0, x1, x2, x3); + return qd_real(x0, x1, x2, x3); + } + + return qd_real(x0, x1, x2, x3); +} + +qd_real ceil(const qd_real &a) { + double x0, x1, x2, x3; + x1 = x2 = x3 = 0.0; + x0 = std::ceil(a[0]); + + if (x0 == a[0]) { + x1 = std::ceil(a[1]); + + if (x1 == a[1]) { + x2 = std::ceil(a[2]); + + if (x2 == a[2]) { + x3 = std::ceil(a[3]); + } + } + + renorm(x0, x1, x2, x3); + return qd_real(x0, x1, x2, x3); + } + + return qd_real(x0, x1, x2, x3); +} + + + +/********** Divisions **********/ +/* quad-double / double */ +qd_real operator/(const qd_real &a, double b) { + /* Strategy: compute approximate quotient using high order + doubles, and then correct it 3 times using the remainder. + (Analogous to long division.) */ + double t0, t1; + double q0, q1, q2, q3; + qd_real r; + + q0 = a[0] / b; /* approximate quotient */ + + /* Compute the remainder a - q0 * b */ + t0 = two_prod(q0, b, t1); + r = a - dd_real(t0, t1); + + /* Compute the first correction */ + q1 = r[0] / b; + t0 = two_prod(q1, b, t1); + r -= dd_real(t0, t1); + + /* Second correction to the quotient. */ + q2 = r[0] / b; + t0 = two_prod(q2, b, t1); + r -= dd_real(t0, t1); + + /* Final correction to the quotient. */ + q3 = r[0] / b; + + renorm(q0, q1, q2, q3); + return qd_real(q0, q1, q2, q3); +} + +qd_real::qd_real(const char *s) { + if (qd_real::read(s, *this)) { + qd_real::error("(qd_real::qd_real): INPUT ERROR."); + *this = qd_real::_nan; + } +} + +qd_real &qd_real::operator=(const char *s) { + if (qd_real::read(s, *this)) { + qd_real::error("(qd_real::operator=): INPUT ERROR."); + *this = qd_real::_nan; + } + return *this; +} + +istream &operator>>(istream &s, qd_real &qd) { + char str[255]; + s >> str; + qd = qd_real(str); + return s; +} + +ostream &operator<<(ostream &os, const qd_real &qd) { + bool showpos = (os.flags() & ios_base::showpos) != 0; + bool uppercase = (os.flags() & ios_base::uppercase) != 0; + return os << qd.to_string((int)os.precision(), (int)os.width(), os.flags(), + showpos, uppercase, os.fill()); +} + +/* Read a quad-double from s. */ +int qd_real::read(const char *s, qd_real &qd) { + const char *p = s; + char ch; + int sign = 0; + int point = -1; /* location of decimal point */ + int nd = 0; /* number of digits read */ + int e = 0; /* exponent. */ + bool done = false; + qd_real r = 0.0; /* number being read */ + + /* Skip any leading spaces */ + while (*p == ' ') p++; + + while (!done && (ch = *p) != '\0') { + if (ch >= '0' && ch <= '9') { + /* It's a digit */ + int d = ch - '0'; + r *= 10.0; + r += static_cast(d); + nd++; + } else { + /* Non-digit */ + switch (ch) { + case '.': + if (point >= 0) + return -1; /* we've already encountered a decimal point. */ + point = nd; + break; + case '-': + case '+': + if (sign != 0 || nd > 0) + return -1; /* we've already encountered a sign, or if its + not at first position. */ + sign = (ch == '-') ? -1 : 1; + break; + case 'E': + case 'e': + int nread; + nread = std::sscanf(p+1, "%d", &e); + done = true; + if (nread != 1) + return -1; /* read of exponent failed. */ + break; + case ' ': + done = true; + break; + default: + return -1; + + } + } + + p++; + } + + + + /* Adjust exponent to account for decimal point */ + if (point >= 0) { + e -= (nd - point); + } + + /* Multiply the the exponent */ + if (e != 0) { + r *= (qd_real(10.0) ^ e); + } + + qd = (sign < 0) ? -r : r; + return 0; +} + +void qd_real::to_digits(char *s, int &expn, int precision) const { + int D = precision + 1; /* number of digits to compute */ + + qd_real r = abs(*this); + int e; /* exponent */ + int i, d; + + if (x[0] == 0.0) { + /* this == 0.0 */ + expn = 0; + for (i = 0; i < precision; i++) s[i] = '0'; + return; + } + + /* First determine the (approximate) exponent. */ + e = static_cast(std::floor(std::log10(std::abs(x[0])))); + + if (e < -300) { + r *= qd_real(10.0) ^ 300; + r /= qd_real(10.0) ^ (e + 300); + } else if (e > 300) { + r = ldexp(r, -53); + r /= qd_real(10.0) ^ e; + r = ldexp(r, 53); + } else { + r /= qd_real(10.0) ^ e; + } + + /* Fix exponent if we are off by one */ + if (r >= 10.0) { + r /= 10.0; + e++; + } else if (r < 1.0) { + r *= 10.0; + e--; + } + + if (r >= 10.0 || r < 1.0) { + qd_real::error("(qd_real::to_digits): can't compute exponent."); + return; + } + + /* Extract the digits */ + for (i = 0; i < D; i++) { + d = static_cast(r[0]); + r -= d; + r *= 10.0; + + s[i] = static_cast(d + '0'); + } + + /* Fix out of range digits. */ + for (i = D-1; i > 0; i--) { + if (s[i] < '0') { + s[i-1]--; + s[i] += 10; + } else if (s[i] > '9') { + s[i-1]++; + s[i] -= 10; + } + } + + if (s[0] <= '0') { + qd_real::error("(qd_real::to_digits): non-positive leading digit."); + return; + } + + /* Round, handle carry */ + if (s[D-1] >= '5') { + s[D-2]++; + + i = D-2; + while (i > 0 && s[i] > '9') { + s[i] -= 10; + s[--i]++; + } + } + + /* If first digit is 10, shift everything. */ + if (s[0] > '9') { + e++; + for (i = precision; i >= 2; i--) s[i] = s[i-1]; + s[0] = '1'; + s[1] = '0'; + } + + s[precision] = 0; + expn = e; +} + +/* Writes the quad-double number into the character array s of length len. + The integer d specifies how many significant digits to write. + The string s must be able to hold at least (d+8) characters. + showpos indicates whether to use the + sign, and uppercase indicates + whether the E or e is to be used for the exponent. */ +void qd_real::write(char *s, int len, int precision, + bool showpos, bool uppercase) const { + string str = to_string(precision, 0, ios_base::scientific, showpos, uppercase); + strncpy(s, str.c_str(), len-1); + s[len-1] = 0; +} + +void round_string_qd(char *s, int precision, int *offset){ + /* + Input string must be all digits or errors will occur. + */ + + int i; + int D = precision ; + + /* Round, handle carry */ + if (D>0 && s[D] >= '5') { + s[D-1]++; + + i = D-1; + while (i > 0 && s[i] > '9') { + s[i] -= 10; + s[--i]++; + } + } + + /* If first digit is 10, shift everything. */ + if (s[0] > '9') { + // e++; // don't modify exponent here + for (i = precision; i >= 1; i--) s[i+1] = s[i]; + s[0] = '1'; + s[1] = '0'; + + (*offset)++ ; // now offset needs to be increased by one + precision++ ; + } + + s[precision] = 0; // add terminator for array +} + + +string qd_real::to_string(int precision, int width, ios_base::fmtflags fmt, + bool showpos, bool uppercase, char fill) const { + string s; + bool fixed = (fmt & ios_base::fixed) != 0; + bool sgn = true; + int i, e = 0; + + if (isinf()) { + if (*this < 0.0) + s += '-'; + else if (showpos) + s += '+'; + else + sgn = false; + s += uppercase ? "INF" : "inf"; + } else if (isnan()) { + s = uppercase ? "NAN" : "nan"; + sgn = false; + } else { + if (*this < 0.0) + s += '-'; + else if (showpos) + s += '+'; + else + sgn = false; + + if (*this == 0.0) { + /* Zero case */ + s += '0'; + if (precision > 0) { + s += '.'; + s.append(precision, '0'); + } + } else { + /* Non-zero case */ + int off = (fixed ? (1 + to_int(floor(log10(abs(*this))))) : 1); + int d = precision + off; + + int d_with_extra = d; + if(fixed) + d_with_extra = std::max(120, d); // longer than the max accuracy for DD + + // highly special case - fixed mode, precision is zero, abs(*this) < 1.0 + // without this trap a number like 0.9 printed fixed with 0 precision prints as 0 + // should be rounded to 1. + if(fixed && (precision == 0) && (abs(*this) < 1.0)){ + if(abs(*this) >= 0.5) + s += '1'; + else + s += '0'; + + return s; + } + + // handle near zero to working precision (but not exactly zero) + if (fixed && d <= 0) { + s += '0'; + if (precision > 0) { + s += '.'; + s.append(precision, '0'); + } + } else { // default + + char *t ; // = new char[d+1]; + int j; + + if(fixed){ + t = new char[d_with_extra+1]; + to_digits(t, e, d_with_extra); + } + else{ + t = new char[d+1]; + to_digits(t, e, d); + } + + off = e + 1; + + if (fixed) { + // fix the string if it's been computed incorrectly + // round here in the decimal string if required + round_string_qd(t, d, &off); + + if (off > 0) { + for (i = 0; i < off; i++) s += t[i]; + if (precision > 0) { + s += '.'; + for (j = 0; j < precision; j++, i++) s += t[i]; + } + } else { + s += "0."; + if (off < 0) s.append(-off, '0'); + for (i = 0; i < d; i++) s += t[i]; + } + } else { + s += t[0]; + if (precision > 0) s += '.'; + + for (i = 1; i <= precision; i++) + s += t[i]; + + } + delete [] t; + } + } + + // trap for improper offset with large values + // without this trap, output of values of the for 10^j - 1 fail for j > 28 + // and are output with the point in the wrong place, leading to a dramatically off value + if(fixed && (precision > 0)){ + // make sure that the value isn't dramatically larger + double from_string = atof(s.c_str()); + + // if this ratio is large, then we've got problems + if( fabs( from_string / this->x[0] ) > 3.0 ){ + + // loop on the string, find the point, move it up one + // don't act on the first character + for(i=1; i < (int)s.length(); i++){ + if(s[i] == '.'){ + s[i] = s[i-1] ; + s[i-1] = '.' ; + break; + } + } + + from_string = atof(s.c_str()); + // if this ratio is large, then the string has not been fixed + if( fabs( from_string / this->x[0] ) > 3.0 ){ + dd_real::error("Re-rounding unsuccessful in large number fixed point trap.") ; + } + } + } + + if (!fixed) { + /* Fill in exponent part */ + s += uppercase ? 'E' : 'e'; + append_expn(s, e); + } + } + + /* Fill in the blanks */ + size_t len = s.length(); + if (len < width) { + int delta = width - len; + if (fmt & ios_base::internal) { + if (sgn) + s.insert(static_cast(1), delta, fill); + else + s.insert(static_cast(0), delta, fill); + } else if (fmt & ios_base::left) { + s.append(delta, fill); + } else { + s.insert(static_cast(0), delta, fill); + } + } + + return s; +} + +/* Computes qd^n, where n is an integer. */ +qd_real pow(const qd_real &a, int n) { + if (n == 0) + return 1.0; + + qd_real r = a; /* odd-case multiplier */ + qd_real s = 1.0; /* current answer */ + int N = std::abs(n); + + if (N > 1) { + + /* Use binary exponentiation. */ + while (N > 0) { + if (N % 2 == 1) { + /* If odd, multiply by r. Note eventually N = 1, so this + eventually executes. */ + s *= r; + } + N /= 2; + if (N > 0) + r = sqr(r); + } + + } else { + s = r; + } + + if (n < 0) + return (1.0 / s); + + return s; +} + +qd_real pow(const qd_real &a, const qd_real &b) { + return exp(b * log(a)); +} + +qd_real npwr(const qd_real &a, int n) { + return pow(a, n); +} + +/* Debugging routines */ +void qd_real::dump_bits(const string &name, std::ostream &os) const { + string::size_type len = name.length(); + if (len > 0) { + os << name << " = "; + len += 3; + } + os << "[ "; + len += 2; + for (int j = 0; j < 4; j++) { + if (j > 0) for (string::size_type i = 0; i < len; i++) os << ' '; + print_double_info(os, x[j]); + if (j < 3) + os << endl; + else + os << " ]" << endl; + } +} + +void qd_real::dump(const string &name, std::ostream &os) const { + std::ios_base::fmtflags old_flags = os.flags(); + std::streamsize old_prec = os.precision(19); + os << std::scientific; + + string::size_type len = name.length(); + if (len > 0) { + os << name << " = "; + len += 3; + } + os << "[ "; + len += 2; + os << setw(27) << x[0] << ", " << setw(26) << x[1] << "," << endl; + for (string::size_type i = 0; i < len; i++) os << ' '; + os << setw(27) << x[2] << ", " << setw(26) << x[3] << " ]" << endl; + + os.precision(old_prec); + os.flags(old_flags); +} + +/* Divisions */ +/* quad-double / double-double */ +qd_real qd_real::sloppy_div(const qd_real &a, const dd_real &b) { + double q0, q1, q2, q3; + qd_real r; + qd_real qd_b(b); + + q0 = a[0] / b._hi(); + r = a - q0 * qd_b; + + q1 = r[0] / b._hi(); + r -= (q1 * qd_b); + + q2 = r[0] / b._hi(); + r -= (q2 * qd_b); + + q3 = r[0] / b._hi(); + + ::renorm(q0, q1, q2, q3); + return qd_real(q0, q1, q2, q3); +} + +qd_real qd_real::accurate_div(const qd_real &a, const dd_real &b) { + double q0, q1, q2, q3, q4; + qd_real r; + qd_real qd_b(b); + + q0 = a[0] / b._hi(); + r = a - q0 * qd_b; + + q1 = r[0] / b._hi(); + r -= (q1 * qd_b); + + q2 = r[0] / b._hi(); + r -= (q2 * qd_b); + + q3 = r[0] / b._hi(); + r -= (q3 * qd_b); + + q4 = r[0] / b._hi(); + + ::renorm(q0, q1, q2, q3, q4); + return qd_real(q0, q1, q2, q3); +} + +/* quad-double / quad-double */ +qd_real qd_real::sloppy_div(const qd_real &a, const qd_real &b) { + double q0, q1, q2, q3; + + qd_real r; + + q0 = a[0] / b[0]; + r = a - (b * q0); + + q1 = r[0] / b[0]; + r -= (b * q1); + + q2 = r[0] / b[0]; + r -= (b * q2); + + q3 = r[0] / b[0]; + + ::renorm(q0, q1, q2, q3); + + return qd_real(q0, q1, q2, q3); +} + +qd_real qd_real::accurate_div(const qd_real &a, const qd_real &b) { + double q0, q1, q2, q3; + + qd_real r; + + q0 = a[0] / b[0]; + r = a - (b * q0); + + q1 = r[0] / b[0]; + r -= (b * q1); + + q2 = r[0] / b[0]; + r -= (b * q2); + + q3 = r[0] / b[0]; + + r -= (b * q3); + double q4 = r[0] / b[0]; + + ::renorm(q0, q1, q2, q3, q4); + + return qd_real(q0, q1, q2, q3); +} + +QD_API qd_real sqrt(const qd_real &a) { + /* Strategy: + + Perform the following Newton iteration: + + x' = x + (1 - a * x^2) * x / 2; + + which converges to 1/sqrt(a), starting with the + double precision approximation to 1/sqrt(a). + Since Newton's iteration more or less doubles the + number of correct digits, we only need to perform it + twice. + */ + + if (a.is_zero()) + return 0.0; + + if (a.is_negative()) { + qd_real::error("(qd_real::sqrt): Negative argument."); + return qd_real::_nan; + } + + qd_real r = (1.0 / std::sqrt(a[0])); + qd_real h = mul_pwr2(a, 0.5); + + r += ((0.5 - h * sqr(r)) * r); + r += ((0.5 - h * sqr(r)) * r); + r += ((0.5 - h * sqr(r)) * r); + + r *= a; + return r; +} + + +/* Computes the n-th root of a */ +qd_real nroot(const qd_real &a, int n) { + /* Strategy: Use Newton's iteration to solve + + 1/(x^n) - a = 0 + + Newton iteration becomes + + x' = x + x * (1 - a * x^n) / n + + Since Newton's iteration converges quadratically, + we only need to perform it twice. + + */ + if (n <= 0) { + qd_real::error("(qd_real::nroot): N must be positive."); + return qd_real::_nan; + } + + if (n % 2 == 0 && a.is_negative()) { + qd_real::error("(qd_real::nroot): Negative argument."); + return qd_real::_nan; + } + + if (n == 1) { + return a; + } + if (n == 2) { + return sqrt(a); + } + if (a.is_zero()) { + return qd_real(0.0); + } + + + /* Note a^{-1/n} = exp(-log(a)/n) */ + qd_real r = abs(a); + qd_real x = std::exp(-std::log(r.x[0]) / n); + + /* Perform Newton's iteration. */ + double dbl_n = static_cast(n); + x += x * (1.0 - r * npwr(x, n)) / dbl_n; + x += x * (1.0 - r * npwr(x, n)) / dbl_n; + x += x * (1.0 - r * npwr(x, n)) / dbl_n; + if (a[0] < 0.0){ + x = -x; + } + return 1.0 / x; +} + +static const int n_inv_fact = 15; +static const qd_real inv_fact[n_inv_fact] = { + qd_real( 1.66666666666666657e-01, 9.25185853854297066e-18, + 5.13581318503262866e-34, 2.85094902409834186e-50), + qd_real( 4.16666666666666644e-02, 2.31296463463574266e-18, + 1.28395329625815716e-34, 7.12737256024585466e-51), + qd_real( 8.33333333333333322e-03, 1.15648231731787138e-19, + 1.60494162032269652e-36, 2.22730392507682967e-53), + qd_real( 1.38888888888888894e-03, -5.30054395437357706e-20, + -1.73868675534958776e-36, -1.63335621172300840e-52), + qd_real( 1.98412698412698413e-04, 1.72095582934207053e-22, + 1.49269123913941271e-40, 1.29470326746002471e-58), + qd_real( 2.48015873015873016e-05, 2.15119478667758816e-23, + 1.86586404892426588e-41, 1.61837908432503088e-59), + qd_real( 2.75573192239858925e-06, -1.85839327404647208e-22, + 8.49175460488199287e-39, -5.72661640789429621e-55), + qd_real( 2.75573192239858883e-07, 2.37677146222502973e-23, + -3.26318890334088294e-40, 1.61435111860404415e-56), + qd_real( 2.50521083854417202e-08, -1.44881407093591197e-24, + 2.04267351467144546e-41, -8.49632672007163175e-58), + qd_real( 2.08767569878681002e-09, -1.20734505911325997e-25, + 1.70222792889287100e-42, 1.41609532150396700e-58), + qd_real( 1.60590438368216133e-10, 1.25852945887520981e-26, + -5.31334602762985031e-43, 3.54021472597605528e-59), + qd_real( 1.14707455977297245e-11, 2.06555127528307454e-28, + 6.88907923246664603e-45, 5.72920002655109095e-61), + qd_real( 7.64716373181981641e-13, 7.03872877733453001e-30, + -7.82753927716258345e-48, 1.92138649443790242e-64), + qd_real( 4.77947733238738525e-14, 4.39920548583408126e-31, + -4.89221204822661465e-49, 1.20086655902368901e-65), + qd_real( 2.81145725434552060e-15, 1.65088427308614326e-31, + -2.87777179307447918e-50, 4.27110689256293549e-67) +}; + +qd_real exp(const qd_real &a) { + /* Strategy: We first reduce the size of x by noting that + + exp(kr + m * log(2)) = 2^m * exp(r)^k + + where m and k are integers. By choosing m appropriately + we can make |kr| <= log(2) / 2 = 0.347. Then exp(r) is + evaluated using the familiar Taylor series. Reducing the + argument substantially speeds up the convergence. */ + + const double k = ldexp(1.0, 16); + const double inv_k = 1.0 / k; + + if (a[0] <= -709.0) + return 0.0; + + if (a[0] >= 709.0) + return qd_real::_inf; + + if (a.is_zero()) + return 1.0; + + if (a.is_one()) + return qd_real::_e; + + double m = std::floor(a.x[0] / qd_real::_log2.x[0] + 0.5); + qd_real r = mul_pwr2(a - qd_real::_log2 * m, inv_k); + qd_real s, p, t; + double thresh = inv_k * qd_real::_eps; + + p = sqr(r); + s = r + mul_pwr2(p, 0.5); + int i = 0; + do { + p *= r; + t = p * inv_fact[i++]; + s += t; + } while (std::abs(to_double(t)) > thresh && i < 9); + + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s += 1.0; + return ldexp(s, static_cast(m)); +} + +/* Logarithm. Computes log(x) in quad-double precision. + This is a natural logarithm (i.e., base e). */ +qd_real log(const qd_real &a) { + /* Strategy. The Taylor series for log converges much more + slowly than that of exp, due to the lack of the factorial + term in the denominator. Hence this routine instead tries + to determine the root of the function + + f(x) = exp(x) - a + + using Newton iteration. The iteration is given by + + x' = x - f(x)/f'(x) + = x - (1 - a * exp(-x)) + = x + a * exp(-x) - 1. + + Two iteration is needed, since Newton's iteration + approximately doubles the number of digits per iteration. */ + + if (a.is_one()) { + return 0.0; + } + + if (a[0] <= 0.0) { + qd_real::error("(qd_real::log): Non-positive argument."); + return qd_real::_nan; + } + + if (a[0] == 0.0) { + return -qd_real::_inf; + } + + qd_real x = std::log(a[0]); /* Initial approximation */ + + x = x + a * exp(-x) - 1.0; + x = x + a * exp(-x) - 1.0; + x = x + a * exp(-x) - 1.0; + + return x; +} + +qd_real log10(const qd_real &a) { + return log(a) / qd_real::_log10; +} + +static const qd_real _pi1024 = qd_real( + 3.067961575771282340e-03, 1.195944139792337116e-19, + -2.924579892303066080e-36, 1.086381075061880158e-52); + +/* Table of sin(k * pi/1024) and cos(k * pi/1024). */ +static const qd_real sin_table [] = { + qd_real( 3.0679567629659761e-03, 1.2690279085455925e-19, + 5.2879464245328389e-36, -1.7820334081955298e-52), + qd_real( 6.1358846491544753e-03, 9.0545257482474933e-20, + 1.6260113133745320e-37, -9.7492001208767410e-55), + qd_real( 9.2037547820598194e-03, -1.2136591693535934e-19, + 5.5696903949425567e-36, 1.2505635791936951e-52), + qd_real( 1.2271538285719925e-02, 6.9197907640283170e-19, + -4.0203726713435555e-36, -2.0688703606952816e-52), + qd_real( 1.5339206284988102e-02, -8.4462578865401696e-19, + 4.6535897505058629e-35, -1.3923682978570467e-51), + qd_real( 1.8406729905804820e-02, 7.4195533812833160e-19, + 3.9068476486787607e-35, 3.6393321292898614e-52), + qd_real( 2.1474080275469508e-02, -4.5407960207688566e-19, + -2.2031770119723005e-35, 1.2709814654833741e-51), + qd_real( 2.4541228522912288e-02, -9.1868490125778782e-20, + 4.8706148704467061e-36, -2.8153947855469224e-52), + qd_real( 2.7608145778965743e-02, -1.5932358831389269e-18, + -7.0475416242776030e-35, -2.7518494176602744e-51), + qd_real( 3.0674803176636626e-02, -1.6936054844107918e-20, + -2.0039543064442544e-36, -1.6267505108658196e-52), + qd_real( 3.3741171851377587e-02, -2.0096074292368340e-18, + -1.3548237016537134e-34, 6.5554881875899973e-51), + qd_real( 3.6807222941358832e-02, 6.1060088803529842e-19, + -4.0448721259852727e-35, -2.1111056765671495e-51), + qd_real( 3.9872927587739811e-02, 4.6657453481183289e-19, + 3.4119333562288684e-35, 2.4007534726187511e-51), + qd_real( 4.2938256934940820e-02, 2.8351940588660907e-18, + 1.6991309601186475e-34, 6.8026536098672629e-51), + qd_real( 4.6003182130914630e-02, -1.1182813940157788e-18, + 7.5235020270378946e-35, 4.1187304955493722e-52), + qd_real( 4.9067674327418015e-02, -6.7961037205182801e-19, + -4.4318868124718325e-35, -9.9376628132525316e-52), + qd_real( 5.2131704680283324e-02, -2.4243695291953779e-18, + -1.3675405320092298e-34, -8.3938137621145070e-51), + qd_real( 5.5195244349689941e-02, -1.3340299860891103e-18, + -3.4359574125665608e-35, 1.1911462755409369e-51), + qd_real( 5.8258264500435759e-02, 2.3299905496077492e-19, + 1.9376108990628660e-36, -5.1273775710095301e-53), + qd_real( 6.1320736302208578e-02, -5.1181134064638108e-19, + -4.2726335866706313e-35, 2.6368495557440691e-51), + qd_real( 6.4382630929857465e-02, -4.2325997000052705e-18, + 3.3260117711855937e-35, 1.4736267706718352e-51), + qd_real( 6.7443919563664065e-02, -6.9221796556983636e-18, + 1.5909286358911040e-34, -7.8828946891835218e-51), + qd_real( 7.0504573389613870e-02, -6.8552791107342883e-18, + -1.9961177630841580e-34, 2.0127129580485300e-50), + qd_real( 7.3564563599667426e-02, -2.7784941506273593e-18, + -9.1240375489852821e-35, -1.9589752023546795e-51), + qd_real( 7.6623861392031492e-02, 2.3253700287958801e-19, + -1.3186083921213440e-36, -4.9927872608099673e-53), + qd_real( 7.9682437971430126e-02, -4.4867664311373041e-18, + 2.8540789143650264e-34, 2.8491348583262741e-51), + qd_real( 8.2740264549375692e-02, 1.4735983530877760e-18, + 3.7284093452233713e-35, 2.9024430036724088e-52), + qd_real( 8.5797312344439894e-02, -3.3881893830684029e-18, + -1.6135529531508258e-34, 7.7294651620588049e-51), + qd_real( 8.8853552582524600e-02, -3.7501775830290691e-18, + 3.7543606373911573e-34, 2.2233701854451859e-50), + qd_real( 9.1908956497132724e-02, 4.7631594854274564e-18, + 1.5722874642939344e-34, -4.8464145447831456e-51), + qd_real( 9.4963495329639006e-02, -6.5885886400417564e-18, + -2.1371116991641965e-34, 1.3819370559249300e-50), + qd_real( 9.8017140329560604e-02, -1.6345823622442560e-18, + -1.3209238810006454e-35, -3.5691060049117942e-52), + qd_real( 1.0106986275482782e-01, 3.3164325719308656e-18, + -1.2004224885132282e-34, 7.2028828495418631e-51), + qd_real( 1.0412163387205457e-01, 6.5760254085385100e-18, + 1.7066246171219214e-34, -4.9499340996893514e-51), + qd_real( 1.0717242495680884e-01, 6.4424044279026198e-18, + -8.3956976499698139e-35, -4.0667730213318321e-51), + qd_real( 1.1022220729388306e-01, -5.6789503537823233e-19, + 1.0380274792383233e-35, 1.5213997918456695e-52), + qd_real( 1.1327095217756435e-01, 2.7100481012132900e-18, + 1.5323292999491619e-35, 4.9564432810360879e-52), + qd_real( 1.1631863091190477e-01, 1.0294914877509705e-18, + -9.3975734948993038e-35, 1.3534827323719708e-52), + qd_real( 1.1936521481099137e-01, -3.9500089391898506e-18, + 3.5317349978227311e-34, 1.8856046807012275e-51), + qd_real( 1.2241067519921620e-01, 2.8354501489965335e-18, + 1.8151655751493305e-34, -2.8716592177915192e-51), + qd_real( 1.2545498341154623e-01, 4.8686751763148235e-18, + 5.9878105258097936e-35, -3.3534629098722107e-51), + qd_real( 1.2849811079379317e-01, 3.8198603954988802e-18, + -1.8627501455947798e-34, -2.4308161133527791e-51), + qd_real( 1.3154002870288312e-01, -5.0039708262213813e-18, + -1.2983004159245552e-34, -4.6872034915794122e-51), + qd_real( 1.3458070850712620e-01, -9.1670359171480699e-18, + 1.5916493007073973e-34, 4.0237002484366833e-51), + qd_real( 1.3762012158648604e-01, 6.6253255866774482e-18, + -2.3746583031401459e-34, -9.3703876173093250e-52), + qd_real( 1.4065823933284924e-01, -7.9193932965524741e-18, + 6.0972464202108397e-34, 2.4566623241035797e-50), + qd_real( 1.4369503315029444e-01, 1.1472723016618666e-17, + -5.1884954557576435e-35, -4.2220684832186607e-51), + qd_real( 1.4673047445536175e-01, 3.7269471470465677e-18, + 3.7352398151250827e-34, -4.0881822289508634e-51), + qd_real( 1.4976453467732151e-01, 8.0812114131285151e-18, + 1.2979142554917325e-34, 9.9380667487736254e-51), + qd_real( 1.5279718525844344e-01, -7.6313573938416838e-18, + 5.7714690450284125e-34, -3.7731132582986687e-50), + qd_real( 1.5582839765426523e-01, 3.0351307187678221e-18, + -1.0976942315176184e-34, 7.8734647685257867e-51), + qd_real( 1.5885814333386145e-01, -4.0163200573859079e-18, + -9.2840580257628812e-35, -2.8567420029274875e-51), + qd_real( 1.6188639378011183e-01, 1.1850519643573528e-17, + -5.0440990519162957e-34, 3.0510028707928009e-50), + qd_real( 1.6491312048996992e-01, -7.0405288319166738e-19, + 3.3211107491245527e-35, 8.6663299254686031e-52), + qd_real( 1.6793829497473117e-01, 5.4284533721558139e-18, + -3.3263339336181369e-34, -1.8536367335123848e-50), + qd_real( 1.7096188876030122e-01, 9.1919980181759094e-18, + -6.7688743940982606e-34, -1.0377711384318389e-50), + qd_real( 1.7398387338746382e-01, 5.8151994618107928e-18, + -1.6751014298301606e-34, -6.6982259797164963e-51), + qd_real( 1.7700422041214875e-01, 6.7329300635408167e-18, + 2.8042736644246623e-34, 3.6786888232793599e-51), + qd_real( 1.8002290140569951e-01, 7.9701826047392143e-18, + -7.0765920110524977e-34, 1.9622512608461784e-50), + qd_real( 1.8303988795514095e-01, 7.7349918688637383e-18, + -4.4803769968145083e-34, 1.1201148793328890e-50), + qd_real( 1.8605515166344666e-01, -1.2564893007679552e-17, + 7.5953844248530810e-34, -3.8471695132415039e-51), + qd_real( 1.8906866414980622e-01, -7.6208955803527778e-18, + -4.4792298656662981e-34, -4.4136824096645007e-50), + qd_real( 1.9208039704989244e-01, 4.3348343941174903e-18, + -2.3404121848139937e-34, 1.5789970962611856e-50), + qd_real( 1.9509032201612828e-01, -7.9910790684617313e-18, + 6.1846270024220713e-34, -3.5840270918032937e-50), + qd_real( 1.9809841071795359e-01, -1.8434411800689445e-18, + 1.4139031318237285e-34, 1.0542811125343809e-50), + qd_real( 2.0110463484209190e-01, 1.1010032669300739e-17, + -3.9123576757413791e-34, 2.4084852500063531e-51), + qd_real( 2.0410896609281687e-01, 6.0941297773957752e-18, + -2.8275409970449641e-34, 4.6101008563532989e-51), + qd_real( 2.0711137619221856e-01, -1.0613362528971356e-17, + 2.2456805112690884e-34, 1.3483736125280904e-50), + qd_real( 2.1011183688046961e-01, 1.1561548476512844e-17, + 6.0355905610401254e-34, 3.3329909618405675e-50), + qd_real( 2.1311031991609136e-01, 1.2031873821063860e-17, + -3.4142699719695635e-34, -1.2436262780241778e-50), + qd_real( 2.1610679707621952e-01, -1.0111196082609117e-17, + 7.2789545335189643e-34, -2.9347540365258610e-50), + qd_real( 2.1910124015686980e-01, -3.6513812299150776e-19, + -2.3359499418606442e-35, 3.1785298198458653e-52), + qd_real( 2.2209362097320354e-01, -3.0337210995812162e-18, + 6.6654668033632998e-35, 2.0110862322656942e-51), + qd_real( 2.2508391135979283e-01, 3.9507040822556510e-18, + 2.4287993958305375e-35, 5.6662797513020322e-52), + qd_real( 2.2807208317088573e-01, 8.2361837339258012e-18, + 6.9786781316397937e-34, -6.4122962482639504e-51), + qd_real( 2.3105810828067111e-01, 1.0129787149761869e-17, + -6.9359234615816044e-34, -2.8877355604883782e-50), + qd_real( 2.3404195858354343e-01, -6.9922402696101173e-18, + -5.7323031922750280e-34, 5.3092579966872727e-51), + qd_real( 2.3702360599436720e-01, 8.8544852285039918e-18, + 1.3588480826354134e-34, 1.0381022520213867e-50), + qd_real( 2.4000302244874150e-01, -1.2137758975632164e-17, + -2.6448807731703891e-34, -1.9929733800670473e-51), + qd_real( 2.4298017990326390e-01, -8.7514315297196632e-18, + -6.5723260373079431e-34, -1.0333158083172177e-50), + qd_real( 2.4595505033579462e-01, -1.1129044052741832e-17, + 4.3805998202883397e-34, 1.2219399554686291e-50), + qd_real( 2.4892760574572018e-01, -8.1783436100020990e-18, + 5.5666875261111840e-34, 3.8080473058748167e-50), + qd_real( 2.5189781815421697e-01, -1.7591436032517039e-17, + -1.0959681232525285e-33, 5.6209426020232456e-50), + qd_real( 2.5486565960451457e-01, -1.3602299806901461e-19, + -6.0073844642762535e-36, -3.0072751311893878e-52), + qd_real( 2.5783110216215899e-01, 1.8480038630879957e-17, + 3.3201664714047599e-34, -5.5547819290576764e-51), + qd_real( 2.6079411791527551e-01, 4.2721420983550075e-18, + 5.6782126934777920e-35, 3.1428338084365397e-51), + qd_real( 2.6375467897483140e-01, -1.8837947680038700e-17, + 1.3720129045754794e-33, -8.2763406665966033e-50), + qd_real( 2.6671275747489837e-01, 2.0941222578826688e-17, + -1.1303466524727989e-33, 1.9954224050508963e-50), + qd_real( 2.6966832557291509e-01, 1.5765657618133259e-17, + -6.9696142173370086e-34, -4.0455346879146776e-50), + qd_real( 2.7262135544994898e-01, 7.8697166076387850e-18, + 6.6179388602933372e-35, -2.7642903696386267e-51), + qd_real( 2.7557181931095814e-01, 1.9320328962556582e-17, + 1.3932094180100280e-33, 1.3617253920018116e-50), + qd_real( 2.7851968938505312e-01, -1.0030273719543544e-17, + 7.2592115325689254e-34, -1.0068516296655851e-50), + qd_real( 2.8146493792575800e-01, -1.2322299641274009e-17, + -1.0564788706386435e-34, 7.5137424251265885e-51), + qd_real( 2.8440753721127182e-01, 2.2209268510661475e-17, + -9.1823095629523708e-34, -5.2192875308892218e-50), + qd_real( 2.8734745954472951e-01, 1.5461117367645717e-17, + -6.3263973663444076e-34, -2.2982538416476214e-50), + qd_real( 2.9028467725446239e-01, -1.8927978707774251e-17, + 1.1522953157142315e-33, 7.4738655654716596e-50), + qd_real( 2.9321916269425863e-01, 2.2385430811901833e-17, + 1.3662484646539680e-33, -4.2451325253996938e-50), + qd_real( 2.9615088824362384e-01, -2.0220736360876938e-17, + -7.9252212533920413e-35, -2.8990577729572470e-51), + qd_real( 2.9907982630804048e-01, 1.6701181609219447e-18, + 8.6091151117316292e-35, 3.9931286230012102e-52), + qd_real( 3.0200594931922808e-01, -1.7167666235262474e-17, + 2.3336182149008069e-34, 8.3025334555220004e-51), + qd_real( 3.0492922973540243e-01, -2.2989033898191262e-17, + -1.4598901099661133e-34, 3.7760487693121827e-51), + qd_real( 3.0784964004153487e-01, 2.7074088527245185e-17, + 1.2568858206899284e-33, 7.2931815105901645e-50), + qd_real( 3.1076715274961147e-01, 2.0887076364048513e-17, + -3.0130590791065942e-34, 1.3876739009935179e-51), + qd_real( 3.1368174039889146e-01, 1.4560447299968912e-17, + 3.6564186898011595e-34, 1.1654264734999375e-50), + qd_real( 3.1659337555616585e-01, 2.1435292512726283e-17, + 1.2338169231377316e-33, 3.3963542100989293e-50), + qd_real( 3.1950203081601569e-01, -1.3981562491096626e-17, + 8.1730000697411350e-34, -7.7671096270210952e-50), + qd_real( 3.2240767880106985e-01, -4.0519039937959398e-18, + 3.7438302780296796e-34, 8.7936731046639195e-51), + qd_real( 3.2531029216226293e-01, 7.9171249463765892e-18, + -6.7576622068146391e-35, 2.3021655066929538e-51), + qd_real( 3.2820984357909255e-01, -2.6693140719641896e-17, + 7.8928851447534788e-34, 2.5525163821987809e-51), + qd_real( 3.3110630575987643e-01, -2.7469465474778694e-17, + -1.3401245916610206e-33, 6.5531762489976163e-50), + qd_real( 3.3399965144200938e-01, 2.2598986806288142e-17, + 7.8063057192586115e-34, 2.0427600895486683e-50), + qd_real( 3.3688985339222005e-01, -4.2000940033475092e-19, + -2.9178652969985438e-36, -1.1597376437036749e-52), + qd_real( 3.3977688440682685e-01, 6.6028679499418282e-18, + 1.2575009988669683e-34, 2.5569067699008304e-51), + qd_real( 3.4266071731199438e-01, 1.9261518449306319e-17, + -9.2754189135990867e-34, 8.5439996687390166e-50), + qd_real( 3.4554132496398904e-01, 2.7251143672916123e-17, + 7.0138163601941737e-34, -1.4176292197454015e-50), + qd_real( 3.4841868024943456e-01, 3.6974420514204918e-18, + 3.5532146878499996e-34, 1.9565462544501322e-50), + qd_real( 3.5129275608556715e-01, -2.2670712098795844e-17, + -1.6994216673139631e-34, -1.2271556077284517e-50), + qd_real( 3.5416352542049040e-01, -1.6951763305764860e-17, + 1.2772331777814617e-33, -3.3703785435843310e-50), + qd_real( 3.5703096123343003e-01, -4.8218191137919166e-19, + -4.1672436994492361e-35, -7.1531167149364352e-52), + qd_real( 3.5989503653498817e-01, -1.7601687123839282e-17, + 1.3375125473046791e-33, 7.9467815593584340e-50), + qd_real( 3.6275572436739723e-01, -9.1668352663749849e-18, + -7.4317843956936735e-34, -2.0199582511804564e-50), + qd_real( 3.6561299780477385e-01, 1.6217898770457546e-17, + 1.1286970151961055e-33, -7.1825287318139010e-50), + qd_real( 3.6846682995337232e-01, 1.0463640796159268e-17, + 2.0554984738517304e-35, 1.0441861305618769e-51), + qd_real( 3.7131719395183754e-01, 3.4749239648238266e-19, + -7.5151053042866671e-37, -2.8153468438650851e-53), + qd_real( 3.7416406297145799e-01, 8.0114103761962118e-18, + 5.3429599813406052e-34, 1.0351378796539210e-50), + qd_real( 3.7700741021641826e-01, -2.7255302041956930e-18, + 6.3646586445018137e-35, 8.3048657176503559e-52), + qd_real( 3.7984720892405116e-01, 9.9151305855172370e-18, + 4.8761409697224886e-34, 1.4025084000776705e-50), + qd_real( 3.8268343236508978e-01, -1.0050772696461588e-17, + -2.0605316302806695e-34, -1.2717724698085205e-50), + qd_real( 3.8551605384391885e-01, 1.5177665396472313e-17, + 1.4198230518016535e-33, 5.8955167159904235e-50), + qd_real( 3.8834504669882630e-01, -1.0053770598398717e-17, + 7.5942999255057131e-34, -3.1967974046654219e-50), + qd_real( 3.9117038430225387e-01, 1.7997787858243995e-17, + -1.0613482402609856e-33, -5.4582148817791032e-50), + qd_real( 3.9399204006104810e-01, 9.7649241641239336e-18, + -2.1233599441284617e-34, -5.5529836795340819e-51), + qd_real( 3.9680998741671031e-01, 2.0545063670840126e-17, + 6.1347058801922842e-34, 1.0733788150636430e-50), + qd_real( 3.9962419984564684e-01, -1.5065497476189372e-17, + -9.9653258881867298e-34, -5.7524323712725355e-50), + qd_real( 4.0243465085941843e-01, 1.0902619339328270e-17, + 7.3998528125989765e-34, 2.2745784806823499e-50), + qd_real( 4.0524131400498986e-01, 9.9111401942899884e-18, + -2.5169070895434648e-34, 9.2772984818436573e-53), + qd_real( 4.0804416286497869e-01, -7.0006015137351311e-18, + -1.4108207334268228e-34, 1.5175546997577136e-52), + qd_real( 4.1084317105790397e-01, -2.4219835190355499e-17, + -1.1418902925313314e-33, -2.0996843165093468e-50), + qd_real( 4.1363831223843456e-01, -1.0393984940597871e-17, + -1.1481681174503880e-34, -2.0281052851028680e-51), + qd_real( 4.1642956009763721e-01, -2.5475580413131732e-17, + -3.4482678506112824e-34, 7.1788619351865480e-51), + qd_real( 4.1921688836322396e-01, -4.2232463750110590e-18, + -3.6053023045255790e-34, -2.2209673210025631e-50), + qd_real( 4.2200027079979968e-01, 4.3543266994128527e-18, + 3.1734310272251190e-34, -1.3573247980738668e-50), + qd_real( 4.2477968120910881e-01, 2.7462312204277281e-17, + -4.6552847802111948e-34, 6.5961781099193122e-51), + qd_real( 4.2755509343028208e-01, 9.4111898162954726e-18, + -1.7446682426598801e-34, -2.2054492626480169e-51), + qd_real( 4.3032648134008261e-01, 2.2259686974092690e-17, + 8.5972591314085075e-34, -2.9420897889003020e-50), + qd_real( 4.3309381885315196e-01, 1.1224283329847517e-17, + 5.3223748041075651e-35, 5.3926192627014212e-51), + qd_real( 4.3585707992225547e-01, 1.6230515450644527e-17, + -6.4371449063579431e-35, -6.9102436481386757e-51), + qd_real( 4.3861623853852766e-01, -2.0883315831075090e-17, + -1.4259583540891877e-34, 6.3864763590657077e-52), + qd_real( 4.4137126873171667e-01, 2.2360783886964969e-17, + 1.1864769603515770e-34, -3.8087003266189232e-51), + qd_real( 4.4412214457042926e-01, -2.4218874422178315e-17, + 2.2205230838703907e-34, 9.2133035911356258e-51), + qd_real( 4.4686884016237421e-01, -1.9222136142309382e-17, + -4.4425678589732049e-35, -1.3673609292149535e-51), + qd_real( 4.4961132965460660e-01, 4.8831924232035243e-18, + 2.7151084498191381e-34, -1.5653993171613154e-50), + qd_real( 4.5234958723377089e-01, -1.4827977472196122e-17, + -7.6947501088972324e-34, 1.7656856882031319e-50), + qd_real( 4.5508358712634384e-01, -1.2379906758116472e-17, + 5.5289688955542643e-34, -8.5382312840209386e-51), + qd_real( 4.5781330359887723e-01, -8.4554254922295949e-18, + -6.3770394246764263e-34, 3.1778253575564249e-50), + qd_real( 4.6053871095824001e-01, 1.8488777492177872e-17, + -1.0527732154209725e-33, 3.3235593490947102e-50), + qd_real( 4.6325978355186020e-01, -7.3514924533231707e-18, + 6.7175396881707035e-34, 3.9594127612123379e-50), + qd_real( 4.6597649576796618e-01, -3.3023547778235135e-18, + 3.4904677050476886e-35, 3.4483855263874246e-51), + qd_real( 4.6868882203582796e-01, -2.2949251681845054e-17, + -1.1364757641823658e-33, 6.8840522501918612e-50), + qd_real( 4.7139673682599764e-01, 6.5166781360690130e-18, + 2.9457546966235984e-34, -6.2159717738836630e-51), + qd_real( 4.7410021465055002e-01, -8.1451601548978075e-18, + -3.4789448555614422e-34, -1.1681943974658508e-50), + qd_real( 4.7679923006332214e-01, -1.0293515338305794e-17, + -3.6582045008369952e-34, 1.7424131479176475e-50), + qd_real( 4.7949375766015301e-01, 1.8419999662684771e-17, + -1.3040838621273312e-33, 1.0977131822246471e-50), + qd_real( 4.8218377207912277e-01, -2.5861500925520442e-17, + -6.2913197606500007e-36, 4.0802359808684726e-52), + qd_real( 4.8486924800079112e-01, -1.8034004203262245e-17, + -3.5244276906958044e-34, -1.7138318654749246e-50), + qd_real( 4.8755016014843594e-01, 1.4231090931273653e-17, + -1.8277733073262697e-34, -1.5208291790429557e-51), + qd_real( 4.9022648328829116e-01, -5.1496145643440404e-18, + -3.6903027405284104e-34, 1.5172940095151304e-50), + qd_real( 4.9289819222978404e-01, -1.0257831676562186e-18, + 6.9520817760885069e-35, -2.4260961214090389e-51), + qd_real( 4.9556526182577254e-01, -9.4323241942365362e-18, + 3.1212918657699143e-35, 4.2009072375242736e-52), + qd_real( 4.9822766697278187e-01, -1.6126383830540798e-17, + -1.5092897319298871e-33, 1.1049298890895917e-50), + qd_real( 5.0088538261124083e-01, -3.9604015147074639e-17, + -2.2208395201898007e-33, 1.3648202735839417e-49), + qd_real( 5.0353838372571758e-01, -1.6731308204967497e-17, + -1.0140233644074786e-33, 4.0953071937671477e-50), + qd_real( 5.0618664534515534e-01, -4.8321592986493711e-17, + 9.2858107226642252e-34, 4.2699802401037005e-50), + qd_real( 5.0883014254310699e-01, 4.7836968268014130e-17, + -1.0727022928806035e-33, 2.7309374513672757e-50), + qd_real( 5.1146885043797041e-01, -1.3088001221007579e-17, + 4.0929033363366899e-34, -3.7952190153477926e-50), + qd_real( 5.1410274419322177e-01, -4.5712707523615624e-17, + 1.5488279442238283e-33, -2.5853959305521130e-50), + qd_real( 5.1673179901764987e-01, 8.3018617233836515e-18, + 5.8251027467695202e-34, -2.2812397190535076e-50), + qd_real( 5.1935599016558964e-01, -5.5331248144171145e-17, + -3.1628375609769026e-35, -2.4091972051188571e-51), + qd_real( 5.2197529293715439e-01, -4.6555795692088883e-17, + 4.6378980936850430e-34, -3.3470542934689532e-51), + qd_real( 5.2458968267846895e-01, -4.3068869040082345e-17, + -4.2013155291932055e-34, -1.5096069926700274e-50), + qd_real( 5.2719913478190139e-01, -4.2202983480560619e-17, + 8.5585916184867295e-34, 7.9974339336732307e-50), + qd_real( 5.2980362468629472e-01, -4.8067841706482342e-17, + 5.8309721046630296e-34, -8.9740761521756660e-51), + qd_real( 5.3240312787719801e-01, -4.1020306135800895e-17, + -1.9239996374230821e-33, -1.5326987913812184e-49), + qd_real( 5.3499761988709726e-01, -5.3683132708358134e-17, + -1.3900569918838112e-33, 2.7154084726474092e-50), + qd_real( 5.3758707629564551e-01, -2.2617365388403054e-17, + -5.9787279033447075e-34, 3.1204419729043625e-51), + qd_real( 5.4017147272989285e-01, 2.7072447965935839e-17, + 1.1698799709213829e-33, -5.9094668515881500e-50), + qd_real( 5.4275078486451589e-01, 1.7148261004757101e-17, + -1.3525905925200870e-33, 4.9724411290727323e-50), + qd_real( 5.4532498842204646e-01, -4.1517817538384258e-17, + -1.5318930219385941e-33, 6.3629921101413974e-50), + qd_real( 5.4789405917310019e-01, -2.4065878297113363e-17, + -3.5639213669362606e-36, -2.6013270854271645e-52), + qd_real( 5.5045797293660481e-01, -8.3319903015807663e-18, + -2.3058454035767633e-34, -2.1611290432369010e-50), + qd_real( 5.5301670558002758e-01, -4.7061536623798204e-17, + -1.0617111545918056e-33, -1.6196316144407379e-50), + qd_real( 5.5557023301960218e-01, 4.7094109405616768e-17, + -2.0640520383682921e-33, 1.2290163188567138e-49), + qd_real( 5.5811853122055610e-01, 1.3481176324765226e-17, + -5.5016743873011438e-34, -2.3484822739335416e-50), + qd_real( 5.6066157619733603e-01, -7.3956418153476152e-18, + 3.9680620611731193e-34, 3.1995952200836223e-50), + qd_real( 5.6319934401383409e-01, 2.3835775146854829e-17, + 1.3511793173769814e-34, 9.3201311581248143e-51), + qd_real( 5.6573181078361323e-01, -3.4096079596590466e-17, + -1.7073289744303546e-33, 8.9147089975404507e-50), + qd_real( 5.6825895267013160e-01, -5.0935673642769248e-17, + -1.6274356351028249e-33, 9.8183151561702966e-51), + qd_real( 5.7078074588696726e-01, 2.4568151455566208e-17, + -1.2844481247560350e-33, -1.8037634376936261e-50), + qd_real( 5.7329716669804220e-01, 8.5176611669306400e-18, + -6.4443208788026766e-34, 2.2546105543273003e-50), + qd_real( 5.7580819141784534e-01, -3.7909495458942734e-17, + -2.7433738046854309e-33, 1.1130841524216795e-49), + qd_real( 5.7831379641165559e-01, -2.6237691512372831e-17, + 1.3679051680738167e-33, -3.1409808935335900e-50), + qd_real( 5.8081395809576453e-01, 1.8585338586613408e-17, + 2.7673843114549181e-34, 1.9605349619836937e-50), + qd_real( 5.8330865293769829e-01, 3.4516601079044858e-18, + 1.8065977478946306e-34, -6.3953958038544646e-51), + qd_real( 5.8579785745643886e-01, -3.7485501964311294e-18, + 2.7965403775536614e-34, -7.1816936024157202e-51), + qd_real( 5.8828154822264533e-01, -2.9292166725006846e-17, + -2.3744954603693934e-33, -1.1571631191512480e-50), + qd_real( 5.9075970185887428e-01, -4.7013584170659542e-17, + 2.4808417611768356e-33, 1.2598907673643198e-50), + qd_real( 5.9323229503979980e-01, 1.2892320944189053e-17, + 5.3058364776359583e-34, 4.1141674699390052e-50), + qd_real( 5.9569930449243336e-01, -1.3438641936579467e-17, + -6.7877687907721049e-35, -5.6046937531684890e-51), + qd_real( 5.9816070699634227e-01, 3.8801885783000657e-17, + -1.2084165858094663e-33, -4.0456610843430061e-50), + qd_real( 6.0061647938386897e-01, -4.6398198229461932e-17, + -1.6673493003710801e-33, 5.1982824378491445e-50), + qd_real( 6.0306659854034816e-01, 3.7323357680559650e-17, + 2.7771920866974305e-33, -1.6194229649742458e-49), + qd_real( 6.0551104140432555e-01, -3.1202672493305677e-17, + 1.2761267338680916e-33, -4.0859368598379647e-50), + qd_real( 6.0794978496777363e-01, 3.5160832362096660e-17, + -2.5546242776778394e-34, -1.4085313551220694e-50), + qd_real( 6.1038280627630948e-01, -2.2563265648229169e-17, + 1.3185575011226730e-33, 8.2316691420063460e-50), + qd_real( 6.1281008242940971e-01, -4.2693476568409685e-18, + 2.5839965886650320e-34, 1.6884412005622537e-50), + qd_real( 6.1523159058062682e-01, 2.6231417767266950e-17, + -1.4095366621106716e-33, 7.2058690491304558e-50), + qd_real( 6.1764730793780398e-01, -4.7478594510902452e-17, + -7.2986558263123996e-34, -3.0152327517439154e-50), + qd_real( 6.2005721176328921e-01, -2.7983410837681118e-17, + 1.1649951056138923e-33, -5.4539089117135207e-50), + qd_real( 6.2246127937414997e-01, 5.2940728606573002e-18, + -4.8486411215945827e-35, 1.2696527641980109e-52), + qd_real( 6.2485948814238634e-01, 3.3671846037243900e-17, + -2.7846053391012096e-33, 5.6102718120012104e-50), + qd_real( 6.2725181549514408e-01, 3.0763585181253225e-17, + 2.7068930273498138e-34, -1.1172240309286484e-50), + qd_real( 6.2963823891492698e-01, 4.1115334049626806e-17, + -1.9167473580230747e-33, 1.1118424028161730e-49), + qd_real( 6.3201873593980906e-01, -4.0164942296463612e-17, + -7.2208643641736723e-34, 3.7828920470544344e-50), + qd_real( 6.3439328416364549e-01, 1.0420901929280035e-17, + 4.1174558929280492e-34, -1.4464152986630705e-51), + qd_real( 6.3676186123628420e-01, 3.1419048711901611e-17, + -2.2693738415126449e-33, -1.6023584204297388e-49), + qd_real( 6.3912444486377573e-01, 1.2416796312271043e-17, + -6.2095419626356605e-34, 2.7762065999506603e-50), + qd_real( 6.4148101280858316e-01, -9.9883430115943310e-18, + 4.1969230376730128e-34, 5.6980543799257597e-51), + qd_real( 6.4383154288979150e-01, -3.2084798795046886e-17, + -1.2595311907053305e-33, -4.0205885230841536e-50), + qd_real( 6.4617601298331639e-01, -2.9756137382280815e-17, + -1.0275370077518259e-33, 8.0852478665893014e-51), + qd_real( 6.4851440102211244e-01, 3.9870270313386831e-18, + 1.9408388509540788e-34, -5.1798420636193190e-51), + qd_real( 6.5084668499638088e-01, 3.9714670710500257e-17, + 2.9178546787002963e-34, 3.8140635508293278e-51), + qd_real( 6.5317284295377676e-01, 8.5695642060026238e-18, + -6.9165322305070633e-34, 2.3873751224185395e-50), + qd_real( 6.5549285299961535e-01, 3.5638734426385005e-17, + 1.2695365790889811e-33, 4.3984952865412050e-50), + qd_real( 6.5780669329707864e-01, 1.9580943058468545e-17, + -1.1944272256627192e-33, 2.8556402616436858e-50), + qd_real( 6.6011434206742048e-01, -1.3960054386823638e-19, + 6.1515777931494047e-36, 5.3510498875622660e-52), + qd_real( 6.6241577759017178e-01, -2.2615508885764591e-17, + 5.0177050318126862e-34, 2.9162532399530762e-50), + qd_real( 6.6471097820334490e-01, -3.6227793598034367e-17, + -9.0607934765540427e-34, 3.0917036342380213e-50), + qd_real( 6.6699992230363747e-01, 3.5284364997428166e-17, + -1.0382057232458238e-33, 7.3812756550167626e-50), + qd_real( 6.6928258834663612e-01, -5.4592652417447913e-17, + -2.5181014709695152e-33, -1.6867875999437174e-49), + qd_real( 6.7155895484701844e-01, -4.0489037749296692e-17, + 3.1995835625355681e-34, -1.4044414655670960e-50), + qd_real( 6.7382900037875604e-01, 2.3091901236161086e-17, + 5.7428037192881319e-34, 1.1240668354625977e-50), + qd_real( 6.7609270357531592e-01, 3.7256902248049466e-17, + 1.7059417895764375e-33, 9.7326347795300652e-50), + qd_real( 6.7835004312986147e-01, 1.8302093041863122e-17, + 9.5241675746813072e-34, 5.0328101116133503e-50), + qd_real( 6.8060099779545302e-01, 2.8473293354522047e-17, + 4.1331805977270903e-34, 4.2579030510748576e-50), + qd_real( 6.8284554638524808e-01, -1.2958058061524531e-17, + 1.8292386959330698e-34, 3.4536209116044487e-51), + qd_real( 6.8508366777270036e-01, 2.5948135194645137e-17, + -8.5030743129500702e-34, -6.9572086141009930e-50), + qd_real( 6.8731534089175916e-01, -5.5156158714917168e-17, + 1.1896489854266829e-33, -7.8505896218220662e-51), + qd_real( 6.8954054473706694e-01, -1.5889323294806790e-17, + 9.1242356240205712e-34, 3.8315454152267638e-50), + qd_real( 6.9175925836415775e-01, 2.7406078472410668e-17, + 1.3286508943202092e-33, 1.0651869129580079e-51), + qd_real( 6.9397146088965400e-01, 7.4345076956280137e-18, + 7.5061528388197460e-34, -1.5928000240686583e-50), + qd_real( 6.9617713149146299e-01, -4.1224081213582889e-17, + -3.1838716762083291e-35, -3.9625587412119131e-51), + qd_real( 6.9837624940897280e-01, 4.8988282435667768e-17, + 1.9134010413244152e-33, 2.6161153243793989e-50), + qd_real( 7.0056879394324834e-01, 3.1027960192992922e-17, + 9.5638250509179997e-34, 4.5896916138107048e-51), + qd_real( 7.0275474445722530e-01, 2.5278294383629822e-18, + -8.6985561210674942e-35, -5.6899862307812990e-51), + qd_real( 7.0493408037590488e-01, 2.7608725585748502e-17, + 2.9816599471629137e-34, 1.1533044185111206e-50), + qd_real( 7.0710678118654757e-01, -4.8336466567264567e-17, + 2.0693376543497068e-33, 2.4677734957341755e-50) +}; + +static const qd_real cos_table [] = { + qd_real( 9.9999529380957619e-01, -1.9668064285322189e-17, + -6.3053955095883481e-34, 5.3266110855726731e-52), + qd_real( 9.9998117528260111e-01, 3.3568103522895585e-17, + -1.4740132559368063e-35, 9.8603097594755596e-52), + qd_real( 9.9995764455196390e-01, -3.1527836866647287e-17, + 2.6363251186638437e-33, 1.0007504815488399e-49), + qd_real( 9.9992470183914450e-01, 3.7931082512668012e-17, + -8.5099918660501484e-35, -4.9956973223295153e-51), + qd_real( 9.9988234745421256e-01, -3.5477814872408538e-17, + 1.7102001035303974e-33, -1.0725388519026542e-49), + qd_real( 9.9983058179582340e-01, 1.8825140517551119e-17, + -5.1383513457616937e-34, -3.8378827995403787e-50), + qd_real( 9.9976940535121528e-01, 4.2681177032289012e-17, + 1.9062302359737099e-33, -6.0221153262881160e-50), + qd_real( 9.9969881869620425e-01, -2.9851486403799753e-17, + -1.9084787370733737e-33, 5.5980260344029202e-51), + qd_real( 9.9961882249517864e-01, -4.1181965521424734e-17, + 2.0915365593699916e-33, 8.1403390920903734e-50), + qd_real( 9.9952941750109314e-01, 2.0517917823755591e-17, + -4.7673802585706520e-34, -2.9443604198656772e-50), + qd_real( 9.9943060455546173e-01, 3.9644497752257798e-17, + -2.3757223716722428e-34, -1.2856759011361726e-51), + qd_real( 9.9932238458834954e-01, -4.2858538440845682e-17, + 3.3235101605146565e-34, -8.3554272377057543e-51), + qd_real( 9.9920475861836389e-01, 9.1796317110385693e-18, + 5.5416208185868570e-34, 8.0267046717615311e-52), + qd_real( 9.9907772775264536e-01, 2.1419007653587032e-17, + -7.9048203318529618e-34, -5.3166296181112712e-50), + qd_real( 9.9894129318685687e-01, -2.0610641910058638e-17, + -1.2546525485913485e-33, -7.5175888806157064e-50), + qd_real( 9.9879545620517241e-01, -1.2291693337075465e-17, + 2.4468446786491271e-34, 1.0723891085210268e-50), + qd_real( 9.9864021818026527e-01, -4.8690254312923302e-17, + -2.9470881967909147e-34, -1.3000650761346907e-50), + qd_real( 9.9847558057329477e-01, -2.2002931182778795e-17, + -1.2371509454944992e-33, -2.4911225131232065e-50), + qd_real( 9.9830154493389289e-01, -5.1869402702792278e-17, + 1.0480195493633452e-33, -2.8995649143155511e-50), + qd_real( 9.9811811290014918e-01, 2.7935487558113833e-17, + 2.4423341255830345e-33, -6.7646699175334417e-50), + qd_real( 9.9792528619859600e-01, 1.7143659778886362e-17, + 5.7885840902887460e-34, -9.2601432603894597e-51), + qd_real( 9.9772306664419164e-01, -2.6394475274898721e-17, + -1.6176223087661783e-34, -9.9924942889362281e-51), + qd_real( 9.9751145614030345e-01, 5.6007205919806937e-18, + -5.9477673514685690e-35, -1.4166807162743627e-54), + qd_real( 9.9729045667869021e-01, 9.1647695371101735e-18, + 6.7824134309739296e-34, -8.6191392795543357e-52), + qd_real( 9.9706007033948296e-01, 1.6734093546241963e-17, + -1.3169951440780028e-33, 1.0311048767952477e-50), + qd_real( 9.9682029929116567e-01, 4.7062820708615655e-17, + 2.8412041076474937e-33, -8.0006155670263622e-50), + qd_real( 9.9657114579055484e-01, 1.1707179088390986e-17, + -7.5934413263024663e-34, 2.8474848436926008e-50), + qd_real( 9.9631261218277800e-01, 1.1336497891624735e-17, + 3.4002458674414360e-34, 7.7419075921544901e-52), + qd_real( 9.9604470090125197e-01, 2.2870031707670695e-17, + -3.9184839405013148e-34, -3.7081260416246375e-50), + qd_real( 9.9576741446765982e-01, -2.3151908323094359e-17, + -1.6306512931944591e-34, -1.5925420783863192e-51), + qd_real( 9.9548075549192694e-01, 3.2084621412226554e-18, + -4.9501292146013023e-36, -2.7811428850878516e-52), + qd_real( 9.9518472667219693e-01, -4.2486913678304410e-17, + 1.3315510772504614e-33, 6.7927987417051888e-50), + qd_real( 9.9487933079480562e-01, 4.2130813284943662e-18, + -4.2062597488288452e-35, 2.5157064556087620e-51), + qd_real( 9.9456457073425542e-01, 3.6745069641528058e-17, + -3.0603304105471010e-33, 1.0397872280487526e-49), + qd_real( 9.9424044945318790e-01, 4.4129423472462673e-17, + -3.0107231708238066e-33, 7.4201582906861892e-50), + qd_real( 9.9390697000235606e-01, -1.8964849471123746e-17, + -1.5980853777937752e-35, -8.5374807150597082e-52), + qd_real( 9.9356413552059530e-01, 2.9752309927797428e-17, + -4.5066707331134233e-34, -3.3548191633805036e-50), + qd_real( 9.9321194923479450e-01, 3.3096906261272262e-17, + 1.5592811973249567e-33, 1.4373977733253592e-50), + qd_real( 9.9285041445986510e-01, -1.4094517733693302e-17, + -1.1954558131616916e-33, 1.8761873742867983e-50), + qd_real( 9.9247953459870997e-01, 3.1093055095428906e-17, + -1.8379594757818019e-33, -3.9885758559381314e-51), + qd_real( 9.9209931314219180e-01, -3.9431926149588778e-17, + -6.2758062911047230e-34, -1.2960929559212390e-50), + qd_real( 9.9170975366909953e-01, -2.3372891311883661e-18, + 2.7073298824968591e-35, -1.2569459441802872e-51), + qd_real( 9.9131085984611544e-01, -2.5192111583372105e-17, + -1.2852471567380887e-33, 5.2385212584310483e-50), + qd_real( 9.9090263542778001e-01, 1.5394565094566704e-17, + -1.0799984133184567e-33, 2.7451115960133595e-51), + qd_real( 9.9048508425645709e-01, -5.5411437553780867e-17, + -1.4614017210753585e-33, -3.8339374397387620e-50), + qd_real( 9.9005821026229712e-01, -1.7055485906233963e-17, + 1.3454939685758777e-33, 7.3117589137300036e-50), + qd_real( 9.8962201746320089e-01, -5.2398217968132530e-17, + 1.3463189211456219e-33, 5.8021640554894872e-50), + qd_real( 9.8917650996478101e-01, -4.0987309937047111e-17, + -4.4857560552048437e-34, -3.9414504502871125e-50), + qd_real( 9.8872169196032378e-01, -1.0976227206656125e-17, + 3.2311342577653764e-34, 9.6367946583575041e-51), + qd_real( 9.8825756773074946e-01, 2.7030607784372632e-17, + 7.7514866488601377e-35, 2.1019644956864938e-51), + qd_real( 9.8778414164457218e-01, -2.3600693397159021e-17, + -1.2323283769707861e-33, 3.0130900716803339e-50), + qd_real( 9.8730141815785843e-01, -5.2332261255715652e-17, + -2.7937644333152473e-33, 1.2074160567958408e-49), + qd_real( 9.8680940181418553e-01, -5.0287214351061075e-17, + -2.2681526238144461e-33, 4.4003694320169133e-50), + qd_real( 9.8630809724459867e-01, -2.1520877103013341e-17, + 1.1866528054187716e-33, -7.8532199199813836e-50), + qd_real( 9.8579750916756748e-01, -5.1439452979953012e-17, + 2.6276439309996725e-33, 7.5423552783286347e-50), + qd_real( 9.8527764238894122e-01, 2.3155637027900207e-17, + -7.5275971545764833e-34, 1.0582231660456094e-50), + qd_real( 9.8474850180190421e-01, 1.0548144061829957e-17, + 2.8786145266267306e-34, -3.6782210081466112e-51), + qd_real( 9.8421009238692903e-01, 4.7983922627050691e-17, + 2.2597419645070588e-34, 1.7573875814863400e-50), + qd_real( 9.8366241921173025e-01, 1.9864948201635255e-17, + -1.0743046281211033e-35, 1.7975662796558100e-52), + qd_real( 9.8310548743121629e-01, 4.2170007522888628e-17, + 8.2396265656440904e-34, -8.0803700139096561e-50), + qd_real( 9.8253930228744124e-01, 1.5149580813777224e-17, + -4.1802771422186237e-34, -2.2150174326226160e-50), + qd_real( 9.8196386910955524e-01, 2.1108443711513084e-17, + -1.5253013442896054e-33, -6.8388082079337969e-50), + qd_real( 9.8137919331375456e-01, 1.3428163260355633e-17, + -6.5294290469962986e-34, 2.7965412287456268e-51), + qd_real( 9.8078528040323043e-01, 1.8546939997825006e-17, + -1.0696564445530757e-33, 6.6668174475264961e-50), + qd_real( 9.8018213596811743e-01, -3.6801786963856159e-17, + 6.3245171387992842e-34, 1.8600176137175971e-50), + qd_real( 9.7956976568544052e-01, 1.5573991584990420e-17, + -1.3401066029782990e-33, -1.7263702199862149e-50), + qd_real( 9.7894817531906220e-01, -2.3817727961148053e-18, + -1.0694750370381661e-34, -8.2293047196087462e-51), + qd_real( 9.7831737071962765e-01, -2.1623082233344895e-17, + 1.0970403012028032e-33, 7.7091923099369339e-50), + qd_real( 9.7767735782450993e-01, 5.0514136167059628e-17, + -1.3254751701428788e-33, 7.0161254312124538e-50), + qd_real( 9.7702814265775439e-01, -4.3353875751555997e-17, + 5.4948839831535478e-34, -9.2755263105377306e-51), + qd_real( 9.7636973133002114e-01, 9.3093931526213780e-18, + -4.1184949155685665e-34, -3.1913926031393690e-50), + qd_real( 9.7570213003852857e-01, -2.5572556081259686e-17, + -9.3174244508942223e-34, -8.3675863211646863e-51), + qd_real( 9.7502534506699412e-01, 2.6642660651899135e-17, + 1.7819392739353853e-34, -3.3159625385648947e-51), + qd_real( 9.7433938278557586e-01, 2.3041221476151512e-18, + 1.0758686005031430e-34, 5.1074116432809478e-51), + qd_real( 9.7364424965081198e-01, -5.1729808691005871e-17, + -1.5508473005989887e-33, -1.6505125917675401e-49), + qd_real( 9.7293995220556018e-01, -3.1311211122281800e-17, + -2.6874087789006141e-33, -2.1652434818822145e-51), + qd_real( 9.7222649707893627e-01, 3.6461169785938221e-17, + 3.0309636883883133e-33, -1.2702716907967306e-51), + qd_real( 9.7150389098625178e-01, -7.9865421122289046e-18, + -4.3628417211263380e-34, 3.4307517798759352e-51), + qd_real( 9.7077214072895035e-01, -4.7992163325114922e-17, + 3.0347528910975783e-33, 8.5989199506479701e-50), + qd_real( 9.7003125319454397e-01, 1.8365300348428844e-17, + -1.4311097571944918e-33, 8.5846781998740697e-51), + qd_real( 9.6928123535654853e-01, -4.5663660261927896e-17, + 9.6147526917239387e-34, 8.1267605207871330e-51), + qd_real( 9.6852209427441727e-01, 4.9475074918244771e-17, + 2.8558738351911241e-33, 6.2948422316507461e-50), + qd_real( 9.6775383709347551e-01, -4.5512132825515820e-17, + -1.4127617988719093e-33, -8.4620609089704578e-50), + qd_real( 9.6697647104485207e-01, 3.8496228837337864e-17, + -5.3881631542745647e-34, -3.5221863171458959e-50), + qd_real( 9.6619000344541250e-01, 5.1298840401665493e-17, + 1.4564075904769808e-34, 1.0095973971377432e-50), + qd_real( 9.6539444169768940e-01, -2.3745389918392156e-17, + 5.9221515590053862e-34, -3.8811192556231094e-50), + qd_real( 9.6458979328981276e-01, -3.4189470735959786e-17, + 2.2982074155463522e-33, -4.5128791045607634e-50), + qd_real( 9.6377606579543984e-01, 2.6463950561220029e-17, + -2.9073234590199323e-36, -1.2938328629395601e-52), + qd_real( 9.6295326687368388e-01, 8.9341960404313634e-18, + -3.9071244661020126e-34, 1.6212091116847394e-50), + qd_real( 9.6212140426904158e-01, 1.5236770453846305e-17, + -1.3050173525597142e-33, 7.9016122394092666e-50), + qd_real( 9.6128048581132064e-01, 2.0933955216674039e-18, + 1.0768607469015692e-34, -5.9453639304361774e-51), + qd_real( 9.6043051941556579e-01, 2.4653904815317185e-17, + -1.3792169410906322e-33, -4.7726598378506903e-51), + qd_real( 9.5957151308198452e-01, 1.1000640085000957e-17, + -4.2036030828223975e-34, 4.0023704842606573e-51), + qd_real( 9.5870347489587160e-01, -4.3685014392372053e-17, + 2.2001800662729131e-33, -1.0553721324358075e-49), + qd_real( 9.5782641302753291e-01, -1.7696710075371263e-17, + 1.9164034110382190e-34, 8.1489235071754813e-51), + qd_real( 9.5694033573220882e-01, 4.0553869861875701e-17, + -1.7147013364302149e-33, 2.5736745295329455e-50), + qd_real( 9.5604525134999641e-01, 3.7705045279589067e-17, + 1.9678699997347571e-33, 8.5093177731230180e-50), + qd_real( 9.5514116830577067e-01, 5.0088652955014668e-17, + -2.6983181838059211e-33, 1.0102323575596493e-49), + qd_real( 9.5422809510910567e-01, -3.7545901690626874e-17, + 1.4951619241257764e-33, -8.2717333151394973e-50), + qd_real( 9.5330604035419386e-01, -2.5190738779919934e-17, + -1.4272239821134379e-33, -4.6717286809283155e-50), + qd_real( 9.5237501271976588e-01, -2.0269300462299272e-17, + -1.0635956887246246e-33, -3.5514537666487619e-50), + qd_real( 9.5143502096900834e-01, 3.1350584123266695e-17, + -2.4824833452737813e-33, 9.5450335525380613e-51), + qd_real( 9.5048607394948170e-01, 1.9410097562630436e-17, + -8.1559393949816789e-34, -1.0501209720164562e-50), + qd_real( 9.4952818059303667e-01, -7.5544151928043298e-18, + -5.1260245024046686e-34, 1.8093643389040406e-50), + qd_real( 9.4856134991573027e-01, 2.0668262262333232e-17, + -5.9440730243667306e-34, 1.4268853111554300e-50), + qd_real( 9.4758559101774109e-01, 4.3417993852125991e-17, + -2.7728667889840373e-34, 5.5709160196519968e-51), + qd_real( 9.4660091308328353e-01, 3.5056800210680730e-17, + 9.8578536940318117e-34, 6.6035911064585197e-50), + qd_real( 9.4560732538052128e-01, 4.6019102478523738e-17, + -6.2534384769452059e-34, 1.5758941215779961e-50), + qd_real( 9.4460483726148026e-01, 8.8100545476641165e-18, + 5.2291695602757842e-34, -3.3487256018407123e-50), + qd_real( 9.4359345816196039e-01, -2.4093127844404214e-17, + 1.0283279856803939e-34, -2.3398232614531355e-51), + qd_real( 9.4257319760144687e-01, 1.3235564806436886e-17, + -5.7048262885386911e-35, 3.9947050442753744e-51), + qd_real( 9.4154406518302081e-01, -2.7896379547698341e-17, + 1.6273236356733898e-33, -5.3075944708471203e-51), + qd_real( 9.4050607059326830e-01, 2.8610421567116268e-17, + 2.9261501147538827e-33, -2.6849867690896925e-50), + qd_real( 9.3945922360218992e-01, -7.0152867943098655e-18, + -5.6395693818011210e-34, 3.5568142678987651e-50), + qd_real( 9.3840353406310806e-01, 5.4242545044795490e-17, + -1.9039966607859759e-33, -1.5627792988341215e-49), + qd_real( 9.3733901191257496e-01, -3.6570926284362776e-17, + -1.1902940071273247e-33, -1.1215082331583223e-50), + qd_real( 9.3626566717027826e-01, -1.3013766145497654e-17, + 5.2229870061990595e-34, -3.3972777075634108e-51), + qd_real( 9.3518350993894761e-01, -3.2609395302485065e-17, + -8.1813015218875245e-34, 5.5642140024928139e-50), + qd_real( 9.3409255040425887e-01, 4.4662824360767511e-17, + -2.5903243047396916e-33, 8.1505209004343043e-50), + qd_real( 9.3299279883473885e-01, 4.2041415555384355e-17, + 9.0285896495521276e-34, 5.3019984977661259e-50), + qd_real( 9.3188426558166815e-01, -4.0785944377318095e-17, + 1.7631450298754169e-33, 2.5776403305507453e-50), + qd_real( 9.3076696107898371e-01, 1.9703775102838329e-17, + 6.5657908718278205e-34, -1.9480347966259524e-51), + qd_real( 9.2964089584318121e-01, 5.1282530016864107e-17, + 2.3719739891916261e-34, -1.7230065426917127e-50), + qd_real( 9.2850608047321559e-01, -2.3306639848485943e-17, + -7.7799084333208503e-34, -5.8597558009300305e-50), + qd_real( 9.2736252565040111e-01, -2.7677111692155437e-17, + 2.2110293450199576e-34, 2.0349190819680613e-50), + qd_real( 9.2621024213831138e-01, -3.7303754586099054e-17, + 2.0464457809993405e-33, 1.3831799631231817e-49), + qd_real( 9.2504924078267758e-01, 6.0529447412576159e-18, + -8.8256517760278541e-35, 1.8285462122388328e-51), + qd_real( 9.2387953251128674e-01, 1.7645047084336677e-17, + -5.0442537321586818e-34, -4.0478677716823890e-50), + qd_real( 9.2270112833387852e-01, 5.2963798918539814e-17, + -5.7135699628876685e-34, 3.0163671797219087e-50), + qd_real( 9.2151403934204190e-01, 4.1639843390684644e-17, + 1.1891485604702356e-33, 2.0862437594380324e-50), + qd_real( 9.2031827670911059e-01, -2.7806888779036837e-17, + 2.7011013677071274e-33, 1.1998578792455499e-49), + qd_real( 9.1911385169005777e-01, -2.6496484622344718e-17, + 6.5403604763461920e-34, -2.8997180201186078e-50), + qd_real( 9.1790077562139050e-01, -3.9074579680849515e-17, + 2.3004636541490264e-33, 3.9851762744443107e-50), + qd_real( 9.1667905992104270e-01, -4.1733978698287568e-17, + 1.2094444804381172e-33, 4.9356916826097816e-50), + qd_real( 9.1544871608826783e-01, -1.3591056692900894e-17, + 5.9923027475594735e-34, 2.1403295925962879e-50), + qd_real( 9.1420975570353069e-01, -3.6316182527814423e-17, + -1.9438819777122554e-33, 2.8340679287728316e-50), + qd_real( 9.1296219042839821e-01, -4.7932505228039469e-17, + -1.7753551889428638e-33, 4.0607782903868160e-51), + qd_real( 9.1170603200542988e-01, -2.6913273175034130e-17, + -5.1928101916162528e-35, 1.1338175936090630e-51), + qd_real( 9.1044129225806725e-01, -5.0433041673313820e-17, + 1.0938746257404305e-33, 9.5378272084170731e-51), + qd_real( 9.0916798309052238e-01, -3.6878564091359894e-18, + 2.9951330310507693e-34, -1.2225666136919926e-50), + qd_real( 9.0788611648766626e-01, -4.9459964301225840e-17, + -1.6599682707075313e-33, -5.1925202712634716e-50), + qd_real( 9.0659570451491533e-01, 3.0506718955442023e-17, + -1.4478836557141204e-33, 1.8906373784448725e-50), + qd_real( 9.0529675931811882e-01, -4.1153099826889901e-17, + 2.9859368705184223e-33, 5.1145293917439211e-50), + qd_real( 9.0398929312344334e-01, -6.6097544687484308e-18, + 1.2728013034680357e-34, -4.3026097234014823e-51), + qd_real( 9.0267331823725883e-01, -1.9250787033961483e-17, + 1.3242128993244527e-33, -5.2971030688703665e-50), + qd_real( 9.0134884704602203e-01, -1.3524789367698682e-17, + 6.3605353115880091e-34, 3.6227400654573828e-50), + qd_real( 9.0001589201616028e-01, -5.0639618050802273e-17, + 1.0783525384031576e-33, 2.8130016326515111e-50), + qd_real( 8.9867446569395382e-01, 2.6316906461033013e-17, + 3.7003137047796840e-35, -2.3447719900465938e-51), + qd_real( 8.9732458070541832e-01, -3.6396283314867290e-17, + -2.3611649895474815e-33, 1.1837247047900082e-49), + qd_real( 8.9596624975618511e-01, 4.9025099114811813e-17, + -1.9440489814795326e-33, -1.7070486667767033e-49), + qd_real( 8.9459948563138270e-01, -1.7516226396814919e-17, + -1.3200670047246923e-33, -1.5953009884324695e-50), + qd_real( 8.9322430119551532e-01, -4.1161239151908913e-18, + 2.5380253805715999e-34, 4.2849455510516192e-51), + qd_real( 8.9184070939234272e-01, 4.6690228137124547e-18, + 1.6150254286841982e-34, -3.9617448820725012e-51), + qd_real( 8.9044872324475788e-01, 1.1781931459051803e-17, + -1.3346142209571930e-34, -9.4982373530733431e-51), + qd_real( 8.8904835585466457e-01, -1.1164514966766675e-17, + -3.4797636107798736e-34, -1.5605079997040631e-50), + qd_real( 8.8763962040285393e-01, 1.2805091918587960e-17, + 3.9948742059584459e-35, 3.8940716325338136e-51), + qd_real( 8.8622253014888064e-01, -6.7307369600274315e-18, + 1.2385593432917413e-34, 2.0364014759133320e-51), + qd_real( 8.8479709843093779e-01, -9.4331469628972690e-18, + -5.7106541478701439e-34, 1.8260134111907397e-50), + qd_real( 8.8336333866573158e-01, 1.5822643380255127e-17, + -7.8921320007588250e-34, -1.4782321016179836e-50), + qd_real( 8.8192126434835505e-01, -1.9843248405890562e-17, + -7.0412114007673834e-34, -1.0636770169389104e-50), + qd_real( 8.8047088905216075e-01, 1.6311096602996350e-17, + -5.7541360594724172e-34, -4.0128611862170021e-50), + qd_real( 8.7901222642863353e-01, -4.7356837291118011e-17, + 1.4388771297975192e-33, -2.9085554304479134e-50), + qd_real( 8.7754529020726124e-01, 5.0113311846499550e-17, + 2.8382769008739543e-34, 1.5550640393164140e-50), + qd_real( 8.7607009419540660e-01, 5.8729024235147677e-18, + 2.7941144391738458e-34, -1.8536073846509828e-50), + qd_real( 8.7458665227817611e-01, -5.7216617730397065e-19, + -2.9705811503689596e-35, 8.7389593969796752e-52), + qd_real( 8.7309497841829009e-01, 7.8424672990129903e-18, + -4.8685015839797165e-34, -2.2815570587477527e-50), + qd_real( 8.7159508665595109e-01, -5.5272998038551050e-17, + -2.2104090204984907e-33, -9.7749763187643172e-50), + qd_real( 8.7008699110871146e-01, -4.1888510868549968e-17, + 7.0900185861878415e-34, 3.7600251115157260e-50), + qd_real( 8.6857070597134090e-01, 2.7192781689782903e-19, + -1.6710140396932428e-35, -1.2625514734637969e-51), + qd_real( 8.6704624551569265e-01, 3.0267859550930567e-18, + -1.1559438782171572e-34, -5.3580556397808012e-52), + qd_real( 8.6551362409056909e-01, -6.3723113549628899e-18, + 2.3725520321746832e-34, 1.5911880348395175e-50), + qd_real( 8.6397285612158670e-01, 4.1486355957361607e-17, + 2.2709976932210266e-33, -8.1228385659479984e-50), + qd_real( 8.6242395611104050e-01, 3.7008992527383130e-17, + 5.2128411542701573e-34, 2.6945600081026861e-50), + qd_real( 8.6086693863776731e-01, -3.0050048898573656e-17, + -8.8706183090892111e-34, 1.5005320558097301e-50), + qd_real( 8.5930181835700836e-01, 4.2435655816850687e-17, + 7.6181814059912025e-34, -3.9592127850658708e-50), + qd_real( 8.5772861000027212e-01, -4.8183447936336620e-17, + -1.1044130517687532e-33, -8.7400233444645562e-50), + qd_real( 8.5614732837519447e-01, 9.1806925616606261e-18, + 5.6328649785951470e-34, 2.3326646113217378e-51), + qd_real( 8.5455798836540053e-01, -1.2991124236396092e-17, + 1.2893407722948080e-34, -3.6506925747583053e-52), + qd_real( 8.5296060493036363e-01, 2.7152984251981370e-17, + 7.4336483283120719e-34, 4.2162417622350668e-50), + qd_real( 8.5135519310526520e-01, -5.3279874446016209e-17, + 2.2281156380919942e-33, -4.0281886404138477e-50), + qd_real( 8.4974176800085244e-01, 5.1812347659974015e-17, + 3.0810626087331275e-33, -2.5931308201994965e-50), + qd_real( 8.4812034480329723e-01, 1.8762563415239981e-17, + 1.4048773307919617e-33, -2.4915221509958691e-50), + qd_real( 8.4649093877405213e-01, -4.7969419958569345e-17, + -2.7518267097886703e-33, -7.3518959727313350e-50), + qd_real( 8.4485356524970712e-01, -4.3631360296879637e-17, + -2.0307726853367547e-33, 4.3097229819851761e-50), + qd_real( 8.4320823964184544e-01, 9.6536707005959077e-19, + 2.8995142431556364e-36, 9.6715076811480284e-53), + qd_real( 8.4155497743689844e-01, -3.4095465391321557e-17, + -8.4130208607579595e-34, -4.9447283960568686e-50), + qd_real( 8.3989379419599952e-01, -1.6673694881511411e-17, + -1.4759184141750289e-33, -7.5795098161914058e-50), + qd_real( 8.3822470555483808e-01, -3.5560085052855026e-17, + 1.1689791577022643e-33, -5.8627347359723411e-50), + qd_real( 8.3654772722351201e-01, -2.0899059027066533e-17, + -9.8104097821002585e-35, -3.1609177868229853e-51), + qd_real( 8.3486287498638001e-01, 4.6048430609159657e-17, + -5.1827423265239912e-34, -7.0505343435504109e-51), + qd_real( 8.3317016470191319e-01, 1.3275129507229764e-18, + 4.8589164115370863e-35, 4.5422281300506859e-51), + qd_real( 8.3146961230254524e-01, 1.4073856984728024e-18, + 4.6951315383980830e-35, 5.1431906049905658e-51), + qd_real( 8.2976123379452305e-01, -2.9349109376485597e-18, + 1.1496917934149818e-34, 3.5186665544980233e-51), + qd_real( 8.2804504525775580e-01, -4.4196593225871532e-17, + 2.7967864855211251e-33, 1.0030777287393502e-49), + qd_real( 8.2632106284566353e-01, -5.3957485453612902e-17, + 6.8976896130138550e-34, 3.8106164274199196e-50), + qd_real( 8.2458930278502529e-01, -2.6512360488868275e-17, + 1.6916964350914386e-34, 6.7693974813562649e-51), + qd_real( 8.2284978137582632e-01, 1.5193019034505495e-17, + 9.6890547246521685e-34, 5.6994562923653264e-50), + qd_real( 8.2110251499110465e-01, 3.0715131609697682e-17, + -1.7037168325855879e-33, -1.1149862443283853e-49), + qd_real( 8.1934752007679701e-01, -4.8200736995191133e-17, + -1.5574489646672781e-35, -9.5647853614522216e-53), + qd_real( 8.1758481315158371e-01, -1.4883149812426772e-17, + -7.8273262771298917e-34, 4.1332149161031594e-50), + qd_real( 8.1581441080673378e-01, 8.2652693782130871e-18, + -2.3028778135179471e-34, 1.5102071387249843e-50), + qd_real( 8.1403632970594841e-01, -5.2127351877042624e-17, + -1.9047670611316360e-33, -1.6937269585941507e-49), + qd_real( 8.1225058658520388e-01, 3.1054545609214803e-17, + 2.2649541922707251e-34, -7.4221684154649405e-51), + qd_real( 8.1045719825259477e-01, 2.3520367349840499e-17, + -7.7530070904846341e-34, -7.2792616357197140e-50), + qd_real( 8.0865618158817498e-01, 9.3251597879721674e-18, + -7.1823301933068394e-34, 2.3925440846132106e-50), + qd_real( 8.0684755354379922e-01, 4.9220603766095546e-17, + 2.9796016899903487e-33, 1.5220754223615788e-49), + qd_real( 8.0503133114296355e-01, 5.1368289568212149e-17, + 6.3082807402256524e-34, 7.3277646085129827e-51), + qd_real( 8.0320753148064494e-01, -3.3060609804814910e-17, + -1.2242726252420433e-33, 2.8413673268630117e-50), + qd_real( 8.0137617172314024e-01, -2.0958013413495834e-17, + -4.3798162198006931e-34, 2.0235690497752515e-50), + qd_real( 7.9953726910790501e-01, 2.0356723822005431e-17, + -9.7448513696896360e-34, 5.3608109599696008e-52), + qd_real( 7.9769084094339116e-01, -4.6730759884788944e-17, + 2.3075897077191757e-33, 3.1605567774640253e-51), + qd_real( 7.9583690460888357e-01, -3.0062724851910721e-17, + -2.2496210832042235e-33, -6.5881774117183040e-50), + qd_real( 7.9397547755433717e-01, -7.4194631759921416e-18, + 2.4124341304631069e-34, -4.9956808616244972e-51), + qd_real( 7.9210657730021239e-01, -3.7087850202326467e-17, + -1.4874457267228264e-33, 2.9323097289153505e-50), + qd_real( 7.9023022143731003e-01, 2.3056905954954492e-17, + 1.4481080533260193e-33, -7.6725237057203488e-50), + qd_real( 7.8834642762660623e-01, 3.4396993154059708e-17, + 1.7710623746737170e-33, 1.7084159098417402e-49), + qd_real( 7.8645521359908577e-01, -9.7841429939305265e-18, + 3.3906063272445472e-34, 5.7269505320382577e-51), + qd_real( 7.8455659715557524e-01, -8.5627965423173476e-18, + -2.1106834459001849e-34, -1.6890322182469603e-50), + qd_real( 7.8265059616657573e-01, 9.0745866975808825e-18, + 6.7623847404278666e-34, -1.7173237731987271e-50), + qd_real( 7.8073722857209449e-01, -9.9198782066678806e-18, + -2.1265794012162715e-36, 3.0772165598957647e-54), + qd_real( 7.7881651238147598e-01, -2.4891385579973807e-17, + 6.7665497024807980e-35, -6.5218594281701332e-52), + qd_real( 7.7688846567323244e-01, 7.7418602570672864e-18, + -5.9986517872157897e-34, 3.0566548232958972e-50), + qd_real( 7.7495310659487393e-01, -5.2209083189826433e-17, + -9.6653593393686612e-34, 3.7027750076562569e-50), + qd_real( 7.7301045336273699e-01, -3.2565907033649772e-17, + 1.3860807251523929e-33, -3.9971329917586022e-50), + qd_real( 7.7106052426181382e-01, -4.4558442347769265e-17, + -2.9863565614083783e-33, -6.8795262083596236e-50), + qd_real( 7.6910333764557959e-01, 5.1546455184564817e-17, + 2.6142829553524292e-33, -1.6199023632773298e-49), + qd_real( 7.6713891193582040e-01, -1.8885903683750782e-17, + -1.3659359331495433e-33, -2.2538834962921934e-50), + qd_real( 7.6516726562245896e-01, -3.2707225612534598e-17, + 1.1177117747079528e-33, -3.7005182280175715e-50), + qd_real( 7.6318841726338127e-01, 2.6314748416750748e-18, + 1.4048039063095910e-34, 8.9601886626630321e-52), + qd_real( 7.6120238548426178e-01, 3.5315510881690551e-17, + 1.2833566381864357e-33, 8.6221435180890613e-50), + qd_real( 7.5920918897838807e-01, -3.8558842175523123e-17, + 2.9720241208332759e-34, -1.2521388928220163e-50), + qd_real( 7.5720884650648457e-01, -1.9909098777335502e-17, + 3.9409283266158482e-34, 2.0744254207802976e-50), + qd_real( 7.5520137689653655e-01, -1.9402238001823017e-17, + -3.7756206444727573e-34, -2.1212242308178287e-50), + qd_real( 7.5318679904361252e-01, -3.7937789838736540e-17, + -6.7009539920231559e-34, -6.7128562115050214e-51), + qd_real( 7.5116513190968637e-01, 4.3499761158645868e-17, + 2.5227718971102212e-33, -6.5969709212757102e-50), + qd_real( 7.4913639452345937e-01, -4.4729078447011889e-17, + -2.4206025249983768e-33, 1.1336681351116422e-49), + qd_real( 7.4710060598018013e-01, 1.1874824875965430e-17, + 2.1992523849833518e-34, 1.1025018564644483e-50), + qd_real( 7.4505778544146595e-01, 1.5078686911877863e-17, + 8.0898987212942471e-34, 8.2677958765323532e-50), + qd_real( 7.4300795213512172e-01, -2.5144629669719265e-17, + 7.1128989512526157e-34, 3.0181629077821220e-50), + qd_real( 7.4095112535495911e-01, -1.4708616952297345e-17, + -4.9550433827142032e-34, 3.1434132533735671e-50), + qd_real( 7.3888732446061511e-01, 3.4324874808225091e-17, + -1.3706639444717610e-33, -3.3520827530718938e-51), + qd_real( 7.3681656887736990e-01, -2.8932468101656295e-17, + -3.4649887126202378e-34, -1.8484474476291476e-50), + qd_real( 7.3473887809596350e-01, -3.4507595976263941e-17, + -2.3718000676666409e-33, -3.9696090387165402e-50), + qd_real( 7.3265427167241282e-01, 1.8918673481573520e-17, + -1.5123719544119886e-33, -9.7922152011625728e-51), + qd_real( 7.3056276922782759e-01, -2.9689959904476928e-17, + -1.1276871244239744e-33, -3.0531520961539007e-50), + qd_real( 7.2846439044822520e-01, 1.1924642323370718e-19, + 5.9001892316611011e-36, 1.2178089069502704e-52), + qd_real( 7.2635915508434601e-01, -3.1917502443460542e-17, + 7.7047912412039396e-34, 4.1455880160182123e-50), + qd_real( 7.2424708295146689e-01, 2.9198471334403004e-17, + 2.3027324968739464e-33, -1.2928820533892183e-51), + qd_real( 7.2212819392921535e-01, -2.3871262053452047e-17, + 1.0636125432862273e-33, -4.4598638837802517e-50), + qd_real( 7.2000250796138165e-01, -2.5689658854462333e-17, + -9.1492566948567925e-34, 4.4403780801267786e-50), + qd_real( 7.1787004505573171e-01, 2.7006476062511453e-17, + -2.2854956580215348e-34, 9.1726903890287867e-51), + qd_real( 7.1573082528381871e-01, -5.1581018476410262e-17, + -1.3736271349300259e-34, -1.2734611344111297e-50), + qd_real( 7.1358486878079364e-01, -4.2342504403133584e-17, + -4.2690366101617268e-34, -2.6352370883066522e-50), + qd_real( 7.1143219574521643e-01, 7.9643298613856813e-18, + 2.9488239510721469e-34, 1.6985236437666356e-50), + qd_real( 7.0927282643886569e-01, -3.7597359110245730e-17, + 1.0613125954645119e-34, 8.9465480185486032e-51), + qd_real( 7.0710678118654757e-01, -4.8336466567264567e-17, + 2.0693376543497068e-33, 2.4677734957341755e-50) +}; + +/* Computes sin(a) and cos(a) using Taylor series. + Assumes |a| <= pi/2048. */ +static void sincos_taylor(const qd_real &a, + qd_real &sin_a, qd_real &cos_a) { + const double thresh = 0.5 * qd_real::_eps * std::abs(to_double(a)); + qd_real p, s, t, x; + + if (a.is_zero()) { + sin_a = 0.0; + cos_a = 1.0; + return; + } + + x = -sqr(a); + s = a; + p = a; + int i = 0; + do { + p *= x; + t = p * inv_fact[i]; + s += t; + i += 2; + } while (i < n_inv_fact && std::abs(to_double(t)) > thresh); + + sin_a = s; + cos_a = sqrt(1.0 - sqr(s)); +} + +static qd_real sin_taylor(const qd_real &a) { + const double thresh = 0.5 * qd_real::_eps * std::abs(to_double(a)); + qd_real p, s, t, x; + + if (a.is_zero()) { + return 0.0; + } + + x = -sqr(a); + s = a; + p = a; + int i = 0; + do { + p *= x; + t = p * inv_fact[i]; + s += t; + i += 2; + } while (i < n_inv_fact && std::abs(to_double(t)) > thresh); + + return s; +} + +static qd_real cos_taylor(const qd_real &a) { + const double thresh = 0.5 * qd_real::_eps; + qd_real p, s, t, x; + + if (a.is_zero()) { + return 1.0; + } + + x = -sqr(a); + s = 1.0 + mul_pwr2(x, 0.5); + p = x; + int i = 1; + do { + p *= x; + t = p * inv_fact[i]; + s += t; + i += 2; + } while (i < n_inv_fact && std::abs(to_double(t)) > thresh); + + return s; +} + +qd_real sin(const qd_real &a) { + + /* Strategy. To compute sin(x), we choose integers a, b so that + + x = s + a * (pi/2) + b * (pi/1024) + + and |s| <= pi/2048. Using a precomputed table of + sin(k pi / 1024) and cos(k pi / 1024), we can compute + sin(x) from sin(s) and cos(s). This greatly increases the + convergence of the sine Taylor series. */ + + if (a.is_zero()) { + return 0.0; + } + + // approximately reduce modulo 2*pi + qd_real z = nint(a / qd_real::_2pi); + qd_real r = a - qd_real::_2pi * z; + + // approximately reduce modulo pi/2 and then modulo pi/1024 + double q = std::floor(r.x[0] / qd_real::_pi2[0] + 0.5); + qd_real t = r - qd_real::_pi2 * q; + int j = static_cast(q); + q = std::floor(t.x[0] / _pi1024[0] + 0.5); + t -= _pi1024 * q; + int k = static_cast(q); + int abs_k = std::abs(k); + + if (j < -2 || j > 2) { + qd_real::error("(qd_real::sin): Cannot reduce modulo pi/2."); + return qd_real::_nan; + } + + if (abs_k > 256) { + qd_real::error("(qd_real::sin): Cannot reduce modulo pi/1024."); + return qd_real::_nan; + } + + if (k == 0) { + switch (j) { + case 0: + return sin_taylor(t); + case 1: + return cos_taylor(t); + case -1: + return -cos_taylor(t); + default: + return -sin_taylor(t); + } + } + + qd_real sin_t, cos_t; + qd_real u = cos_table[abs_k-1]; + qd_real v = sin_table[abs_k-1]; + sincos_taylor(t, sin_t, cos_t); + + if (j == 0) { + if (k > 0) { + r = u * sin_t + v * cos_t; + } else { + r = u * sin_t - v * cos_t; + } + } else if (j == 1) { + if (k > 0) { + r = u * cos_t - v * sin_t; + } else { + r = u * cos_t + v * sin_t; + } + } else if (j == -1) { + if (k > 0) { + r = v * sin_t - u * cos_t; + } else { + r = - u * cos_t - v * sin_t; + } + } else { + if (k > 0) { + r = - u * sin_t - v * cos_t; + } else { + r = v * cos_t - u * sin_t; + } + } + + return r; +} + +qd_real cos(const qd_real &a) { + + if (a.is_zero()) { + return 1.0; + } + + // approximately reduce modulo 2*pi + qd_real z = nint(a / qd_real::_2pi); + qd_real r = a - qd_real::_2pi * z; + + // approximately reduce modulo pi/2 and then modulo pi/1024 + double q = std::floor(r.x[0] / qd_real::_pi2.x[0] + 0.5); + qd_real t = r - qd_real::_pi2 * q; + int j = static_cast(q); + q = std::floor(t.x[0] / _pi1024.x[0] + 0.5); + t -= _pi1024 * q; + int k = static_cast(q); + int abs_k = std::abs(k); + + if (j < -2 || j > 2) { + qd_real::error("(qd_real::cos): Cannot reduce modulo pi/2."); + return qd_real::_nan; + } + + if (abs_k > 256) { + qd_real::error("(qd_real::cos): Cannot reduce modulo pi/1024."); + return qd_real::_nan; + } + + if (k == 0) { + switch (j) { + case 0: + return cos_taylor(t); + case 1: + return -sin_taylor(t); + case -1: + return sin_taylor(t); + default: + return -cos_taylor(t); + } + } + + qd_real sin_t, cos_t; + sincos_taylor(t, sin_t, cos_t); + + qd_real u = cos_table[abs_k-1]; + qd_real v = sin_table[abs_k-1]; + + if (j == 0) { + if (k > 0) { + r = u * cos_t - v * sin_t; + } else { + r = u * cos_t + v * sin_t; + } + } else if (j == 1) { + if (k > 0) { + r = - u * sin_t - v * cos_t; + } else { + r = v * cos_t - u * sin_t; + } + } else if (j == -1) { + if (k > 0) { + r = u * sin_t + v * cos_t; + } else { + r = u * sin_t - v * cos_t; + } + } else { + if (k > 0) { + r = v * sin_t - u * cos_t; + } else { + r = - u * cos_t - v * sin_t; + } + } + + return r; +} + +void sincos(const qd_real &a, qd_real &sin_a, qd_real &cos_a) { + + if (a.is_zero()) { + sin_a = 0.0; + cos_a = 1.0; + return; + } + + // approximately reduce by 2*pi + qd_real z = nint(a / qd_real::_2pi); + qd_real t = a - qd_real::_2pi * z; + + // approximately reduce by pi/2 and then by pi/1024. + double q = std::floor(t.x[0] / qd_real::_pi2.x[0] + 0.5); + t -= qd_real::_pi2 * q; + int j = static_cast(q); + q = std::floor(t.x[0] / _pi1024.x[0] + 0.5); + t -= _pi1024 * q; + int k = static_cast(q); + int abs_k = std::abs(k); + + if (j < -2 || j > 2) { + qd_real::error("(qd_real::sincos): Cannot reduce modulo pi/2."); + cos_a = sin_a = qd_real::_nan; + return; + } + + if (abs_k > 256) { + qd_real::error("(qd_real::sincos): Cannot reduce modulo pi/1024."); + cos_a = sin_a = qd_real::_nan; + return; + } + + qd_real sin_t, cos_t; + sincos_taylor(t, sin_t, cos_t); + + if (k == 0) { + if (j == 0) { + sin_a = sin_t; + cos_a = cos_t; + } else if (j == 1) { + sin_a = cos_t; + cos_a = -sin_t; + } else if (j == -1) { + sin_a = -cos_t; + cos_a = sin_t; + } else { + sin_a = -sin_t; + cos_a = -cos_t; + } + return; + } + + qd_real u = cos_table[abs_k-1]; + qd_real v = sin_table[abs_k-1]; + + if (j == 0) { + if (k > 0) { + sin_a = u * sin_t + v * cos_t; + cos_a = u * cos_t - v * sin_t; + } else { + sin_a = u * sin_t - v * cos_t; + cos_a = u * cos_t + v * sin_t; + } + } else if (j == 1) { + if (k > 0) { + cos_a = - u * sin_t - v * cos_t; + sin_a = u * cos_t - v * sin_t; + } else { + cos_a = v * cos_t - u * sin_t; + sin_a = u * cos_t + v * sin_t; + } + } else if (j == -1) { + if (k > 0) { + cos_a = u * sin_t + v * cos_t; + sin_a = v * sin_t - u * cos_t; + } else { + cos_a = u * sin_t - v * cos_t; + sin_a = - u * cos_t - v * sin_t; + } + } else { + if (k > 0) { + sin_a = - u * sin_t - v * cos_t; + cos_a = v * sin_t - u * cos_t; + } else { + sin_a = v * cos_t - u * sin_t; + cos_a = - u * cos_t - v * sin_t; + } + } +} + +qd_real atan(const qd_real &a) { + return atan2(a, qd_real(1.0)); +} + +qd_real atan2(const qd_real &y, const qd_real &x) { + /* Strategy: Instead of using Taylor series to compute + arctan, we instead use Newton's iteration to solve + the equation + + sin(z) = y/r or cos(z) = x/r + + where r = sqrt(x^2 + y^2). + The iteration is given by + + z' = z + (y - sin(z)) / cos(z) (for equation 1) + z' = z - (x - cos(z)) / sin(z) (for equation 2) + + Here, x and y are normalized so that x^2 + y^2 = 1. + If |x| > |y|, then first iteration is used since the + denominator is larger. Otherwise, the second is used. + */ + + if (x.is_zero()) { + + if (y.is_zero()) { + /* Both x and y is zero. */ + qd_real::error("(qd_real::atan2): Both arguments zero."); + return qd_real::_nan; + } + + return (y.is_positive()) ? qd_real::_pi2 : -qd_real::_pi2; + } else if (y.is_zero()) { + return (x.is_positive()) ? qd_real(0.0) : qd_real::_pi; + } + + if (x == y) { + return (y.is_positive()) ? qd_real::_pi4 : -qd_real::_3pi4; + } + + if (x == -y) { + return (y.is_positive()) ? qd_real::_3pi4 : -qd_real::_pi4; + } + + qd_real r = sqrt(sqr(x) + sqr(y)); + qd_real xx = x / r; + qd_real yy = y / r; + + /* Compute double precision approximation to atan. */ + qd_real z = std::atan2(to_double(y), to_double(x)); + qd_real sin_z, cos_z; + + if (std::abs(xx.x[0]) > std::abs(yy.x[0])) { + /* Use Newton iteration 1. z' = z + (y - sin(z)) / cos(z) */ + sincos(z, sin_z, cos_z); + z += (yy - sin_z) / cos_z; + sincos(z, sin_z, cos_z); + z += (yy - sin_z) / cos_z; + sincos(z, sin_z, cos_z); + z += (yy - sin_z) / cos_z; + } else { + /* Use Newton iteration 2. z' = z - (x - cos(z)) / sin(z) */ + sincos(z, sin_z, cos_z); + z -= (xx - cos_z) / sin_z; + sincos(z, sin_z, cos_z); + z -= (xx - cos_z) / sin_z; + sincos(z, sin_z, cos_z); + z -= (xx - cos_z) / sin_z; + } + + return z; +} + + +qd_real drem(const qd_real &a, const qd_real &b) { + qd_real n = nint(a/b); + return (a - n * b); +} + +qd_real divrem(const qd_real &a, const qd_real &b, qd_real &r) { + qd_real n = nint(a/b); + r = a - n * b; + return n; +} + +qd_real tan(const qd_real &a) { + qd_real s, c; + sincos(a, s, c); + return s/c; +} + +qd_real asin(const qd_real &a) { + qd_real abs_a = abs(a); + + if (abs_a > 1.0) { + qd_real::error("(qd_real::asin): Argument out of domain."); + return qd_real::_nan; + } + + if (abs_a.is_one()) { + return (a.is_positive()) ? qd_real::_pi2 : -qd_real::_pi2; + } + + return atan2(a, sqrt(1.0 - sqr(a))); +} + +qd_real acos(const qd_real &a) { + qd_real abs_a = abs(a); + + if (abs_a > 1.0) { + qd_real::error("(qd_real::acos): Argument out of domain."); + return qd_real::_nan; + } + + if (abs_a.is_one()) { + return (a.is_positive()) ? qd_real(0.0) : qd_real::_pi; + } + + return atan2(sqrt(1.0 - sqr(a)), a); +} + +qd_real sinh(const qd_real &a) { + if (a.is_zero()) { + return 0.0; + } + + if (abs(a) > 0.05) { + qd_real ea = exp(a); + return mul_pwr2(ea - inv(ea), 0.5); + } + + /* Since a is small, using the above formula gives + a lot of cancellation. So use Taylor series. */ + qd_real s = a; + qd_real t = a; + qd_real r = sqr(t); + double m = 1.0; + double thresh = std::abs(to_double(a) * qd_real::_eps); + + do { + m += 2.0; + t *= r; + t /= (m-1) * m; + + s += t; + } while (abs(t) > thresh); + + return s; +} + +qd_real cosh(const qd_real &a) { + if (a.is_zero()) { + return 1.0; + } + + qd_real ea = exp(a); + return mul_pwr2(ea + inv(ea), 0.5); +} + +qd_real tanh(const qd_real &a) { + if (a.is_zero()) { + return 0.0; + } + + if (std::abs(to_double(a)) > 0.05) { + qd_real ea = exp(a); + qd_real inv_ea = inv(ea); + return (ea - inv_ea) / (ea + inv_ea); + } else { + qd_real s, c; + s = sinh(a); + c = sqrt(1.0 + sqr(s)); + return s / c; + } +} + +void sincosh(const qd_real &a, qd_real &s, qd_real &c) { + if (std::abs(to_double(a)) <= 0.05) { + s = sinh(a); + c = sqrt(1.0 + sqr(s)); + } else { + qd_real ea = exp(a); + qd_real inv_ea = inv(ea); + s = mul_pwr2(ea - inv_ea, 0.5); + c = mul_pwr2(ea + inv_ea, 0.5); + } +} + +qd_real asinh(const qd_real &a) { + return log(a + sqrt(sqr(a) + 1.0)); +} + +qd_real acosh(const qd_real &a) { + if (a < 1.0) { + qd_real::error("(qd_real::acosh): Argument out of domain."); + return qd_real::_nan; + } + + return log(a + sqrt(sqr(a) - 1.0)); +} + +qd_real atanh(const qd_real &a) { + if (abs(a) >= 1.0) { + qd_real::error("(qd_real::atanh): Argument out of domain."); + return qd_real::_nan; + } + + return mul_pwr2(log((1.0 + a) / (1.0 - a)), 0.5); +} + +QD_API qd_real fmod(const qd_real &a, const qd_real &b) { + qd_real n = aint(a / b); + return (a - b * n); +} + +QD_API qd_real qdrand() { + static const double m_const = 4.6566128730773926e-10; /* = 2^{-31} */ + double m = m_const; + qd_real r = 0.0; + double d; + + /* Strategy: Generate 31 bits at a time, using lrand48 + random number generator. Shift the bits, and repeat + 7 times. */ + + for (int i = 0; i < 7; i++, m *= m_const) { + d = std::rand() * m; + r += d; + } + + return r; +} + + +/* polyeval(c, n, x) + Evaluates the given n-th degree polynomial at x. + The polynomial is given by the array of (n+1) coefficients. */ +qd_real polyeval(const qd_real *c, int n, const qd_real &x) { + /* Just use Horner's method of polynomial evaluation. */ + qd_real r = c[n]; + + for (int i = n-1; i >= 0; i--) { + r *= x; + r += c[i]; + } + + return r; +} + +/* polyroot(c, n, x0) + Given an n-th degree polynomial, finds a root close to + the given guess x0. Note that this uses simple Newton + iteration scheme, and does not work for multiple roots. */ +QD_API qd_real polyroot(const qd_real *c, int n, + const qd_real &x0, int max_iter, double thresh) { + qd_real x = x0; + qd_real f; + qd_real *d = new qd_real[n]; + bool conv = false; + int i; + double max_c = std::abs(to_double(c[0])); + double v; + + if (thresh == 0.0) thresh = qd_real::_eps; + + /* Compute the coefficients of the derivatives. */ + for (i = 1; i <= n; i++) { + v = std::abs(to_double(c[i])); + if (v > max_c) max_c = v; + d[i-1] = c[i] * static_cast(i); + } + thresh *= max_c; + + /* Newton iteration. */ + for (i = 0; i < max_iter; i++) { + f = polyeval(c, n, x); + + if (abs(f) < thresh) { + conv = true; + break; + } + x -= (f / polyeval(d, n-1, x)); + } + delete [] d; + + if (!conv) { + qd_real::error("(qd_real::polyroot): Failed to converge."); + return qd_real::_nan; + } + + return x; +} + +qd_real qd_real::debug_rand() { + if (std::rand() % 2 == 0) + return qdrand(); + + int expn = 0; + qd_real a = 0.0; + double d; + for (int i = 0; i < 4; i++) { + d = std::ldexp(std::rand() / static_cast(RAND_MAX), -expn); + a += d; + expn = expn + 54 + std::rand() % 200; + } + return a; +} + diff --git a/external/PackedCSparse/qd/qd_real.h b/external/PackedCSparse/qd/qd_real.h new file mode 100644 index 000000000..1ecfc732c --- /dev/null +++ b/external/PackedCSparse/qd/qd_real.h @@ -0,0 +1,296 @@ +/* + * include/qd_real.h + * + * This work was supported by the Director, Office of Science, Division + * of Mathematical, Information, and Computational Sciences of the + * U.S. Department of Energy under contract number DE-AC03-76SF00098. + * + * Copyright (c) 2000-2007 + * + * Quad-double precision (>= 212-bit significand) floating point arithmetic + * package, written in ANSI C++, taking full advantage of operator overloading. + * Uses similar techniques as that of David Bailey's double-double package + * and that of Jonathan Shewchuk's adaptive precision floating point + * arithmetic package. See + * + * http://www.nersc.gov/~dhbailey/mpdist/mpdist.html + * http://www.cs.cmu.edu/~quake/robust.html + * + * for more details. + * + * Yozo Hida + */ +#ifndef _QD_QD_REAL_H +#define _QD_QD_REAL_H + +#include +#include +#include +#include "qd_config.h" +#include "dd_real.h" + +struct QD_API qd_real { + double x[4]; /* The Components. */ + + /* Eliminates any zeros in the middle component(s). */ + void zero_elim(); + void zero_elim(double &e); + + void renorm(); + void renorm(double &e); + + void quick_accum(double d, double &e); + void quick_prod_accum(double a, double b, double &e); + + qd_real(double x0, double x1, double x2, double x3); + explicit qd_real(const double *xx); + + static const qd_real _2pi; + static const qd_real _pi; + static const qd_real _3pi4; + static const qd_real _pi2; + static const qd_real _pi4; + static const qd_real _e; + static const qd_real _log2; + static const qd_real _log10; + static const qd_real _nan; + static const qd_real _inf; + + static const double _eps; + static const double _min_normalized; + static const qd_real _max; + static const qd_real _safe_max; + static const int _ndigits; + + qd_real(); + qd_real(const char *s); + qd_real(const dd_real &dd); + qd_real(double d); + qd_real(int i); + + double operator[](int i) const; + double &operator[](int i); + + static void error(const char *msg); + + bool isnan() const; + bool isfinite() const { return QD_ISFINITE(x[0]); } + bool isinf() const { return QD_ISINF(x[0]); } + + static qd_real ieee_add(const qd_real &a, const qd_real &b); + static qd_real sloppy_add(const qd_real &a, const qd_real &b); + + qd_real &operator+=(double a); + qd_real &operator+=(const dd_real &a); + qd_real &operator+=(const qd_real &a); + + qd_real &operator-=(double a); + qd_real &operator-=(const dd_real &a); + qd_real &operator-=(const qd_real &a); + + static qd_real sloppy_mul(const qd_real &a, const qd_real &b); + static qd_real accurate_mul(const qd_real &a, const qd_real &b); + + qd_real &operator*=(double a); + qd_real &operator*=(const dd_real &a); + qd_real &operator*=(const qd_real &a); + + static qd_real sloppy_div(const qd_real &a, const dd_real &b); + static qd_real accurate_div(const qd_real &a, const dd_real &b); + static qd_real sloppy_div(const qd_real &a, const qd_real &b); + static qd_real accurate_div(const qd_real &a, const qd_real &b); + + qd_real &operator/=(double a); + qd_real &operator/=(const dd_real &a); + qd_real &operator/=(const qd_real &a); + + qd_real operator^(int n) const; + + qd_real operator-() const; + + qd_real &operator=(double a); + qd_real &operator=(const dd_real &a); + qd_real &operator=(const char *s); + + bool is_zero() const; + bool is_one() const; + bool is_positive() const; + bool is_negative() const; + + explicit operator bool() const; // new + explicit operator double() const; // new + + static qd_real rand(void); + + void to_digits(char *s, int &expn, int precision = _ndigits) const; + void write(char *s, int len, int precision = _ndigits, + bool showpos = false, bool uppercase = false) const; + std::string to_string(int precision = _ndigits, int width = 0, + std::ios_base::fmtflags fmt = static_cast(0), + bool showpos = false, bool uppercase = false, char fill = ' ') const; + static int read(const char *s, qd_real &a); + + /* Debugging methods */ + void dump(const std::string &name, std::ostream &os = std::cerr) const; + void dump_bits(const std::string &name, + std::ostream &os = std::cerr) const; + + static qd_real debug_rand(); + +}; + +namespace std { + template <> + class numeric_limits : public numeric_limits { + public: + inline static double epsilon() { return qd_real::_eps; } + inline static double min() { return qd_real::_min_normalized; } + inline static qd_real max() { return qd_real::_max; } + inline static qd_real safe_max() { return qd_real::_safe_max; } + static const int digits = 209; + static const int digits10 = 62; + }; +} + +QD_API qd_real polyeval(const qd_real *c, int n, const qd_real &x); +QD_API qd_real polyroot(const qd_real *c, int n, + const qd_real &x0, int max_iter = 64, double thresh = 0.0); + +QD_API qd_real qdrand(void); +QD_API qd_real sqrt(const qd_real &a); + +QD_API inline bool isnan(const qd_real &a) { return a.isnan(); } +QD_API inline bool isfinite(const qd_real &a) { return a.isfinite(); } +QD_API inline bool isinf(const qd_real &a) { return a.isinf(); } + +/* Computes qd * d where d is known to be a power of 2. + This can be done component wise. */ +QD_API qd_real mul_pwr2(const qd_real &qd, double d); + +QD_API qd_real operator+(const qd_real &a, const qd_real &b); +QD_API qd_real operator+(const dd_real &a, const qd_real &b); +QD_API qd_real operator+(const qd_real &a, const dd_real &b); +QD_API qd_real operator+(const qd_real &a, double b); +QD_API qd_real operator+(double a, const qd_real &b); + +QD_API qd_real operator-(const qd_real &a, const qd_real &b); +QD_API qd_real operator-(const dd_real &a, const qd_real &b); +QD_API qd_real operator-(const qd_real &a, const dd_real &b); +QD_API qd_real operator-(const qd_real &a, double b); +QD_API qd_real operator-(double a, const qd_real &b); + +QD_API qd_real operator*(const qd_real &a, const qd_real &b); +QD_API qd_real operator*(const dd_real &a, const qd_real &b); +QD_API qd_real operator*(const qd_real &a, const dd_real &b); +QD_API qd_real operator*(const qd_real &a, double b); +QD_API qd_real operator*(double a, const qd_real &b); + +QD_API qd_real operator/(const qd_real &a, const qd_real &b); +QD_API qd_real operator/(const dd_real &a, const qd_real &b); +QD_API qd_real operator/(const qd_real &a, const dd_real &b); +QD_API qd_real operator/(const qd_real &a, double b); +QD_API qd_real operator/(double a, const qd_real &b); + +QD_API qd_real sqr(const qd_real &a); +QD_API qd_real sqrt(const qd_real &a); +QD_API qd_real pow(const qd_real &a, int n); +QD_API qd_real pow(const qd_real &a, const qd_real &b); +QD_API qd_real npwr(const qd_real &a, int n); + +QD_API qd_real nroot(const qd_real &a, int n); + +QD_API qd_real rem(const qd_real &a, const qd_real &b); +QD_API qd_real drem(const qd_real &a, const qd_real &b); +QD_API qd_real divrem(const qd_real &a, const qd_real &b, qd_real &r); + +dd_real to_dd_real(const qd_real &a); +double to_double(const qd_real &a); +int to_int(const qd_real &a); + +QD_API bool operator==(const qd_real &a, const qd_real &b); +QD_API bool operator==(const qd_real &a, const dd_real &b); +QD_API bool operator==(const dd_real &a, const qd_real &b); +QD_API bool operator==(double a, const qd_real &b); +QD_API bool operator==(const qd_real &a, double b); + +QD_API bool operator<(const qd_real &a, const qd_real &b); +QD_API bool operator<(const qd_real &a, const dd_real &b); +QD_API bool operator<(const dd_real &a, const qd_real &b); +QD_API bool operator<(double a, const qd_real &b); +QD_API bool operator<(const qd_real &a, double b); + +QD_API bool operator>(const qd_real &a, const qd_real &b); +QD_API bool operator>(const qd_real &a, const dd_real &b); +QD_API bool operator>(const dd_real &a, const qd_real &b); +QD_API bool operator>(double a, const qd_real &b); +QD_API bool operator>(const qd_real &a, double b); + +QD_API bool operator<=(const qd_real &a, const qd_real &b); +QD_API bool operator<=(const qd_real &a, const dd_real &b); +QD_API bool operator<=(const dd_real &a, const qd_real &b); +QD_API bool operator<=(double a, const qd_real &b); +QD_API bool operator<=(const qd_real &a, double b); + +QD_API bool operator>=(const qd_real &a, const qd_real &b); +QD_API bool operator>=(const qd_real &a, const dd_real &b); +QD_API bool operator>=(const dd_real &a, const qd_real &b); +QD_API bool operator>=(double a, const qd_real &b); +QD_API bool operator>=(const qd_real &a, double b); + +QD_API bool operator!=(const qd_real &a, const qd_real &b); +QD_API bool operator!=(const qd_real &a, const dd_real &b); +QD_API bool operator!=(const dd_real &a, const qd_real &b); +QD_API bool operator!=(double a, const qd_real &b); +QD_API bool operator!=(const qd_real &a, double b); + +QD_API qd_real fabs(const qd_real &a); +QD_API qd_real abs(const qd_real &a); /* same as fabs */ + +QD_API qd_real ldexp(const qd_real &a, int n); + +QD_API qd_real nint(const qd_real &a); +QD_API qd_real quick_nint(const qd_real &a); +QD_API qd_real floor(const qd_real &a); +QD_API qd_real ceil(const qd_real &a); +QD_API qd_real aint(const qd_real &a); + +QD_API qd_real sin(const qd_real &a); +QD_API qd_real cos(const qd_real &a); +QD_API qd_real tan(const qd_real &a); +QD_API void sincos(const qd_real &a, qd_real &s, qd_real &c); + +QD_API qd_real asin(const qd_real &a); +QD_API qd_real acos(const qd_real &a); +QD_API qd_real atan(const qd_real &a); +QD_API qd_real atan2(const qd_real &y, const qd_real &x); + +QD_API qd_real exp(const qd_real &a); +QD_API qd_real log(const qd_real &a); +QD_API qd_real log10(const qd_real &a); + +QD_API qd_real sinh(const qd_real &a); +QD_API qd_real cosh(const qd_real &a); +QD_API qd_real tanh(const qd_real &a); +QD_API void sincosh(const qd_real &a, qd_real &sin_qd, qd_real &cos_qd); + +QD_API qd_real asinh(const qd_real &a); +QD_API qd_real acosh(const qd_real &a); +QD_API qd_real atanh(const qd_real &a); + +QD_API qd_real qdrand(void); + +QD_API qd_real max(const qd_real &a, const qd_real &b); +QD_API qd_real max(const qd_real &a, const qd_real &b, const qd_real &c); +QD_API qd_real min(const qd_real &a, const qd_real &b); +QD_API qd_real min(const qd_real &a, const qd_real &b, const qd_real &c); + +QD_API qd_real fmod(const qd_real &a, const qd_real &b); + +QD_API std::ostream &operator<<(std::ostream &s, const qd_real &a); +QD_API std::istream &operator>>(std::istream &s, qd_real &a); +#ifdef QD_INLINE +#include "qd_inline.h" +#endif + +#endif /* _QD_QD_REAL_H */ + diff --git a/external/PackedCSparse/qd/util.cc b/external/PackedCSparse/qd/util.cc new file mode 100644 index 000000000..ab9620817 --- /dev/null +++ b/external/PackedCSparse/qd/util.cc @@ -0,0 +1,22 @@ +#include +#include "util.h" + +void append_expn(std::string &str, int expn) { + int k; + + str += (expn < 0 ? '-' : '+'); + expn = std::abs(expn); + + if (expn >= 100) { + k = (expn / 100); + str += '0' + k; + expn -= 100*k; + } + + k = (expn / 10); + str += '0' + k; + expn -= 10*k; + + str += '0' + expn; +} + diff --git a/external/PackedCSparse/qd/util.h b/external/PackedCSparse/qd/util.h new file mode 100644 index 000000000..7de358363 --- /dev/null +++ b/external/PackedCSparse/qd/util.h @@ -0,0 +1,4 @@ +#include + +void append_expn(std::string &str, int expn); + diff --git a/external/cmake-files/LPSolve.cmake b/external/cmake-files/LPSolve.cmake index b3f3cf98b..c5a173837 100644 --- a/external/cmake-files/LPSolve.cmake +++ b/external/cmake-files/LPSolve.cmake @@ -26,7 +26,7 @@ function(GetLPSolve) message(STATUS "lp_solve library found: ${LP_SOLVE_DIR}") endif() - + include_directories(${LP_SOLVE_DIR}) endfunction() diff --git a/external/cmake-files/QD.cmake b/external/cmake-files/QD.cmake index b65e4f51c..a2e3e5e6d 100644 --- a/external/cmake-files/QD.cmake +++ b/external/cmake-files/QD.cmake @@ -1,54 +1,18 @@ set(QD_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR}) function(GetQD) - find_path(QD_DIR NAMES config.h PATHS ${QD_CMAKE_DIR}/../_deps/qd-src/) - - if (NOT QD_DIR) - include(FetchContent) - set(FETCHCONTENT_BASE_DIR "${QD_CMAKE_DIR}/../_deps") - FetchContent_Declare( - qd - URL https://www.davidhbailey.com/dhbsoftware/qd-2.3.23.tar.gz - ) - - FetchContent_GetProperties(qd) - - if(NOT qd_POPULATED) - message(STATUS "QD library not found locally, downloading it.") - FetchContent_Populate(qd) - endif() - - set(QD_DIR "${qd_SOURCE_DIR}") - message(STATUS "Using downloaded QD at: ${QD_DIR}") - - else() - - message(STATUS "QD library found: ${QD_DIR}") - - endif() - - include_directories(BEFORE "${QD_DIR}/include/") - message(STATUS "configuring the QD library") - execute_process( - COMMAND ./configure - WORKING_DIRECTORY ${QD_DIR} - OUTPUT_FILE CMD_OUTPUT - RESULT_VARIABLE EXECUTE - ) - if(NOT ${EXECUTE} EQUAL "0") - message(FATAL_ERROR "./configure QD library failed") - endif() - - execute_process( - COMMAND make - WORKING_DIRECTORY ${QD_DIR} - OUTPUT_FILE qd_compilation.txt - RESULT_VARIABLE EXECUTE_MAKE - ) - - if(NOT ${EXECUTE_MAKE} EQUAL "0") - message(FATAL_ERROR "building the QD library failed") - endif() - - find_library(QD_LIB NAMES libqd.a PATHS "${QD_DIR}/src/.libs") + set(QD_DIR "${QD_CMAKE_DIR}/../PackedCSparse/qd") + include_directories(BEFORE "${QD_DIR}") + set(QD_SOURCES + ${QD_DIR}/bits.cc + ${QD_DIR}/c_dd.cc + ${QD_DIR}/c_qd.cc + ${QD_DIR}/dd_const.cc + ${QD_DIR}/dd_real.cc + ${QD_DIR}/fpu.cc + ${QD_DIR}/qd_const.cc + ${QD_DIR}/qd_real.cc + ${QD_DIR}/util.cc + ) + add_library(QD_LIB ${QD_SOURCES}) endfunction() diff --git a/external/cmake-files/lpsolve_modified_header_files/lp_rlp.h b/external/cmake-files/lpsolve_modified_header_files/lp_rlp.h new file mode 100644 index 000000000..058b45232 --- /dev/null +++ b/external/cmake-files/lpsolve_modified_header_files/lp_rlp.h @@ -0,0 +1,2460 @@ +// Copyright(c) 2016-2018 Kjell Konis . +// Version: 5.5.2.0-17 +// Description: The lpSolveAPI package provides an R interface to 'lp_solve', +// a Mixed Integer Linear Programming (MILP) solver with support for pure +// linear, (mixed) integer/binary, semi-continuous and special ordered sets +// (SOS) models. +// License: LGPL-2 +// Repository: CRAN + + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define lp_yyconst const +#else +#define lp_yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* lp_yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define lp_yyin lp_yyg->lp_yyin_r +#define lp_yyout lp_yyg->lp_yyout_r +#define lp_yyextra lp_yyg->lp_yyextra_r +#define lp_yyleng lp_yyg->lp_yyleng_r +#define lp_yytext lp_yyg->lp_yytext_r +#define lp_yylineno (YY_CURRENT_BUFFER_LVALUE->lp_yy_bs_lineno) +#define lp_yycolumn (YY_CURRENT_BUFFER_LVALUE->lp_yy_bs_column) +#define lp_yy_flex_debug lp_yyg->lp_yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN lp_yyg->lp_yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((lp_yyg->lp_yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE lp_yyrestart(lp_yyin ,lp_yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(lp_yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct lp_yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for lp_yy_rule_can_match_eol because it requires + * access to the local variable lp_yy_act. Since lp_yyless() is a macro, it would break + * existing scanners that call lp_yyless() from OUTSIDE lp_yylex. + * One obvious solution it to make lp_yy_act a global. I tried that, and saw + * a 5% performance hit in a non-lp_yylineno scanner, because lp_yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int lp_yyl;\ + for ( lp_yyl = n; lp_yyl < lp_yyleng; ++lp_yyl )\ + if ( lp_yytext[lp_yyl] == '\n' )\ + --lp_yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define lp_yyless(n) \ + do \ + { \ + /* Undo effects of setting up lp_yytext. */ \ + int lp_yyless_macro_arg = (n); \ + YY_LESS_LINENO(lp_yyless_macro_arg);\ + *lp_yy_cp = lp_yyg->lp_yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + lp_yyg->lp_yy_c_buf_p = lp_yy_cp = lp_yy_bp + lp_yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up lp_yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) lp_yyunput( c, lp_yyg->lp_yytext_ptr , lp_yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t lp_yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct lp_yy_buffer_state + { + FILE *lp_yy_input_file; + + char *lp_yy_ch_buf; /* input buffer */ + char *lp_yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + lp_yy_size_t lp_yy_buf_size; + + /* Number of characters read into lp_yy_ch_buf, not including EOB + * characters. + */ + int lp_yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int lp_yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int lp_yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int lp_yy_at_bol; + + int lp_yy_bs_lineno; /**< The line count. */ + int lp_yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int lp_yy_fill_buffer; + + int lp_yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via lp_yyrestart()), so that the user can continue scanning by + * just pointing lp_yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( lp_yyg->lp_yy_buffer_stack \ + ? lp_yyg->lp_yy_buffer_stack[lp_yyg->lp_yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE lp_yyg->lp_yy_buffer_stack[lp_yyg->lp_yy_buffer_stack_top] + +void lp_yyrestart (FILE *input_file ,lp_yyscan_t lp_yyscanner ); +void lp_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,lp_yyscan_t lp_yyscanner ); +YY_BUFFER_STATE lp_yy_create_buffer (FILE *file,int size ,lp_yyscan_t lp_yyscanner ); +void lp_yy_delete_buffer (YY_BUFFER_STATE b ,lp_yyscan_t lp_yyscanner ); +void lp_yy_flush_buffer (YY_BUFFER_STATE b ,lp_yyscan_t lp_yyscanner ); +void lp_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,lp_yyscan_t lp_yyscanner ); +void lp_yypop_buffer_state (lp_yyscan_t lp_yyscanner ); + +static void lp_yyensure_buffer_stack (lp_yyscan_t lp_yyscanner ); +static void lp_yy_load_buffer_state (lp_yyscan_t lp_yyscanner ); +static void lp_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,lp_yyscan_t lp_yyscanner ); + +#define YY_FLUSH_BUFFER lp_yy_flush_buffer(YY_CURRENT_BUFFER ,lp_yyscanner) + +YY_BUFFER_STATE lp_yy_scan_buffer (char *base,lp_yy_size_t size ,lp_yyscan_t lp_yyscanner ); +YY_BUFFER_STATE lp_yy_scan_string (lp_yyconst char *lp_yy_str ,lp_yyscan_t lp_yyscanner ); +YY_BUFFER_STATE lp_yy_scan_bytes (lp_yyconst char *bytes,int len ,lp_yyscan_t lp_yyscanner ); + +void *lp_yyalloc (lp_yy_size_t ,lp_yyscan_t lp_yyscanner ); +void *lp_yyrealloc (void *,lp_yy_size_t ,lp_yyscan_t lp_yyscanner ); +void lp_yyfree (void * ,lp_yyscan_t lp_yyscanner ); + +#define lp_yy_new_buffer lp_yy_create_buffer + +#define lp_yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + lp_yyensure_buffer_stack (lp_yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + lp_yy_create_buffer(lp_yyin,YY_BUF_SIZE ,lp_yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->lp_yy_is_interactive = is_interactive; \ + } + +#define lp_yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + lp_yyensure_buffer_stack (lp_yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + lp_yy_create_buffer(lp_yyin,YY_BUF_SIZE ,lp_yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->lp_yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->lp_yy_at_bol) + +/* Begin user sect3 */ + +#define lp_yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int lp_yy_state_type; + +#define lp_yytext_ptr lp_yytext_r + +static lp_yy_state_type lp_yy_get_previous_state (lp_yyscan_t lp_yyscanner ); +static lp_yy_state_type lp_yy_try_NUL_trans (lp_yy_state_type current_state ,lp_yyscan_t lp_yyscanner); +static int lp_yy_get_next_buffer (lp_yyscan_t lp_yyscanner ); +static void lp_yy_fatal_error (lp_yyconst char msg[] ,lp_yyscan_t lp_yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up lp_yytext. + */ +#define YY_DO_BEFORE_ACTION \ + lp_yyg->lp_yytext_ptr = lp_yy_bp; \ + lp_yyleng = (size_t) (lp_yy_cp - lp_yy_bp); \ + lp_yyg->lp_yy_hold_char = *lp_yy_cp; \ + *lp_yy_cp = '\0'; \ + lp_yyg->lp_yy_c_buf_p = lp_yy_cp; + +#define YY_NUM_RULES 33 +#define YY_END_OF_BUFFER 34 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct lp_yy_trans_info + { + flex_int32_t lp_yy_verify; + flex_int32_t lp_yy_nxt; + }; +static lp_yyconst flex_int16_t lp_yy_accept[144] = + { 0, + 0, 0, 0, 0, 0, 0, 34, 32, 10, 10, + 27, 17, 11, 32, 32, 14, 26, 31, 29, 28, + 30, 25, 25, 10, 25, 25, 25, 25, 3, 4, + 3, 3, 9, 7, 8, 10, 17, 17, 0, 15, + 1, 6, 15, 14, 0, 29, 30, 0, 25, 24, + 0, 25, 25, 10, 0, 0, 0, 0, 25, 25, + 25, 25, 25, 2, 0, 15, 0, 15, 22, 0, + 25, 25, 0, 0, 0, 0, 0, 19, 25, 18, + 20, 25, 25, 21, 0, 25, 0, 13, 25, 0, + 12, 25, 19, 0, 18, 20, 21, 25, 23, 25, + + 20, 21, 21, 16, 16, 0, 25, 25, 0, 23, + 0, 21, 25, 25, 0, 0, 25, 25, 0, 0, + 19, 25, 0, 0, 25, 25, 19, 0, 18, 0, + 0, 25, 25, 18, 0, 0, 0, 0, 0, 0, + 0, 0, 0 + } ; + +static lp_yyconst flex_int32_t lp_yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 5, 6, 5, 5, 5, 1, + 1, 7, 8, 9, 10, 11, 12, 13, 14, 14, + 13, 13, 13, 13, 13, 13, 13, 15, 16, 17, + 18, 19, 1, 5, 20, 21, 22, 23, 24, 25, + 26, 23, 27, 23, 23, 23, 28, 29, 30, 23, + 23, 31, 32, 33, 34, 23, 23, 35, 36, 37, + 5, 1, 5, 5, 5, 1, 20, 21, 22, 23, + + 24, 25, 26, 23, 27, 23, 23, 23, 28, 29, + 30, 23, 23, 31, 32, 33, 34, 23, 23, 35, + 36, 37, 5, 1, 5, 5, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static lp_yyconst flex_int32_t lp_yy_meta[38] = + { 0, + 1, 2, 3, 3, 4, 5, 6, 3, 6, 3, + 5, 5, 5, 5, 7, 6, 7, 6, 6, 4, + 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4 + } ; + +static lp_yyconst flex_int16_t lp_yy_base[150] = + { 0, + 0, 36, 36, 38, 43, 45, 366, 388, 48, 62, + 388, 338, 388, 40, 48, 60, 388, 388, 346, 388, + 326, 60, 65, 91, 81, 74, 85, 102, 388, 388, + 388, 330, 388, 388, 388, 125, 313, 134, 308, 96, + 388, 388, 117, 132, 139, 388, 388, 88, 146, 320, + 0, 149, 152, 0, 307, 301, 294, 83, 153, 156, + 157, 189, 160, 388, 286, 126, 65, 108, 388, 289, + 181, 185, 272, 273, 250, 249, 220, 199, 203, 208, + 192, 211, 219, 227, 243, 109, 163, 225, 202, 174, + 224, 215, 213, 207, 191, 388, 189, 227, 228, 231, + + 244, 240, 253, 276, 388, 170, 260, 262, 166, 388, + 169, 179, 263, 241, 166, 159, 270, 272, 149, 155, + 284, 288, 130, 124, 296, 303, 388, 103, 300, 96, + 45, 324, 328, 388, 82, 311, 79, 68, 54, 56, + 25, 12, 388, 345, 353, 360, 367, 372, 379 + } ; + +static lp_yyconst flex_int16_t lp_yy_def[150] = + { 0, + 143, 1, 144, 144, 145, 145, 143, 143, 143, 143, + 143, 146, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 147, 147, 143, 147, 147, 147, 147, 143, 143, + 143, 143, 143, 143, 143, 143, 146, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 147, 143, + 148, 147, 147, 24, 143, 143, 143, 143, 147, 147, + 147, 147, 147, 143, 143, 143, 143, 143, 143, 148, + 147, 147, 143, 143, 143, 143, 143, 147, 147, 147, + 147, 147, 147, 147, 149, 143, 143, 143, 62, 143, + 143, 62, 143, 143, 143, 143, 143, 62, 62, 62, + + 62, 62, 62, 143, 143, 143, 62, 62, 143, 143, + 143, 143, 62, 62, 143, 143, 62, 62, 143, 143, + 62, 62, 143, 143, 62, 62, 143, 143, 62, 143, + 143, 147, 147, 143, 143, 149, 143, 143, 143, 143, + 143, 143, 0, 143, 143, 143, 143, 143, 143 + } ; + +static lp_yyconst flex_int16_t lp_yy_nxt[426] = + { 0, + 8, 9, 10, 9, 8, 8, 11, 12, 13, 12, + 14, 15, 16, 16, 17, 18, 19, 20, 21, 22, + 22, 22, 22, 22, 22, 22, 22, 23, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 24, 30, 31, + 30, 31, 32, 96, 32, 34, 35, 34, 35, 36, + 36, 36, 40, 40, 41, 37, 25, 37, 142, 42, + 26, 48, 27, 36, 36, 36, 48, 28, 136, 37, + 43, 37, 44, 44, 50, 48, 51, 68, 68, 50, + 136, 51, 48, 45, 52, 141, 48, 140, 50, 48, + 51, 53, 54, 36, 36, 50, 139, 51, 37, 50, + + 37, 51, 50, 48, 60, 138, 76, 59, 40, 40, + 48, 55, 77, 61, 137, 56, 50, 57, 51, 45, + 68, 68, 58, 50, 135, 62, 36, 36, 36, 66, + 66, 63, 37, 134, 37, 38, 38, 38, 66, 66, + 45, 38, 43, 38, 44, 44, 67, 48, 67, 45, + 48, 68, 68, 48, 48, 45, 131, 48, 48, 130, + 50, 48, 51, 50, 87, 51, 50, 50, 51, 51, + 50, 50, 51, 51, 50, 90, 51, 88, 128, 79, + 72, 78, 87, 71, 127, 124, 90, 123, 91, 80, + 48, 84, 112, 48, 120, 88, 119, 51, 116, 91, + + 48, 51, 112, 50, 48, 51, 50, 89, 51, 48, + 81, 92, 48, 50, 111, 51, 82, 50, 98, 51, + 48, 83, 50, 49, 51, 50, 99, 51, 48, 107, + 110, 100, 109, 50, 49, 51, 49, 101, 69, 69, + 103, 50, 108, 51, 104, 104, 104, 49, 49, 49, + 102, 97, 49, 115, 49, 49, 114, 113, 49, 49, + 49, 49, 49, 49, 122, 49, 103, 49, 49, 106, + 96, 49, 49, 49, 49, 81, 49, 104, 104, 104, + 49, 49, 95, 49, 49, 49, 117, 49, 118, 49, + 49, 49, 49, 49, 49, 49, 94, 49, 121, 49, + + 93, 125, 49, 126, 49, 49, 125, 86, 126, 49, + 85, 49, 104, 104, 104, 49, 49, 49, 129, 132, + 49, 49, 75, 49, 49, 87, 133, 49, 49, 90, + 49, 74, 49, 73, 69, 49, 65, 143, 88, 39, + 51, 64, 91, 47, 51, 29, 29, 29, 29, 29, + 29, 29, 29, 33, 33, 33, 33, 33, 33, 33, + 33, 38, 38, 46, 39, 143, 143, 38, 49, 143, + 49, 49, 143, 49, 49, 70, 70, 143, 143, 70, + 105, 105, 143, 105, 105, 105, 105, 7, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143 + } ; + +static lp_yyconst flex_int16_t lp_yy_chk[426] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, + 4, 4, 3, 142, 4, 5, 5, 6, 6, 9, + 9, 9, 14, 14, 15, 9, 2, 9, 141, 15, + 2, 22, 2, 10, 10, 10, 23, 2, 131, 10, + 16, 10, 16, 16, 22, 26, 22, 67, 67, 23, + 131, 23, 25, 16, 23, 140, 27, 139, 26, 48, + 26, 23, 24, 24, 24, 25, 138, 25, 24, 27, + + 24, 27, 48, 28, 26, 137, 58, 25, 40, 40, + 86, 24, 58, 27, 135, 24, 28, 24, 28, 40, + 68, 68, 24, 86, 130, 28, 36, 36, 36, 43, + 43, 28, 36, 128, 36, 38, 38, 38, 66, 66, + 43, 38, 44, 38, 44, 44, 45, 49, 45, 66, + 52, 45, 45, 53, 59, 44, 124, 60, 61, 123, + 49, 63, 49, 52, 87, 52, 53, 59, 53, 59, + 60, 61, 60, 61, 63, 90, 63, 87, 120, 60, + 53, 59, 71, 52, 119, 116, 72, 115, 90, 61, + 62, 63, 112, 81, 111, 71, 109, 71, 106, 72, + + 78, 72, 97, 62, 79, 62, 81, 71, 81, 80, + 62, 72, 82, 78, 95, 78, 62, 79, 78, 79, + 83, 62, 80, 89, 80, 82, 79, 82, 84, 89, + 94, 80, 93, 83, 89, 83, 92, 82, 91, 88, + 84, 84, 92, 84, 85, 85, 85, 92, 98, 99, + 83, 77, 100, 101, 98, 99, 100, 98, 100, 98, + 99, 102, 114, 100, 114, 101, 103, 102, 114, 85, + 76, 101, 102, 114, 103, 101, 101, 104, 104, 104, + 103, 107, 75, 108, 113, 103, 107, 107, 108, 108, + 113, 117, 107, 118, 108, 113, 74, 117, 113, 118, + + 73, 117, 117, 118, 118, 121, 117, 70, 118, 122, + 65, 121, 136, 136, 136, 122, 121, 125, 122, 125, + 122, 129, 57, 125, 126, 132, 126, 129, 125, 133, + 126, 56, 129, 55, 50, 126, 39, 136, 132, 37, + 132, 32, 133, 21, 133, 144, 144, 144, 144, 144, + 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, + 145, 146, 146, 19, 12, 7, 0, 146, 147, 0, + 147, 147, 0, 147, 147, 148, 148, 0, 0, 148, + 149, 149, 0, 149, 149, 149, 149, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143 + } ; + +/* Table of booleans, true if rule could match eol. */ +static lp_yyconst flex_int32_t lp_yy_rule_can_match_eol[34] = + { 0, +0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define lp_yymore() lp_yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +/* + made reentrant with help of + http://www.usualcoding.eu/post/2007/09/03/Building-a-reentrant-parser-in-C-with-Flex/Bison +*/ +/* + Note that a minimum version of flex is needed to be able to compile this. + Older version don't know the reentrant code. + Version 2.5.4 is not enough. Probably at least v2.5.31 is needed. Tested with v2.5.35 +*/ +/* +** We want the scanner to be reentrant, therefore generate no global variables. +** That what the 'reentrant' option is for. +** 'bison-bridge' is used to create a bison compatible scanner and share lp_yylval +*/ + +#define INITIAL 0 +#define COMMENT 1 +#define LINECOMMENT 2 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct lp_yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE lp_yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *lp_yyin_r, *lp_yyout_r; + size_t lp_yy_buffer_stack_top; /**< index of top of stack. */ + size_t lp_yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * lp_yy_buffer_stack; /**< Stack as an array. */ + char lp_yy_hold_char; + int lp_yy_n_chars; + int lp_yyleng_r; + char *lp_yy_c_buf_p; + int lp_yy_init; + int lp_yy_start; + int lp_yy_did_buffer_switch_on_eof; + int lp_yy_start_stack_ptr; + int lp_yy_start_stack_depth; + int *lp_yy_start_stack; + lp_yy_state_type lp_yy_last_accepting_state; + char* lp_yy_last_accepting_cpos; + + int lp_yylineno_r; + int lp_yy_flex_debug_r; + + char *lp_yytext_r; + int lp_yy_more_flag; + int lp_yy_more_len; + + YYSTYPE * lp_yylval_r; + + }; /* end struct lp_yyguts_t */ + +static int lp_yy_init_globals (lp_yyscan_t lp_yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define lp_yylval lp_yyg->lp_yylval_r + +int lp_yylex_init (lp_yyscan_t* scanner); + +int lp_yylex_init_extra (YY_EXTRA_TYPE user_defined,lp_yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int lp_yylex_destroy (lp_yyscan_t lp_yyscanner ); + +int lp_yyget_debug (lp_yyscan_t lp_yyscanner ); + +void lp_yyset_debug (int debug_flag ,lp_yyscan_t lp_yyscanner ); + +YY_EXTRA_TYPE lp_yyget_extra (lp_yyscan_t lp_yyscanner ); + +void lp_yyset_extra (YY_EXTRA_TYPE user_defined ,lp_yyscan_t lp_yyscanner ); + +FILE *lp_yyget_in (lp_yyscan_t lp_yyscanner ); + +void lp_yyset_in (FILE * in_str ,lp_yyscan_t lp_yyscanner ); + +FILE *lp_yyget_out (lp_yyscan_t lp_yyscanner ); + +void lp_yyset_out (FILE * out_str ,lp_yyscan_t lp_yyscanner ); + +int lp_yyget_leng (lp_yyscan_t lp_yyscanner ); + +char *lp_yyget_text (lp_yyscan_t lp_yyscanner ); + +int lp_yyget_lineno (lp_yyscan_t lp_yyscanner ); + +void lp_yyset_lineno (int line_number ,lp_yyscan_t lp_yyscanner ); + +YYSTYPE * lp_yyget_lval (lp_yyscan_t lp_yyscanner ); + +void lp_yyset_lval (YYSTYPE * lp_yylval_param ,lp_yyscan_t lp_yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int lp_yywrap (lp_yyscan_t lp_yyscanner ); +#else +extern int lp_yywrap (lp_yyscan_t lp_yyscanner ); +#endif +#endif + + static void lp_yyunput (int c,char *buf_ptr ,lp_yyscan_t lp_yyscanner); + +#ifndef lp_yytext_ptr +static void lp_yy_flex_strncpy (char *,lp_yyconst char *,int ,lp_yyscan_t lp_yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int lp_yy_flex_strlen (lp_yyconst char * ,lp_yyscan_t lp_yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int lp_yyinput (lp_yyscan_t lp_yyscanner ); +#else +static int input (lp_yyscan_t lp_yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO fwrite( lp_yytext, lp_yyleng, 1, lp_yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->lp_yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( lp_yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( lp_yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, lp_yyin))==0 && ferror(lp_yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(lp_yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "lp_yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef lp_yyterminate +#define lp_yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) lp_yy_fatal_error( msg , lp_yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int lp_yylex \ + (YYSTYPE * lp_yylval_param ,lp_yyscan_t lp_yyscanner); + +#define YY_DECL int lp_yylex \ + (YYSTYPE * lp_yylval_param , lp_yyscan_t lp_yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after lp_yytext and lp_yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( lp_yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->lp_yy_at_bol = \ + (lp_yytext[lp_yyleng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register lp_yy_state_type lp_yy_current_state; + register char *lp_yy_cp, *lp_yy_bp; + register int lp_yy_act; + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + lp_yylval = lp_yylval_param; + + if ( !lp_yyg->lp_yy_init ) + { + lp_yyg->lp_yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! lp_yyg->lp_yy_start ) + lp_yyg->lp_yy_start = 1; /* first start state */ + + if ( ! lp_yyin ) + lp_yyin = stdin; + + if ( ! lp_yyout ) + lp_yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + lp_yyensure_buffer_stack (lp_yyscanner); + YY_CURRENT_BUFFER_LVALUE = + lp_yy_create_buffer(lp_yyin,YY_BUF_SIZE ,lp_yyscanner); + } + + lp_yy_load_buffer_state(lp_yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + lp_yy_cp = lp_yyg->lp_yy_c_buf_p; + + /* Support of lp_yytext. */ + *lp_yy_cp = lp_yyg->lp_yy_hold_char; + + /* lp_yy_bp points to the position in lp_yy_ch_buf of the start of + * the current run. + */ + lp_yy_bp = lp_yy_cp; + + lp_yy_current_state = lp_yyg->lp_yy_start; + lp_yy_current_state += YY_AT_BOL(); +lp_yy_match: + do + { + register YY_CHAR lp_yy_c = lp_yy_ec[YY_SC_TO_UI(*lp_yy_cp)]; + if ( lp_yy_accept[lp_yy_current_state] ) + { + lp_yyg->lp_yy_last_accepting_state = lp_yy_current_state; + lp_yyg->lp_yy_last_accepting_cpos = lp_yy_cp; + } + while ( lp_yy_chk[lp_yy_base[lp_yy_current_state] + lp_yy_c] != lp_yy_current_state ) + { + lp_yy_current_state = (int) lp_yy_def[lp_yy_current_state]; + if ( lp_yy_current_state >= 144 ) + lp_yy_c = lp_yy_meta[(unsigned int) lp_yy_c]; + } + lp_yy_current_state = lp_yy_nxt[lp_yy_base[lp_yy_current_state] + (unsigned int) lp_yy_c]; + ++lp_yy_cp; + } + while ( lp_yy_base[lp_yy_current_state] != 388 ); + +lp_yy_find_action: + lp_yy_act = lp_yy_accept[lp_yy_current_state]; + if ( lp_yy_act == 0 ) + { /* have to back up */ + lp_yy_cp = lp_yyg->lp_yy_last_accepting_cpos; + lp_yy_current_state = lp_yyg->lp_yy_last_accepting_state; + lp_yy_act = lp_yy_accept[lp_yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( lp_yy_act != YY_END_OF_BUFFER && lp_yy_rule_can_match_eol[lp_yy_act] ) + { + int lp_yyl; + for ( lp_yyl = 0; lp_yyl < lp_yyleng; ++lp_yyl ) + if ( lp_yytext[lp_yyl] == '\n' ) + + do{ lp_yylineno++; + lp_yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( lp_yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *lp_yy_cp = lp_yyg->lp_yy_hold_char; + lp_yy_cp = lp_yyg->lp_yy_last_accepting_cpos; + lp_yy_current_state = lp_yyg->lp_yy_last_accepting_state; + goto lp_yy_find_action; + +case 1: +YY_RULE_SETUP +{ + BEGIN COMMENT; +} /* begin skip comment */ + YY_BREAK +case 2: +YY_RULE_SETUP +{ + BEGIN INITIAL; +} /* end skip comment */ + YY_BREAK +case 3: +YY_RULE_SETUP +{ +} + YY_BREAK +case 4: +/* rule 4 can match eol */ +YY_RULE_SETUP +{ +} + YY_BREAK +case 5: +YY_RULE_SETUP +{ +} + YY_BREAK +case 6: +YY_RULE_SETUP +{ + BEGIN LINECOMMENT; +} /* begin skip LINECOMMENT */ + YY_BREAK +case 7: +/* rule 7 can match eol */ +YY_RULE_SETUP +{ + BEGIN INITIAL; +} /* end skip LINECOMMENT */ + YY_BREAK +case 8: +YY_RULE_SETUP +{ + BEGIN INITIAL; +} /* end skip LINECOMMENT */ + YY_BREAK +case 9: +YY_RULE_SETUP +{ +} + YY_BREAK +case 10: +/* rule 10 can match eol */ +YY_RULE_SETUP +{ +} + YY_BREAK +case 11: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + + pp->lineno = lp_yylineno; + return(COMMA); +} + YY_BREAK +case 12: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + + pp->lineno = lp_yylineno; + return(MINIMISE); +} + YY_BREAK +case 13: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + + pp->lineno = lp_yylineno; + return(MAXIMISE); +} + YY_BREAK +case 14: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + pv->f = atof((char *)lp_yytext); + return(INTCONS); +} /* f contains the last float */ + YY_BREAK +case 15: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + pv->f = atof((char *)lp_yytext); + return(CONS); +} /* f contains the last float */ + YY_BREAK +case 16: +/* rule 16 can match eol */ +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + char *ptr, c; + + pp->lineno = lp_yylineno; + pv->f = DEF_INFINITE; + pv->Sign = 0; + ptr = (char *)lp_yytext; + while (isspace(*ptr)) ptr++; + if(*ptr == '-') + pv->Sign = 1; + if(lp_yyleng > 0) { + c = lp_yytext[lp_yyleng - 1]; + if(!isalnum(c)) + unput(c); + } + return(INF); +} /* f contains the last float */ + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + int x; + + pp->lineno = lp_yylineno; + pv->Sign = 0; + for(x = 0; x < lp_yyleng; x++) + if(lp_yytext[x] == '-' || lp_yytext[x] == '+') + pv->Sign = (pv->Sign == (lp_yytext[x] == '+')); + return (TOK_SIGN); + /* Sign is TRUE if the sign-string + represents a '-'. Otherwise Sign + is FALSE */ +} + YY_BREAK +case 18: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + if((!pv->Within_int_decl) && (!pv->Within_sec_decl) && (!pv->Within_sos_decl) && (!pv->Within_free_decl)) { + pv->Within_int_decl = 1; + pv->Within_sos_decl1 = FALSE; + } + return(SEC_INT); +} + YY_BREAK +case 19: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + if((!pv->Within_int_decl) && (!pv->Within_sec_decl) && (!pv->Within_sos_decl) && (!pv->Within_free_decl)) { + pv->Within_int_decl = 2; + pv->Within_sos_decl1 = FALSE; + } + return(SEC_BIN); +} + YY_BREAK +case 20: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + if((!pv->Within_int_decl) && (!pv->Within_sec_decl) && (!pv->Within_sos_decl) && (!pv->Within_free_decl)) { + pv->Within_sec_decl = TRUE; + pv->Within_sos_decl1 = FALSE; + } + return(SEC_SEC); +} + YY_BREAK +case 21: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + if(!pv->Within_sos_decl) + pv->SOStype0 = (short)atoi(((char *)lp_yytext) + 3); + if((!pv->Within_int_decl) && (!pv->Within_sec_decl) && (!pv->Within_sos_decl) && (!pv->Within_free_decl)) + pv->Within_sos_decl = TRUE; + return(SEC_SOS); +} + YY_BREAK +case 22: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + FREE(pv->Last_var); + pv->Last_var = strdup((char *)lp_yytext); + pv->Last_var[strlen(pv->Last_var) - 2] = 0; + return(SOSDESCR); +} + YY_BREAK +case 23: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + if((!pv->Within_int_decl) && (!pv->Within_sec_decl) && (!pv->Within_sos_decl) && (!pv->Within_free_decl)) { + pv->Within_free_decl = TRUE; + pv->Within_sos_decl1 = FALSE; + } + return(SEC_FREE); +} + YY_BREAK +case 24: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + char *ptr; + + pp->lineno = lp_yylineno; + FREE(pv->Last_var); + pv->Last_var = strdup((char *)lp_yytext); + ptr = pv->Last_var + strlen(pv->Last_var); + ptr[-1] = ' '; + while ((--ptr >= pv->Last_var) && (isspace(*ptr))) + *ptr = 0; + return(VARIABLECOLON); +} + YY_BREAK +case 25: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + FREE(pv->Last_var); + pv->Last_var = strdup((char *)lp_yytext); + return(VAR); +} + YY_BREAK +case 26: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + + pp->lineno = lp_yylineno; + return (COLON); +} + YY_BREAK +case 27: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + + pp->lineno = lp_yylineno; + return(AR_M_OP); +} + YY_BREAK +case 28: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + pv->OP = *lp_yytext; + return(RE_OPEQ); +} + YY_BREAK +case 29: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + pv->OP = *lp_yytext; + return(RE_OPLE); +} + YY_BREAK +case 30: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + pv->OP = *lp_yytext; + return(RE_OPGE); +} + YY_BREAK +case 31: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + parse_vars *pv = (parse_vars *) pp->parse_vars; + + pp->lineno = lp_yylineno; + pv->Within_int_decl = pv->Within_sec_decl = pv->Within_sos_decl = pv->Within_free_decl = FALSE; + check_int_sec_sos_free_decl(pp, (int) pv->Within_int_decl, (int) pv->Within_sec_decl, (int) pv->Within_sos_decl, (int) pv->Within_free_decl); + return(END_C); +} + YY_BREAK +case 32: +YY_RULE_SETUP +{ + parse_parm *pp = PARM; + + pp->lineno = lp_yylineno; + report(NULL, CRITICAL, "LEX ERROR : %s lineno %d\n", lp_yytext, lp_yylineno); + return(UNDEFINED); +} + YY_BREAK +case 33: +YY_RULE_SETUP +ECHO; + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMENT): +case YY_STATE_EOF(LINECOMMENT): + lp_yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int lp_yy_amount_of_matched_text = (int) (lp_yy_cp - lp_yyg->lp_yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *lp_yy_cp = lp_yyg->lp_yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->lp_yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed lp_yyin at a new source and called + * lp_yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + lp_yyg->lp_yy_n_chars = YY_CURRENT_BUFFER_LVALUE->lp_yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->lp_yy_input_file = lp_yyin; + YY_CURRENT_BUFFER_LVALUE->lp_yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for lp_yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since lp_yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( lp_yyg->lp_yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[lp_yyg->lp_yy_n_chars] ) + { /* This was really a NUL. */ + lp_yy_state_type lp_yy_next_state; + + lp_yyg->lp_yy_c_buf_p = lp_yyg->lp_yytext_ptr + lp_yy_amount_of_matched_text; + + lp_yy_current_state = lp_yy_get_previous_state( lp_yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * lp_yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + lp_yy_next_state = lp_yy_try_NUL_trans( lp_yy_current_state , lp_yyscanner); + + lp_yy_bp = lp_yyg->lp_yytext_ptr + YY_MORE_ADJ; + + if ( lp_yy_next_state ) + { + /* Consume the NUL. */ + lp_yy_cp = ++lp_yyg->lp_yy_c_buf_p; + lp_yy_current_state = lp_yy_next_state; + goto lp_yy_match; + } + + else + { + lp_yy_cp = lp_yyg->lp_yy_c_buf_p; + goto lp_yy_find_action; + } + } + + else switch ( lp_yy_get_next_buffer( lp_yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + lp_yyg->lp_yy_did_buffer_switch_on_eof = 0; + + if ( lp_yywrap(lp_yyscanner ) ) + { + /* Note: because we've taken care in + * lp_yy_get_next_buffer() to have set up + * lp_yytext, we can now set up + * lp_yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + lp_yyg->lp_yy_c_buf_p = lp_yyg->lp_yytext_ptr + YY_MORE_ADJ; + + lp_yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! lp_yyg->lp_yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + lp_yyg->lp_yy_c_buf_p = + lp_yyg->lp_yytext_ptr + lp_yy_amount_of_matched_text; + + lp_yy_current_state = lp_yy_get_previous_state( lp_yyscanner ); + + lp_yy_cp = lp_yyg->lp_yy_c_buf_p; + lp_yy_bp = lp_yyg->lp_yytext_ptr + YY_MORE_ADJ; + goto lp_yy_match; + + case EOB_ACT_LAST_MATCH: + lp_yyg->lp_yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[lp_yyg->lp_yy_n_chars]; + + lp_yy_current_state = lp_yy_get_previous_state( lp_yyscanner ); + + lp_yy_cp = lp_yyg->lp_yy_c_buf_p; + lp_yy_bp = lp_yyg->lp_yytext_ptr + YY_MORE_ADJ; + goto lp_yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of lp_yylex */ + +/* lp_yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int lp_yy_get_next_buffer (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf; + register char *source = lp_yyg->lp_yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( lp_yyg->lp_yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[lp_yyg->lp_yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->lp_yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( lp_yyg->lp_yy_c_buf_p - lp_yyg->lp_yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (lp_yyg->lp_yy_c_buf_p - lp_yyg->lp_yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->lp_yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->lp_yy_n_chars = lp_yyg->lp_yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int lp_yy_c_buf_p_offset = + (int) (lp_yyg->lp_yy_c_buf_p - b->lp_yy_ch_buf); + + if ( b->lp_yy_is_our_buffer ) + { + int new_size = b->lp_yy_buf_size * 2; + + if ( new_size <= 0 ) + b->lp_yy_buf_size += b->lp_yy_buf_size / 8; + else + b->lp_yy_buf_size *= 2; + + b->lp_yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + lp_yyrealloc((void *) b->lp_yy_ch_buf,b->lp_yy_buf_size + 2 ,lp_yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->lp_yy_ch_buf = 0; + + if ( ! b->lp_yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + lp_yyg->lp_yy_c_buf_p = &b->lp_yy_ch_buf[lp_yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[number_to_move]), + lp_yyg->lp_yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->lp_yy_n_chars = lp_yyg->lp_yy_n_chars; + } + + if ( lp_yyg->lp_yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + lp_yyrestart(lp_yyin ,lp_yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->lp_yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((lp_yy_size_t) (lp_yyg->lp_yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + lp_yy_size_t new_size = lp_yyg->lp_yy_n_chars + number_to_move + (lp_yyg->lp_yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf = (char *) lp_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf,new_size ,lp_yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in lp_yy_get_next_buffer()" ); + } + + lp_yyg->lp_yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[lp_yyg->lp_yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[lp_yyg->lp_yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + lp_yyg->lp_yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[0]; + + return ret_val; +} + +/* lp_yy_get_previous_state - get the state just before the EOB char was reached */ + + static lp_yy_state_type lp_yy_get_previous_state (lp_yyscan_t lp_yyscanner) +{ + register lp_yy_state_type lp_yy_current_state; + register char *lp_yy_cp; + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + lp_yy_current_state = lp_yyg->lp_yy_start; + lp_yy_current_state += YY_AT_BOL(); + + for ( lp_yy_cp = lp_yyg->lp_yytext_ptr + YY_MORE_ADJ; lp_yy_cp < lp_yyg->lp_yy_c_buf_p; ++lp_yy_cp ) + { + register YY_CHAR lp_yy_c = (*lp_yy_cp ? lp_yy_ec[YY_SC_TO_UI(*lp_yy_cp)] : 1); + if ( lp_yy_accept[lp_yy_current_state] ) + { + lp_yyg->lp_yy_last_accepting_state = lp_yy_current_state; + lp_yyg->lp_yy_last_accepting_cpos = lp_yy_cp; + } + while ( lp_yy_chk[lp_yy_base[lp_yy_current_state] + lp_yy_c] != lp_yy_current_state ) + { + lp_yy_current_state = (int) lp_yy_def[lp_yy_current_state]; + if ( lp_yy_current_state >= 144 ) + lp_yy_c = lp_yy_meta[(unsigned int) lp_yy_c]; + } + lp_yy_current_state = lp_yy_nxt[lp_yy_base[lp_yy_current_state] + (unsigned int) lp_yy_c]; + } + + return lp_yy_current_state; +} + +/* lp_yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = lp_yy_try_NUL_trans( current_state ); + */ + static lp_yy_state_type lp_yy_try_NUL_trans (lp_yy_state_type lp_yy_current_state , lp_yyscan_t lp_yyscanner) +{ + register int lp_yy_is_jam; + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; /* This var may be unused depending upon options. */ + register char *lp_yy_cp = lp_yyg->lp_yy_c_buf_p; + + register YY_CHAR lp_yy_c = 1; + if ( lp_yy_accept[lp_yy_current_state] ) + { + lp_yyg->lp_yy_last_accepting_state = lp_yy_current_state; + lp_yyg->lp_yy_last_accepting_cpos = lp_yy_cp; + } + while ( lp_yy_chk[lp_yy_base[lp_yy_current_state] + lp_yy_c] != lp_yy_current_state ) + { + lp_yy_current_state = (int) lp_yy_def[lp_yy_current_state]; + if ( lp_yy_current_state >= 144 ) + lp_yy_c = lp_yy_meta[(unsigned int) lp_yy_c]; + } + lp_yy_current_state = lp_yy_nxt[lp_yy_base[lp_yy_current_state] + (unsigned int) lp_yy_c]; + lp_yy_is_jam = (lp_yy_current_state == 143); + + return lp_yy_is_jam ? 0 : lp_yy_current_state; +} + + static void lp_yyunput (int c, register char * lp_yy_bp , lp_yyscan_t lp_yyscanner) +{ + register char *lp_yy_cp; + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + lp_yy_cp = lp_yyg->lp_yy_c_buf_p; + + /* undo effects of setting up lp_yytext */ + *lp_yy_cp = lp_yyg->lp_yy_hold_char; + + if ( lp_yy_cp < YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = lp_yyg->lp_yy_n_chars + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf ) + *--dest = *--source; + + lp_yy_cp += (int) (dest - source); + lp_yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->lp_yy_n_chars = + lp_yyg->lp_yy_n_chars = YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_size; + + if ( lp_yy_cp < YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--lp_yy_cp = (char) c; + + if ( c == '\n' ){ + --lp_yylineno; + } + + lp_yyg->lp_yytext_ptr = lp_yy_bp; + lp_yyg->lp_yy_hold_char = *lp_yy_cp; + lp_yyg->lp_yy_c_buf_p = lp_yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static inline int lp_yyinput (lp_yyscan_t lp_yyscanner) +#else + static inline int input (lp_yyscan_t lp_yyscanner) +#endif + +{ + int c; + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + *lp_yyg->lp_yy_c_buf_p = lp_yyg->lp_yy_hold_char; + + if ( *lp_yyg->lp_yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* lp_yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( lp_yyg->lp_yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[lp_yyg->lp_yy_n_chars] ) + /* This was really a NUL. */ + *lp_yyg->lp_yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = lp_yyg->lp_yy_c_buf_p - lp_yyg->lp_yytext_ptr; + ++lp_yyg->lp_yy_c_buf_p; + + switch ( lp_yy_get_next_buffer( lp_yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because lp_yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + lp_yyrestart(lp_yyin ,lp_yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( lp_yywrap(lp_yyscanner ) ) + return EOF; + + if ( ! lp_yyg->lp_yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return lp_yyinput(lp_yyscanner); +#else + return input(lp_yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + lp_yyg->lp_yy_c_buf_p = lp_yyg->lp_yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) lp_yyg->lp_yy_c_buf_p; /* cast for 8-bit char's */ + *lp_yyg->lp_yy_c_buf_p = '\0'; /* preserve lp_yytext */ + lp_yyg->lp_yy_hold_char = *++lp_yyg->lp_yy_c_buf_p; + + YY_CURRENT_BUFFER_LVALUE->lp_yy_at_bol = (c == '\n'); + if ( YY_CURRENT_BUFFER_LVALUE->lp_yy_at_bol ) + + do{ lp_yylineno++; + lp_yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param lp_yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void lp_yyrestart (FILE * input_file , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + lp_yyensure_buffer_stack (lp_yyscanner); + YY_CURRENT_BUFFER_LVALUE = + lp_yy_create_buffer(lp_yyin,YY_BUF_SIZE ,lp_yyscanner); + } + + lp_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,lp_yyscanner); + lp_yy_load_buffer_state(lp_yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param lp_yyscanner The scanner object. + */ + void lp_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * lp_yypop_buffer_state(); + * lp_yypush_buffer_state(new_buffer); + */ + lp_yyensure_buffer_stack (lp_yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *lp_yyg->lp_yy_c_buf_p = lp_yyg->lp_yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_pos = lp_yyg->lp_yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->lp_yy_n_chars = lp_yyg->lp_yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + lp_yy_load_buffer_state(lp_yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (lp_yywrap()) processing, but the only time this flag + * is looked at is after lp_yywrap() is called, so it's safe + * to go ahead and always set it. + */ + lp_yyg->lp_yy_did_buffer_switch_on_eof = 1; +} + +static void lp_yy_load_buffer_state (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + lp_yyg->lp_yy_n_chars = YY_CURRENT_BUFFER_LVALUE->lp_yy_n_chars; + lp_yyg->lp_yytext_ptr = lp_yyg->lp_yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_pos; + lp_yyin = YY_CURRENT_BUFFER_LVALUE->lp_yy_input_file; + lp_yyg->lp_yy_hold_char = *lp_yyg->lp_yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param lp_yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE lp_yy_create_buffer (FILE * file, int size , lp_yyscan_t lp_yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) lp_yyalloc(sizeof( struct lp_yy_buffer_state ) ,lp_yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in lp_yy_create_buffer()" ); + + b->lp_yy_buf_size = size; + + /* lp_yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->lp_yy_ch_buf = (char *) lp_yyalloc(b->lp_yy_buf_size + 2 ,lp_yyscanner ); + if ( ! b->lp_yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in lp_yy_create_buffer()" ); + + b->lp_yy_is_our_buffer = 1; + + lp_yy_init_buffer(b,file ,lp_yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with lp_yy_create_buffer() + * @param lp_yyscanner The scanner object. + */ + void lp_yy_delete_buffer (YY_BUFFER_STATE b , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->lp_yy_is_our_buffer ) + lp_yyfree((void *) b->lp_yy_ch_buf ,lp_yyscanner ); + + lp_yyfree((void *) b ,lp_yyscanner ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a lp_yyrestart() or at EOF. + */ + static void lp_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , lp_yyscan_t lp_yyscanner) + +{ + int oerrno = errno; + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + lp_yy_flush_buffer(b ,lp_yyscanner); + + b->lp_yy_input_file = file; + b->lp_yy_fill_buffer = 1; + + /* If b is the current buffer, then lp_yy_init_buffer was _probably_ + * called from lp_yyrestart() or through lp_yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->lp_yy_bs_lineno = 1; + b->lp_yy_bs_column = 0; + } + + b->lp_yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param lp_yyscanner The scanner object. + */ + void lp_yy_flush_buffer (YY_BUFFER_STATE b , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + if ( ! b ) + return; + + b->lp_yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->lp_yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->lp_yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->lp_yy_buf_pos = &b->lp_yy_ch_buf[0]; + + b->lp_yy_at_bol = 1; + b->lp_yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + lp_yy_load_buffer_state(lp_yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param lp_yyscanner The scanner object. + */ +void lp_yypush_buffer_state (YY_BUFFER_STATE new_buffer , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + if (new_buffer == NULL) + return; + + lp_yyensure_buffer_stack(lp_yyscanner); + + /* This block is copied from lp_yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *lp_yyg->lp_yy_c_buf_p = lp_yyg->lp_yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_pos = lp_yyg->lp_yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->lp_yy_n_chars = lp_yyg->lp_yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + lp_yyg->lp_yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from lp_yy_switch_to_buffer. */ + lp_yy_load_buffer_state(lp_yyscanner ); + lp_yyg->lp_yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param lp_yyscanner The scanner object. + */ +void lp_yypop_buffer_state (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + lp_yy_delete_buffer(YY_CURRENT_BUFFER ,lp_yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (lp_yyg->lp_yy_buffer_stack_top > 0) + --lp_yyg->lp_yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + lp_yy_load_buffer_state(lp_yyscanner ); + lp_yyg->lp_yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void lp_yyensure_buffer_stack (lp_yyscan_t lp_yyscanner) +{ + int num_to_alloc; + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + if (!lp_yyg->lp_yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + lp_yyg->lp_yy_buffer_stack = (struct lp_yy_buffer_state**)lp_yyalloc + (num_to_alloc * sizeof(struct lp_yy_buffer_state*) + , lp_yyscanner); + if ( ! lp_yyg->lp_yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in lp_yyensure_buffer_stack()" ); + + memset(lp_yyg->lp_yy_buffer_stack, 0, num_to_alloc * sizeof(struct lp_yy_buffer_state*)); + + lp_yyg->lp_yy_buffer_stack_max = num_to_alloc; + lp_yyg->lp_yy_buffer_stack_top = 0; + return; + } + + if (lp_yyg->lp_yy_buffer_stack_top >= (lp_yyg->lp_yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = lp_yyg->lp_yy_buffer_stack_max + grow_size; + lp_yyg->lp_yy_buffer_stack = (struct lp_yy_buffer_state**)lp_yyrealloc + (lp_yyg->lp_yy_buffer_stack, + num_to_alloc * sizeof(struct lp_yy_buffer_state*) + , lp_yyscanner); + if ( ! lp_yyg->lp_yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in lp_yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(lp_yyg->lp_yy_buffer_stack + lp_yyg->lp_yy_buffer_stack_max, 0, grow_size * sizeof(struct lp_yy_buffer_state*)); + lp_yyg->lp_yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param lp_yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE lp_yy_scan_buffer (char * base, lp_yy_size_t size , lp_yyscan_t lp_yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) lp_yyalloc(sizeof( struct lp_yy_buffer_state ) ,lp_yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in lp_yy_scan_buffer()" ); + + b->lp_yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->lp_yy_buf_pos = b->lp_yy_ch_buf = base; + b->lp_yy_is_our_buffer = 0; + b->lp_yy_input_file = 0; + b->lp_yy_n_chars = b->lp_yy_buf_size; + b->lp_yy_is_interactive = 0; + b->lp_yy_at_bol = 1; + b->lp_yy_fill_buffer = 0; + b->lp_yy_buffer_status = YY_BUFFER_NEW; + + lp_yy_switch_to_buffer(b ,lp_yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to lp_yylex() will + * scan from a @e copy of @a str. + * @param lp_yystr a NUL-terminated string to scan + * @param lp_yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * lp_yy_scan_bytes() instead. + */ +YY_BUFFER_STATE lp_yy_scan_string (lp_yyconst char * lp_yystr , lp_yyscan_t lp_yyscanner) +{ + + return lp_yy_scan_bytes(lp_yystr,strlen(lp_yystr) ,lp_yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to lp_yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param lp_yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE lp_yy_scan_bytes (lp_yyconst char * lp_yybytes, int _lp_yybytes_len , lp_yyscan_t lp_yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + lp_yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _lp_yybytes_len + 2; + buf = (char *) lp_yyalloc(n ,lp_yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in lp_yy_scan_bytes()" ); + + for ( i = 0; i < _lp_yybytes_len; ++i ) + buf[i] = lp_yybytes[i]; + + buf[_lp_yybytes_len] = buf[_lp_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = lp_yy_scan_buffer(buf,n ,lp_yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in lp_yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->lp_yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void lp_yy_fatal_error (lp_yyconst char* msg , lp_yyscan_t lp_yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine lp_yyless() so it works in section 3 code. */ + +#undef lp_yyless +#define lp_yyless(n) \ + do \ + { \ + /* Undo effects of setting up lp_yytext. */ \ + int lp_yyless_macro_arg = (n); \ + YY_LESS_LINENO(lp_yyless_macro_arg);\ + lp_yytext[lp_yyleng] = lp_yyg->lp_yy_hold_char; \ + lp_yyg->lp_yy_c_buf_p = lp_yytext + lp_yyless_macro_arg; \ + lp_yyg->lp_yy_hold_char = *lp_yyg->lp_yy_c_buf_p; \ + *lp_yyg->lp_yy_c_buf_p = '\0'; \ + lp_yyleng = lp_yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param lp_yyscanner The scanner object. + */ +YY_EXTRA_TYPE lp_yyget_extra (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + return lp_yyextra; +} + +/** Get the current line number. + * @param lp_yyscanner The scanner object. + */ +int lp_yyget_lineno (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return lp_yylineno; +} + +/** Get the current column number. + * @param lp_yyscanner The scanner object. + */ +int lp_yyget_column (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return lp_yycolumn; +} + +/** Get the input stream. + * @param lp_yyscanner The scanner object. + */ +FILE *lp_yyget_in (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + return lp_yyin; +} + +/** Get the output stream. + * @param lp_yyscanner The scanner object. + */ +FILE *lp_yyget_out (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + return lp_yyout; +} + +/** Get the length of the current token. + * @param lp_yyscanner The scanner object. + */ +int lp_yyget_leng (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + return lp_yyleng; +} + +/** Get the current token. + * @param lp_yyscanner The scanner object. + */ + +char *lp_yyget_text (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + return lp_yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param lp_yyscanner The scanner object. + */ +void lp_yyset_extra (YY_EXTRA_TYPE user_defined , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + lp_yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param lp_yyscanner The scanner object. + */ +void lp_yyset_lineno (int line_number , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + lp_yy_fatal_error( "lp_yyset_lineno called with no buffer" , lp_yyscanner); + + lp_yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param lp_yyscanner The scanner object. + */ +void lp_yyset_column (int column_no , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + lp_yy_fatal_error( "lp_yyset_column called with no buffer" , lp_yyscanner); + + lp_yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param lp_yyscanner The scanner object. + * @see lp_yy_switch_to_buffer + */ +void lp_yyset_in (FILE * in_str , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + lp_yyin = in_str ; +} + +void lp_yyset_out (FILE * out_str , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + lp_yyout = out_str ; +} + +int lp_yyget_debug (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + return lp_yy_flex_debug; +} + +void lp_yyset_debug (int bdebug , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + lp_yy_flex_debug = bdebug ; +} + +/* Accessor methods for lp_yylval and lp_yylloc */ + +YYSTYPE * lp_yyget_lval (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + return lp_yylval; +} + +void lp_yyset_lval (YYSTYPE * lp_yylval_param , lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + lp_yylval = lp_yylval_param; +} + +/* User-visible API */ + +/* lp_yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int lp_yylex_init(lp_yyscan_t* ptr_lp_yy_globals) + +{ + if (ptr_lp_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_lp_yy_globals = (lp_yyscan_t) lp_yyalloc ( sizeof( struct lp_yyguts_t ), NULL ); + + if (*ptr_lp_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in lp_yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_lp_yy_globals,0x00,sizeof(struct lp_yyguts_t)); + + return lp_yy_init_globals ( *ptr_lp_yy_globals ); +} + +/* lp_yylex_init_extra has the same functionality as lp_yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to lp_yyalloc in + * the lp_yyextra field. + */ + +int lp_yylex_init_extra(YY_EXTRA_TYPE lp_yy_user_defined,lp_yyscan_t* ptr_lp_yy_globals ) + +{ + struct lp_yyguts_t dummy_lp_yyguts; + + lp_yyset_extra (lp_yy_user_defined, &dummy_lp_yyguts); + + if (ptr_lp_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_lp_yy_globals = (lp_yyscan_t) lp_yyalloc ( sizeof( struct lp_yyguts_t ), &dummy_lp_yyguts ); + + if (*ptr_lp_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + lp_yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_lp_yy_globals,0x00,sizeof(struct lp_yyguts_t)); + + lp_yyset_extra (lp_yy_user_defined, *ptr_lp_yy_globals); + + return lp_yy_init_globals ( *ptr_lp_yy_globals ); +} + +static int lp_yy_init_globals (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from lp_yylex_destroy(), so don't allocate here. + */ + + lp_yyg->lp_yy_buffer_stack = 0; + lp_yyg->lp_yy_buffer_stack_top = 0; + lp_yyg->lp_yy_buffer_stack_max = 0; + lp_yyg->lp_yy_c_buf_p = (char *) 0; + lp_yyg->lp_yy_init = 0; + lp_yyg->lp_yy_start = 0; + + lp_yyg->lp_yy_start_stack_ptr = 0; + lp_yyg->lp_yy_start_stack_depth = 0; + lp_yyg->lp_yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + lp_yyin = stdin; + lp_yyout = stdout; +#else + lp_yyin = (FILE *) 0; + lp_yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * lp_yylex_init() + */ + return 0; +} + +/* lp_yylex_destroy is for both reentrant and non-reentrant scanners. */ +int lp_yylex_destroy (lp_yyscan_t lp_yyscanner) +{ + struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + lp_yy_delete_buffer(YY_CURRENT_BUFFER ,lp_yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + lp_yypop_buffer_state(lp_yyscanner); + } + + /* Destroy the stack itself. */ + lp_yyfree(lp_yyg->lp_yy_buffer_stack ,lp_yyscanner); + lp_yyg->lp_yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + lp_yyfree(lp_yyg->lp_yy_start_stack ,lp_yyscanner ); + lp_yyg->lp_yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * lp_yylex() is called, initialization will occur. */ + lp_yy_init_globals( lp_yyscanner); + + /* Destroy the main struct (reentrant only). */ + lp_yyfree ( lp_yyscanner , lp_yyscanner ); + lp_yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef lp_yytext_ptr +static void lp_yy_flex_strncpy (char* s1, lp_yyconst char * s2, int n , lp_yyscan_t lp_yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int lp_yy_flex_strlen (lp_yyconst char * s , lp_yyscan_t lp_yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *lp_yyalloc (lp_yy_size_t size , lp_yyscan_t lp_yyscanner) +{ + return (void *) malloc( size ); +} + +void *lp_yyrealloc (void * ptr, lp_yy_size_t size , lp_yyscan_t lp_yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void lp_yyfree (void * ptr , lp_yyscan_t lp_yyscanner) +{ + free( (char *) ptr ); /* see lp_yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "lp_yytables" + diff --git a/include/cartesian_geom/point.h b/include/cartesian_geom/point.h index a2209f4f5..b8c8e32b4 100644 --- a/include/cartesian_geom/point.h +++ b/include/cartesian_geom/point.h @@ -81,6 +81,7 @@ class point void set_dimension(const unsigned int dim) { d = dim; + coeffs.setZero(d); } void set_coord(const unsigned int i, FT coord) diff --git a/include/convex_bodies/ellipsoid.h b/include/convex_bodies/ellipsoid.h index 18c7570c5..654bb5a54 100644 --- a/include/convex_bodies/ellipsoid.h +++ b/include/convex_bodies/ellipsoid.h @@ -47,7 +47,7 @@ typedef Point PointType; Ellipsoid() {} // TODO(vaithak): Add a flag for telling whether the matrix passed is already inverse - Ellipsoid(MT& Ain) : A(Ain) { + Ellipsoid(const MT& Ain) : A(Ain) { Eigen::SelfAdjointEigenSolver eigensolver(A); if (eigensolver.info() != Eigen::Success) { throw std::runtime_error("Eigen solver returned error!"); @@ -164,8 +164,8 @@ typedef Point PointType; } - int is_in(Point const& p) const { - return mat_mult(p) > 1 ? 0 : -1; + int is_in(Point const& p, NT tol=NT(0)) const { + return mat_mult(p) > 1 + NT(tol) ? 0 : -1; } diff --git a/include/convex_bodies/ellipsoidintersectconvex.h b/include/convex_bodies/ellipsoidintersectconvex.h new file mode 100644 index 000000000..5d0b9aa3e --- /dev/null +++ b/include/convex_bodies/ellipsoidintersectconvex.h @@ -0,0 +1,284 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2023 Vissarion Fisikopoulos +// Copyright (c) 2018-2023 Apostolos Chalkis +// Copyright (c) 2029-2023 Elias Tsigaridas + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef ELLIPSOIDINTERSECTCONVEX_H +#define ELLIPSOIDINTERSECTCONVEX_H + +/// This class represents a polytope intersected with an ellipsoid +/// \tparam Polytope Polytope Type +/// \tparam CEllipsoid Ellipsoid Type +template +class EllipsoidIntersectPolytope { +private: + Polytope P; + CEllipsoid E; +public: + typedef typename Polytope::MT MT; + typedef typename Polytope::VT VT; + typedef typename CEllipsoid::NT NT; + typedef typename CEllipsoid::PointType PointType; + + EllipsoidIntersectPolytope() {} + + EllipsoidIntersectPolytope(const Polytope& PP, const CEllipsoid &EE) : P(PP), E(EE) {}; + + Polytope first() const { return P; } + CEllipsoid second() const { return E; } + + std::pair InnerBall() const + { + return P.InnerBall(); + } + + MT get_mat() const { + return P.get_mat(); + } + + MT get_T() const { + return P.get_mat(); + } + + MT get_vec() const { + return P.get_vec(); + } + + int is_in(PointType const& p, NT tol=NT(0)) const + { + if (P.is_in(p, tol)==-1) + return E.is_in(p, tol); + return 0; + } + + int num_of_hyperplanes() const { + return P.num_of_hyperplanes(); + } + + unsigned int dimension() const { + return P.dimension(); + } + + NT radius() const { + return E.radius(); + } + + std::pair line_intersect(PointType const& r, PointType const& v) const + { + + std::pair polypair = P.line_intersect(r, v); + std::pair ellipsoidpair = E.line_intersect(r, v); + return std::pair(std::min(polypair.first, ellipsoidpair.first), + std::max(polypair.second, ellipsoidpair.second)); + } + + std::pair line_intersect(PointType const& r, + PointType const& v, + VT &Ar, + VT &Av) const + { + std::pair polypair = P.line_intersect(r, v, Ar, Av); + std::pair ellipsoidpair = E.line_intersect(r, v); + return std::pair(std::min(polypair.first, ellipsoidpair.first), + std::max(polypair.second, ellipsoidpair.second)); + } + + std::pair line_intersect(PointType const& r, + PointType const& v, + VT &Ar, + VT &Av, + NT &lambda_prev) const + { + std::pair polypair = P.line_intersect(r, v, Ar, Av, lambda_prev); + std::pair ellipsoidpair = E.line_intersect(r, v); + return std::pair(std::min(polypair.first, ellipsoidpair.first), + std::max(polypair.second, ellipsoidpair.second)); + } + + std::pair line_positive_intersect(PointType const& r, + PointType const& v, + VT &Ar, + VT &Av) + { + std::pair polypair = P.line_positive_intersect(r, v, Ar, Av); + std::pair ellipsoid_lambda = E.line_positive_intersect(r, v); + int facet = (polypair.first < ellipsoid_lambda.first) ? polypair.second : P.num_of_hyperplanes(); + + return std::pair(std::min(polypair.first, ellipsoid_lambda.first), facet); + } + + + std::pair line_positive_intersect(PointType const& r, + PointType const& v, + VT &Ar, + VT &Av, + NT &lambda_prev) + { + std::pair polypair = P.line_positive_intersect(r, v, Ar, Av, lambda_prev); + std::pair ellipsoid_lambda = E.line_positive_intersect(r, v); + int facet = (polypair.first < ellipsoid_lambda.first) ? polypair.second : P.num_of_hyperplanes(); + + return std::pair(std::min(polypair.first, ellipsoid_lambda.first), facet); + } + + //---------------------accelerated billiard---------------------// + template + std::pair line_first_positive_intersect(PointType const& r, + PointType const& v, + VT& Ar, + VT& Av, + update_parameters& params) + { + std::pair polypair = P.line_first_positive_intersect(r, v, Ar, Av, params); + std::pair ellipsoid_lambda = E.line_positive_intersect(r, v); + + params.hit_ball = (polypair.first < ellipsoid_lambda.first) ? false : true; + int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; + params.facet_prev = polypair.second; + + return std::pair(std::min(polypair.first, ellipsoid_lambda.first), facet); + } + + template + std::pair line_positive_intersect(PointType const& r, + PointType const& v, + VT& Ar, + VT& Av, + NT const& lambda_prev, + MT const& AA, + update_parameters& params) + { + std::pair polypair = P.line_positive_intersect(r, v, Ar, Av, lambda_prev, params); + std::pair ellipsoid_lambda = E.line_positive_intersect(r, v); + + params.hit_ball = (polypair.first < ellipsoid_lambda.first) ? false : true; + int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; + params.facet_prev = polypair.second; + + return std::pair(std::min(polypair.first, ellipsoid_lambda.first), facet); + } + + template + std::pair line_positive_intersect(PointType const& r, + PointType const& v, + VT& Ar, + VT& Av, + NT const& lambda_prev, + update_parameters& params) + { + std::pair polypair = P.line_positive_intersect(r, v, Ar, Av, lambda_prev, params); + std::pair ellipsoid_lambda = E.line_positive_intersect(r, v); + + params.hit_ball = (polypair.first < ellipsoid_lambda.first) ? false : true; + int facet = params.hit_ball ? P.num_of_hyperplanes() : polypair.second; + params.facet_prev = polypair.second; + + return std::pair(std::min(polypair.first, ellipsoid_lambda.first), facet); + } +//-------------------------------------------------------------------------// + + //First coordinate ray shooting intersecting convex body + std::pair line_intersect_coord(PointType const& r, + unsigned int const& rand_coord, + VT &lamdas) const + { + + std::pair polypair = P.line_intersect_coord(r, rand_coord, lamdas); + std::pair ellipsoidpair = E.line_intersect_coord(r, rand_coord); + return std::pair(std::min(polypair.first, ellipsoidpair.first), + std::max(polypair.second, ellipsoidpair.second)); + } + + //Not the first coordinate ray shooting intersecting convex body + std::pair line_intersect_coord(PointType const& r, + PointType const& r_prev, + unsigned int const& rand_coord, + unsigned int const& rand_coord_prev, + VT &lamdas) const + { + std::pair polypair = P.line_intersect_coord(r, r_prev, rand_coord, + rand_coord_prev, lamdas); + std::pair ellipsoidpair = E.line_intersect_coord(r, rand_coord); + return std::pair(std::min(polypair.first, ellipsoidpair.first), + std::max(polypair.second, ellipsoidpair.second)); + } + + std::pair query_dual(PointType const& p, + unsigned int const& rand_coord) + { + std::pair polypair = P.query_dual(p, rand_coord); + std::pair ellipsoidpair = E.line_intersect_coord(p, rand_coord); + return std::pair(std::min(polypair.first, ellipsoidpair.first), + std::max(polypair.second, ellipsoidpair.second)); + } + + void compute_reflection (PointType& v, PointType const& p, int &facet) + { + + if (facet == P.num_of_hyperplanes()) { + E.compute_reflection(v, p); + } else { + P.compute_reflection(v, p, facet); + } + + } + + template + void compute_reflection (PointType &v, PointType const& p, update_parameters ¶ms) + { + if (params.hit_ball) { + E.compute_reflection(v, p, params); + } else { + P.compute_reflection(v, p, params); + } + } + + void update_position_internal(NT&){} + + void resetFlags() {} + + std::pair ComputeInnerBall() + { + return P.ComputeInnerBall(); + } + + // Not supported oracles + + std::pair quadratic_positive_intersect(PointType const& r, //current poistion + PointType const& v, // current velocity + VT& Ac, // the product Ac where c is the bias vector of the exponential distribution + NT const& T, // the variance of the exponential distribution + VT& Ar, // the product Ar + VT& Av, // the product Av + int& facet_prev) const //the facet that the trajectory hit in the previous reflection + { + std::runtime_error("Quadratic oracle is not supported by the intersection of an H-polytope with an ellipsoid."); + return std::make_pair(NT(0), 0); // this is added to avoid warnings + } + + std::pair quadratic_positive_intersect(PointType const& r, //current poistion + PointType const& v, // current velocity + VT& Ac, // the product Ac where c is the bias vector of the exponential distribution + NT const& T, // the variance of the exponential distribution + VT& Ar, // the product Ar + VT& Av, // the product Av + NT const& lambda_prev, // the intersection time of the previous reflection + int& facet_prev) const //the facet that the trajectory hit in the previous reflection + { + std::runtime_error("Quadratic oracle is not supported by the intersection of an H-polytope with an ellipsoid."); + return std::make_pair(NT(0), 0); // this is added to avoid warnings + } + + std::pair trigonometric_positive_intersect(PointType const& r, PointType const& v, + NT const& omega, int &facet_prev) const + { + std::runtime_error("Trigonometric oracle is not supported by the intersection of an H-polytope with an ellipsoid."); + return std::make_pair(NT(0), 0); // this is added to avoid warnings + } + +}; + +#endif // ELLIPSOIDINTERSECTCONVEX_H diff --git a/include/ode_solvers/implicit_midpoint.hpp b/include/ode_solvers/implicit_midpoint.hpp index 71408e542..786734d84 100644 --- a/include/ode_solvers/implicit_midpoint.hpp +++ b/include/ode_solvers/implicit_midpoint.hpp @@ -53,16 +53,15 @@ inline std::vector operator-(const std::vector &v1, return v1 + v2 * (-1.0); } -template +template struct ImplicitMidpointODESolver { using VT = typename Polytope::VT; using MT = typename Polytope::MT; - using pts = std::vector; - using hamiltonian = Hamiltonian; + using pts = std::vector; + using hamiltonian = Hamiltonian; using Opts = opts; unsigned int dim; - NT eta; int num_steps = 0; NT t; @@ -75,17 +74,14 @@ struct ImplicitMidpointODESolver { func F; Polytope &P; Opts &options; - VT nu; - + MT nu; + int num_runs = 0; hamiltonian ham; - bool done; #ifdef TIME_KEEPING std::chrono::time_point start, end; - std::chrono::duration DU_duration = - std::chrono::duration::zero(); - std::chrono::duration approxDK_duration = - std::chrono::duration::zero(); + std::chrono::duration DU_duration = std::chrono::duration::zero(); + std::chrono::duration approxDK_duration = std::chrono::duration::zero(); #endif ImplicitMidpointODESolver(NT initial_time, NT step, @@ -101,10 +97,11 @@ struct ImplicitMidpointODESolver { options(user_options), ham(hamiltonian(boundaries)) { - dim = xs[0].dimension(); + dim = xs[0].rows(); }; void step(int k, bool accepted) { + num_runs++; pts partialDerivatives; #ifdef TIME_KEEPING start = std::chrono::system_clock::now(); @@ -117,7 +114,7 @@ struct ImplicitMidpointODESolver { xs = xs + partialDerivatives * (eta / 2); xs_prev = xs; done = false; - nu = VT::Zero(P.equations()); + nu = MT::Zero(P.equations(), simdLen); for (int i = 0; i < options.maxODEStep; i++) { pts xs_old = xs; pts xmid = (xs_prev + xs) / 2.0; @@ -125,20 +122,21 @@ struct ImplicitMidpointODESolver { start = std::chrono::system_clock::now(); #endif partialDerivatives = ham.approxDK(xmid, nu); + #ifdef TIME_KEEPING end = std::chrono::system_clock::now(); approxDK_duration += end - start; #endif xs = xs_prev + partialDerivatives * (eta); - NT dist = ham.x_norm(xmid, xs - xs_old) / eta; - NT maxdist = dist; + VT dist = ham.x_norm(xmid, xs - xs_old) / eta; + NT maxdist = dist.maxCoeff(); //If the estimate does not change terminate if (maxdist < options.implicitTol) { done = true; num_steps = i; break; - //If the estimate is very bad sample another velocity - } else if (maxdist > options.convergence_limit) { + //If the estimate is very bad, sample another velocity + } else if (maxdist > options.convergence_bound) { xs = xs * std::nan("1"); done = true; num_steps = i; @@ -163,16 +161,15 @@ struct ImplicitMidpointODESolver { } } - Point get_state(int index) { return xs[index]; } + MT get_state(int index) { return xs[index]; } - void set_state(int index, Point p) { xs[index] = p; } - void print_state() { + void set_state(int index, MT p) { xs[index] = p; } + template + void print_state(StreamType &stream) { for (int j = 0; j < xs.size(); j++) { - std::cerr << "state " << j << ": "; - for (unsigned int i = 0; i < xs[j].dimension(); i++) { - std::cerr << xs[j][i] << " "; - } - std::cerr << '\n'; + stream << "state " << j << ": \n"; + stream << xs[j]; + stream << '\n'; } } }; diff --git a/include/ode_solvers/leapfrog.hpp b/include/ode_solvers/leapfrog.hpp index 4c1f299b0..b7f2724b4 100644 --- a/include/ode_solvers/leapfrog.hpp +++ b/include/ode_solvers/leapfrog.hpp @@ -56,6 +56,8 @@ struct LeapfrogODESolver { pts xs; pts xs_prev; + Point grad_x; + MT _AA; std::pair pbpair; @@ -69,11 +71,11 @@ struct LeapfrogODESolver { eta(step), eta0(step), t(initial_time), F(oracle), Ks(boundaries), xs(initial_state), adaptive(adaptive_) { dim = xs[0].dimension(); _update_parameters = update_parameters(); + grad_x.set_dimension(dim); initialize(); }; - void initialize() { for (unsigned int i = 0; i < xs.size(); i++) { VT ar, av; @@ -88,7 +90,6 @@ struct LeapfrogODESolver { Av.push_back(av); lambda_prev.push_back(NT(0)); } - //step(); } void disable_adaptive() { @@ -101,27 +102,28 @@ struct LeapfrogODESolver { void step(int k, bool accepted) { num_steps++; - if (adaptive) eta = (eta0 * num_steps) / (num_steps + num_reflections); xs_prev = xs; unsigned int x_index, v_index, it; t += eta; + Point y; for (unsigned int i = 1; i < xs.size(); i += 2) { - //pbpair.second = -1; + x_index = i - 1; v_index = i; // v' <- v + eta / 2 F(x) - Point z = F(v_index, xs_prev, t); - z = (eta / 2) * z; - xs[v_index] = xs[v_index] + z; + if (k == 0 && !accepted) { + grad_x = F(v_index, xs_prev, t); + } + xs[v_index] += (eta / 2) * grad_x; // x <- x + eta v' - Point y = xs[v_index]; + y = xs[v_index]; if (Ks[x_index] == NULL) { - xs[x_index] = xs_prev[x_index] + eta*y; + xs[x_index] += eta*y; } else { // Find intersection (assuming a line trajectory) between x and y @@ -173,10 +175,8 @@ struct LeapfrogODESolver { } // tilde v <- v + eta / 2 F(tilde x) - z = F(v_index, xs, t); - z = (eta / 2) * z; - xs[v_index] = xs[v_index] + z; - + grad_x = F(v_index, xs, t); + xs[v_index] += (eta / 2) * grad_x; } } @@ -202,6 +202,19 @@ struct LeapfrogODESolver { xs[index] = p; } + NT get_eta() { + return eta; + } + + void set_eta(NT &eta_) { + eta = eta_; + eta0 = eta_; + } + + bounds get_bounds() { + return Ks; + } + }; diff --git a/include/ode_solvers/oracle_functors.hpp b/include/ode_solvers/oracle_functors.hpp index 056e96c3a..fef8ce7e5 100644 --- a/include/ode_solvers/oracle_functors.hpp +++ b/include/ode_solvers/oracle_functors.hpp @@ -142,11 +142,11 @@ struct IsotropicQuadraticFunctor { return xs[i + 1]; // returns derivative } } - - Point operator()(Point const&x){ - Point y = (-params.alpha)*x; - return y; - } + + Point operator()(Point const &x){ + Point y = (-params.alpha) * x; + return y; + } }; @@ -392,4 +392,103 @@ struct HessianFunctor { }; +struct DirichletFunctor { + + // Sample from the Dirichlet distribution + template < + typename NT, + typename Point + > + struct parameters { + typedef typename Point::Coeff VT; + + unsigned int order; + NT L; // Lipschitz constant for gradient + NT m; // Strong convexity constant + NT kappa; // Condition number + VT a_vec; // Coefficients of LP objective + NT eta; + + parameters(VT a_vec_) : order(2), L(1), m(1), kappa(1), eta(-1), a_vec(a_vec_) {}; + parameters(VT a_vec_, NT eta_) : order(2), L(1), m(1), kappa(1), a_vec(a_vec_), eta(eta_) {}; + + }; + + template + < + typename Point + > + struct GradientFunctor { + typedef typename Point::FT NT; + typedef typename Point::Coeff VT; + typedef std::vector pts; + + parameters ¶ms; + unsigned int dim; + + GradientFunctor(parameters ¶ms_) : params(params_) { + dim = params_.a_vec.size(); + } + + // The index i represents the state vector index + Point operator() (unsigned int const& i, pts const& xs, NT const& t) const { + if (i == params.order - 1) { + VT grad(dim); + VT x = xs[0].getCoefficients(); + NT *grad_data = grad.data(); + for (int i = 0; i < dim; i++) + { + *grad_data = ((params.a_vec.coeff(i) - NT(1)) / x.getCoefficients().coeff(i)); + grad_data++; + } + Point y(grad); + return y; + } else { + return xs[i + 1]; // returns derivative + } + } + + Point operator()(Point const&x){ + VT grad(dim); + NT *grad_data = grad.data(); + for (int i = 0; i < dim; i++) + { + *grad_data = ((params.a_vec.coeff(i) - NT(1)) / x.getCoefficients().coeff(i)); + grad_data++; + } + Point y(grad); + return y; + } + + }; + + template + < + typename Point + > + struct FunctionFunctor { + typedef typename Point::FT NT; + typedef typename Point::Coeff VT; + + parameters ¶ms; + unsigned int dim; + + FunctionFunctor(parameters ¶ms_) : params(params_) { + dim = params_.a_vec.size(); + }; + + // The index i represents the state vector index + NT operator() (Point const& x) const { + NT neg_val = NT(0); + for (int i = 0; i < dim; i++) + { + neg_val -= (params.a_vec.coeff(i) - NT(1)) * std::log(x.getCoefficients().coeff(i)); + } + return neg_val; + } + + }; + +}; + #endif diff --git a/include/ode_solvers/oracle_functors_rcpp.hpp b/include/ode_solvers/oracle_functors_rcpp.hpp index 558ac1b07..853dcb3c0 100644 --- a/include/ode_solvers/oracle_functors_rcpp.hpp +++ b/include/ode_solvers/oracle_functors_rcpp.hpp @@ -91,6 +91,17 @@ struct RcppFunctor { } } + Point operator() (Point const& x) const { + VT y = Rcpp::as(neg_grad_f(Rcpp::wrap(x.getCoefficients()))); + + Point z(y); + + if (negate) z = (-1.0) * z; + + // Return result as Point + return z; + } + }; // Negative log-probability functor @@ -118,6 +129,31 @@ struct RcppFunctor { }; + // Log-probability hessian functor + template + < + typename Point + > + struct HessianFunctor { + typedef typename Point::FT NT; + typedef typename Point::Coeff VT; + + parameters params; + Rcpp::Function hessian; // Negative hessian as an Rcpp::Function + + HessianFunctor( + parameters params_, + Rcpp::Function hessian_) : + params(params_), + hessian(hessian_) + {}; + + Point operator() (Point const& x) const { + VT y= Rcpp::as(hessian(Rcpp::wrap(x.getCoefficients()))); + return Point(y); + } + + }; }; #endif diff --git a/include/preprocess/crhmc/analytic_center.h b/include/preprocess/crhmc/analytic_center.h index 35d4349aa..7124626b4 100644 --- a/include/preprocess/crhmc/analytic_center.h +++ b/include/preprocess/crhmc/analytic_center.h @@ -27,14 +27,6 @@ #endif const size_t chol_k2 = (SIMD_LEN == 0) ? 1 : SIMD_LEN; -using NT = double; -using MT = Eigen::Matrix; -using VT = Eigen::Matrix; -using SpMat = Eigen::SparseMatrix; -using CholObj = PackedChol; -using Triple = Eigen::Triplet; -using Tx = FloatArray; -using Opts = opts; /*This function computes the analytic center of the polytope*/ //And detects additional constraint that need to be added // x - It outputs the minimizer of min f(x) subjects to {Ax=b} @@ -43,9 +35,12 @@ using Opts = opts; // because of the dom(f), the algorithm will detect the collapsed dimension // and output the detected constraint C x = d // d - detected constraint vector -template +template std::tuple analytic_center(SpMat const &A, VT const &b, Polytope &f, Opts const &options, VT x = VT::Zero(0, 1)) { + using CholObj = typename Polytope::CholObj; + using Triple = typename Polytope::Triple; + using Tx = typename Polytope::Tx; // initial conditions int n = A.cols(); int m = A.rows(); @@ -65,7 +60,7 @@ std::tuple analytic_center(SpMat const &A, VT const &b, Polytope std::vector idx; CholObj solver = CholObj(transform_format(A)); - + solver.accuracyThreshold = 0; for (int iter = 0; iter < options.ipmMaxIter; iter++) { std::pair pair_analytic_oracle = f.analytic_center_oracle(x); @@ -159,14 +154,14 @@ std::tuple analytic_center(SpMat const &A, VT const &b, Polytope std::pair pboundary = f.barrier.boundary(x); VT A_ = pboundary.first; VT b_ = pboundary.second; - A_ = A_(idx); std::vector sparseIdx; for (int i = 0; i < idx.size(); i++) { - sparseIdx.push_back(Triple(i, i, A_(i))); + sparseIdx.push_back(Triple(i, idx[i], A_(idx[i]))); } C.setFromTriplets(sparseIdx.begin(), sparseIdx.end()); - d = b_(idx); + d.resize(idx.size(), 1); + copy_indicies(d, b_, idx); } else { diff --git a/include/preprocess/crhmc/constraint_problem.h b/include/preprocess/crhmc/constraint_problem.h new file mode 100644 index 000000000..829315059 --- /dev/null +++ b/include/preprocess/crhmc/constraint_problem.h @@ -0,0 +1,81 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis +// Copyright (c) 2022-2022 Ioannis Iakovidis + +// Contributed and/or modified by Ioannis Iakovidis, as part of Google Summer of +// Code 2022 program. + +// Licensed under GNU LGPL.3, see LICENCE file + +#ifndef CONSTRAINT_PROBLEM_H +#define CONSTRAINT_PROBLEM_H +#include "Eigen/Eigen" +/*Input structure: With this the user can define a polytope sampling problem*/ +template +class constraint_problem { +public: + using Type = typename Point::FT; + using PointType = Point; + using VT = Eigen::Matrix; + using MT = MatrixType; +private: + unsigned int num_vars; // num_vars of the original problem + MatrixType Aeq; // Matrix of coefficients for the equality constraints + VT beq; // Right hand side of the equality constraints + MatrixType Aineq; // Matrix of coefficients for the inequality constraints + VT bineq; // Right hand side of the inequality constraints + VT lb; // lb on the output coordinates preset to -1e9 + VT ub; // ub on the output coordinates preset to +1e9 + Type inf = 1e9; +public: + /*Constructors for different input instances*/ + constraint_problem(const int dim, MT const &Aeq_, VT const &beq_, MT const &Aineq_, + VT const &bineq_, VT const &lb_, VT const &ub_) + : num_vars(dim), Aeq(Aeq_), beq(beq_), Aineq(Aineq_), bineq(bineq_), + lb(lb_), ub(ub_) { + } + + constraint_problem(const int dim) { + num_vars = dim; + init(num_vars); + } + + + void init(int num_vars) { + Aineq.resize(0, num_vars); + Aeq.resize(0, num_vars); + bineq.resize(0, 1); + beq.resize(0, 1); + lb = -VT::Ones(num_vars) * inf; + ub = VT::Ones(num_vars) * inf; + } + void set_equality_constraints(MT const &Aeq_, VT const &beq_){ + Aeq = Aeq_; + beq = beq_; + } + void set_inequality_constraints(MT const &Aineq_, VT const &bineq_){ + Aineq = Aineq_; + bineq = bineq_; + } + void set_bounds(VT const &lb_, VT const &ub_){ + lb = lb_; + ub = ub_; + } + std::pair get_equations(){ + return std::make_pair(Aeq,beq); + } + std::pair get_inequalities(){ + return std::make_pair(Aineq,bineq); + } + std::pair get_bounds(){ + return std::make_pair(lb,ub); + } + unsigned int dimension(){ + return num_vars; + } + +}; + +#endif diff --git a/include/preprocess/crhmc/crhmc_input.h b/include/preprocess/crhmc/crhmc_input.h index 1a674f1e4..05f61c4b8 100644 --- a/include/preprocess/crhmc/crhmc_input.h +++ b/include/preprocess/crhmc/crhmc_input.h @@ -17,12 +17,20 @@ #define CRHMC_INPUT_H #include "Eigen/Eigen" #include "opts.h" +#include "convex_bodies/hpolytope.h" +#include "preprocess/crhmc/constraint_problem.h" /*0 funciton handles are given as a reference in case the user gives no function. Then the uniform function is implied*/ template struct ZeroFunctor { + using Type = typename Point::FT; Point operator()(Point const &x) const { return Point(x.dimension()); } + struct parameters { + Type L=1; + Type eta=1; + }; + struct parameters params; }; template struct ZeroScalarFunctor @@ -45,9 +53,11 @@ class crhmc_input ZeroScalarFunctor zerosf; public: + using MT = MatrixType; using Func = func; using Grad = grad; using Hess = hess; + using point= Point; MatrixType Aineq; // Matrix of coefficients for the inequality constraints VT bineq; // Right hand side of the inequality constraints MatrixType Aeq; // Matrix of coefficients for the equality constraints @@ -62,37 +72,38 @@ class crhmc_input bool fHandle; // whether f is handle or not bool dfHandle; // whether df is handle or not bool ddfHandle; // whether ddf is handle or not + unsigned int dimension; // dimension of the original problem const Type inf = options.max_coord + 1; // helper for barrier handling /*Constructors for different input instances*/ - crhmc_input(int dimension, func &function, grad &g, hess &h) + crhmc_input(int dim, func &function, grad &g, hess &h) : f(function), df(g), ddf(h) - { + { dimension=dim; fZero = false; fHandle = true; dfHandle = true; ddfHandle = true; init(dimension); } - crhmc_input(int dimension, func &function) + crhmc_input(int dim, func &function) : f(function), df(zerof), ddf(zerof) - { + { dimension=dim; fZero = false; fHandle = true; dfHandle = false; ddfHandle = false; init(dimension); } - crhmc_input(int dimension, func &function, grad &g) + crhmc_input(int dim, func &function, grad &g) : f(function), df(g), ddf(zerof) - { + { dimension=dim; fZero = false; fHandle = true; dfHandle = true; ddfHandle = false; init(dimension); } - crhmc_input(int dimension) : f(zerosf), df(zerof), ddf(zerof) - { + crhmc_input(int dim) : f(zerosf), df(zerof), ddf(zerof) + { dimension=dim; fZero = true; fHandle = false; dfHandle = false; @@ -110,4 +121,52 @@ class crhmc_input ub = VT::Ones(dimension) * inf; } }; +#include + +template < + typename Input, typename Polytope, typename Func, typename Grad, typename Hess, + typename std::enable_if>::value>::type * = nullptr> +inline Input convert2crhmc_input(Polytope &P, Func &f, Grad &g, Hess &h) { + int dimension = P.dimension(); + Input input = Input(dimension, f, g, h); + if (std::is_same< + Hess, ZeroFunctor>::value){ + input.ddfHandle=false; + } + input.Aineq = P.get_mat(); + input.bineq = P.get_vec(); + return input; +} + +template >::value>::type + * = nullptr> +inline Input convert2crhmc_input(Polytope &P, Func &f, Grad &g, Hess &h) { + int dimension = P.dimension(); + Input input = Input(dimension, f, g, h); + if (std::is_same< + Hess, ZeroFunctor>::value){ + input.ddfHandle=false; + } + std::tie(input.Aineq, input.bineq) = P.get_inequalities(); + std::tie(input.Aeq, input.beq) = P.get_equations(); + std::tie(input.lb, input.ub) = P.get_bounds(); + return input; +} +template >::value && + !std::is_same>::value>:: + type * = nullptr> +inline Input convert2crhmc_input(Polytope &P, Func &f, Grad &g, Hess &h) { + /*CRHMC works only for H-polytopes and constraint_problems for now*/ + int dimension = 0; + Input input = Input(dimension, f, g, h); + return input; +} #endif diff --git a/include/preprocess/crhmc/crhmc_problem.h b/include/preprocess/crhmc/crhmc_problem.h index 68ccb25e5..c501bce62 100644 --- a/include/preprocess/crhmc/crhmc_problem.h +++ b/include/preprocess/crhmc/crhmc_problem.h @@ -60,6 +60,7 @@ class crhmc_problem { using Func = typename Input::Func; using Grad = typename Input::Grad; using Hess = typename Input::Hess; + using Crhmc_problem=crhmc_problem; unsigned int _d; // dimension // Problem variables Ax=b st lb<=x<=ub @@ -93,15 +94,20 @@ class crhmc_problem { bool fHandle; // whether f is handle or not bool dfHandle; // whether df is handle or not bool ddfHandle; // whether ddf is handle or not + /*Invalid polytope variables*/ + bool terminate=false; + std::string terminate_message; #ifdef TIME_KEEPING //Timing information std::chrono::duration rescale_duration, sparsify_duration, reordering_duration, rm_rows_duration, rm_fixed_vars_duration, ex_collapsed_vars_duration, shift_barrier_duration, lewis_center_duration; #endif - const NT inf = options.max_coord + 1; // helper for barrier handling + const NT inf = options.max_coord; // helper for barrier handling + const NT barrier_bound = 1e7; int equations() const { return Asp.rows(); } int dimension() const { return Asp.cols(); } + int nnz() const { return Asp.nonZeros(); } // Remove varibles that have width under some tolerance int remove_fixed_variables(const NT tol = 1e-12) { @@ -109,6 +115,7 @@ class crhmc_problem { int n = Asp.cols(); VT d = estimate_width(); CholObj solver = CholObj(transform_format(Asp)); + solver.accuracyThreshold = 0; VT w = VT::Ones(n, 1); solver.decompose((Tx *)w.data()); VT out_vector = VT(m, 1); @@ -133,7 +140,16 @@ class crhmc_problem { SpMat S = SpMat(n, freeIndices.size()); S.setFromTriplets(freeIndices.begin(), freeIndices.end()); append_map(S, x); - barrier.set_bound(barrier.lb(indices), barrier.ub(indices)); + copy_indicies(barrier.lb, barrier.lb, indices); + copy_indicies(barrier.ub, barrier.ub, indices); + barrier.lb.conservativeResize(indices.size()); + barrier.ub.conservativeResize(indices.size()); + + barrier.set_bound(barrier.lb, barrier.ub); + if (!isempty_center) { + copy_indicies(center, center, indices); + center.conservativeResize(indices.size()); + } return 1; } return 0; @@ -143,20 +159,20 @@ class crhmc_problem { SpMat Ac; VT bc; if (isempty_center) { - std::tie(center, Ac, bc) = analytic_center(Asp, b, *this, options); + std::tie(center, Ac, bc) = analytic_center(Asp, b, *this, options); isempty_center = false; } else { std::tie(center, Ac, bc) = - analytic_center(Asp, b, *this, options, center); + analytic_center(Asp, b, *this, options, center); analytic_ctr=center; } if (Ac.rows() == 0) { return 0; } - SpMat _A = Asp; - sparse_stack_v(Ac, _A, Asp); - b.resize(b.rows() + bc.rows(), 1); - b << bc, b; + SpMat _A = SpMat(Asp); + sparse_stack_v(_A, Ac, Asp); + b.conservativeResize(b.rows() + bc.rows(), 1); + b.bottomRows(bc.rows()) = bc; return 1; } // Rescale the polytope for numerical stability @@ -273,45 +289,41 @@ class crhmc_problem { // Reorder the polytope accordint to the AMD Reordering for better sparsity // pattern in the Cholesky decomposition void reorder() { - if (!options.EnableReordering) { + if (!options.EnableReordering || Asp.rows()*Asp.cols() < options.maxNZ) { return; } - Asp.prune(0.0); - Asp.makeCompressed(); - int m = Asp.rows(); - SpMat H; - H = Asp * SpMat(Asp.transpose()) + MT::Identity(m, m); - H.makeCompressed(); - PM permed = permuteMatAMD(H); - H = permed * H * permed.transpose(); - PM post_perm = postOrderPerm(H); - PM perm = permed * post_perm; - Asp = perm * Asp; - b = perm * b; + fillin_reduce(Asp,b); } //Using the Cholesky decomposition remove dependent rows in the systen Asp*x=b int remove_dependent_rows(NT tolerance = 1e-12, NT infinity = 1e+64) { - //this approach does not work with 0 collumns - remove_zero_rows(Asp); + //this approach does not work with 0 rows + remove_zero_rows(Asp, b); int m = Asp.rows(); int n = Asp.cols(); VT v = VT(m); VT w = VT::Ones(n, 1); CholObj solver = CholObj(transform_format(Asp)); + solver.accuracyThreshold = 0; solver.decompose((Tx *)w.data()); solver.diagL((Tx *)v.data()); - std::vector indices; + std::vector indices(m, false); + std::vector idx; + bool changed = false; for (int i = 0; i < m; i++) { if ((v(i) > tolerance) && (v(i) < infinity)) { - indices.push_back(i); + indices[i] = true; + idx.push_back(i); + }else{ + changed=true; } } - if (indices.size() == m) { + if (!changed) { return 0; } - Asp = A(indices, Eigen::all).sparseView(); - b = b(indices); + remove_rows(Asp, indices); + copy_indicies(b, b, idx); + b.conservativeResize(idx.size(), 1); return 1; } //Apply number of operations that simplify the problem @@ -373,10 +385,14 @@ class crhmc_problem { } } - VT estimate_width() { + VT estimate_width(bool use_center=false) { int n = Asp.cols(); VT hess = VT::Ones(n, 1); + if(use_center){ + std::tie(std::ignore, hess)=analytic_center_oracle(center); + } CholObj solver = CholObj(transform_format(Asp)); + solver.accuracyThreshold = 0; solver.decompose((Tx *)hess.data()); VT w_vector(n, 1); solver.leverageScoreComplement((Tx *)w_vector.data()); @@ -386,75 +402,110 @@ class crhmc_problem { return tau; } - void print(std::string const message = "Printing Sparse problem") { - std::cerr << "----------------" << message << "--------------" << '\n'; - std::cerr << "(m,n) = " << equations() << " , " << dimension() + template + void print(StreamType &stream, std::string const message = "Printing Sparse problem") { + stream << "----------------" << message << "--------------" << '\n'; + stream << "(m,n) = " << equations() << " , " << dimension() << " nnz= " << Asp.nonZeros() << "\n"; if (equations() > 20 || dimension() > 20) { - std::cerr << "too big for complete visulization\n"; + stream << "too big for complete visulization\n"; return; } - std::cerr << "A=\n"; + stream << "A=\n"; - std::cerr << MT(Asp); - std::cerr << "\n"; + stream << MT(Asp); + stream << "\n"; - std::cerr << "b=\n"; - std::cerr << b; - std::cerr << "\n"; + stream << "b=\n"; + stream << b; + stream << "\n"; - std::cerr << "lb=\n"; - std::cerr << barrier.lb; - std::cerr << "\n"; + stream << "lb=\n"; + stream << barrier.lb; + stream << "\n"; - std::cerr << "ub=\n"; - std::cerr << barrier.ub; - std::cerr << "\n"; + stream << "ub=\n"; + stream << barrier.ub; + stream << "\n"; - std::cerr << "T=\n"; - std::cerr << MT(T); - std::cerr << "\n"; + stream << "T=\n"; + stream << MT(T); + stream << "\n"; - std::cerr << "y=\n"; - std::cerr << y; - std::cerr << "\n"; + stream << "y=\n"; + stream << y; + stream << "\n"; - std::cerr << "center=\n"; - std::cerr << center; - std::cerr << "\n"; + stream << "center=\n"; + stream << center; + stream << "\n"; } - void print(const char *fileName) { - std::ofstream myfile; - myfile.open(fileName); - myfile << Asp.rows() << " " << Asp.cols() << "\n"; - - myfile << MT(Asp); - myfile << "\n"; - myfile << "\n"; - - myfile << b; - myfile << "\n"; - myfile << "\n"; - - myfile << barrier.lb; - myfile << "\n"; - myfile << "\n"; - - myfile << barrier.ub; - myfile << "\n"; - myfile << "\n"; - - myfile << MT(T); - myfile << "\n"; - myfile << "\n"; - - myfile << y; - myfile << "\n"; - myfile << "\n"; - - myfile << center; - } + void make_format(Input const &input, MT const &S) { + nP = input.Aeq.cols(); + int nIneq = input.Aineq.rows(); + int nEq = input.Aeq.rows(); + A.resize(nEq + nIneq, nP + nIneq); + A << input.Aeq, MT::Zero(nEq, nIneq), input.Aineq, MT::Identity(nIneq, nIneq); + b.resize(nEq + nIneq, 1); + b << input.beq, input.bineq; + lb.resize(nP + nIneq, 1); + ub.resize(nP + nIneq, 1); + lb << input.lb, MT::Zero(nIneq, 1); + ub << input.ub, MT::Ones(nIneq, 1) * inf; + Asp.resize(nEq + nIneq, nP + nIneq); + int n = dimension(); + /*Move lb=ub to Ax=b*/ + for (int i = 0; i < n; i++) { + if (doubleVectorEqualityComparison(lb(i), ub(i))) { + MT temp = MT::Zero(1, n); + temp(i) = 1; + A.conservativeResize(A.rows() + 1, A.cols()); + A.row(A.rows() - 1) = temp; + b.conservativeResize(b.rows() + 1); + b(b.rows() - 1) = (lb(i) + ub(i)) / 2; + lb(i) = -inf; + ub(i) = inf; + } + } + Asp = A.sparseView(); + } + void make_format(Input const &input, SpMat const &S) { + nP = input.Aeq.cols(); + int nIneq = input.Aineq.rows(); + int nEq = input.Aeq.rows(); + Asp.resize(nEq + nIneq, nP + nIneq); + SpMat B = SpMat(input.Aeq); + SpMat C = SpMat(input.Aineq); + B.conservativeResize(nEq, nIneq + nP); + SpMat temp = SpMat(nIneq, nIneq); + temp.setIdentity(); + sparse_stack_h_inplace(C, temp); + sparse_stack_v(B, C, Asp); + b.resize(nEq + nIneq, 1); + b << input.beq, input.bineq; + lb.resize(nP + nIneq, 1); + ub.resize(nP + nIneq, 1); + lb << input.lb, MT::Zero(nIneq, 1); + ub << input.ub, MT::Ones(nIneq, 1) * inf; + int n = dimension(); + /*Move lb=ub to Ax=b*/ + for (int i = 0; i < n; i++) { + if (doubleVectorEqualityComparison(lb(i), ub(i))) { + B.resize(Asp.rows(), Asp.cols()); + B = SpMat(Asp); + MT temp = MT::Zero(1, n); + temp(i) = 1; + C = temp.sparseView(); + sparse_stack_v(B, C, Asp); + b.conservativeResize(b.rows() + 1); + b(b.rows() - 1) = (lb(i) + ub(i)) / 2; + lb(i) = -inf; + ub(i) = inf; + } + } + Asp.makeCompressed(); + } //Class constructor crhmc_problem(Input const &input, Opts _options = Opts()) : options(_options), func(input.f), df(input.df), ddf(input.ddf), @@ -467,41 +518,13 @@ class crhmc_problem { std::chrono::duration::zero(); #endif - nP = input.Aeq.cols(); - int nIneq = input.Aineq.rows(); - int nEq = input.Aeq.rows(); - A.resize(nEq + nIneq, nP + nIneq); - A << input.Aeq, MT::Zero(nEq, nIneq), input.Aineq, - MT::Identity(nIneq, nIneq); - b.resize(nEq + nIneq, 1); - b << input.beq, input.bineq; - lb.resize(nP + nIneq, 1); - ub.resize(nP + nIneq, 1); - lb << input.lb, MT::Zero(nIneq, 1); - ub << input.ub, MT::Ones(nIneq, 1) * inf; - Asp.resize(nEq + nIneq, nP + nIneq); + make_format(input, input.Aeq); PreproccessProblem(); } // Initialization funciton void PreproccessProblem() { int n = dimension(); - /*Move lb=ub to Ax=b*/ - for (int i = 0; i < n; i++) { - if (doubleVectorEqualityComparison(lb(i), ub(i))) { - MT temp = MT::Zero(1, n); - temp(i) = 1; - A.conservativeResize(A.rows() + 1, A.cols()); - A.row(A.rows() - 1) = temp; - b.conservativeResize(b.rows() + 1); - b(b.rows() - 1) = (lb(i) + ub(i)) / 2; - lb(i) = -inf; - ub(i) = inf; - } - } - - barrier.set_bound(lb.cwiseMax(-1e7), ub.cwiseMin(1e7)); - - Asp = A.sparseView(); + barrier.set_bound(lb.cwiseMax(-barrier_bound), ub.cwiseMin(barrier_bound)); NT tol = std::numeric_limits::epsilon(); Asp.prune(tol, tol); /*Update the transformation Tx + y*/ @@ -527,7 +550,7 @@ class crhmc_problem { #endif if (isempty_center) { std::tie(center, std::ignore, std::ignore) = - analytic_center(Asp, b, *this, options); + analytic_center(Asp, b, *this, options); isempty_center = false; } shift_barrier(center); @@ -537,22 +560,17 @@ class crhmc_problem { #endif reorder(); - width = estimate_width(); - if (width.maxCoeff() > 1e9) { - std::cerr << "Domain seems to be unbounded. Either add a Gaussian term " - "via f, df, ddf or add bounds to variable via lb and ub." - << '\n'; - exit(1); - } + width = estimate_width(true); // Recenter again and make sure it is feasible VT hess; #ifdef TIME_KEEPING start = std::chrono::system_clock::now(); #endif std::tie(center, std::ignore, std::ignore, w_center) = - lewis_center(Asp, b, *this, options, center); + lewis_center(Asp, b, *this, options, center); std::tie(std::ignore, hess) = lewis_center_oracle(center, w_center); CholObj solver = CholObj(transform_format(Asp)); + solver.accuracyThreshold = 0; VT Hinv = hess.cwiseInverse(); solver.decompose((Tx *)Hinv.data()); VT out(equations(), 1); @@ -565,81 +583,101 @@ class crhmc_problem { #endif if ((center.array() > barrier.ub.array()).any() || (center.array() < barrier.lb.array()).any()) { - std::cerr << "Polytope:Infeasible. The algorithm cannot find a feasible " - "point.\n"; - exit(1); + terminate = true; + terminate_message = "Polytope:Infeasible. The algorithm cannot find a feasible point.\n"; + return; } + } #ifdef TIME_KEEPING - std::cerr << "Rescale completed in time, "; - std::cerr << rescale_duration.count() << " secs " << std::endl; - std::cerr << "Split dense columns completed in time, "; - std::cerr << sparsify_duration.count() << " secs " << std::endl; - std::cerr << "Reordering completed in time, "; - std::cerr << reordering_duration.count() << " secs " << std::endl; - std::cerr << "Removing dependent rows completed in time, "; - std::cerr << rm_rows_duration.count() << " secs " << std::endl; - std::cerr << "Removing fixed variables completed in time, "; - std::cerr << rm_fixed_vars_duration.count() << " secs " << std::endl; - std::cerr << "Extracting collapsed variables completed in time, "; - std::cerr << ex_collapsed_vars_duration.count() << " secs " << std::endl; - std::cerr << "Shift_barrier completed in time, "; - std::cerr << shift_barrier_duration.count() << " secs " << std::endl; - std::cerr << "Finding Center completed in time, "; - std::cerr << lewis_center_duration.count() << " secs " << std::endl; +template +void print_preparation_time(StreamType& stream){ + stream << "---Preparation Timing Information"<< std::endl; + stream << "Rescale completed in time, "; + stream << rescale_duration.count() << " secs " << std::endl; + stream << "Split dense columns completed in time, "; + stream << sparsify_duration.count() << " secs " << std::endl; + stream << "Reordering completed in time, "; + stream << reordering_duration.count() << " secs " << std::endl; + stream << "Removing dependent rows completed in time, "; + stream << rm_rows_duration.count() << " secs " << std::endl; + stream << "Removing fixed variables completed in time, "; + stream << rm_fixed_vars_duration.count() << " secs " << std::endl; + stream << "Extracting collapsed variables completed in time, "; + stream << ex_collapsed_vars_duration.count() << " secs " << std::endl; + stream << "Shift_barrier completed in time, "; + stream << shift_barrier_duration.count() << " secs " << std::endl; + stream << "Finding Center completed in time, "; + stream << lewis_center_duration.count() << " secs " << std::endl; +} #endif - } - // Gradient and hessian of for the analytic center std::pair analytic_center_oracle(VT const &x) { - VT g, h; + MT g, h; std::tie(std::ignore, g, h) = f_oracle(x); return std::make_pair(g + barrier.gradient(x), h + barrier.hessian(x)); } // Gradient and hessian of for the lewis center std::pair lewis_center_oracle(VT const &x, VT const &w) { - VT g, h; + MT g, h; std::tie(std::ignore, g, h) = f_oracle(x); return std::make_pair(g + w.cwiseProduct(barrier.gradient(x)), h + w.cwiseProduct(barrier.hessian(x))); } // Function that uses the transformation (T,y) to apply the function to the // original variables - std::tuple f_oracle(VT x) { - NT f; - VT g, h; + std::tuple f_oracle(MT const &x) { int n = x.rows(); + int m=x.cols(); + VT f=VT(m); + MT g=MT(n,m); + MT h=MT(n,m); if (fZero) { - f = 0; - g = VT::Zero(n); - h = VT::Zero(n); + f = VT::Zero(m); + g = MT::Zero(n,m); + h = MT::Zero(n,m); return std::make_tuple(f, g, h); } // Take the correpsonding point in the original space - VT z = VT::Zero(n); + MT z = MT::Zero(y.rows(), m); if (fHandle || dfHandle || ddfHandle) { - z(Tidx, Eigen::all) = Ta.cwiseProduct(x(Tidx, Eigen::all)) + y; + for(int k=0;k #include "PackedCSparse/SparseMatrix.h" #include #include @@ -93,6 +94,7 @@ void sparse_stack_h(const SparseMatrixType &left, const SparseMatrixType &right, [&](int i) { return i + left.nonZeros(); }); } +#include template void sparse_stack_h_inplace(SparseMatrixType &left, @@ -116,16 +118,13 @@ void sparse_stack_h_inplace(SparseMatrixType &left, { return i + leftnz; }); } -template -void remove_zero_rows(SparseMatrixType &A) -{ +template +void remove_zero_rows(SparseMatrixType &A, VectorType &b) { std::vector> tripletList; unsigned Ndata = A.cols(); unsigned Nbins = A.rows(); - for (int k = 0; k < A.outerSize(); ++k) - { - for (typename SparseMatrixType::InnerIterator it(A, k); it; ++it) - { + for (int k = 0; k < A.outerSize(); ++k) { + for (typename SparseMatrixType::InnerIterator it(A, k); it; ++it) { tripletList.push_back( Eigen::Triplet(it.row(), it.col(), it.value())); } @@ -134,20 +133,19 @@ void remove_zero_rows(SparseMatrixType &A) std::vector has_value(Nbins, false); for (auto tr : tripletList) has_value[tr.row()] = true; - if (std::all_of(has_value.begin(), has_value.end(), - [](bool v) - { return v; })) - { + [](bool v) { return v; })) { return; } // create map from old to new indices std::map row_map; unsigned new_idx = 0; for (unsigned old_idx = 0; old_idx < Nbins; old_idx++) - if (has_value[old_idx]) - row_map[old_idx] = new_idx++; - + if (has_value[old_idx]) { + row_map[old_idx] = new_idx; + b(new_idx) = b(old_idx); + new_idx++; + } // make new triplet list, dropping empty rows std::vector> newTripletList; newTripletList.reserve(Ndata); @@ -156,36 +154,15 @@ void remove_zero_rows(SparseMatrixType &A) Eigen::Triplet(row_map[tr.row()], tr.col(), tr.value())); // form new matrix and return - SparseMatrixType ret(new_idx, Ndata); - ret.setFromTriplets(newTripletList.begin(), newTripletList.end()); - A = SparseMatrixType(ret); + A.resize(new_idx, Ndata); + A.setFromTriplets(newTripletList.begin(), newTripletList.end()); + b.conservativeResize(new_idx); } template -void remove_rows(SparseMatrixType &A, std::vector indices) -{ - std::vector> tripletList; +void remove_rows(SparseMatrixType &A, std::vector ¬Removed) { unsigned Ndata = A.cols(); unsigned Nbins = A.rows(); - for (int k = 0; k < A.outerSize(); ++k) - { - for (typename SparseMatrixType::InnerIterator it(A, k); it; ++it) - { - tripletList.push_back( - Eigen::Triplet(it.row(), it.col(), it.value())); - } - } - - std::vector notRemoved(Nbins, false); - for (auto tr : indices) - notRemoved[tr] = true; - - if (std::all_of(notRemoved.begin(), notRemoved.end(), - [](bool v) - { return v; })) - { - return; - } // create map from old to new indices std::map row_map; unsigned new_idx = 0; @@ -193,17 +170,18 @@ void remove_rows(SparseMatrixType &A, std::vector indices) if (notRemoved[old_idx]) row_map[old_idx] = new_idx++; - // make new triplet list, dropping empty rows - std::vector> newTripletList; - newTripletList.reserve(Ndata); - for (auto tr : tripletList) - newTripletList.push_back( - Eigen::Triplet(row_map[tr.row()], tr.col(), tr.value())); - + std::vector> tripletList; + for (int k = 0; k < A.outerSize(); ++k) { + for (typename SparseMatrixType::InnerIterator it(A, k); it; ++it) { + if (notRemoved[it.row()]) { + tripletList.push_back( + Eigen::Triplet(row_map[it.row()], it.col(), it.value())); + } + } + } // form new matrix and return - SparseMatrixType ret(new_idx, Ndata); - ret.setFromTriplets(newTripletList.begin(), newTripletList.end()); - A = SparseMatrixType(ret); + A.resize(new_idx, Ndata); + A.setFromTriplets(tripletList.begin(), tripletList.end()); } template @@ -352,6 +330,17 @@ PM postOrderPerm(SparseMatrixType const &A) return post_perm; } +template +void fillin_reduce(SparseMatrixType &X,VectorType& b){ + SparseMatrixType I = SparseMatrixType(Eigen::VectorXd::Ones(X.rows()).asDiagonal()); + SparseMatrixType XX = X * X.transpose() + I; + XX.makeCompressed(); + Eigen::SimplicialLDLT> cholesky; + cholesky.analyzePattern(XX); + X = cholesky.permutationP() * X; + b = cholesky.permutationP() *b; +} template PackedCSparse::SparseMatrix transform_format(SparseMatrixType const &mat) { PackedCSparse::SparseMatrix A = PackedCSparse::SparseMatrix(mat.rows(), mat.cols(), mat.nonZeros()); @@ -367,5 +356,51 @@ PackedCSparse::SparseMatrix transform_format(SparseMatrixType co A.p[A.n] = nnz; return A; } - +template +void copy_indicies(MatrixType& a, MatrixType& b, std::vectorconst & a_idx, std::vectorconst & b_idx){ +for(int i=0;i +void copy_indicies(MatrixType& a, MatrixType b, std::vectorconst & b_idx){ +for(int i=0;i +void set(MatrixType &a, std::vectorconst & idx, const Type c){ + for(int i=0;i +void saxpy(MatrixType &a,MatrixType const &b,MatrixType const& c, std::vectorconst & a_idx, std::vectorconst & b_idx){ +for(int i=0;i +void load_problem(SpMat &A, VT &b, VT &lb, VT &ub, int &dimension, + std::string problem_name) { + { + std::string fileName(problem_name); + fileName.append(".mm"); + SpMat X; + loadMarket(X, fileName); + int m = X.rows(); + dimension = X.cols() - 1; + A = X.leftCols(dimension); + b = VT(X.col(dimension)); + } + { + std::string fileName(problem_name); + fileName.append("_bounds.mm"); + SpMat bounds; + loadMarket(bounds, fileName); + lb = VT(bounds.col(0)); + ub = VT(bounds.col(1)); + } +} #endif diff --git a/include/preprocess/crhmc/lewis_center.h b/include/preprocess/crhmc/lewis_center.h index f6ee7b22e..5bf89d151 100644 --- a/include/preprocess/crhmc/lewis_center.h +++ b/include/preprocess/crhmc/lewis_center.h @@ -28,15 +28,6 @@ #endif const size_t chol_k3 = (SIMD_LEN == 0) ? 1 : SIMD_LEN; -using NT = double; -using MT = Eigen::Matrix; -using VT = Eigen::Matrix; -using SpMat = Eigen::SparseMatrix; -using CholObj = PackedChol; -using Triple = Eigen::Triplet; -using Tx = FloatArray; -using Opts = opts; -NT epsilon = 1e-8; /*This function computes the Lewis center of the polytope*/ //And detects additional constraint that need to be added // x - It outputs the minimizer of min f(x) subjects to {Ax=b} @@ -46,9 +37,13 @@ NT epsilon = 1e-8; // because of the dom(f), the algorithm will detect the collapsed dimension // and output the detected constraint C x = d // d - detected constraint vector -template +template std::tuple lewis_center(SpMat const &A, VT const &b, Polytope &f, Opts const &options, VT x = VT::Zero(0, 1)) { + using CholObj = typename Polytope::CholObj; + using Triple = typename Polytope::Triple; + using Tx = typename Polytope::Tx; + NT epsilon = 1e-8; // initial conditions int n = A.cols(); int m = A.rows(); @@ -173,14 +168,14 @@ std::tuple lewis_center(SpMat const &A, VT const &b, Polytope std::pair pboundary = f.barrier.boundary(x); VT A_ = pboundary.first; VT b_ = pboundary.second; - A_ = A_(idx); std::vector sparseIdx; for (int i = 0; i < idx.size(); i++) { - sparseIdx.push_back(Triple(i, i, A_(i))); + sparseIdx.push_back(Triple(i, idx[i], A_(idx[i]))); } C.setFromTriplets(sparseIdx.begin(), sparseIdx.end()); - d = b_(idx); + d.resize(idx.size(), 1); + copy_indicies(d, b_, idx); } else { diff --git a/include/preprocess/crhmc/opts.h b/include/preprocess/crhmc/opts.h index df73d5a7c..573a69dbd 100644 --- a/include/preprocess/crhmc/opts.h +++ b/include/preprocess/crhmc/opts.h @@ -26,28 +26,31 @@ template class opts { const Type ipmDistanceTol = 1e-8; const Type ipmDualTol = 1e-12; int maxNZ = 30; - Type max_coord = 1e7; - bool EnableReordering = false; + Type max_coord = 1e9; + bool EnableReordering = true; const int min_convergence_steps=8; /*ODE options*/ const Type implicitTol = 1e-5; const int maxODEStep = 30; Type initialStep = 0.2; - Type convergence_limit = 1e16; + Type convergence_bound = 1e16; + + /*PackedCS Solver Options*/ Type solver_accuracy_threshold=1e-2; + int simdLen=1; /*Sampler options*/ bool DynamicWeight = true; //Enable the use of dynamic weights for each variable when sampling bool DynamicStepSize = true; // Enable adaptive step size that avoids low acceptance probability bool DynamicRegularizer = true; //Enable the addition of a regularization term - + Type regularization_factor=1e-20; /*Dynamic step choices*/ Type warmUpStep = 10; - Type maxConsecutiveBadStep = 10; + int maxConsecutiveBadStep = 10; Type targetODEStep = 10; Type shrinkFactor = 1.1; - Type minStepSize = 0.001; + Type minStepSize = 1e-5; Type effectiveStepSize = 1; opts() {} diff --git a/include/preprocess/crhmc/two_sided_barrier.h b/include/preprocess/crhmc/two_sided_barrier.h index 39b27bab9..7e279ab7f 100644 --- a/include/preprocess/crhmc/two_sided_barrier.h +++ b/include/preprocess/crhmc/two_sided_barrier.h @@ -21,6 +21,7 @@ #include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" +#include "preprocess/crhmc/crhmc_utils.h" #include /// @brief A two sided barrier used by crhmc sampler @@ -43,16 +44,18 @@ template class two_sided_barrier { const NT max_step = 1e16; // largest step size const NT regularization_constant = 1e-20; // small regularization to not have a large inverse const NT unbounded_center_coord = 1e6; - VT extraHessian; //Regularization factor + MT extraHessian; const NT inf = std::numeric_limits::infinity(); - //initialization function - void set_bound(VT const &_lb, VT const &_ub) { + void set_bound(VT const &_lb, VT const &_ub) { + n = _lb.rows(); + extraHessian.resize(n, 1); + lb.resize(n); + ub.resize(n); lb = _lb; ub = _ub; - n = lb.rows(); - extraHessian = regularization_constant * VT::Ones(n); + extraHessian = regularization_constant * MT::Ones(n, 1); int x1 = 0, x2 = 0, x3 = 0; for (int i = 0; i < n; i++) { if (lb(i) == -inf) { @@ -69,35 +72,44 @@ template class two_sided_barrier { } VT c = (ub + lb) / 2; - - c(lowerIdx) = lb(lowerIdx) + VT::Ones(x2, 1) * unbounded_center_coord; - c(upperIdx) = ub(upperIdx) - VT::Ones(x1, 1) * unbounded_center_coord; - c(freeIdx) *= 0.0; + VT bias1=VT::Ones(x2, 1) * unbounded_center_coord; + saxpy(c,lb,bias1,lowerIdx,lowerIdx); + VT bias2=-VT::Ones(x1, 1) * unbounded_center_coord; + saxpy(c,ub,bias2,upperIdx,upperIdx); + set(c, freeIdx, 0.0); center = c; } two_sided_barrier(VT const &_lb, VT const &_ub, int _vdim = 1) { set_bound(_lb, _ub); vdim = _vdim; - extraHessian = regularization_constant * VT::Ones(n); + extraHessian = regularization_constant * MT::Ones(n,1); } two_sided_barrier() { vdim = 1; } - //barrier function gradient + VT gradient(VT const &x) { return (ub - x).cwiseInverse() - (x - lb).cwiseInverse(); } - //Return the barrier hessian with the extra Regularization + VT hessian(VT const &x) { VT d = ((ub - x).cwiseProduct((ub - x))).cwiseInverse() + ((x - lb).cwiseProduct((x - lb))).cwiseInverse(); return d + extraHessian; } - //third derivative of the barrier - VT tensor(VT const &x) { - VT d = 2 * (((ub - x).cwiseProduct((ub - x))).cwiseProduct((ub - x))).cwiseInverse() - - 2 * (((x - lb).cwiseProduct((x - lb))).cwiseProduct((x - lb))).cwiseInverse(); + MT hessian(MT const &x){ + MT d = (((- x).colwise()+ub).cwiseProduct(((- x).colwise()+ub))).cwiseInverse() + + ((x.colwise() - lb).cwiseProduct((x.colwise() - lb))).cwiseInverse(); + return d + extraHessian; + } + MT tensor(MT const &x) { + MT d = 2 * ((((-x).colwise()+ub).cwiseProduct(((-x).colwise()+ub))).cwiseProduct(((-x).colwise()+ub))).cwiseInverse() - + 2 * (((x.colwise() - lb).cwiseProduct(( x.colwise() - lb))).cwiseProduct(( x.colwise() - lb))).cwiseInverse(); return d; } + MT quadratic_form_gradient(MT const &x, MT const &u) { + // Output the -grad of u' (hess phi(x)) u. + return (u.cwiseProduct(u)).cwiseProduct(tensor(x)); + } VT quadratic_form_gradient(VT const &x, VT const &u) { // Output the -grad of u' (hess phi(x)) u. @@ -119,13 +131,19 @@ template class two_sided_barrier { VT boundary_distance(VT const &x) { // Output the distance of x with its closest boundary for each // coordinate - return ((x - lb).cwiseMin(ub - x)).cwiseAbs(); } bool feasible(VT const &x) { return (x.array() > lb.array() && x.array() < ub.array()).all(); } + VT feasible(MT const &x) { + VT result=VT::Ones(x.cols()); + for(int i=0;i lb.array() && x.col(i).array() < ub.array()).all(); + } + return result; + } std::pair analytic_center_oracle(VT const &x) { VT g = VT::Zero(n, 1); @@ -136,8 +154,7 @@ template class two_sided_barrier { std::pair lewis_center_oracle(VT const &x, VT const &w) { VT g = VT::Zero(n, 1); VT h = VT::Zero(n, 1); - return std::make_pair(g + w.cwiseProduct(gradient(x)), - h + w.cwiseProduct(hessian(x))); + return std::make_pair(g + w.cwiseProduct(gradient(x)),h + w.cwiseProduct(hessian(x))); } std::pair boundary(VT const &x) { @@ -145,11 +162,9 @@ template class two_sided_barrier { // Assume: only 1 vector is given VT A = VT::Ones(x.rows(), 1); - VT b = ub; b = (x.array() < center.array()).select(-lb, b); - A = (x.array() < center.array()).select(-A, A); return std::make_pair(A, b); diff --git a/include/preprocess/crhmc/weighted_two_sided_barrier.h b/include/preprocess/crhmc/weighted_two_sided_barrier.h index 1bda5d3bf..09f5eb798 100644 --- a/include/preprocess/crhmc/weighted_two_sided_barrier.h +++ b/include/preprocess/crhmc/weighted_two_sided_barrier.h @@ -21,6 +21,7 @@ #include "Eigen/Eigen" #include "cartesian_geom/cartesian_kernel.h" +#include "preprocess/crhmc/crhmc_utils.h" #include /// @brief A weighted two sided barrier used by crhmc sampler @@ -43,8 +44,7 @@ template class weighted_two_sided_barrier { const NT max_step = 1e16; // largest step size const NT regularization_constant = 1e-20; // small regularization to not have a large inverse const NT unbounded_center_coord = 1e6; - VT extraHessian; - + MT extraHessian; const NT inf = std::numeric_limits::infinity(); VT w; @@ -54,7 +54,7 @@ template class weighted_two_sided_barrier { set_bound(_lb, _ub); w = _w; vdim = _vdim; - extraHessian = regularization_constant * VT::Ones(n); + extraHessian = regularization_constant * VT::Ones(n,1); } weighted_two_sided_barrier() { vdim = 1; } @@ -67,11 +67,25 @@ template class weighted_two_sided_barrier { w.cwiseQuotient((x - lb).cwiseProduct((x - lb))); return d + extraHessian; } + MT hessian(MT const &x){ + MT d = (((- x).colwise()+ub).cwiseProduct(((- x).colwise()+ub))).cwiseInverse() + + ((x.colwise() - lb).cwiseProduct((x.colwise() - lb))).cwiseInverse(); + return w.asDiagonal()*d + extraHessian; + } VT tensor(VT const &x) { VT d = 2 * w.cwiseQuotient(((ub - x).cwiseProduct((ub - x))).cwiseProduct((ub - x))) - 2 * w.cwiseQuotient(((x - lb).cwiseProduct((x - lb))).cwiseProduct((x - lb))); return d; } + MT tensor(MT const &x) { + MT d = 2 * ((((-x).colwise()+ub).cwiseProduct(((-x).colwise()+ub))).cwiseProduct(((-x).colwise()+ub))).cwiseInverse() - + 2 * (((x.colwise() - lb).cwiseProduct(( x.colwise() - lb))).cwiseProduct(( x.colwise() - lb))).cwiseInverse(); + return w.asDiagonal()*d; + } + MT quadratic_form_gradient(MT const &x, MT const &u) { + // Output the -grad of u' (hess phi(x)) u. + return (u.cwiseProduct(u)).cwiseProduct(tensor(x)); + } VT quadratic_form_gradient(VT const &x, VT const &u) { // Output the -grad of u' (hess phi(x)) u. @@ -99,7 +113,13 @@ template class weighted_two_sided_barrier { bool feasible(VT const &x) { return (x.array() > lb.array() && x.array() < ub.array()).all(); } - + VT feasible(MT const &x) { + VT result=VT::Ones(x.cols()); + for(int i=0;i lb.array() && x.col(i).array() < ub.array()).all(); + } + return result; + } void set_bound(VT const &_lb, VT const &_ub) { lb = _lb; @@ -122,10 +142,11 @@ template class weighted_two_sided_barrier { } VT c = (ub + lb) / 2; - - c(lowerIdx) = lb(lowerIdx) + VT::Ones(x2, 1) * unbounded_center_coord; - c(upperIdx) = ub(upperIdx) - VT::Ones(x1, 1) * unbounded_center_coord; - c(freeIdx) *= 0.0; + VT bias1=VT::Ones(x2, 1) * unbounded_center_coord; + saxpy(c,lb,bias1,lowerIdx,lowerIdx); + VT bias2=-VT::Ones(x1, 1) * unbounded_center_coord; + saxpy(c,ub,bias2,upperIdx,upperIdx); + set(c, freeIdx, 0.0); center = c; } @@ -133,13 +154,10 @@ template class weighted_two_sided_barrier { std::pair boundary(VT const &x) { // Output the normal at the boundary around x for each barrier. // Assume: only 1 vector is given - VT A = VT::Ones(x.rows(), 1); - VT b = ub; b = (x.array() < center.array()).select(-lb, b); - A = (x.array() < center.array()).select(-A, A); return std::make_pair(A, b); diff --git a/include/preprocess/estimate_L_smooth_parameter.hpp b/include/preprocess/estimate_L_smooth_parameter.hpp new file mode 100644 index 000000000..8f5a1e89c --- /dev/null +++ b/include/preprocess/estimate_L_smooth_parameter.hpp @@ -0,0 +1,73 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2020 Vissarion Fisikopoulos +// Copyright (c) 2018-2020 Apostolos Chalkis + +//Contributed and/or modified by Alexandros Manochis, as part of Google Summer of Code 2020 program. + +// Licensed under GNU LGPL.3, see LICENCE file + + +#ifndef ESTIMATE_L_SMOOTH_PARAMETER_HPP +#define ESTIMATE_L_SMOOTH_PARAMETER_HPP + +#include "random_walks/random_walks.hpp" + +template +< + typename WalkTypePolicy = AcceleratedBilliardWalk, + typename Polytope, + typename Point, + typename NegativeGradientFunctor, + typename RandomNumberGenerator +> +double estimate_L_smooth(Polytope &P, Point &p, unsigned int const& walk_length, + NegativeGradientFunctor F, RandomNumberGenerator &rng) +{ + typedef typename Point::FT NT; + typedef typename WalkTypePolicy::template Walk + < + Polytope, + RandomNumberGenerator + > RandomWalk; + + P.ComputeInnerBall(); + + unsigned int d = P.dimension(); + unsigned int rnum = 5 * d; + std::vector randPoints(1); + std::vector vecPoint1; + std::vector vecPoint2; + std::vector< std::vector > listOfPoints; + Point F1; + + RandomWalk walk(P, p, rng); + for (unsigned int i=0; i::lowest(), Ltemp; + + for (auto pit=listOfPoints.begin(); pit!=(listOfPoints.end()-1); ++pit) + { + F1 = F(1, *pit, 0); + + for (auto qit=(pit+1); qit!=listOfPoints.end(); ++qit) + { + vecPoint2 = *qit; + Ltemp = (F1 - F(1, *qit, 0)).length() / ((*pit)[0] - (*qit)[0]).length(); + + if (Ltemp > L) + { + L = Ltemp; + } + } + } + return L; +} + + +#endif diff --git a/include/random_walks/compute_diameter.hpp b/include/random_walks/compute_diameter.hpp index b20aa839a..44ae9a54a 100644 --- a/include/random_walks/compute_diameter.hpp +++ b/include/random_walks/compute_diameter.hpp @@ -9,7 +9,9 @@ #define RANDOM_WALKS_COMPUTE_DIAMETER_HPP #include "convex_bodies/ball.h" +#include "convex_bodies/ellipsoid.h" #include "convex_bodies/ballintersectconvex.h" +#include "convex_bodies/ellipsoidintersectconvex.h" #include "convex_bodies/hpolytope.h" #include "convex_bodies/spectrahedra/spectrahedron.h" #ifndef DISABLE_LPSOLVE @@ -201,6 +203,16 @@ struct compute_diameter>> } }; +template +struct compute_diameter>> +{ + template + static NT compute(EllipsoidIntersectPolytope> &P) + { + return NT(1.5) * P.radius(); + } +}; + template struct compute_diameter> { diff --git a/include/random_walks/crhmc/additional_units/auto_tuner.hpp b/include/random_walks/crhmc/additional_units/auto_tuner.hpp index 0fc50e79a..66a8d51a7 100644 --- a/include/random_walks/crhmc/additional_units/auto_tuner.hpp +++ b/include/random_walks/crhmc/additional_units/auto_tuner.hpp @@ -33,24 +33,23 @@ class auto_tuner { public: Opts options; - weight_tuner *tune_weights; - regularizion_tuner *tune_regularization; - step_size_tuner *tune_step_size; + std::unique_ptr tune_weights; + std::unique_ptr tune_regularization; + std::unique_ptr tune_step_size; auto_tuner(Sampler &s) : options(s.params.options) { if (options.DynamicWeight) { - tune_weights = new weight_tuner(s); + tune_weights = std::unique_ptr(new weight_tuner(s)); } if (options.DynamicRegularizer) { - tune_regularization = new regularizion_tuner(s); + tune_regularization = std::unique_ptr(new regularizion_tuner(s)); } if (options.DynamicStepSize) { - tune_step_size = new step_size_tuner(s); + tune_step_size = std::unique_ptr(new step_size_tuner(s)); } } - void updateModules(Sampler &s, RandomNumberGenerator &rng) - { + void updateModules(Sampler &s, RandomNumberGenerator &rng) { if (options.DynamicWeight) { tune_weights->update_weights(s, rng); } diff --git a/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp b/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp index 9cd80b18d..81449836b 100644 --- a/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp +++ b/include/random_walks/crhmc/additional_units/dynamic_regularizer.hpp @@ -25,33 +25,34 @@ class dynamic_regularizer { public: using NT = typename Sampler::NT; using Point = typename Sampler::point; - using VT = Eigen::Matrix; + using MT = Eigen::Matrix; using Opts = typename Sampler::Opts; int n; - VT bound; + int simdLen; + MT bound; Opts &options; - VT &extraHessian; + MT &extraHessian; dynamic_regularizer(Sampler &s) : + simdLen(s.simdLen), options(s.params.options), extraHessian(options.DynamicWeight ? s.solver->ham.weighted_barrier->extraHessian : s.solver->ham.barrier->extraHessian) { n = s.dim; - bound = VT::Ones(n); - extraHessian = VT::Ones(n); + bound = MT::Ones(n, simdLen); + extraHessian = MT::Ones(n, simdLen); } - void update_regularization_factor(Sampler &s, RandomNumberGenerator &rng) - { - VT x = s.x.getCoefficients(); - x = (x.cwiseAbs()).cwiseMax(VT::Ones(n)); + void update_regularization_factor(Sampler &s, RandomNumberGenerator &rng) { + MT x = s.x; + x = (x.cwiseAbs()).cwiseMax(1); bound = bound.cwiseMax(x); - if ((2 / (bound.array() * bound.array()) < n * extraHessian.array()).any()) { extraHessian = (0.5 / n) * (bound.cwiseProduct(bound)).cwiseInverse(); + s.solver->ham.forceUpdate = true; s.solver->ham.move({s.x, s.v}); - s.v = s.get_direction_with_momentum(n, rng, s.x, Point(n), false); + s.v = s.get_direction_with_momentum(n, rng, s.x, MT::Zero(n, simdLen), 0, false); } } }; diff --git a/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp b/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp index ef1871731..367211962 100644 --- a/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp +++ b/include/random_walks/crhmc/additional_units/dynamic_step_size.hpp @@ -22,26 +22,34 @@ template class dynamic_step_size { using NT = typename Sampler::NT; using Opts = typename Sampler::Opts; + using IVT = Eigen::Array; + using VT = Eigen::Array; public: - int consecutiveBadStep = 0; + int simdLen; + IVT consecutiveBadStep; int iterSinceShrink = 0; - NT rejectSinceShrink = 0; + VT rejectSinceShrink; int ODEStepSinceShrink = 0; int effectiveStep = 0; bool warmupFinished = false; Opts &options; NT η NT &momentum; - NT acceptedStep = 0; + VT acceptedStep; + VT nEffectiveStep; // number of effective steps NT accumulatedMomentum = 0; - NT nEffectiveStep = 0; // number of effective steps - dynamic_step_size(Sampler &s) : + simdLen(s.simdLen), options(s.params.options), eta(s.solver->eta), momentum(s.params.momentum) { + nEffectiveStep = VT::Zero(simdLen); + acceptedStep = VT::Zero(simdLen); + consecutiveBadStep = IVT::Zero(simdLen); + rejectSinceShrink = VT::Zero(simdLen); + if (options.warmUpStep > 0) { eta = 1e-3; } else { @@ -49,53 +57,58 @@ class dynamic_step_size { } } void update_step_size(Sampler &s) { - acceptedStep = acceptedStep + s.prob; - accumulatedMomentum = s.prob * momentum * accumulatedMomentum + eta; - nEffectiveStep = nEffectiveStep + eta * accumulatedMomentum * s.accept; - - int bad_step = s.prob < 0.5 || s.solver->num_steps == options.maxODEStep ? 1 : 0; + acceptedStep = acceptedStep + s.prob.array(); + accumulatedMomentum = s.prob.mean() * momentum * accumulatedMomentum + eta; + Eigen::Matrix accept = (s.accept.template cast()); + nEffectiveStep = nEffectiveStep + eta * accumulatedMomentum * accept.array(); + IVT bad_step = IVT::Zero(simdLen); + if (s.solver->num_steps == options.maxODEStep) { + bad_step += 1; + } else { + bad_step = (s.prob.array() < 0.5).select(1, IVT::Zero(simdLen)); + } consecutiveBadStep = bad_step * consecutiveBadStep + bad_step; - NT warmupRatio = nEffectiveStep / options.warmUpStep; + NT warmupRatio = nEffectiveStep.mean() / options.warmUpStep; if (warmupRatio < 1 && !warmupFinished && - consecutiveBadStep < options.maxConsecutiveBadStep) { + consecutiveBadStep.maxCoeff() < options.maxConsecutiveBadStep) { eta = options.initialStep * std::min(warmupRatio + 1e-2, 1.0); momentum = 1 - std::min(1.0, eta / options.effectiveStepSize); return; } + if (!warmupFinished) { - acceptedStep = 0; - nEffectiveStep = 0; + acceptedStep = VT::Zero(simdLen); + nEffectiveStep = VT::Zero(simdLen); warmupFinished = true; } iterSinceShrink++; - rejectSinceShrink += 1 - s.prob; + rejectSinceShrink += 1 - s.prob.array(); ODEStepSinceShrink += s.solver->num_steps; int shrink = 0; NT shiftedIter = iterSinceShrink + 20 / (1 - momentum); NT targetProbability = std::pow((1.0 - momentum), (2 / 3)) / 4; - if (rejectSinceShrink > targetProbability * shiftedIter || - consecutiveBadStep > options.maxConsecutiveBadStep || + if (rejectSinceShrink.maxCoeff() > targetProbability * shiftedIter|| + consecutiveBadStep.maxCoeff() > options.maxConsecutiveBadStep || ODEStepSinceShrink > options.targetODEStep * shiftedIter) { shrink = 1; } if (shrink == 1) { iterSinceShrink = 0; - rejectSinceShrink = 0; ODEStepSinceShrink = 0; - consecutiveBadStep = 0; + rejectSinceShrink = VT::Zero(simdLen); + consecutiveBadStep = IVT::Zero(simdLen); eta /= options.shrinkFactor; momentum = 1 - std::min(0.999, eta / options.effectiveStepSize); if (eta < options.minStepSize) { - std::cerr << "Algorithm fails to converge even with step size h = " - << eta << "\n"; - exit(1); + s.P.terminate=true; + s.P.terminate_message="Algorithm fails to converge even with step size h = "+std::to_string(eta)+"\n"; } } diff --git a/include/random_walks/crhmc/additional_units/dynamic_weight.hpp b/include/random_walks/crhmc/additional_units/dynamic_weight.hpp index ce945216f..6b9433774 100644 --- a/include/random_walks/crhmc/additional_units/dynamic_weight.hpp +++ b/include/random_walks/crhmc/additional_units/dynamic_weight.hpp @@ -23,48 +23,52 @@ class dynamic_weight { using NT = typename Sampler::NT; using Point = typename Sampler::point; using VT = Eigen::Matrix; + using MT = Eigen::Matrix; + using IVT = Eigen::Array; using Opts = typename Sampler::Opts; public: - int consecutiveBadStep = 0; + int simdLen; + IVT consecutiveBadStep; int n; VT &w; Opts options; - dynamic_weight(Sampler &s) : - w(s.solver->ham.weighted_barrier->w), - options(s.params.options) + dynamic_weight(Sampler &s) + : simdLen(s.simdLen), w(s.solver->ham.weighted_barrier->w), options(s.params.options) { n = s.dim; + consecutiveBadStep = IVT::Zero(simdLen); } // If we have consecutive bad steps update the weights with // the help of the leverage scores. void update_weights(Sampler &s, RandomNumberGenerator &rng) { - int bad_step = 0; - NT threshold; - if (s.prob < 0.5 || s.solver->num_steps == options.maxODEStep) { - bad_step = 1; + IVT bad_step = IVT::Zero(simdLen); + if (s.solver->num_steps == options.maxODEStep) { + bad_step += 1; + } else { + bad_step = (s.prob.array() < 0.5).select(1, IVT::Zero(simdLen)); } + NT threshold; consecutiveBadStep = bad_step * consecutiveBadStep + bad_step; - if (!s.accepted) { - VT lsc = s.solver->ham.lsc; + if (s.accept.sum() < simdLen) { + VT lsc = s.solver->ham.lsc.colwise().maxCoeff().transpose(); /*The more bad steps in a row we have the higher we want the threshold to be In order to change w more drasticaly according to the leverage scores. So if we have more than 2 bad steps in a row we elect to set the threshold to 4 else to 16. Not many changes will be possible as the w should be upperbounded by 1*/ - if (consecutiveBadStep > 2) { + if (consecutiveBadStep.maxCoeff() > 2) { threshold = 4; } else { threshold = 16; } bool changed = (lsc.array() > threshold * w.array()).any(); - w = (lsc.array() > threshold * w.array()) - .select((w * threshold).cwiseMin(VT::Ones(n)), w); if (changed) { + w = (lsc.array() > threshold * w.array()).select((w * threshold).cwiseMin(1), w); s.solver->ham.forceUpdate = true; s.solver->ham.move({s.x, s.v}); - s.v = s.get_direction_with_momentum(n, rng, s.x, Point(n), false); + s.v = s.get_direction_with_momentum(n, rng, s.x, MT::Zero(n, simdLen), false); } } } diff --git a/include/random_walks/crhmc/crhmc_walk.hpp b/include/random_walks/crhmc/crhmc_walk.hpp index b97d79fa9..21ed8d6bb 100644 --- a/include/random_walks/crhmc/crhmc_walk.hpp +++ b/include/random_walks/crhmc/crhmc_walk.hpp @@ -36,7 +36,7 @@ struct CRHMCWalk { parameters(OracleFunctor const &F, unsigned int dim, Opts &user_options, - NT epsilon_ = 2) : + NT epsilon_ = 2) : options(user_options) { epsilon = epsilon_; @@ -59,17 +59,19 @@ struct CRHMCWalk { using pts = std::vector; using NT = typename Point::FT; using VT = Eigen::Matrix; + using MT = Eigen::Matrix; using Sampler = CRHMCWalk::Walk; using Opts = typename Polytope::Opts; + using IVT = Eigen::Matrix; // Hyperparameters of the sampler parameters ¶ms; // Numerical ODE solver - Solver *solver; + std::unique_ptr solver; // Dimension unsigned int dim; @@ -87,25 +89,25 @@ struct CRHMCWalk { float average_acceptance_prob = 0; // Acceptance probability - NT prob; + VT prob; bool accepted; - NT accept; + IVT accept; bool update_modules; - + int simdLen; // References to xs - Point x, v; + MT x, v; // Proposal points - Point x_tilde, v_tilde; + MT x_tilde, v_tilde; // Gradient function NegativeGradientFunctor &F; // Auto tuner - auto_tuner *module_update; + std::unique_ptr>module_update; // Helper variables - NT H, H_tilde, log_prob, u_logprob; + VT H, H_tilde; // Density exponent NegativeLogprobFunctor &f; #ifdef TIME_KEEPING @@ -118,41 +120,50 @@ struct CRHMCWalk { NegativeLogprobFunctor &neg_logprob_f, parameters ¶m) : params(param), + P(Problem), F(neg_grad_f), - f(neg_logprob_f), - P(Problem) + f(neg_logprob_f) { dim = p.dimension(); - + simdLen = params.options.simdLen; // Starting point is provided from outside - x = p; + x = p.getCoefficients() * MT::Ones(1, simdLen); accepted = false; // Initialize solver - solver = - new Solver(0.0, params.eta, pts{x, x}, F, Problem, params.options); - v = solver->get_state(1); - module_update = new auto_tuner(*this); + solver = std::unique_ptr(new Solver(0.0, params.eta, {x, x}, F, Problem, params.options)); + v = MT::Zero(dim, simdLen); + module_update = std::unique_ptr>(new auto_tuner(*this)); update_modules = params.options.DynamicWeight || params.options.DynamicRegularizer || params.options.DynamicStepSize; }; - Point get_direction_with_momentum(unsigned int const &dim, - RandomNumberGenerator &rng, - Point x, - Point v, - NT momentum = 0, - bool normalize = true) + // Sample a new velocity with momentum + MT get_direction_with_momentum(unsigned int const &dim, + RandomNumberGenerator &rng, MT const &x, MT v, + NT momentum = 0, bool normalize = true) { - Point z = GetDirection::apply(dim, rng, normalize); + MT z = MT(dim, simdLen); + for (int i = 0; i < simdLen; i++) + { + z.col(i) = GetDirection::apply(dim, rng, normalize).getCoefficients(); + } solver->ham.move({x, v}); - VT sqrthess = (solver->ham.hess).cwiseSqrt(); - z = Point(sqrthess.cwiseProduct(z.getCoefficients())); + MT sqrthess = (solver->ham.hess).cwiseSqrt(); + z = sqrthess.cwiseProduct(z); return v * std::sqrt(momentum) + z * std::sqrt(1 - momentum); } // Returns the current point in the tranformed in the original space - inline Point getPoint() { return Point(P.T * x.getCoefficients() + P.y); } + inline MT getPoints() { return (P.T * x).colwise() + P.y; } + // Returns the current point in the tranformed in the original space + inline Point getPoint() { return Point(P.T * x.col(0) + P.y); } + inline MT masked_choose(MT &x, MT &x_tilde, IVT &accept) { + return accept.transpose().replicate(x.rows(), 1).select(x_tilde, x); + } + inline void disable_adaptive(){ + update_modules=false; + } inline void apply(RandomNumberGenerator &rng, int walk_length = 1, bool metropolis_filter = true) @@ -160,47 +171,45 @@ struct CRHMCWalk { num_runs++; // Pick a random velocity with momentum v = get_direction_with_momentum(dim, rng, x, v, params.momentum, false); - solver->set_state(0, x); solver->set_state(1, v); // Get proposals solver->steps(walk_length, accepted); x_tilde = solver->get_state(0); v_tilde = solver->get_state(1); - if (metropolis_filter) { #ifdef TIME_KEEPING start = std::chrono::system_clock::now(); #endif // Calculate initial Hamiltonian H = solver->ham.hamiltonian(x, v); + // Calculate new Hamiltonian - H_tilde = solver->ham.hamiltonian(x_tilde, Point(dim) - v_tilde); + H_tilde = solver->ham.hamiltonian(x_tilde, -v_tilde); + #ifdef TIME_KEEPING end = std::chrono::system_clock::now(); H_duration += end - start; #endif - NT feasible = solver->ham.feasible(x_tilde.getCoefficients(), - v_tilde.getCoefficients()); - prob = std::min(1.0, exp(H - H_tilde)) * feasible; - - log_prob = log(prob); - total_acceptance_prob += prob; - - // Decide to switch - if (rng.sample_urdist() < prob) { - x = x_tilde; - v = v_tilde; - accepted = true; - } - else { - total_discarded_samples++; - accepted = false; - v = Point(dim) - v; + VT feasible = solver->ham.feasible(x_tilde, + v_tilde); + prob = (1.0 < exp((H - H_tilde).array())).select(1.0, exp((H - H_tilde).array())); + prob = (feasible.array() > 0.5).select(prob, 0); + + total_acceptance_prob += prob.sum(); + VT rng_vector = VT(simdLen); + for (int i = 0; i < simdLen; i++) + { + rng_vector(i) = rng.sample_urdist(); } - discard_ratio = (1.0 * total_discarded_samples) / num_runs; - average_acceptance_prob = total_acceptance_prob / num_runs; - accept = accepted ? 1 : 0; + accept = (rng_vector.array() < prob.array()).select(1 * IVT::Ones(simdLen), 0 * IVT::Ones(simdLen)); + + x = masked_choose(x, x_tilde, accept); + v = -v; + v = masked_choose(v, v_tilde, accept); + total_discarded_samples += simdLen - accept.sum(); + discard_ratio = (1.0 * total_discarded_samples) / (num_runs * simdLen); + average_acceptance_prob = total_acceptance_prob / (num_runs * simdLen); } else { x = x_tilde; v = v_tilde; @@ -210,18 +219,24 @@ struct CRHMCWalk { } } #ifdef TIME_KEEPING - void print_timing_information() { - std::cerr << "--------------Timing Information--------------\n"; + void initialize_timers() { + H_duration = std::chrono::duration::zero(); + solver->DU_duration = std::chrono::duration::zero(); + solver->approxDK_duration = std::chrono::duration::zero(); + } + template + void print_timing_information(StreamType &stream) { + stream << "---Sampling Timing Information" << std::endl; double DU_time = solver->DU_duration.count(); double DK_time = solver->approxDK_duration.count(); double H_time = H_duration.count(); double total_time = H_time + DK_time + DU_time; - std::cerr << "Computing the Hamiltonian in time, " << H_time << " secs\n"; - std::cerr << "Computing DU partial derivatives in time, " << DU_time - << " secs\n"; - std::cerr << "Computing DK partial derivatives in time, " << DK_time - << " secs\n"; - std::cerr << "H_time + DK_time + DU_time: " << total_time << "\n"; + stream << "Computing the Hamiltonian in time, " << H_time << " secs\n"; + stream << "Computing DU partial derivatives in time, " << DU_time + << " secs\n"; + stream << "Computing DK partial derivatives in time, " << DK_time + << " secs\n"; + stream << "H_time + DK_time + DU_time: " << total_time << "\n"; } #endif }; diff --git a/include/random_walks/crhmc/hamiltonian.hpp b/include/random_walks/crhmc/hamiltonian.hpp index d8cb5a82e..0d9ef5465 100644 --- a/include/random_walks/crhmc/hamiltonian.hpp +++ b/include/random_walks/crhmc/hamiltonian.hpp @@ -17,42 +17,43 @@ #define HAMILTONIAN_HPP #include "preprocess/crhmc/two_sided_barrier.h" #include "preprocess/crhmc/weighted_two_sided_barrier.h" +#include "PackedCSparse/PackedChol.h" #include "preprocess/crhmc/crhmc_utils.h" #include -/// @brief Class for the hamiltonian used in crhmc sampler -/// @tparam Polytope Polytope Type -/// @tparam Point Point Type -template +template class Hamiltonian { using VT = typename Polytope::VT; + using IVT = Eigen::Array; + using BVT = Eigen::Matrix; using NT = typename Polytope::NT; using MT = typename Polytope::MT; - using Tx = typename Polytope::Tx; - using CholObj = typename Polytope::CholObj; - using Opts = typename Polytope::Opts; using SpMat = typename Polytope::SpMat; - using pts = std::vector; + using Tx = FloatArray; + using CholObj = PackedChol; + using Opts = typename Polytope::Opts; + using pts = std::vector; using Barrier = two_sided_barrier; using WeightedBarrier = weighted_two_sided_barrier; public: bool prepared = false; - bool forceUpdate = true; + bool forceUpdate = true; // Update function oracle temporary varibles Polytope &P; - VT hess; + MT hess; bool dUDx_empty = true; - Point last_dUdx; + MT last_dUdx; CholObj solver; pts xs; - VT x; - VT dfx; - VT lsc; - NT fx = 0; + MT x; + MT dfx; + MT lsc; + VT fx; int n; int m; + int num_runs = 0; Barrier *barrier; - WeightedBarrier *weighted_barrier; + std::unique_ptr weighted_barrier; Opts &options; Hamiltonian(Polytope &boundaries) : P(boundaries), @@ -61,111 +62,122 @@ class Hamiltonian { { n = P.dimension(); m = P.equations(); - x = VT::Zero(n); - xs = {Point(n), Point(n)}; - lsc = VT::Zero(n); + x = MT::Zero(n, simdLen); + xs = {x, x}; + lsc = MT::Zero(simdLen, n); solver.accuracyThreshold = options.solver_accuracy_threshold; - if (options.DynamicWeight) { + if (options.DynamicWeight) + { weighted_barrier = - new WeightedBarrier(P.barrier.lb, P.barrier.ub, P.w_center); + std::unique_ptr(new WeightedBarrier(P.barrier.lb, P.barrier.ub, P.w_center)); + weighted_barrier->extraHessian.resize(n, simdLen); + weighted_barrier->extraHessian = MT::Ones(n, simdLen) * options.regularization_factor; } barrier = &P.barrier; + barrier->extraHessian.resize(n, simdLen); + barrier->extraHessian = MT::Ones(n, simdLen) * options.regularization_factor; } // Compute H(x,v) - NT hamiltonian(Point x, Point v) + VT hamiltonian(MT x, MT v) { prepare({x, v}); pts pd = DK({x, v}); - NT K = 0.5 * v.dot(pd[0]); - NT U = 0.5 * (solver.logdet() + ((hess.array()).log()).sum()); - U = U + fx; - NT E = U + K; + VT K = 0.5 * (v.cwiseProduct(pd[0])).colwise().sum(); + Tx out=solver.logdet(); + VT logdet=VT(simdLen); + for (int i = 0; i < simdLen; i++) + logdet(i) = get(out, i); + VT U = ((hess.array()).log()).colwise().sum(); + U = (U + logdet) * 0.5 + fx; + VT E = U + K; return E; } // Helper is nan function for vectors template - bool isnan(MatrixType x) + IVT is_not_nan(MatrixType x) { + IVT result = IVT::Ones(x.cols()); for (int i = 0; i < x.rows(); i++) { for (int j = 0; j < x.cols(); j++) { if (std::isnan(x(i, j))) { - return true; + result(j) = 0; } } } - return false; + return result; } // Test if the values of x and v are valid and if x is feasible - NT feasible(VT x, VT v) + VT feasible(MT x, MT v) { - bool feasible_coordinate = true; + VT feasible_coordinate = VT::Ones(x.cols()); if (options.DynamicWeight) { feasible_coordinate = weighted_barrier->feasible(x); } else { feasible_coordinate = barrier->feasible(x); } - bool r = !isnan(x) && !isnan(v) && feasible_coordinate; - if (r) { - return 1; - } - return 0; + VT r = feasible_coordinate.cwiseProduct((is_not_nan(x) * is_not_nan(v)).matrix()); + return r; } // prepare the solver weighted by the hessian void prepare(pts const &xs) { move(xs); if (!prepared) { - VT Hinv = hess.cwiseInverse(); + MT Hinv = (hess.cwiseInverse()).transpose(); solver.decompose((Tx *)Hinv.data()); + dUDx_empty = true; } - dUDx_empty = true; prepared = true; } // Computation of the partial derivatives of the K term pts DK(pts const &x_bar) { - VT x = x_bar[0].getCoefficients(); - VT v = x_bar[1].getCoefficients(); + MT x = x_bar[0]; + MT v = x_bar[1]; move(x_bar); - VT invHessV = v.cwiseQuotient(hess); - VT input_vector = P.Asp * invHessV; - VT out_vector = VT::Zero(m); + MT invHessV = v.cwiseQuotient(hess); + MT input_vector = P.Asp * invHessV; + input_vector.transposeInPlace(); + MT out_vector = MT::Zero(simdLen, m); solver.solve((Tx *)input_vector.data(), (Tx *)out_vector.data()); - Point dKdv = - Point(invHessV - (P.Asp.transpose() * out_vector).cwiseQuotient(hess)); + out_vector.transposeInPlace(); + MT dKdv = + invHessV - (P.Asp.transpose() * out_vector).cwiseQuotient(hess); - Point dKdx = Point(n); + MT dKdx = MT::Zero(n, simdLen); if (options.DynamicWeight) { - dKdx = Point( - weighted_barrier->quadratic_form_gradient(x, dKdv.getCoefficients()) / - 2); + dKdx = + weighted_barrier->quadratic_form_gradient(x, dKdv) / + 2; } else { - dKdx = Point(barrier->quadratic_form_gradient(x, dKdv.getCoefficients()) / - 2); + dKdx = barrier->quadratic_form_gradient(x, dKdv) / + 2; } return {dKdv, dKdx}; } // Approximate computation of the partial derivatives of the K term - pts approxDK(pts const &x_bar, VT &nu) + pts approxDK(pts const &x_bar, MT &nu) { - VT x = x_bar[0].getCoefficients(); - VT v = x_bar[1].getCoefficients(); + MT x = x_bar[0]; + MT v = x_bar[1]; move(x_bar); - VT dUdv_b = P.Asp * (v - P.Asp.transpose() * nu).cwiseQuotient(hess); - VT out_solver = VT(nu.rows(), nu.cols()); + MT dUdv_b = P.Asp * (v - P.Asp.transpose() * nu).cwiseQuotient(hess); + dUdv_b.transposeInPlace(); + MT out_solver = MT(nu.cols(), nu.rows()); solver.solve((Tx *)dUdv_b.data(), (Tx *)out_solver.data()); - nu = nu + out_solver; - Point dKdv = Point((v - P.Asp.transpose() * nu).cwiseQuotient(hess)); - Point dKdx = Point(n); + nu = nu + out_solver.transpose(); + + MT dKdv = (v - P.Asp.transpose() * nu).cwiseQuotient(hess); + MT dKdx = MT::Zero(n, simdLen); if (options.DynamicWeight) { - dKdx = Point( - weighted_barrier->quadratic_form_gradient(x, dKdv.getCoefficients()) / - 2); + dKdx = + weighted_barrier->quadratic_form_gradient(x, dKdv) / + 2; } else { - dKdx = Point(barrier->quadratic_form_gradient(x, dKdv.getCoefficients()) / - 2); + dKdx = barrier->quadratic_form_gradient(x, dKdv) / + 2; } return {dKdv, dKdx}; } @@ -173,24 +185,25 @@ class Hamiltonian { // This is only dependent on x and so DU/Dv=0 pts DU(pts const &x_bar) { - VT x = x_bar[0].getCoefficients(); + MT x = x_bar[0]; move(x_bar); if (!prepared || dUDx_empty) { prepare(x_bar); solver.leverageScoreComplement((Tx *)lsc.data()); if (options.DynamicWeight) { - last_dUdx = Point(-(weighted_barrier->tensor(x).cwiseProduct(lsc)) - .cwiseQuotient(2 * hess) - - dfx); + last_dUdx = (weighted_barrier->tensor(x).cwiseProduct(lsc.transpose())) + .cwiseQuotient(2 * hess) + + dfx; } else { - last_dUdx = Point( - -(barrier->tensor(x).cwiseProduct(lsc)).cwiseQuotient(2 * hess) - - dfx); + last_dUdx = + (barrier->tensor(x).cwiseProduct(lsc.transpose())).cwiseQuotient(2 * hess) + + dfx; } dUDx_empty = false; } - return {Point(n), last_dUdx}; + + return {MT::Zero(n, simdLen), -last_dUdx}; } // Compute the computations involving only x iff x has been changed // Else they are stored @@ -200,37 +213,37 @@ class Hamiltonian { return; } xs = y; - x = xs[0].getCoefficients(); - VT h; + x = xs[0]; + MT h; std::tie(fx, dfx, h) = P.f_oracle(x); if (options.DynamicWeight) { hess = weighted_barrier->hessian(x) + h; } else { hess = barrier->hessian(x) + h; } - forceUpdate = false; prepared = false; } // Project x to the polytope - void project(pts &xs) - { + void project(pts &xs) { move(xs); - VT x = xs[0].getCoefficients(); + MT x = xs[0]; int m = P.Asp.rows(); - VT out_vector = VT(m); - VT in_vector = P.b - P.Asp * x; + MT out_vector = MT(simdLen, m); + MT in_vector = (-P.Asp * x).colwise() + P.b; + in_vector.transposeInPlace(); solver.solve((Tx *)in_vector.data(), (Tx *)out_vector.data()); + out_vector.transposeInPlace(); out_vector = P.Asp.transpose() * out_vector; - xs[0] = xs[0] + Point((out_vector).cwiseQuotient(hess)); + xs[0] = xs[0] + (out_vector).cwiseQuotient(hess); } // Get the inner product of x and ds weighted by the hessian - NT x_norm(pts const &xs, pts const &dx) + VT x_norm(pts const &xs, pts const &dx) { move(xs); - VT dx_x = dx[0].getCoefficients(); - VT r = (dx_x.cwiseProduct(dx_x)).cwiseProduct(hess); - return r.sum(); + MT dx_x = dx[0]; + MT r = (dx_x.cwiseProduct(dx_x)).cwiseProduct(hess); + return r.colwise().sum(); } }; #endif diff --git a/include/random_walks/hamiltonian_monte_carlo_walk.hpp b/include/random_walks/hamiltonian_monte_carlo_walk.hpp index 3c50ca5e9..23342ea57 100644 --- a/include/random_walks/hamiltonian_monte_carlo_walk.hpp +++ b/include/random_walks/hamiltonian_monte_carlo_walk.hpp @@ -114,12 +114,10 @@ struct HamiltonianMonteCarloWalk { }; - inline void apply( - RandomNumberGenerator &rng, - int walk_length=1, - bool metropolis_filter=true) + inline void apply(RandomNumberGenerator &rng, + int walk_length=1, + bool metropolis_filter=true) { - num_runs++; // Pick a random velocity @@ -156,6 +154,7 @@ struct HamiltonianMonteCarloWalk { } } else { x = x_tilde; + accepted = true; } discard_ratio = (1.0 * total_discarded_samples) / num_runs; diff --git a/include/random_walks/nuts_hmc_walk.hpp b/include/random_walks/nuts_hmc_walk.hpp new file mode 100644 index 000000000..857064c0e --- /dev/null +++ b/include/random_walks/nuts_hmc_walk.hpp @@ -0,0 +1,380 @@ +// VolEsti (volume computation and sampling library) + +// Copyright (c) 2012-2022 Vissarion Fisikopoulos +// Copyright (c) 2018-2022 Apostolos Chalkis +// Copyright (c) 2020-2022 Elias Tsigaridas +// Copyright (c) 2020-2022 Marios Papachristou + +// Licensed under GNU LGPL.3, see LICENCE file + +// References +// Matthew D. Hoffman, Andrew Gelman. "The No-U-Turn Sampler: +// Adaptively Setting Path Lengths in Hamiltonian Monte Carlo", 2011. + +// Comment: Compared to [Matthew D. Hoffman, Andrew Gelman, 2011] +// we modify the step of Nesterov's algorithm in the burn in phase. + +#ifndef NUTS_HAMILTONIAN_MONTE_CARLO_WALK_HPP +#define NUTS_HAMILTONIAN_MONTE_CARLO_WALK_HPP + + +#include "generators/boost_random_number_generator.hpp" +#include "random_walks/gaussian_helpers.hpp" +#include "ode_solvers/ode_solvers.hpp" +#include "preprocess/estimate_L_smooth_parameter.hpp" + +struct NutsHamiltonianMonteCarloWalk { + + template + < + typename NT, + typename OracleFunctor + > + struct parameters { + NT epsilon; // tolerance in mixing + NT eta; // step size + + parameters( + OracleFunctor const& F, + unsigned int dim, + NT epsilon_=2) + { + epsilon = epsilon_; + eta = F.params.L > 0 ? 10.0 / (dim * sqrt(F.params.L)) : 0.005; + } + }; + + template + < + typename Point, + typename Polytope, + typename RandomNumberGenerator, + typename NegativeGradientFunctor, + typename NegativeLogprobFunctor, + typename Solver + > + struct Walk { + + typedef std::vector pts; + typedef typename Point::FT NT; + typedef std::vector bounds; + + // Hyperparameters of the sampler + parameters ¶ms; + + // Numerical ODE solver + Solver *solver; + + // Dimension + unsigned int dim; + + // Discarded Samples + long num_runs = 0; + long total_acceptance = 0; + + // Average acceptance probability + NT average_acceptance = 0; + + // References to xs + Point x, v; + + // Helper points + Point v_pl, v_min, v_min_j, v_pl_j, X_pl, X_pl_j, X_min, X, X_rnd_j, X_min_j, x_pl_min; + + // Gradient function + NegativeGradientFunctor &F; + + bool accepted; + + // Burnin parameters + NT eps_step, mu, log_tilde_eps, H_tilde, alpha, na; + const NT delta = NT(0.65), Delta_max = NT(1000), gamma = NT(0.05), t0 = NT(10), kk = NT(0.85); + + // Density exponent + NegativeLogprobFunctor &f; + + Walk(Polytope *P, + Point &p, + NegativeGradientFunctor &neg_grad_f, + NegativeLogprobFunctor &neg_logprob_f, + parameters ¶m, + bool burn_in_phase = true) : + params(param), + F(neg_grad_f), + f(neg_logprob_f) + { + dim = p.dimension(); + + v_pl.set_dimension(dim); + v_min.set_dimension(dim); + v_min_j.set_dimension(dim); + v_pl_j.set_dimension(dim); + X_pl.set_dimension(dim); + X_pl_j.set_dimension(dim); + X_min.set_dimension(dim); + X.set_dimension(dim); + X_rnd_j.set_dimension(dim); + X_min_j.set_dimension(dim); + x_pl_min.set_dimension(dim); + + eps_step = params.eta; + mu = std::log(10*eps_step); + log_tilde_eps = NT(0); + H_tilde = NT(0); + alpha = NT(0); + na = NT(0); + + // Starting point is provided from outside + x = p; + + accepted = false; + + // Initialize solver + solver = new Solver(0, params.eta, pts{x, x}, F, bounds{P, NULL}); + disable_adaptive(); + + if (burn_in_phase) + { + RandomNumberGenerator rng(dim); + burnin(rng); + } + }; + + + inline void burnin(RandomNumberGenerator &rng, + unsigned int N = 1000, + unsigned int walk_length=1) + { + reset_num_runs(); + Point p = x; + NT L; + + if ((solver->get_bounds())[0] == NULL) + { + L = (NT(100) / NT(dim)) * (NT(100) / NT(dim)); + } + else + { + Polytope K = *(solver->get_bounds())[0]; + L = estimate_L_smooth(K, p, walk_length, F, rng); + } + + eps_step = NT(5) / (NT(dim) * std::sqrt(L)); + solver->set_eta(eps_step); + + for (int i = 0; i < N; i++) + { + apply(rng, walk_length, true); + solver->set_eta(eps_step); + } + reset_num_runs(); + } + + + inline void apply(RandomNumberGenerator &rng, + unsigned int walk_length=1, + bool burnin = false) + { + num_runs++; + + int x_counting_total = 0; + + // Pick a random velocity + v = GetDirection::apply(dim, rng, false); + + v_pl = v; + v_min = NT(-1) * v; + X_pl = x; + X_min = x; + + NT h1 = hamiltonian(x, v); + + NT uu = std::log(rng.sample_urdist()) - h1; + int j = -1; + bool s = true; + bool updated = false; + bool pos_state_single = false; + + if (burnin) + { + alpha = NT(0); + } + + while (s) + { + j++; + + if (burnin) + { + na = std::pow(NT(2), NT(j)); + } + + NT dir = rng.sample_urdist(); + + if (dir > 0.5) + { + v = v_pl; + X = X_pl; + } + else + { + v = v_min; + X = X_min; + } + X_rnd_j = X; + + int x_counting = 0; + int num_samples = int(std::pow(NT(2), NT(j))); + accepted = false; + + for (int k = 1; k <= num_samples; k++) + { + if (!accepted) + { + solver->set_state(0, X); + solver->set_state(1, v); + } + + // Get proposals + solver->steps(walk_length, accepted); + accepted = true; + + X = solver->get_state(0); + v = solver->get_state(1); + + NT hj = hamiltonian(X, v); + + if (burnin) + { + alpha += std::min(NT(1), std::exp(-hj + h1)); + } + + if (uu > Delta_max - hj) + { + s = false; + break; + } + + bool pos_state = false; + if (uu < -hj) + { + pos_state = true; + pos_state_single = true; + x_counting = x_counting + 1; + x_counting_total = x_counting_total + 1; + } + + if (k == 1) + { + if (dir > 0.5) + { + X_min_j = X; + v_min_j = v; + } + else + { + X_pl_j = X; + v_pl_j = v; + } + } + if (k == num_samples) + { + if (dir > 0.5) + { + x_pl_min = X - X_min_j; + if ((x_pl_min.dot(v) < 0) || (x_pl_min.dot(v_min_j) < 0)) + { + s = false; + } + } + else + { + x_pl_min = X_pl_j - X; + if ((x_pl_min.dot(v) < 0) || (x_pl_min.dot(v_pl_j) < 0)) + { + s = false; + } + } + } + if ((rng.sample_urdist() < (1/NT(x_counting))) && pos_state) + { + X_rnd_j = X; + } + } + + if (dir > 0.5) + { + X_pl = X; + v_pl = v; + } + else + { + X_min = X; + v_min = v; + } + + if (s && (rng.sample_urdist() < (NT(x_counting) / NT(x_counting_total)))) + { + x = X_rnd_j; + if (pos_state_single) + { + updated = true; + } + } + + if (s) + { + x_pl_min = X_pl - X_min; + if ((x_pl_min.dot(v_min) < 0) || (x_pl_min.dot(v_pl) < 0)) + { + s = false; + } + } + } + + if (updated) + { + total_acceptance++; + } + average_acceptance = NT(total_acceptance) / NT(num_runs); + + if (burnin) + { + H_tilde = (NT(1) - NT(1) / (NT(num_runs) + t0)) * H_tilde + (NT(1) / (NT(num_runs) + t0)) * (delta - alpha / na); + NT log_eps = mu - (std::sqrt(NT(num_runs)) / gamma) * H_tilde; + + // TODO: use the following to generalize Nesterov's algorithm + //log_tilde_eps = std::pow(mu,-kk) * log_eps + (NT(1) - std::pow(mu,-kk))*log_tilde_eps; + + eps_step = std::exp(log_eps); + } + } + + inline NT hamiltonian(Point &pos, Point &vel) const { + return f(pos) + 0.5 * vel.dot(vel); + } + + inline NT get_eta_solver() { + return solver->get_eta(); + } + + void disable_adaptive() { + solver->disable_adaptive(); + } + + void enable_adaptive() { + solver->enable_adaptive(); + } + + void reset_num_runs() { + num_runs = 0; + total_acceptance = 0; + } + + NT get_ratio_acceptance() { + return average_acceptance; + } + }; +}; + +#endif // HAMILTONIAN_MONTE_CARLO_WALK_HPP diff --git a/include/random_walks/random_walks.hpp b/include/random_walks/random_walks.hpp index 4affee74d..6c36457c1 100644 --- a/include/random_walks/random_walks.hpp +++ b/include/random_walks/random_walks.hpp @@ -28,6 +28,7 @@ #include "random_walks/exponential_hamiltonian_monte_carlo_exact_walk.hpp" #include "random_walks/uniform_accelerated_billiard_walk_parallel.hpp" #include "random_walks/hamiltonian_monte_carlo_walk.hpp" +#include "random_walks/nuts_hmc_walk.hpp" #include "random_walks/langevin_walk.hpp" #include "random_walks/crhmc/crhmc_walk.hpp" #endif // RANDOM_WALKS_RANDOM_WALKS_HPP diff --git a/include/sampling/random_point_generators.hpp b/include/sampling/random_point_generators.hpp index 86b10666c..e70e14617 100644 --- a/include/sampling/random_point_generators.hpp +++ b/include/sampling/random_point_generators.hpp @@ -228,6 +228,38 @@ template typename Walk > struct LogconcaveRandomPointGenerator +{ + + template + < typename PointList, + typename WalkPolicy, + typename RandomNumberGenerator + > + static void apply(unsigned int const& rnum, + unsigned int const& walk_length, + PointList &randPoints, + WalkPolicy &policy, + RandomNumberGenerator &rng, + Walk &walk) + { + typedef double NT; + + for (unsigned int i = 0; i < rnum; ++i) + { + // Gather one sample + walk.apply(rng, walk_length); + + // Use PushBackWalkPolicy + policy.apply(randPoints, walk.x); + } + } +}; + +template +< + typename Walk +> +struct CrhmcRandomPointGenerator { template @@ -251,22 +283,38 @@ struct LogconcaveRandomPointGenerator NegativeGradientFunctor &F, NegativeLogprobFunctor &f, Parameters ¶meters, - Walk &walk) + Walk &walk, + int simdLen=1, + bool raw_output= false) { - typedef double NT; - - for (unsigned int i = 0; i < rnum; ++i) + typedef typename Walk::MT MT; + for (unsigned int i = 0; i < std::ceil((float)rnum/simdLen); ++i) { // Gather one sample walk.apply(rng, walk_length); - + if(walk.P.terminate){return;} + MT x; + if(raw_output){ + x=walk.x; + }else{ + x=walk.getPoints(); + } + if((i + 1) * simdLen > rnum){ + for(int j = 0; j < rnum-simdLen*i; j++){ + Point p = Point(x.col(j)); + policy.apply(randPoints, p); + } + break; + } // Use PushBackWalkPolicy - policy.apply(randPoints, walk.x); + for(int j=0; j void uniform_sampling(PointList &randPoints, Polytope &P, @@ -232,14 +232,14 @@ template < typename Solver > void logconcave_sampling(PointList &randPoints, - Polytope &P, - RandomNumberGenerator &rng, - const unsigned int &walk_len, - const unsigned int &rnum, - const Point &starting_point, - unsigned int const& nburns, - NegativeGradientFunctor &F, - NegativeLogprobFunctor &f) + Polytope &P, + RandomNumberGenerator &rng, + const unsigned int &walk_len, + const unsigned int &rnum, + const Point &starting_point, + unsigned int const& nburns, + NegativeGradientFunctor &F, + NegativeLogprobFunctor &f) { typedef typename WalkTypePolicy::template Walk < @@ -272,19 +272,168 @@ void logconcave_sampling(PointList &randPoints, walk logconcave_walk(&P, p, F, f, params); typedef LogconcaveRandomPointGenerator RandomPointGenerator; - - RandomPointGenerator::apply(P, p, nburns, walk_len, randPoints, - push_back_policy, rng, F, f, params, logconcave_walk); - + + if (nburns > 0) { + RandomPointGenerator::apply(nburns, walk_len, randPoints, + push_back_policy, rng, logconcave_walk); + } logconcave_walk.disable_adaptive(); randPoints.clear(); - RandomPointGenerator::apply(P, p, rnum, walk_len, randPoints, - push_back_policy, rng, F, f, params, logconcave_walk); - + RandomPointGenerator::apply(rnum, walk_len, randPoints, + push_back_policy, rng, logconcave_walk); +} +#include "preprocess/crhmc/crhmc_input.h" +#include "preprocess/crhmc/crhmc_problem.h" +template + < + typename PointList, + typename Polytope, + typename RandomNumberGenerator, + typename WalkTypePolicy, + typename NT, + typename Point, + typename NegativeGradientFunctor, + typename NegativeLogprobFunctor, + typename HessianFunctor, + typename Solver + > +void crhmc_sampling(PointList &randPoints, + Polytope &P, + RandomNumberGenerator &rng, + const int walk_len, + const unsigned int rnum, + const unsigned int nburns, + NegativeGradientFunctor &F, + NegativeLogprobFunctor &f, + HessianFunctor &h, + int simdLen = 1, + bool raw_output=false) { + typedef typename Polytope::MT MatrixType; + typedef crhmc_input + < + MatrixType, + Point, + NegativeLogprobFunctor, + NegativeGradientFunctor, + HessianFunctor + > Input; + Input input = convert2crhmc_input(P, f, F, h); + typedef crhmc_problem CrhmcProblem; + CrhmcProblem problem = CrhmcProblem(input); + if(problem.terminate){return;} + typedef typename WalkTypePolicy::template Walk + < + Point, + CrhmcProblem, + RandomNumberGenerator, + NegativeGradientFunctor, + NegativeLogprobFunctor, + Solver + > walk; + typedef typename WalkTypePolicy::template parameters + < + NT, + NegativeGradientFunctor + > walk_params; + Point p = Point(problem.center); + problem.options.simdLen=simdLen; + walk_params params(input.df, p.dimension(), problem.options); + + if (input.df.params.eta > 0) { + params.eta = input.df.params.eta; + } + + PushBackWalkPolicy push_back_policy; + + walk crhmc_walk = walk(problem, p, input.df, input.f, params); + + typedef CrhmcRandomPointGenerator RandomPointGenerator; + + RandomPointGenerator::apply(problem, p, nburns, walk_len, randPoints, + push_back_policy, rng, F, f, params, crhmc_walk); + //crhmc_walk.disable_adaptive(); + randPoints.clear(); + RandomPointGenerator::apply(problem, p, rnum, walk_len, randPoints, + push_back_policy, rng, F, f, params, crhmc_walk, simdLen, raw_output); +} +#include "ode_solvers/ode_solvers.hpp" +template < + typename Polytope, + typename RNGType, + typename PointList, + typename NegativeGradientFunctor, + typename NegativeLogprobFunctor, + typename HessianFunctor, + typename CRHMCWalk, + int simdLen=1 +> +void execute_crhmc(Polytope &P, RNGType &rng, PointList &randPoints, + unsigned int const& walkL, unsigned int const& numpoints, + unsigned int const& nburns, NegativeGradientFunctor *F=NULL, + NegativeLogprobFunctor *f=NULL, HessianFunctor *h=NULL, bool raw_output= false){ +typedef typename Polytope::MT MatrixType; +typedef typename Polytope::PointType Point; +typedef typename Point::FT NT; +if(h!=NULL){ +typedef crhmc_input + < + MatrixType, + Point, + NegativeLogprobFunctor, + NegativeGradientFunctor, + HessianFunctor + > Input; +typedef crhmc_problem CrhmcProblem; +crhmc_sampling < + PointList, + Polytope, + RNGType, + CRHMCWalk, + NT, + Point, + NegativeGradientFunctor, + NegativeLogprobFunctor, + HessianFunctor, + ImplicitMidpointODESolver < + Point, + NT, + CrhmcProblem, + NegativeGradientFunctor, + simdLen + > +>(randPoints, P, rng, walkL, numpoints, nburns, *F, *f, *h, simdLen, raw_output); +}else{ + typedef crhmc_input + < + MatrixType, + Point, + NegativeLogprobFunctor, + NegativeGradientFunctor, + ZeroFunctor + > Input; + typedef crhmc_problem CrhmcProblem; + ZeroFunctor zerof; +crhmc_sampling < + PointList, + Polytope, + RNGType, + CRHMCWalk, + NT, + Point, + NegativeGradientFunctor, + NegativeLogprobFunctor, + ZeroFunctor, + ImplicitMidpointODESolver < + Point, + NT, + CrhmcProblem, + NegativeGradientFunctor, + simdLen + > +>(randPoints, P, rng, walkL, numpoints, nburns, *F, *f, zerof, simdLen, raw_output); +} } - - template < typename WalkTypePolicy, diff --git a/include/volume/volume_sequence_of_balls.hpp b/include/volume/volume_sequence_of_balls.hpp index b79358a6e..da96f6bb2 100644 --- a/include/volume/volume_sequence_of_balls.hpp +++ b/include/volume/volume_sequence_of_balls.hpp @@ -27,6 +27,8 @@ #endif #include "convex_bodies/ball.h" #include "convex_bodies/ballintersectconvex.h" +#include "convex_bodies/ellipsoid.h" +#include "convex_bodies/ellipsoidintersectconvex.h" #include "random_walks/uniform_cdhr_walk.hpp" #include "sampling/random_point_generators.hpp" #include "volume/sampling_policies.hpp" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ddd40e362..3adbe4681 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -318,13 +318,20 @@ else () COMMAND logconcave_sampling_test -tc=uld) add_test(NAME logconcave_sampling_test_exponential_biomass_sampling COMMAND logconcave_sampling_test -tc=exponential_biomass_sampling) + add_test(NAME logconcave_sampling_test_nuts_hmc_truncated + COMMAND logconcave_sampling_test -tc=benchmark_nuts_hmc_truncated) + add_test(NAME logconcave_sampling_test_nuts_hmc + COMMAND logconcave_sampling_test -tc=benchmark_nuts_hmc) + + add_executable (crhmc_sampling_test crhmc_sampling_test.cpp $) add_test(NAME crhmc_sampling_test_crhmc COMMAND crhmc_sampling_test -tc=crhmc) add_test(NAME crhmc_test_polytope_sampling COMMAND crhmc_sampling_test -tc=test_polytope_sampling_crhmc) - + add_test(NAME crhmc_test_sparse_sampling + COMMAND crhmc_sampling_test -tc=test_sampling_sparse_problem) add_executable (simple_mc_integration simple_mc_integration.cpp $) add_test(NAME simple_mc_integration_over_limits COMMAND simple_mc_integration -tc=rectangle) @@ -360,7 +367,7 @@ else () #set_target_properties(benchmarks_crhmc # PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) #set_target_properties(benchmarks_crhmc_sampling - # PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) + # PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) set_target_properties(crhmc_polytope_preparation_test PROPERTIES COMPILE_FLAGS ${ADDITIONAL_FLAGS}) set_target_properties(crhmc_sampling_test @@ -384,15 +391,15 @@ else () TARGET_LINK_LIBRARIES(benchmarks_sob ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(benchmarks_cg ${LP_SOLVE} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(benchmarks_cb ${LP_SOLVE} ${MKL_LINK} coverage_config) - #TARGET_LINK_LIBRARIES(benchmarks_crhmc_sampling ${LP_SOLVE} ${MKL_LINK} ${QD_LIB} coverage_config) - #TARGET_LINK_LIBRARIES(benchmarks_crhmc ${LP_SOLVE} ${MKL_LINK} ${QD_LIB} coverage_config) + #TARGET_LINK_LIBRARIES(benchmarks_crhmc_sampling ${LP_SOLVE} ${MKL_LINK} QD_LIB coverage_config) + #TARGET_LINK_LIBRARIES(benchmarks_crhmc ${LP_SOLVE} ${MKL_LINK} QD_LIB coverage_config) TARGET_LINK_LIBRARIES(simple_mc_integration ${LP_SOLVE} ${MKL_LINK} coverage_config) - TARGET_LINK_LIBRARIES(ode_solvers_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} ${QD_LIB} coverage_config) + TARGET_LINK_LIBRARIES(ode_solvers_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} QD_LIB coverage_config) TARGET_LINK_LIBRARIES(boundary_oracles_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) TARGET_LINK_LIBRARIES(root_finders_test ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) - TARGET_LINK_LIBRARIES(crhmc_polytope_preparation_test ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} ${QD_LIB} coverage_config) + TARGET_LINK_LIBRARIES(crhmc_polytope_preparation_test ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} QD_LIB coverage_config) TARGET_LINK_LIBRARIES(logconcave_sampling_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} coverage_config) - TARGET_LINK_LIBRARIES(crhmc_sampling_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} ${QD_LIB} coverage_config) + TARGET_LINK_LIBRARIES(crhmc_sampling_test ${LP_SOLVE} ${IFOPT} ${IFOPT_IPOPT} ${PTHREAD} ${GMP} ${MPSOLVE} ${FFTW3} ${MKL_LINK} QD_LIB coverage_config) TARGET_LINK_LIBRARIES(order_polytope ${LP_SOLVE} coverage_config) TARGET_LINK_LIBRARIES(matrix_sampling_test ${LP_SOLVE} ${MKL_LINK} coverage_config) diff --git a/test/benchmarks_crhmc.cpp b/test/benchmarks_crhmc.cpp index 848c4d6db..3088cb656 100644 --- a/test/benchmarks_crhmc.cpp +++ b/test/benchmarks_crhmc.cpp @@ -24,12 +24,13 @@ #include #include using NT = double; +using VT = Eigen::Matrix; +using MT = Eigen::Matrix; using Kernel = Cartesian; using Point = typename Kernel::Point; using Hpolytope = HPolytope; using Input = crhmc_input; using CrhmcProblem = crhmc_problem; -using VT = Eigen::Matrix; inline bool exists_check(const std::string &name) { std::ifstream f(name.c_str()); diff --git a/test/benchmarks_crhmc_sampling.cpp b/test/benchmarks_crhmc_sampling.cpp index 27460b5be..6706553a7 100644 --- a/test/benchmarks_crhmc_sampling.cpp +++ b/test/benchmarks_crhmc_sampling.cpp @@ -51,8 +51,7 @@ struct SimulationStats { NT average_acceptance_prob = NT(0); NT step_size = NT(0); - friend std::ostream &operator<<(std::ostream &out, - const SimulationStats &stats) + friend std::ostream &operator<<(std::ostream &out, const SimulationStats &stats) { out << stats.method << "," << stats.walk_length << "," << stats.min_ess << "," << stats.max_psrf << "," << stats.time_per_draw << "," @@ -147,13 +146,12 @@ NT check_interval_psrf(MT &samples, NT target = NT(1.2)) { } return max_psrf; } -template -std::vector> benchmark_polytope_sampling( - Polytope &P, NT eta = NT(-1), unsigned int walk_length = 1, - double target_time = std::numeric_limits::max(), bool rounding = false, - bool centered = false, unsigned int max_draws = 80000, - unsigned int num_burns = 20000) -{ +template +std::vector> benchmark_polytope_sampling(StreamType &stream, + Polytope &P, NT eta = NT(-1), unsigned int walk_length = 1, + double target_time = std::numeric_limits::max(), bool rounding = false, + bool centered = false, unsigned int max_draws = 80000, + unsigned int num_burns = 20000) { using Kernel = Cartesian; using Point = typename Kernel::Point; using MT = typename Polytope::MT; @@ -164,7 +162,7 @@ std::vector> benchmark_polytope_sampling( using Input = crhmc_input; using CrhmcProblem = crhmc_problem; using Opts = opts; - using Solver = ImplicitMidpointODESolver; + using Solver = ImplicitMidpointODESolver; using RandomNumberGenerator = BoostRandomNumberGenerator; SimulationStats rdhr_stats; @@ -187,7 +185,7 @@ std::vector> benchmark_polytope_sampling( unsigned int dim = x0.dimension(); if (rounding) { - std::cout << "SVD Rounding" << std::endl; + stream << "SVD Rounding" << std::endl; svd_rounding(P, inner_ball, walk_length, rng); } @@ -207,12 +205,17 @@ std::vector> benchmark_polytope_sampling( std::chrono::time_point start, stop; Opts options; + options.simdLen = simdLen; CRHMCWalk::parameters crhmc_params(F, dim, options); Input input = Input(P.dimension(), f, F, H); input.Aineq = P.get_mat(); input.bineq = P.get_vec(); CrhmcProblem crhmc_problem = CrhmcProblem(input); +#ifdef TIME_KEEPING + crhmc_problem.print_preparation_time(stream); +#endif + Point x_start(crhmc_problem.center); CRHMCWalk::Walk @@ -237,13 +240,20 @@ std::vector> benchmark_polytope_sampling( std::cout << std::endl; std::cout << "Sampling" << std::endl; - +#ifdef TIME_KEEPING + crhmc.initialize_timers(); +#endif start = std::chrono::high_resolution_clock::now(); - for (unsigned int i = 0; i < max_actual_draws; i++) { + for (unsigned int i = 0; i < std::ceil(max_actual_draws / simdLen); i++) { for (int k = 0; k < walk_length; k++) { crhmc.apply(rng, 1); } - samples.col(i) = crhmc.getPoint().getCoefficients(); + MT sample = crhmc.getPoints(); + if (i * simdLen + simdLen - 1 < max_actual_draws) { + samples(Eigen::all, Eigen::seq(i * simdLen, i * simdLen + simdLen - 1)) = sample; + } else { + samples(Eigen::all, Eigen::seq(i * simdLen, max_actual_draws - 1)) = sample(Eigen::all, Eigen::seq(0, max_actual_draws - 1 - simdLen * i)); + } if (i % 1000 == 0 && i > 0) std::cout << "."; } @@ -251,30 +261,31 @@ std::vector> benchmark_polytope_sampling( ETA = (NT)std::chrono::duration_cast(stop - start) .count(); - std::cout << std::endl; -#ifdef TIME_KEEPING std::chrono::duration total_time = stop - start; - std::cerr << "Total time: " << total_time.count() << "\n"; + stream << "Total Sampling time: " << total_time.count() << "\n"; assert(total_time.count() < target_time); - std::cout << "Assertion (preparation_time< " << target_time - << " secs) passed!" << std::endl - << std::endl; - crhmc.print_timing_information(); + stream << "Assertion (preparation_time< " << target_time + << " secs) passed!" << std::endl + << std::endl; +#ifdef TIME_KEEPING + crhmc.print_timing_information(stream); #endif print_diagnostics(samples, min_ess, std::cout); - std::cout << "min ess " << min_ess << "us" << std::endl; - std::cout << "Average time per sample: " << ETA / max_actual_draws << "us" - << std::endl; - std::cout << "Average time per independent sample: " << ETA / min_ess << "us" - << std::endl; - std::cout << "Step size (final): " << crhmc.solver->eta << std::endl; - std::cout << "Discard Ratio: " << crhmc.discard_ratio << std::endl; - std::cout << "Average Acceptance Probability: " - << crhmc.average_acceptance_prob << std::endl; + stream << "Problem original size: m= " << P.num_of_hyperplanes() << ", n= " << P.dimension() << std::endl; + stream << "Number of non Zeros: " << crhmc_problem.nnz() << std::endl; + stream << "min ess " << min_ess << std::endl; + stream << "Average time per sample: " << ETA / max_actual_draws << "us" + << std::endl; + stream << "Average time per independent sample: " << ETA / min_ess << "us" + << std::endl; + stream << "Step size (final): " << crhmc.solver->eta << std::endl; + stream << "Discard Ratio: " << crhmc.discard_ratio << std::endl; + stream << "Average Acceptance Probability: " + << crhmc.average_acceptance_prob << std::endl; max_psrf = check_interval_psrf(samples); - std::cout << "max_psrf: " << max_psrf << std::endl; - std::cout << std::endl; + stream << "max_psrf: " << max_psrf << std::endl; + stream << std::endl; crhmc_stats.method = "CRHMC"; crhmc_stats.walk_length = walk_length; @@ -288,31 +299,33 @@ std::vector> benchmark_polytope_sampling( return std::vector>{rdhr_stats, crhmc_stats}; } -template -void test_benchmark_polytope( - HPolytope &P, std::string &name, bool centered, - double target_time = std::numeric_limits::max(), int walk_length = 1) -{ +template +void test_benchmark_polytope(StreamType &stream, + HPolytope &P, std::string &name, bool centered, + double target_time = std::numeric_limits::max(), int walk_length = 1) { + stream << "CRHMC polytope preparation for " << name << std::endl; std::cout << "CRHMC polytope preparation for " << name << std::endl; std::vector> results; NT step_size = 0; std::pair inner_ball; std::ofstream outfile; - std::cout << name << std::endl; outfile.open("results_" + name + "_new.txt"); P.normalize(); inner_ball = P.ComputeInnerBall(); step_size = inner_ball.second / 10; - results = benchmark_polytope_sampling(P, step_size, walk_length, target_time, - false, centered); + results = benchmark_polytope_sampling(stream, P, step_size, walk_length, target_time, + false, centered); outfile << results[0]; outfile << results[1]; outfile.close(); } -template +template void call_test_benchmark_polytope() { + std::ofstream stream; + stream.open("CRHMC_SIMD_" + std::to_string(simdLen) + ".txt"); + stream << "---------------Using simdLen= " << simdLen << "---------------" << std::endl; using Kernel = Cartesian; using Point = typename Kernel::Point; using Hpolytope = HPolytope; @@ -321,7 +334,7 @@ void call_test_benchmark_polytope() { std::string name = "100_skinny_cube"; bool centered = false; double target_time = 20; // secs - test_benchmark_polytope(P, name, false, target_time); + test_benchmark_polytope(stream, P, name, target_time, false); } { @@ -329,23 +342,23 @@ void call_test_benchmark_polytope() { std::string name = "5_cross"; bool centered = false; double target_time = 10; // secs - test_benchmark_polytope(P, name, centered, target_time); + test_benchmark_polytope(stream, P, name, target_time, centered); } { Hpolytope P = generate_simplex(100, false); std::string name = "100_simplex"; bool centered = false; - double target_time = 15; // secs - test_benchmark_polytope(P, name, centered, target_time); + double target_time = 20; // secs + test_benchmark_polytope(stream, P, name, target_time, centered); } { Hpolytope P = generate_prod_simplex(50, false); std::string name = "50_prod_simplex"; bool centered = false; - double target_time = 15; // secs - test_benchmark_polytope(P, name, centered, target_time); + double target_time = 20; // secs + test_benchmark_polytope(stream, P, name, target_time, centered); } { @@ -353,35 +366,36 @@ void call_test_benchmark_polytope() { std::string name = "10_birkhoff"; bool centered = false; double target_time = 15; // secs - test_benchmark_polytope(P, name, centered, target_time); + test_benchmark_polytope(stream, P, name, target_time, centered); } - if (exists_check("netlib/afiro.ine")) - { - Hpolytope P = read_polytope("netlib/afiro.ine"); + if (exists_check("../test/netlib/afiro.ine")) { + Hpolytope P = read_polytope("../test/netlib/afiro.ine"); std::string name = "afiro"; bool centered = true; double target_time = 100; // secs - test_benchmark_polytope(P, name, centered, target_time); + test_benchmark_polytope(stream, P, name, target_time, centered); } - if (exists_check("metabolic_full_dim/polytope_e_coli.ine")) - { + if (exists_check("../test/metabolic_full_dim/polytope_e_coli.ine")) { Hpolytope P = - read_polytope("metabolic_full_dim/polytope_e_coli.ine"); + read_polytope("../test/metabolic_full_dim/polytope_e_coli.ine"); std::string name = "e_coli"; bool centered = true; double target_time = 600; // secs - test_benchmark_polytope(P, name, centered, target_time); + test_benchmark_polytope(stream, P, name, target_time, centered); } + + stream.close(); } int main() { - std::cout << "---------------CRHMC polytope sampling benchmarking---------------" << std::endl << std::endl; - call_test_benchmark_polytope(); + call_test_benchmark_polytope(); + call_test_benchmark_polytope(); + call_test_benchmark_polytope(); return 0; } diff --git a/test/crhmc_polytope_preparation_test.cpp b/test/crhmc_polytope_preparation_test.cpp index 6da13269b..db6fa0674 100644 --- a/test/crhmc_polytope_preparation_test.cpp +++ b/test/crhmc_polytope_preparation_test.cpp @@ -117,6 +117,8 @@ template void test_crhmc_dependent_polytope() { using VT = Eigen::Matrix; using Input = crhmc_input; using CrhmcProblem = crhmc_problem; + using SpMat = typename CrhmcProblem::SpMat; + using InputSparse = crhmc_input; using PolytopeType = HPolytope; using Opts = opts; unsigned d = 3; @@ -131,6 +133,13 @@ template void test_crhmc_dependent_polytope() { options.EnableReordering = true; CrhmcProblem P = CrhmcProblem(input, options); CHECK(P.equations() == 2); + + SpMat A = Aeq.sparseView(); + InputSparse input_sparse = InputSparse(d); + input_sparse.Aeq = A; + input_sparse.beq = beq; + crhmc_problem Q = crhmc_problem(input_sparse,options); + CHECK(Q.equations() == 2); } template void test_center_computation() { @@ -188,6 +197,7 @@ template void call_test_center_computation(){ std::cout << "--- Testing CRHMC polytope-center computation" << std::endl; test_center_computation(); } + TEST_CASE("test_preparation_crhmc") { call_test_crhmc_preprocesssing(); } diff --git a/test/crhmc_sampling_test.cpp b/test/crhmc_sampling_test.cpp index 2bd1b7995..a13a6e299 100644 --- a/test/crhmc_sampling_test.cpp +++ b/test/crhmc_sampling_test.cpp @@ -16,6 +16,8 @@ #include "ode_solvers.hpp" #include "preprocess/crhmc/crhmc_input.h" #include "preprocess/crhmc/crhmc_problem.h" +#include "preprocess/crhmc/crhmc_problem.h" +#include "preprocess/crhmc/crhmc_utils.h" #include "random.hpp" #include "random/normal_distribution.hpp" #include "random/uniform_int.hpp" @@ -33,6 +35,7 @@ #include #include #include "preprocess/svd_rounding.hpp" +#include "sampling/sampling.hpp" struct InnerBallFunctor { // Gaussian density centered at the inner ball center @@ -178,15 +181,14 @@ template = skip_samples) { - Point x = sampler.getPoint(); + Point x = Point(sampler.getPoints().rowwise().sum()); mean = mean + x; } @@ -228,12 +230,11 @@ Polytope read_polytope(std::string filename) { return P; } -template +template void crhmc_polytope_sampling( Polytope &P, NT eta = NT(-1), unsigned int walk_length = 1, bool rounding = false, bool centered = false, - unsigned int max_draws = 80000, unsigned int num_burns = 20000) -{ + unsigned int max_draws = 80000, unsigned int num_burns = 20000) { using Kernel = Cartesian; using Point = typename Kernel::Point; using RandomNumberGenerator = BoostRandomNumberGenerator; @@ -246,8 +247,7 @@ void crhmc_polytope_sampling( NegativeGradientFunctor, HessianFunctor>; using CrhmcProblem = crhmc_problem; using Opts = opts; - using Solver = ImplicitMidpointODESolver; + using Solver = ImplicitMidpointODESolver; std::pair inner_ball; if (centered) { @@ -286,8 +286,8 @@ void crhmc_polytope_sampling( NT max_psrf; Opts options; - CRHMCWalk::parameters crhmc_params(F, dim, - options); + options.simdLen = simdLen; + CRHMCWalk::parameters crhmc_params(F, dim,options); Input input = Input(P.dimension(), f, F, H); input.Aineq = P.get_mat(); input.bineq = P.get_vec(); @@ -318,11 +318,16 @@ void crhmc_polytope_sampling( std::cout << std::endl; std::cout << "Sampling" << std::endl; - for (unsigned int i = 0; i < max_actual_draws; i++) { + for (unsigned int i = 0; i < std::ceil(max_actual_draws / simdLen); i++) { for (int k = 0; k < walk_length; k++) { crhmc.apply(rng, 1); } - samples.col(i) = crhmc.getPoint().getCoefficients(); + MT sample = crhmc.getPoints(); + if (i * simdLen + simdLen - 1 < max_actual_draws) { + samples(Eigen::all, Eigen::seq(i * simdLen, i * simdLen + simdLen - 1)) = sample; + } else { + samples(Eigen::all, Eigen::seq(i * simdLen, max_actual_draws - 1)) = sample(Eigen::all, Eigen::seq(0, max_actual_draws - 1 - simdLen * i)); + } if (i % 1000 == 0 && i > 0) std::cout << "."; } @@ -340,7 +345,7 @@ inline bool exists_check(const std::string &name) { return f.good(); } -template +template void test_sampling_polytope(HPolytope &P, std::string &name, bool centered, int walk_length = 1) { NT step_size = 0; @@ -349,9 +354,9 @@ void test_sampling_polytope(HPolytope &P, std::string &name, bool centered, P.normalize(); inner_ball = P.ComputeInnerBall(); step_size = inner_ball.second / 10; - crhmc_polytope_sampling(P, step_size, walk_length, false, centered); + crhmc_polytope_sampling(P, step_size, walk_length, false, centered); } -template +template void call_test_sampling_polytope() { using Kernel = Cartesian; using Point = typename Kernel::Point; @@ -362,35 +367,35 @@ void call_test_sampling_polytope() { Hpolytope P = generate_skinny_cube(100, false); std::string name = "100_skinny_cube"; bool centered = false; - test_sampling_polytope(P, name, false); + test_sampling_polytope(P, name, false); } { Hpolytope P = generate_cross(5, false); std::string name = "5_cross"; bool centered = false; - test_sampling_polytope(P, name, centered); + test_sampling_polytope(P, name, centered); } { Hpolytope P = generate_simplex(100, false); std::string name = "100_simplex"; bool centered = false; - test_sampling_polytope(P, name, centered); + test_sampling_polytope(P, name, centered); } { Hpolytope P = generate_prod_simplex(50, false); std::string name = "50_prod_simplex"; bool centered = false; - test_sampling_polytope(P, name, centered); + test_sampling_polytope(P, name, centered); } { Hpolytope P = generate_birkhoff(10); std::string name = "10_birkhoff"; bool centered = false; - test_sampling_polytope(P, name, centered); + test_sampling_polytope(P, name, centered); } } @@ -443,7 +448,7 @@ void benchmark_cube_crhmc() { } } -template +template void test_crhmc() { using Kernel = Cartesian; using Point = typename Kernel::Point; @@ -458,8 +463,7 @@ void test_crhmc() { crhmc_input; using CrhmcProblem = crhmc_problem; using RandomNumberGenerator = BoostRandomNumberGenerator; - using Solver = ImplicitMidpointODESolver; + using Solver = ImplicitMidpointODESolver; using Opts = opts; IsotropicQuadraticFunctor::parameters params; params.order = 2; @@ -468,12 +472,16 @@ void test_crhmc() { RandomNumberGenerator rng(1); unsigned int dim = 10; Opts options; + options.simdLen = simdLen; + options.DynamicWeight=false; + options.DynamicStepSize=false; + options.DynamicRegularizer=false; CRHMCWalk::parameters crhmc_params(g, dim, options); Input input = Input(dim, f, g); input.lb = -VT::Ones(dim); input.ub = VT::Ones(dim); - CrhmcProblem P = CrhmcProblem(input); + CrhmcProblem P = CrhmcProblem(input,options); Point x0(dim); CRHMCWalk::Walk @@ -486,13 +494,68 @@ template void call_test_crhmc() { std::cout << "--- Testing Constrained Riemannian Hamiltonian Monte Carlo" << std::endl; - test_crhmc(); + std::cout << "------------SIMDLEN=1-------------------\n" + << std::endl; + test_crhmc(); + std::cout << "------------SIMDLEN=4-------------------\n" + << std::endl; + test_crhmc(); } template void call_test_benchmark_cube_crhmc() { benchmark_cube_crhmc(); } +template +void test_polytope_sampling_sparse_problem(ConstraintProblem &problem, int n_samples = 80000, int n_burns = 20000){ + using NT = typename Point::FT; + using VT = Eigen::Matrix; + using MT = Eigen::Matrix; + using Func = GaussianFunctor::FunctionFunctor; + using Grad = GaussianFunctor::GradientFunctor; + using Hess = GaussianFunctor::HessianFunctor; + using func_params = GaussianFunctor::parameters; + using RNG = BoostRandomNumberGenerator; + func_params params = func_params(Point(problem.dimension()), 0.5, 1); + Func* f= new Func(params); + Grad* g= new Grad(params); + Hess* h= new Hess(params); + RNG rng(1); + std::list PointList; + execute_crhmc, Grad, Func, Hess, CRHMCWalk, simdLen>(problem, rng, PointList, 1, n_samples, n_burns, g, f, h, true); + std::cout<<"Here--------------------------\n"; + MT samples = MT(PointList.front().dimension(), PointList.size()); + int i=0; + for (typename std::list::iterator it = PointList.begin(); it != PointList.end(); ++it){ + samples.col(i) = (*it).getCoefficients(); + i++; + } + NT max_psrf = check_interval_psrf(samples); + std::cout<<"PSRF: "< +void call_test_polytope_sampling_sparse_problem(){ + std::cout << " ---Sampling sparse problems " << std::endl; + using SpMat = Eigen::SparseMatrix; + using Kernel = Cartesian; + using Point = typename Kernel::Point; + using VT = Eigen::Matrix; + using ConstraintProblem =constraint_problem; + if(exists_check("../test/netlib/degen2.mm")){ + std::cout<<"Problem name: degen2" << std::endl; + SpMat A; + VT b, lb, ub; + int dimension; + load_problem(A, b, lb, ub, dimension, "../test/netlib/degen2"); + ConstraintProblem problem = ConstraintProblem(dimension); + problem.set_equality_constraints(A, b); + problem.set_bounds(lb, ub); + test_polytope_sampling_sparse_problem(problem); + } +} TEST_CASE("crhmc") { call_test_crhmc(); } @@ -502,5 +565,19 @@ TEST_CASE("benchmark_crhmc_cube") { } TEST_CASE("test_polytope_sampling_crhmc") { - call_test_sampling_polytope(); + std::cout << "------------SIMDLEN=1-------------------\n" + << std::endl; + call_test_sampling_polytope(); + std::cout << "------------SIMDLEN=4-------------------\n" + << std::endl; + call_test_sampling_polytope(); +} + +TEST_CASE("test_sampling_sparse_problem") { + std::cout << "------------SIMDLEN=1-------------------\n" + << std::endl; + call_test_polytope_sampling_sparse_problem(); + std::cout << "------------SIMDLEN=4-------------------\n" + << std::endl; + call_test_polytope_sampling_sparse_problem(); } diff --git a/test/logconcave_sampling_test.cpp b/test/logconcave_sampling_test.cpp index f8f6901cd..8e53f489b 100644 --- a/test/logconcave_sampling_test.cpp +++ b/test/logconcave_sampling_test.cpp @@ -39,6 +39,8 @@ #include "generators/h_polytopes_generator.h" #include "generators/convex_bodies_generator.h" +#include "diagnostics/univariate_psrf.hpp" + #include "preprocess/svd_rounding.hpp" #include "misc/misc.h" @@ -308,6 +310,80 @@ void benchmark_hmc(bool truncated) { } +template +void benchmark_nuts_hmc(bool truncated) { + typedef Cartesian Kernel; + typedef typename Kernel::Point Point; + typedef std::vector pts; + typedef HPolytope Hpolytope; + typedef BoostRandomNumberGenerator RandomNumberGenerator; + typedef CustomFunctor::GradientFunctor NegativeGradientFunctor; + typedef CustomFunctor::FunctionFunctor NegativeLogprobFunctor; + typedef LeapfrogODESolver Solver; + + typedef Eigen::Matrix MT; + typedef Eigen::Matrix VT; + + NegativeGradientFunctor F; + NegativeLogprobFunctor f; + RandomNumberGenerator rng(1); + unsigned int dim_min = 10; + unsigned int dim_max = 100; + int n_samples = 1000; + long ETA; + bool automatic_burnin = false; + std::chrono::time_point start, stop; + + for (unsigned int dim = dim_min; dim <= dim_max; dim+=10) + { + MT samples(dim, n_samples); + Point x0(dim); + NutsHamiltonianMonteCarloWalk::parameters hmc_params(F, dim); + if (truncated) + { + Hpolytope P = generate_cube(dim, false); + + std::cout << "eta0: " << hmc_params.eta << std::endl; + + NutsHamiltonianMonteCarloWalk::Walk + hmc(&P, x0, F, f, hmc_params, automatic_burnin); + + hmc.burnin(rng); + std::cout << "eta: " << hmc.get_eta_solver() << std::endl; + + start = std::chrono::high_resolution_clock::now(); + for (int i = 0; i < n_samples; i++) { + hmc.apply(rng); + samples.col(i) = hmc.x.getCoefficients(); + } + stop = std::chrono::high_resolution_clock::now(); + std::cout << "proportion of sucussfull steps: " << hmc.get_ratio_acceptance() << std::endl; + } + else + { + NutsHamiltonianMonteCarloWalk::Walk + hmc(NULL, x0, F, f, hmc_params, automatic_burnin); + + hmc.burnin(rng); + std::cout << "eta: " << hmc.get_eta_solver() << std::endl; + + start = std::chrono::high_resolution_clock::now(); + for (int i = 0; i < n_samples; i++) { + hmc.apply(rng); + samples.col(i) = hmc.x.getCoefficients(); + } + stop = std::chrono::high_resolution_clock::now(); + std::cout << "proportion of sucussfull steps: " << hmc.get_ratio_acceptance() << std::endl; + } + + std::cout << "PSRF: " << univariate_psrf(samples).maxCoeff() << std::endl; + + ETA = (long) std::chrono::duration_cast(stop - start).count(); + std::cout<< "time: " << ETA << "\n" << std::endl; + } + +} + template void test_hmc() { typedef Cartesian Kernel; @@ -878,6 +954,11 @@ void call_test_benchmark_hmc(bool truncated) { benchmark_hmc(truncated); } +template +void call_test_benchmark_nuts_hmc(bool truncated) { + benchmark_nuts_hmc(truncated); +} + template void call_test_benchmark_polytopes_grid_search() { typedef Cartesian Kernel; @@ -1196,6 +1277,14 @@ TEST_CASE("exponential_biomass_sampling") { call_test_exp_sampling(); } +TEST_CASE("benchmark_nuts_hmc_truncated") { + call_test_benchmark_nuts_hmc(true); +} + +TEST_CASE("benchmark_nuts_hmc") { + call_test_benchmark_nuts_hmc(false); +} + TEST_CASE("benchmark_hmc") { call_test_benchmark_hmc(false); } diff --git a/test/netlib/degen2.mm b/test/netlib/degen2.mm new file mode 100644 index 000000000..0232eff96 --- /dev/null +++ b/test/netlib/degen2.mm @@ -0,0 +1,4447 @@ +%%MatrixMarket matrix coordinate real general +% Generated 28-Oct-2022 +444 758 4444 +1 1 1 +2 2 1 +3 3 1 +225 4 1 +226 5 1 +227 6 1 +228 7 1 +229 8 1 +230 9 1 +231 10 1 +232 11 1 +233 12 1 +234 13 1 +235 14 1 +236 15 1 +237 16 1 +238 17 1 +239 18 1 +240 19 1 +241 20 1 +242 21 1 +243 22 1 +244 23 1 +245 24 1 +246 25 1 +247 26 1 +248 27 1 +249 28 1 +250 29 1 +251 30 1 +252 31 1 +253 32 1 +254 33 1 +255 34 1 +256 35 1 +257 36 1 +258 37 1 +259 38 1 +260 39 1 +261 40 1 +262 41 1 +263 42 1 +264 43 1 +265 44 1 +266 45 1 +267 46 1 +268 47 1 +269 48 1 +270 49 1 +271 50 1 +272 51 1 +273 52 1 +274 53 1 +275 54 1 +276 55 1 +277 56 1 +278 57 1 +279 58 1 +280 59 1 +281 60 1 +282 61 1 +283 62 1 +284 63 1 +285 64 1 +286 65 1 +287 66 1 +288 67 1 +289 68 1 +290 69 1 +291 70 1 +292 71 1 +293 72 1 +294 73 1 +295 74 1 +296 75 1 +297 76 1 +298 77 1 +299 78 1 +300 79 1 +301 80 1 +302 81 1 +303 82 1 +304 83 1 +305 84 1 +306 85 1 +307 86 1 +308 87 1 +309 88 1 +310 89 1 +311 90 1 +312 91 1 +313 92 1 +314 93 1 +315 94 1 +316 95 1 +317 96 1 +318 97 1 +319 98 1 +320 99 1 +321 100 1 +322 101 1 +323 102 1 +324 103 1 +325 104 1 +326 105 1 +327 106 1 +328 107 1 +329 108 1 +330 109 1 +331 110 1 +332 111 1 +333 112 1 +334 113 1 +335 114 1 +336 115 1 +337 116 1 +338 117 1 +339 118 1 +340 119 1 +341 120 1 +342 121 1 +343 122 1 +344 123 1 +345 124 1 +346 125 1 +347 126 1 +348 127 1 +349 128 1 +350 129 1 +351 130 1 +352 131 1 +353 132 1 +354 133 1 +355 134 1 +356 135 1 +357 136 1 +358 137 1 +359 138 1 +360 139 1 +361 140 1 +362 141 1 +363 142 1 +364 143 1 +365 144 1 +366 145 1 +367 146 1 +368 147 1 +369 148 1 +370 149 1 +371 150 1 +372 151 1 +373 152 1 +374 153 1 +375 154 1 +376 155 1 +377 156 1 +378 157 1 +379 158 1 +380 159 1 +381 160 1 +382 161 1 +383 162 1 +384 163 1 +385 164 1 +386 165 1 +387 166 1 +388 167 1 +389 168 1 +390 169 1 +391 170 1 +392 171 1 +393 172 1 +394 173 1 +395 174 1 +396 175 1 +397 176 1 +398 177 1 +399 178 1 +400 179 1 +401 180 1 +402 181 1 +403 182 1 +404 183 1 +405 184 1 +406 185 1 +407 186 1 +408 187 1 +409 188 1 +410 189 1 +411 190 1 +412 191 1 +413 192 1 +414 193 1 +415 194 1 +416 195 1 +417 196 1 +418 197 1 +419 198 1 +420 199 1 +421 200 1 +422 201 1 +423 202 1 +424 203 1 +425 204 1 +426 205 1 +427 206 1 +428 207 1 +429 208 1 +430 209 1 +431 210 1 +432 211 1 +433 212 1 +434 213 1 +435 214 1 +436 215 1 +437 216 1 +438 217 1 +439 218 1 +440 219 1 +441 220 1 +442 221 1 +443 222 1 +444 223 1 +1 224 1 +4 224 1 +193 224 -1 +202 224 1 +291 224 -1 +292 224 -1 +2 225 1 +4 225 1 +194 225 -1 +203 225 1 +296 225 -1 +297 225 -1 +1 226 1 +5 226 1 +197 226 1 +202 226 -1 +331 226 -1 +332 226 -1 +333 226 -1 +334 226 -1 +2 227 1 +5 227 1 +198 227 1 +203 227 -1 +339 227 -1 +340 227 -1 +341 227 -1 +1 228 1 +6 228 1 +197 228 -1 +202 228 1 +305 228 -1 +306 228 -1 +2 229 1 +6 229 1 +198 229 -1 +203 229 1 +308 229 -1 +309 229 -1 +1 230 1 +7 230 1 +197 230 1 +202 230 -1 +327 230 -1 +328 230 -1 +329 230 -1 +330 230 -1 +331 230 -1 +332 230 -1 +333 230 -1 +334 230 -1 +2 231 1 +7 231 1 +198 231 1 +203 231 -1 +336 231 -1 +337 231 -1 +338 231 -1 +339 231 -1 +340 231 -1 +341 231 -1 +8 232 1 +197 232 -1 +202 232 1 +306 232 -1 +327 232 1 +328 232 1 +329 232 1 +330 232 1 +331 232 1 +332 232 1 +333 232 1 +334 232 1 +8 233 1 +198 233 -1 +203 233 1 +309 233 -1 +336 233 1 +337 233 1 +338 233 1 +339 233 1 +340 233 1 +341 233 1 +9 234 1 +193 234 1 +202 234 -1 +291 234 1 +292 234 1 +333 234 -1 +334 234 -1 +9 235 1 +194 235 1 +203 235 -1 +296 235 1 +297 235 1 +341 235 -1 +10 236 1 +193 236 -1 +202 236 1 +292 236 -1 +329 236 1 +330 236 1 +331 236 1 +332 236 1 +333 236 1 +334 236 1 +10 237 1 +194 237 -1 +203 237 1 +297 237 -1 +337 237 1 +338 237 1 +339 237 1 +340 237 1 +341 237 1 +11 238 1 +197 238 1 +202 238 -1 +305 238 1 +306 238 1 +333 238 -1 +334 238 -1 +11 239 1 +198 239 1 +203 239 -1 +308 239 1 +309 239 1 +341 239 -1 +1 240 1 +12 240 1 +197 240 1 +220 240 -1 +418 240 -1 +419 240 -1 +2 241 1 +12 241 1 +198 241 1 +221 241 -1 +421 241 -1 +422 241 -1 +13 242 1 +197 242 -1 +220 242 1 +306 242 -1 +418 242 1 +419 242 1 +13 243 1 +198 243 -1 +221 243 1 +309 243 -1 +421 243 1 +422 243 1 +14 244 1 +193 244 1 +202 244 -1 +288 244 1 +289 244 1 +290 244 1 +291 244 1 +292 244 1 +326 244 -1 +327 244 -1 +328 244 -1 +329 244 -1 +330 244 -1 +331 244 -1 +332 244 -1 +333 244 -1 +334 244 -1 +14 245 1 +194 245 1 +203 245 -1 +293 245 1 +294 245 1 +295 245 1 +296 245 1 +297 245 1 +335 245 -1 +336 245 -1 +337 245 -1 +338 245 -1 +339 245 -1 +340 245 -1 +341 245 -1 +15 246 1 +197 246 -1 +222 246 1 +428 246 1 +429 246 1 +430 246 1 +431 246 1 +432 246 1 +15 247 1 +198 247 -1 +223 247 1 +436 247 1 +437 247 1 +438 247 1 +439 247 1 +440 247 1 +1 248 1 +16 248 1 +197 248 1 +222 248 -1 +427 248 -1 +428 248 -1 +429 248 -1 +430 248 -1 +431 248 -1 +432 248 -1 +2 249 1 +16 249 1 +198 249 1 +223 249 -1 +435 249 -1 +436 249 -1 +437 249 -1 +438 249 -1 +439 249 -1 +440 249 -1 +1 250 1 +17 250 1 +197 250 -1 +222 250 1 +305 250 -1 +306 250 -1 +2 251 1 +17 251 1 +198 251 -1 +223 251 1 +308 251 -1 +309 251 -1 +18 252 1 +197 252 -1 +222 252 1 +431 252 1 +432 252 1 +18 253 1 +198 253 -1 +223 253 1 +439 253 1 +440 253 1 +1 254 1 +19 254 1 +197 254 1 +222 254 -1 +429 254 -1 +430 254 -1 +431 254 -1 +432 254 -1 +2 255 1 +19 255 1 +198 255 1 +223 255 -1 +437 255 -1 +438 255 -1 +439 255 -1 +440 255 -1 +20 256 1 +197 256 -1 +202 256 1 +334 256 1 +20 257 1 +198 257 -1 +203 257 1 +341 257 1 +21 258 1 +197 258 1 +222 258 -1 +305 258 1 +306 258 1 +431 258 -1 +432 258 -1 +21 259 1 +198 259 1 +223 259 -1 +308 259 1 +309 259 1 +439 259 -1 +440 259 -1 +22 260 1 +193 260 -1 +222 260 1 +428 260 1 +429 260 1 +430 260 1 +431 260 1 +432 260 1 +22 261 1 +194 261 -1 +223 261 1 +436 261 1 +437 261 1 +438 261 1 +439 261 1 +440 261 1 +22 262 1 +442 262 1 +23 263 1 +193 263 1 +222 263 -1 +288 263 1 +289 263 1 +290 263 1 +291 263 1 +292 263 1 +428 263 -1 +429 263 -1 +430 263 -1 +431 263 -1 +432 263 -1 +23 264 1 +194 264 1 +223 264 -1 +293 264 1 +294 264 1 +295 264 1 +296 264 1 +297 264 1 +436 264 -1 +437 264 -1 +438 264 -1 +439 264 -1 +440 264 -1 +3 265 1 +23 265 1 +442 265 -1 +24 266 1 +193 266 1 +202 266 -1 +292 266 1 +24 267 1 +194 267 1 +203 267 -1 +297 267 1 +1 268 1 +25 268 1 +193 268 -1 +202 268 1 +288 268 -1 +289 268 -1 +290 268 -1 +291 268 -1 +292 268 -1 +333 268 1 +334 268 1 +2 269 1 +25 269 1 +194 269 -1 +203 269 1 +293 269 -1 +294 269 -1 +295 269 -1 +296 269 -1 +297 269 -1 +341 269 1 +1 270 1 +26 270 1 +197 270 -1 +220 270 1 +304 270 -1 +305 270 -1 +306 270 -1 +2 271 1 +26 271 1 +198 271 -1 +221 271 1 +307 271 -1 +308 271 -1 +309 271 -1 +27 272 1 +197 272 1 +220 272 -1 +305 272 1 +306 272 1 +27 273 1 +198 273 1 +221 273 -1 +308 273 1 +309 273 1 +1 274 1 +28 274 1 +195 274 -1 +222 274 1 +302 274 -1 +2 275 1 +28 275 1 +196 275 -1 +223 275 1 +303 275 -1 +1 276 1 +29 276 1 +195 276 -1 +202 276 1 +302 276 -1 +2 277 1 +29 277 1 +196 277 -1 +203 277 1 +303 277 -1 +1 278 1 +30 278 1 +185 278 1 +222 278 -1 +427 278 -1 +428 278 -1 +429 278 -1 +430 278 -1 +431 278 -1 +432 278 -1 +2 279 1 +30 279 1 +186 279 1 +223 279 -1 +435 279 -1 +436 279 -1 +437 279 -1 +438 279 -1 +439 279 -1 +440 279 -1 +31 280 1 +202 280 1 +212 280 -1 +329 280 1 +330 280 1 +331 280 1 +332 280 1 +333 280 1 +334 280 1 +31 281 1 +203 281 1 +213 281 -1 +337 281 1 +338 281 1 +339 281 1 +340 281 1 +341 281 1 +32 282 1 +195 282 1 +202 282 -1 +302 282 1 +333 282 -1 +334 282 -1 +32 283 1 +196 283 1 +203 283 -1 +303 283 1 +341 283 -1 +33 284 1 +195 284 1 +222 284 -1 +302 284 1 +431 284 -1 +432 284 -1 +33 285 1 +196 285 1 +223 285 -1 +303 285 1 +439 285 -1 +440 285 -1 +34 286 1 +185 286 -1 +222 286 1 +427 286 1 +428 286 1 +429 286 1 +430 286 1 +431 286 1 +432 286 1 +34 287 1 +186 287 -1 +223 287 1 +435 287 1 +436 287 1 +437 287 1 +438 287 1 +439 287 1 +440 287 1 +1 288 1 +35 288 1 +195 288 1 +202 288 -1 +326 288 -1 +327 288 -1 +328 288 -1 +329 288 -1 +330 288 -1 +331 288 -1 +332 288 -1 +333 288 -1 +334 288 -1 +2 289 1 +35 289 1 +196 289 1 +203 289 -1 +335 289 -1 +336 289 -1 +337 289 -1 +338 289 -1 +339 289 -1 +340 289 -1 +341 289 -1 +36 290 1 +187 290 1 +208 290 -1 +247 290 1 +248 290 1 +36 291 1 +188 291 1 +209 291 -1 +250 291 1 +251 291 1 +36 292 1 +253 292 1 +254 292 1 +37 293 1 +181 293 -1 +202 293 1 +326 293 1 +327 293 1 +328 293 1 +329 293 1 +330 293 1 +331 293 1 +332 293 1 +333 293 1 +334 293 1 +37 294 1 +182 294 -1 +203 294 1 +335 294 1 +336 294 1 +337 294 1 +338 294 1 +339 294 1 +340 294 1 +341 294 1 +38 295 1 +183 295 1 +222 295 -1 +236 295 1 +237 295 1 +431 295 -1 +432 295 -1 +38 296 1 +184 296 1 +223 296 -1 +239 296 1 +240 296 1 +439 296 -1 +440 296 -1 +39 297 1 +183 297 -1 +222 297 1 +427 297 1 +428 297 1 +429 297 1 +430 297 1 +431 297 1 +432 297 1 +39 298 1 +184 298 -1 +223 298 1 +435 298 1 +436 298 1 +437 298 1 +438 298 1 +439 298 1 +440 298 1 +1 299 1 +40 299 1 +183 299 1 +222 299 -1 +427 299 -1 +428 299 -1 +429 299 -1 +430 299 -1 +431 299 -1 +432 299 -1 +2 300 1 +40 300 1 +184 300 1 +223 300 -1 +435 300 -1 +436 300 -1 +437 300 -1 +438 300 -1 +439 300 -1 +440 300 -1 +1 301 1 +41 301 1 +183 301 -1 +222 301 1 +236 301 -1 +237 301 -1 +2 302 1 +41 302 1 +184 302 -1 +223 302 1 +239 302 -1 +240 302 -1 +1 303 1 +42 303 1 +181 303 1 +202 303 -1 +328 303 -1 +329 303 -1 +330 303 -1 +331 303 -1 +332 303 -1 +333 303 -1 +334 303 -1 +2 304 1 +42 304 1 +182 304 1 +203 304 -1 +337 304 -1 +338 304 -1 +339 304 -1 +340 304 -1 +341 304 -1 +43 305 1 +195 305 -1 +202 305 1 +334 305 1 +43 306 1 +196 306 -1 +203 306 1 +341 306 1 +1 307 1 +44 307 1 +202 307 -1 +212 307 1 +327 307 -1 +328 307 -1 +329 307 -1 +330 307 -1 +331 307 -1 +332 307 -1 +333 307 -1 +334 307 -1 +2 308 1 +44 308 1 +203 308 -1 +213 308 1 +336 308 -1 +337 308 -1 +338 308 -1 +339 308 -1 +340 308 -1 +341 308 -1 +1 309 1 +45 309 1 +183 309 -1 +202 309 1 +237 309 -1 +2 310 1 +45 310 1 +184 310 -1 +203 310 1 +240 310 -1 +1 311 1 +46 311 1 +202 311 -1 +214 311 1 +328 311 -1 +329 311 -1 +330 311 -1 +331 311 -1 +332 311 -1 +333 311 -1 +334 311 -1 +2 312 1 +46 312 1 +203 312 -1 +215 312 1 +337 312 -1 +338 312 -1 +339 312 -1 +340 312 -1 +341 312 -1 +47 313 1 +202 313 1 +214 313 -1 +329 313 1 +330 313 1 +331 313 1 +332 313 1 +333 313 1 +334 313 1 +47 314 1 +203 314 1 +215 314 -1 +337 314 1 +338 314 1 +339 314 1 +340 314 1 +341 314 1 +48 315 1 +202 315 -1 +208 315 1 +333 315 -1 +334 315 -1 +365 315 1 +366 315 1 +367 315 1 +368 315 1 +48 316 1 +203 316 -1 +209 316 1 +341 316 -1 +377 316 1 +378 316 1 +379 316 1 +380 316 1 +49 317 1 +202 317 1 +208 317 -1 +331 317 1 +332 317 1 +333 317 1 +334 317 1 +49 318 1 +203 318 1 +209 318 -1 +339 318 1 +340 318 1 +341 318 1 +1 319 1 +50 319 1 +202 319 -1 +212 319 1 +332 319 -1 +333 319 -1 +334 319 -1 +2 320 1 +50 320 1 +203 320 -1 +213 320 1 +340 320 -1 +341 320 -1 +51 321 1 +183 321 1 +202 321 -1 +237 321 1 +51 322 1 +184 322 1 +203 322 -1 +240 322 1 +52 323 1 +199 323 1 +202 323 -1 +52 324 1 +53 325 1 +208 325 1 +222 325 -1 +360 325 1 +361 325 1 +362 325 1 +363 325 1 +364 325 1 +365 325 1 +366 325 1 +367 325 1 +368 325 1 +430 325 -1 +431 325 -1 +432 325 -1 +53 326 1 +209 326 1 +223 326 -1 +374 326 1 +375 326 1 +376 326 1 +377 326 1 +378 326 1 +379 326 1 +380 326 1 +438 326 -1 +439 326 -1 +440 326 -1 +1 327 1 +54 327 1 +212 327 -1 +222 327 1 +398 327 -1 +2 328 1 +54 328 1 +213 328 -1 +223 328 1 +401 328 -1 +1 329 1 +55 329 1 +212 329 1 +222 329 -1 +427 329 -1 +428 329 -1 +429 329 -1 +430 329 -1 +431 329 -1 +432 329 -1 +2 330 1 +55 330 1 +213 330 1 +223 330 -1 +435 330 -1 +436 330 -1 +437 330 -1 +438 330 -1 +439 330 -1 +440 330 -1 +1 331 1 +56 331 1 +431 331 -1 +432 331 -1 +3 332 1 +56 332 1 +57 333 1 +208 333 1 +222 333 -1 +358 333 1 +359 333 1 +360 333 1 +361 333 1 +362 333 1 +363 333 1 +364 333 1 +365 333 1 +366 333 1 +367 333 1 +368 333 1 +426 333 -1 +427 333 -1 +428 333 -1 +429 333 -1 +430 333 -1 +431 333 -1 +432 333 -1 +57 334 1 +209 334 1 +223 334 -1 +371 334 1 +372 334 1 +373 334 1 +374 334 1 +375 334 1 +376 334 1 +377 334 1 +378 334 1 +379 334 1 +380 334 1 +434 334 -1 +435 334 -1 +436 334 -1 +437 334 -1 +438 334 -1 +439 334 -1 +440 334 -1 +58 335 1 +212 335 -1 +222 335 1 +427 335 1 +428 335 1 +429 335 1 +430 335 1 +431 335 1 +432 335 1 +58 336 1 +213 336 -1 +223 336 1 +435 336 1 +436 336 1 +437 336 1 +438 336 1 +439 336 1 +440 336 1 +59 337 1 +208 337 -1 +222 337 1 +430 337 1 +431 337 1 +432 337 1 +59 338 1 +209 338 -1 +223 338 1 +438 338 1 +439 338 1 +440 338 1 +60 339 1 +199 339 -1 +202 339 1 +328 339 1 +329 339 1 +330 339 1 +331 339 1 +332 339 1 +333 339 1 +334 339 1 +60 340 1 +342 340 1 +343 340 1 +344 340 1 +345 340 1 +61 341 1 +212 341 1 +222 341 -1 +396 341 1 +397 341 1 +398 341 1 +431 341 -1 +432 341 -1 +61 342 1 +213 342 1 +223 342 -1 +399 342 1 +400 342 1 +401 342 1 +439 342 -1 +440 342 -1 +1 343 1 +62 343 1 +208 343 -1 +222 343 1 +357 343 -1 +358 343 -1 +359 343 -1 +360 343 -1 +361 343 -1 +362 343 -1 +363 343 -1 +364 343 -1 +365 343 -1 +366 343 -1 +367 343 -1 +368 343 -1 +432 343 1 +2 344 1 +62 344 1 +209 344 -1 +223 344 1 +369 344 -1 +370 344 -1 +371 344 -1 +372 344 -1 +373 344 -1 +374 344 -1 +375 344 -1 +376 344 -1 +377 344 -1 +378 344 -1 +379 344 -1 +380 344 -1 +440 344 1 +1 345 1 +63 345 1 +193 345 -1 +220 345 1 +291 345 -1 +292 345 -1 +2 346 1 +63 346 1 +194 346 -1 +221 346 1 +296 346 -1 +297 346 -1 +3 347 1 +63 347 1 +301 347 -1 +1 348 1 +64 348 1 +212 348 -1 +220 348 1 +2 349 1 +64 349 1 +213 349 -1 +221 349 1 +3 350 1 +64 350 1 +65 351 1 +208 351 1 +210 351 -1 +365 351 1 +366 351 1 +367 351 1 +368 351 1 +65 352 1 +209 352 1 +211 352 -1 +377 352 1 +378 352 1 +379 352 1 +380 352 1 +65 353 1 +388 353 1 +389 353 1 +390 353 1 +391 353 1 +66 354 1 +208 354 -1 +210 354 1 +364 354 -1 +365 354 -1 +366 354 -1 +367 354 -1 +368 354 -1 +392 354 1 +393 354 1 +2 355 1 +66 355 1 +209 355 -1 +211 355 1 +376 355 -1 +377 355 -1 +378 355 -1 +379 355 -1 +380 355 -1 +3 356 1 +66 356 1 +387 356 -1 +388 356 -1 +389 356 -1 +390 356 -1 +391 356 -1 +1 357 1 +67 357 1 +183 357 -1 +220 357 1 +236 357 -1 +237 357 -1 +2 358 1 +67 358 1 +184 358 -1 +221 358 1 +239 358 -1 +240 358 -1 +3 359 1 +67 359 1 +242 359 -1 +68 360 1 +193 360 1 +220 360 -1 +289 360 1 +290 360 1 +291 360 1 +292 360 1 +68 361 1 +194 361 1 +221 361 -1 +294 361 1 +295 361 1 +296 361 1 +297 361 1 +68 362 1 +298 362 1 +299 362 1 +300 362 1 +301 362 1 +69 363 1 +181 363 1 +220 363 -1 +226 363 1 +227 363 1 +69 364 1 +182 364 1 +221 364 -1 +229 364 1 +230 364 1 +69 365 1 +232 365 1 +233 365 1 +1 366 1 +70 366 1 +183 366 1 +220 366 -1 +419 366 -1 +2 367 1 +70 367 1 +184 367 1 +221 367 -1 +422 367 -1 +3 368 1 +70 368 1 +424 368 -1 +71 369 1 +189 369 1 +197 369 -1 +256 369 1 +257 369 1 +258 369 1 +259 369 1 +260 369 1 +261 369 1 +262 369 1 +305 369 -1 +306 369 -1 +71 370 1 +190 370 1 +198 370 -1 +264 370 1 +265 370 1 +266 370 1 +267 370 1 +268 370 1 +269 370 1 +270 370 1 +308 370 -1 +309 370 -1 +71 371 1 +272 371 1 +273 371 1 +274 371 1 +275 371 1 +276 371 1 +277 371 1 +278 371 1 +310 371 -1 +1 372 1 +72 372 1 +197 372 1 +202 372 -1 +330 372 -1 +331 372 -1 +332 372 -1 +333 372 -1 +334 372 -1 +2 373 1 +72 373 1 +198 373 1 +203 373 -1 +338 373 -1 +339 373 -1 +340 373 -1 +341 373 -1 +3 374 1 +72 374 1 +344 374 -1 +345 374 -1 +73 375 1 +197 375 1 +222 375 -1 +304 375 1 +305 375 1 +306 375 1 +432 375 -1 +73 376 1 +198 376 1 +223 376 -1 +307 376 1 +308 376 1 +309 376 1 +440 376 -1 +3 377 1 +73 377 1 +74 378 1 +189 378 1 +197 378 -1 +259 378 1 +260 378 1 +261 378 1 +262 378 1 +74 379 1 +190 379 1 +198 379 -1 +267 379 1 +268 379 1 +269 379 1 +270 379 1 +74 380 1 +275 380 1 +276 380 1 +277 380 1 +278 380 1 +75 381 1 +193 381 -1 +202 381 1 +330 381 1 +331 381 1 +332 381 1 +333 381 1 +334 381 1 +75 382 1 +194 382 -1 +203 382 1 +338 382 1 +339 382 1 +340 382 1 +341 382 1 +75 383 1 +344 383 1 +345 383 1 +76 384 1 +193 384 1 +222 384 -1 +290 384 1 +291 384 1 +292 384 1 +431 384 -1 +432 384 -1 +76 385 1 +194 385 1 +223 385 -1 +295 385 1 +296 385 1 +297 385 1 +439 385 -1 +440 385 -1 +76 386 1 +300 386 1 +301 386 1 +77 387 1 +193 387 -1 +218 387 1 +410 387 1 +411 387 1 +77 388 1 +194 388 -1 +219 388 1 +412 388 1 +413 388 1 +414 388 1 +77 389 1 +415 389 1 +416 389 1 +1 390 1 +78 390 1 +202 390 1 +212 390 -1 +397 390 -1 +398 390 -1 +2 391 1 +78 391 1 +203 391 1 +213 391 -1 +400 391 -1 +401 391 -1 +78 392 1 +79 393 1 +193 393 -1 +200 393 1 +313 393 1 +314 393 1 +315 393 1 +79 394 1 +194 394 -1 +201 394 1 +318 394 1 +319 394 1 +320 394 1 +79 395 1 +323 395 1 +324 395 1 +325 395 1 +1 396 1 +80 396 1 +191 396 1 +200 396 -1 +312 396 -1 +313 396 -1 +314 396 -1 +315 396 -1 +2 397 1 +80 397 1 +192 397 1 +201 397 -1 +317 397 -1 +318 397 -1 +319 397 -1 +320 397 -1 +3 398 1 +80 398 1 +322 398 -1 +323 398 -1 +324 398 -1 +325 398 -1 +81 399 1 +193 399 1 +218 399 -1 +288 399 1 +289 399 1 +290 399 1 +291 399 1 +292 399 1 +410 399 -1 +411 399 -1 +81 400 1 +194 400 1 +219 400 -1 +293 400 1 +294 400 1 +295 400 1 +296 400 1 +297 400 1 +412 400 -1 +413 400 -1 +414 400 -1 +3 401 1 +81 401 1 +415 401 -1 +416 401 -1 +1 402 -1 +82 402 1 +189 402 1 +216 402 -1 +255 402 1 +256 402 1 +257 402 1 +258 402 1 +259 402 1 +260 402 1 +261 402 1 +262 402 1 +2 403 -1 +82 403 1 +190 403 1 +217 403 -1 +263 403 1 +264 403 1 +265 403 1 +266 403 1 +267 403 1 +268 403 1 +269 403 1 +270 403 1 +3 404 -1 +82 404 1 +271 404 1 +272 404 1 +273 404 1 +274 404 1 +275 404 1 +276 404 1 +277 404 1 +278 404 1 +83 405 1 +189 405 -1 +208 405 1 +368 405 1 +83 406 1 +190 406 -1 +209 406 1 +380 406 1 +83 407 1 +391 407 1 +84 408 1 +191 408 -1 +200 408 1 +312 408 1 +313 408 1 +314 408 1 +315 408 1 +84 409 1 +192 409 -1 +201 409 1 +317 409 1 +318 409 1 +319 409 1 +320 409 1 +84 410 1 +322 410 1 +323 410 1 +324 410 1 +325 410 1 +1 411 1 +85 411 1 +195 411 1 +202 411 -1 +331 411 -1 +332 411 -1 +333 411 -1 +334 411 -1 +2 412 1 +85 412 1 +196 412 1 +203 412 -1 +339 412 -1 +340 412 -1 +341 412 -1 +3 413 1 +85 413 1 +345 413 -1 +86 414 1 +189 414 1 +208 414 -1 +261 414 1 +262 414 1 +86 415 1 +190 415 1 +209 415 -1 +269 415 1 +270 415 1 +86 416 1 +277 416 1 +278 416 1 +87 417 1 +208 417 -1 +212 417 1 +367 417 -1 +368 417 -1 +398 417 1 +87 418 1 +209 418 -1 +213 418 1 +379 418 -1 +380 418 -1 +401 418 1 +3 419 1 +87 419 1 +390 419 -1 +391 419 -1 +88 420 1 +181 420 -1 +208 420 1 +226 420 -1 +227 420 -1 +359 420 1 +360 420 1 +361 420 1 +362 420 1 +363 420 1 +364 420 1 +365 420 1 +366 420 1 +367 420 1 +368 420 1 +88 421 1 +182 421 -1 +209 421 1 +229 421 -1 +230 421 -1 +373 421 1 +374 421 1 +375 421 1 +376 421 1 +377 421 1 +378 421 1 +379 421 1 +380 421 1 +88 422 1 +232 422 -1 +233 422 -1 +385 422 1 +386 422 1 +387 422 1 +388 422 1 +389 422 1 +390 422 1 +391 422 1 +89 423 1 +189 423 1 +204 423 -1 +257 423 1 +258 423 1 +259 423 1 +260 423 1 +261 423 1 +262 423 1 +346 423 -1 +347 423 -1 +89 424 1 +190 424 1 +205 424 -1 +265 424 1 +266 424 1 +267 424 1 +268 424 1 +269 424 1 +270 424 1 +348 424 -1 +349 424 -1 +89 425 1 +273 425 1 +274 425 1 +275 425 1 +276 425 1 +277 425 1 +278 425 1 +350 425 -1 +351 425 -1 +1 426 1 +90 426 1 +187 426 -1 +189 426 1 +246 426 -1 +247 426 -1 +248 426 -1 +2 427 1 +90 427 1 +188 427 -1 +190 427 1 +249 427 -1 +250 427 -1 +251 427 -1 +3 428 1 +90 428 1 +252 428 -1 +253 428 -1 +254 428 -1 +91 429 1 +193 429 1 +208 429 -1 +291 429 1 +292 429 1 +367 429 -1 +368 429 -1 +91 430 1 +194 430 1 +209 430 -1 +296 430 1 +297 430 1 +379 430 -1 +380 430 -1 +91 431 1 +301 431 1 +390 431 -1 +391 431 -1 +92 432 1 +193 432 -1 +208 432 1 +290 432 -1 +291 432 -1 +292 432 -1 +359 432 1 +360 432 1 +361 432 1 +362 432 1 +363 432 1 +364 432 1 +365 432 1 +366 432 1 +367 432 1 +368 432 1 +92 433 1 +194 433 -1 +209 433 1 +295 433 -1 +296 433 -1 +297 433 -1 +373 433 1 +374 433 1 +375 433 1 +376 433 1 +377 433 1 +378 433 1 +379 433 1 +380 433 1 +92 434 1 +299 434 -1 +300 434 -1 +301 434 -1 +385 434 1 +386 434 1 +387 434 1 +388 434 1 +389 434 1 +390 434 1 +391 434 1 +1 435 1 +93 435 1 +2 436 1 +93 436 1 +3 437 1 +93 437 1 +94 438 1 +189 438 -1 +222 438 1 +261 438 -1 +262 438 -1 +429 438 1 +430 438 1 +431 438 1 +432 438 1 +94 439 1 +190 439 -1 +223 439 1 +269 439 -1 +270 439 -1 +437 439 1 +438 439 1 +439 439 1 +440 439 1 +94 440 1 +277 440 -1 +278 440 -1 +442 440 1 +1 441 -1 +95 441 1 +206 441 -1 +208 441 1 +358 441 1 +359 441 1 +360 441 1 +361 441 1 +362 441 1 +363 441 1 +364 441 1 +365 441 1 +366 441 1 +367 441 1 +368 441 1 +2 442 -1 +95 442 1 +207 442 -1 +209 442 1 +371 442 1 +372 442 1 +373 442 1 +374 442 1 +375 442 1 +376 442 1 +377 442 1 +378 442 1 +379 442 1 +380 442 1 +95 443 1 +355 443 -1 +356 443 -1 +383 443 1 +384 443 1 +385 443 1 +386 443 1 +387 443 1 +388 443 1 +389 443 1 +390 443 1 +391 443 1 +96 444 1 +183 444 -1 +189 444 1 +259 444 1 +260 444 1 +261 444 1 +262 444 1 +96 445 1 +184 445 -1 +190 445 1 +267 445 1 +268 445 1 +269 445 1 +270 445 1 +96 446 1 +275 446 1 +276 446 1 +277 446 1 +278 446 1 +97 447 1 +195 447 -1 +220 447 1 +417 447 1 +418 447 1 +419 447 1 +97 448 1 +196 448 -1 +221 448 1 +420 448 1 +421 448 1 +422 448 1 +97 449 1 +423 449 1 +424 449 1 +1 450 1 +98 450 1 +206 450 -1 +216 450 1 +2 451 1 +98 451 1 +207 451 -1 +217 451 1 +3 452 1 +98 452 1 +99 453 1 +209 453 1 +224 453 -1 +372 453 1 +373 453 1 +374 453 1 +375 453 1 +376 453 1 +377 453 1 +378 453 1 +379 453 1 +380 453 1 +443 453 -1 +99 454 1 +384 454 1 +385 454 1 +386 454 1 +387 454 1 +388 454 1 +389 454 1 +390 454 1 +391 454 1 +444 454 -1 +100 455 1 +183 455 -1 +200 455 1 +311 455 1 +312 455 1 +313 455 1 +314 455 1 +315 455 1 +100 456 1 +184 456 -1 +201 456 1 +316 456 1 +317 456 1 +318 456 1 +319 456 1 +320 456 1 +100 457 1 +321 457 1 +322 457 1 +323 457 1 +324 457 1 +325 457 1 +101 458 1 +197 458 1 +208 458 -1 +306 458 1 +101 459 1 +198 459 1 +209 459 -1 +309 459 1 +101 460 1 +310 460 1 +102 461 1 +193 461 1 +200 461 -1 +288 461 1 +289 461 1 +290 461 1 +291 461 1 +292 461 1 +314 461 -1 +315 461 -1 +102 462 1 +194 462 1 +201 462 -1 +293 462 1 +294 462 1 +295 462 1 +296 462 1 +297 462 1 +319 462 -1 +320 462 -1 +3 463 1 +102 463 1 +324 463 -1 +325 463 -1 +103 464 1 +187 464 -1 +208 464 1 +247 464 -1 +248 464 -1 +358 464 1 +359 464 1 +360 464 1 +361 464 1 +362 464 1 +363 464 1 +364 464 1 +365 464 1 +366 464 1 +367 464 1 +368 464 1 +103 465 1 +188 465 -1 +209 465 1 +250 465 -1 +251 465 -1 +371 465 1 +372 465 1 +373 465 1 +374 465 1 +375 465 1 +376 465 1 +377 465 1 +378 465 1 +379 465 1 +380 465 1 +103 466 1 +253 466 -1 +254 466 -1 +383 466 1 +384 466 1 +385 466 1 +386 466 1 +387 466 1 +388 466 1 +389 466 1 +390 466 1 +391 466 1 +104 467 1 +187 467 1 +208 467 -1 +246 467 1 +247 467 1 +248 467 1 +359 467 -1 +360 467 -1 +361 467 -1 +362 467 -1 +363 467 -1 +364 467 -1 +365 467 -1 +366 467 -1 +367 467 -1 +368 467 -1 +104 468 1 +188 468 1 +209 468 -1 +249 468 1 +250 468 1 +251 468 1 +373 468 -1 +374 468 -1 +375 468 -1 +376 468 -1 +377 468 -1 +378 468 -1 +379 468 -1 +380 468 -1 +104 469 1 +252 469 1 +253 469 1 +254 469 1 +385 469 -1 +386 469 -1 +387 469 -1 +388 469 -1 +389 469 -1 +390 469 -1 +391 469 -1 +105 470 1 +189 470 -1 +204 470 1 +260 470 -1 +261 470 -1 +262 470 -1 +346 470 1 +347 470 1 +105 471 1 +190 471 -1 +205 471 1 +268 471 -1 +269 471 -1 +270 471 -1 +348 471 1 +349 471 1 +105 472 1 +276 472 -1 +277 472 -1 +278 472 -1 +350 472 1 +351 472 1 +1 473 1 +106 473 1 +204 473 1 +208 473 -1 +359 473 -1 +360 473 -1 +361 473 -1 +362 473 -1 +363 473 -1 +364 473 -1 +365 473 -1 +366 473 -1 +367 473 -1 +368 473 -1 +2 474 1 +106 474 1 +205 474 1 +209 474 -1 +373 474 -1 +374 474 -1 +375 474 -1 +376 474 -1 +377 474 -1 +378 474 -1 +379 474 -1 +380 474 -1 +3 475 1 +106 475 1 +385 475 -1 +386 475 -1 +387 475 -1 +388 475 -1 +389 475 -1 +390 475 -1 +391 475 -1 +107 476 1 +204 476 -1 +218 476 1 +411 476 1 +107 477 1 +205 477 -1 +219 477 1 +414 477 1 +107 478 1 +416 478 1 +108 479 1 +189 479 -1 +191 479 1 +281 479 1 +108 480 1 +190 480 -1 +192 480 1 +284 480 1 +108 481 1 +287 481 1 +109 482 1 +181 482 1 +189 482 -1 +225 482 1 +226 482 1 +227 482 1 +259 482 -1 +260 482 -1 +261 482 -1 +262 482 -1 +109 483 1 +182 483 1 +190 483 -1 +228 483 1 +229 483 1 +230 483 1 +267 483 -1 +268 483 -1 +269 483 -1 +270 483 -1 +109 484 1 +231 484 1 +232 484 1 +233 484 1 +275 484 -1 +276 484 -1 +277 484 -1 +278 484 -1 +110 485 1 +187 485 1 +204 485 -1 +248 485 1 +347 485 -1 +110 486 1 +188 486 1 +205 486 -1 +251 486 1 +349 486 -1 +110 487 1 +254 487 1 +351 487 -1 +1 488 1 +111 488 1 +187 488 -1 +206 488 1 +248 488 -1 +2 489 1 +111 489 1 +188 489 -1 +207 489 1 +251 489 -1 +111 490 1 +254 490 -1 +355 490 1 +356 490 1 +1 491 1 +112 491 1 +189 491 -1 +208 491 1 +255 491 -1 +256 491 -1 +257 491 -1 +258 491 -1 +259 491 -1 +260 491 -1 +261 491 -1 +262 491 -1 +365 491 1 +366 491 1 +367 491 1 +368 491 1 +2 492 1 +112 492 1 +190 492 -1 +209 492 1 +263 492 -1 +264 492 -1 +265 492 -1 +266 492 -1 +267 492 -1 +268 492 -1 +269 492 -1 +270 492 -1 +377 492 1 +378 492 1 +379 492 1 +380 492 1 +3 493 1 +112 493 1 +271 493 -1 +272 493 -1 +273 493 -1 +274 493 -1 +275 493 -1 +276 493 -1 +277 493 -1 +278 493 -1 +388 493 1 +389 493 1 +390 493 1 +391 493 1 +1 494 1 +113 494 1 +189 494 -1 +200 494 1 +255 494 -1 +256 494 -1 +257 494 -1 +258 494 -1 +259 494 -1 +260 494 -1 +261 494 -1 +262 494 -1 +314 494 1 +315 494 1 +2 495 1 +113 495 1 +190 495 -1 +201 495 1 +263 495 -1 +264 495 -1 +265 495 -1 +266 495 -1 +267 495 -1 +268 495 -1 +269 495 -1 +270 495 -1 +319 495 1 +320 495 1 +3 496 1 +113 496 1 +271 496 -1 +272 496 -1 +273 496 -1 +274 496 -1 +275 496 -1 +276 496 -1 +277 496 -1 +278 496 -1 +324 496 1 +325 496 1 +1 497 1 +114 497 1 +200 497 -1 +202 497 1 +311 497 -1 +312 497 -1 +313 497 -1 +314 497 -1 +315 497 -1 +2 498 1 +114 498 1 +201 498 -1 +203 498 1 +316 498 -1 +317 498 -1 +318 498 -1 +319 498 -1 +320 498 -1 +3 499 1 +114 499 1 +321 499 -1 +322 499 -1 +323 499 -1 +324 499 -1 +325 499 -1 +1 500 1 +115 500 1 +191 500 1 +208 500 -1 +357 500 -1 +358 500 -1 +359 500 -1 +360 500 -1 +361 500 -1 +362 500 -1 +363 500 -1 +364 500 -1 +365 500 -1 +366 500 -1 +367 500 -1 +368 500 -1 +2 501 1 +115 501 1 +192 501 1 +209 501 -1 +370 501 -1 +371 501 -1 +372 501 -1 +373 501 -1 +374 501 -1 +375 501 -1 +376 501 -1 +377 501 -1 +378 501 -1 +379 501 -1 +380 501 -1 +3 502 1 +115 502 1 +382 502 -1 +383 502 -1 +384 502 -1 +385 502 -1 +386 502 -1 +387 502 -1 +388 502 -1 +389 502 -1 +390 502 -1 +391 502 -1 +116 503 1 +208 503 -1 +216 503 1 +366 503 -1 +367 503 -1 +368 503 -1 +407 503 1 +116 504 1 +209 504 -1 +217 504 1 +378 504 -1 +379 504 -1 +380 504 -1 +408 504 1 +116 505 1 +389 505 -1 +390 505 -1 +391 505 -1 +409 505 1 +1 506 1 +117 506 1 +187 506 1 +189 506 -1 +258 506 -1 +259 506 -1 +260 506 -1 +261 506 -1 +262 506 -1 +2 507 1 +117 507 1 +188 507 1 +190 507 -1 +266 507 -1 +267 507 -1 +268 507 -1 +269 507 -1 +270 507 -1 +3 508 1 +117 508 1 +274 508 -1 +275 508 -1 +276 508 -1 +277 508 -1 +278 508 -1 +118 509 1 +185 509 -1 +189 509 1 +243 509 -1 +256 509 1 +257 509 1 +258 509 1 +259 509 1 +260 509 1 +261 509 1 +262 509 1 +118 510 1 +186 510 -1 +190 510 1 +244 510 -1 +264 510 1 +265 510 1 +266 510 1 +267 510 1 +268 510 1 +269 510 1 +270 510 1 +118 511 1 +245 511 -1 +272 511 1 +273 511 1 +274 511 1 +275 511 1 +276 511 1 +277 511 1 +278 511 1 +119 512 1 +191 512 -1 +208 512 1 +279 512 -1 +280 512 -1 +281 512 -1 +358 512 1 +359 512 1 +360 512 1 +361 512 1 +362 512 1 +363 512 1 +364 512 1 +365 512 1 +366 512 1 +367 512 1 +368 512 1 +119 513 1 +192 513 -1 +209 513 1 +282 513 -1 +283 513 -1 +284 513 -1 +371 513 1 +372 513 1 +373 513 1 +374 513 1 +375 513 1 +376 513 1 +377 513 1 +378 513 1 +379 513 1 +380 513 1 +119 514 1 +285 514 -1 +286 514 -1 +287 514 -1 +383 514 1 +384 514 1 +385 514 1 +386 514 1 +387 514 1 +388 514 1 +389 514 1 +390 514 1 +391 514 1 +1 515 1 +120 515 1 +193 515 1 +208 515 -1 +358 515 -1 +359 515 -1 +360 515 -1 +361 515 -1 +362 515 -1 +363 515 -1 +364 515 -1 +365 515 -1 +366 515 -1 +367 515 -1 +368 515 -1 +2 516 1 +120 516 1 +194 516 1 +209 516 -1 +371 516 -1 +372 516 -1 +373 516 -1 +374 516 -1 +375 516 -1 +376 516 -1 +377 516 -1 +378 516 -1 +379 516 -1 +380 516 -1 +3 517 1 +120 517 1 +383 517 -1 +384 517 -1 +385 517 -1 +386 517 -1 +387 517 -1 +388 517 -1 +389 517 -1 +390 517 -1 +391 517 -1 +1 518 1 +121 518 1 +181 518 -1 +208 518 1 +225 518 -1 +226 518 -1 +227 518 -1 +2 519 1 +121 519 1 +182 519 -1 +209 519 1 +228 519 -1 +229 519 -1 +230 519 -1 +3 520 1 +121 520 1 +231 520 -1 +232 520 -1 +233 520 -1 +122 521 1 +193 521 1 +218 521 -1 +290 521 1 +291 521 1 +292 521 1 +122 522 1 +194 522 1 +219 522 -1 +295 522 1 +296 522 1 +297 522 1 +122 523 1 +299 523 1 +300 523 1 +301 523 1 +123 524 1 +189 524 1 +208 524 -1 +257 524 1 +258 524 1 +259 524 1 +260 524 1 +261 524 1 +262 524 1 +366 524 -1 +367 524 -1 +368 524 -1 +123 525 1 +190 525 1 +209 525 -1 +265 525 1 +266 525 1 +267 525 1 +268 525 1 +269 525 1 +270 525 1 +378 525 -1 +379 525 -1 +380 525 -1 +123 526 1 +273 526 1 +274 526 1 +275 526 1 +276 526 1 +277 526 1 +278 526 1 +389 526 -1 +390 526 -1 +391 526 -1 +124 527 1 +202 527 -1 +212 527 1 +333 527 -1 +334 527 -1 +397 527 1 +398 527 1 +124 528 1 +203 528 -1 +213 528 1 +341 528 -1 +400 528 1 +401 528 1 +3 529 1 +124 529 1 +125 530 1 +183 530 1 +189 530 -1 +236 530 1 +237 530 1 +262 530 -1 +125 531 1 +184 531 1 +190 531 -1 +239 531 1 +240 531 1 +270 531 -1 +125 532 1 +242 532 1 +278 532 -1 +126 533 1 +198 533 -1 +223 533 1 +309 533 -1 +433 533 1 +434 533 1 +435 533 1 +436 533 1 +437 533 1 +438 533 1 +439 533 1 +440 533 1 +126 534 1 +310 534 -1 +441 534 1 +442 534 1 +127 535 1 +181 535 1 +189 535 -1 +225 535 1 +226 535 1 +227 535 1 +260 535 -1 +261 535 -1 +262 535 -1 +127 536 1 +182 536 1 +190 536 -1 +228 536 1 +229 536 1 +230 536 1 +268 536 -1 +269 536 -1 +270 536 -1 +127 537 1 +231 537 1 +232 537 1 +233 537 1 +276 537 -1 +277 537 -1 +278 537 -1 +128 538 1 +189 538 -1 +200 538 1 +315 538 1 +128 539 1 +190 539 -1 +201 539 1 +320 539 1 +128 540 1 +325 540 1 +129 541 1 +189 541 1 +191 541 -1 +256 541 1 +257 541 1 +258 541 1 +259 541 1 +260 541 1 +261 541 1 +262 541 1 +280 541 -1 +281 541 -1 +129 542 1 +190 542 1 +192 542 -1 +264 542 1 +265 542 1 +266 542 1 +267 542 1 +268 542 1 +269 542 1 +270 542 1 +283 542 -1 +284 542 -1 +129 543 1 +272 543 1 +273 543 1 +274 543 1 +275 543 1 +276 543 1 +277 543 1 +278 543 1 +286 543 -1 +287 543 -1 +1 544 1 +130 544 1 +200 544 1 +208 544 -1 +361 544 -1 +362 544 -1 +363 544 -1 +364 544 -1 +365 544 -1 +366 544 -1 +367 544 -1 +368 544 -1 +2 545 1 +130 545 1 +201 545 1 +209 545 -1 +375 545 -1 +376 545 -1 +377 545 -1 +378 545 -1 +379 545 -1 +380 545 -1 +3 546 1 +130 546 1 +386 546 -1 +387 546 -1 +388 546 -1 +389 546 -1 +390 546 -1 +391 546 -1 +131 547 1 +200 547 -1 +206 547 1 +352 547 1 +131 548 1 +201 548 -1 +207 548 1 +354 548 1 +131 549 1 +356 549 1 +1 550 1 +132 550 1 +183 550 1 +200 550 -1 +313 550 -1 +314 550 -1 +315 550 -1 +2 551 1 +132 551 1 +184 551 1 +201 551 -1 +318 551 -1 +319 551 -1 +320 551 -1 +3 552 1 +132 552 1 +323 552 -1 +324 552 -1 +325 552 -1 +1 553 1 +133 553 1 +206 553 -1 +222 553 1 +352 553 -1 +2 554 1 +133 554 1 +207 554 -1 +223 554 1 +354 554 -1 +3 555 1 +133 555 1 +356 555 -1 +1 556 1 +134 556 1 +189 556 -1 +210 556 1 +255 556 -1 +256 556 -1 +257 556 -1 +258 556 -1 +259 556 -1 +260 556 -1 +261 556 -1 +262 556 -1 +393 556 1 +2 557 1 +134 557 1 +190 557 -1 +211 557 1 +263 557 -1 +264 557 -1 +265 557 -1 +266 557 -1 +267 557 -1 +268 557 -1 +269 557 -1 +270 557 -1 +394 557 1 +3 558 1 +134 558 1 +271 558 -1 +272 558 -1 +273 558 -1 +274 558 -1 +275 558 -1 +276 558 -1 +277 558 -1 +278 558 -1 +395 558 1 +1 559 1 +135 559 1 +189 559 1 +212 559 -1 +396 559 -1 +397 559 -1 +398 559 -1 +2 560 1 +135 560 1 +190 560 1 +213 560 -1 +399 560 -1 +400 560 -1 +401 560 -1 +135 561 1 +136 562 1 +202 562 -1 +208 562 1 +327 562 -1 +328 562 -1 +329 562 -1 +330 562 -1 +331 562 -1 +332 562 -1 +333 562 -1 +334 562 -1 +358 562 1 +359 562 1 +360 562 1 +361 562 1 +362 562 1 +363 562 1 +364 562 1 +365 562 1 +366 562 1 +367 562 1 +368 562 1 +136 563 1 +203 563 -1 +209 563 1 +336 563 -1 +337 563 -1 +338 563 -1 +339 563 -1 +340 563 -1 +341 563 -1 +371 563 1 +372 563 1 +373 563 1 +374 563 1 +375 563 1 +376 563 1 +377 563 1 +378 563 1 +379 563 1 +380 563 1 +136 564 1 +342 564 -1 +343 564 -1 +344 564 -1 +345 564 -1 +383 564 1 +384 564 1 +385 564 1 +386 564 1 +387 564 1 +388 564 1 +389 564 1 +390 564 1 +391 564 1 +137 565 1 +181 565 -1 +189 565 1 +258 565 1 +259 565 1 +260 565 1 +261 565 1 +262 565 1 +137 566 1 +182 566 -1 +190 566 1 +266 566 1 +267 566 1 +268 566 1 +269 566 1 +270 566 1 +137 567 1 +274 567 1 +275 567 1 +276 567 1 +277 567 1 +278 567 1 +1 568 1 +138 568 1 +208 568 -1 +218 568 1 +361 568 -1 +362 568 -1 +363 568 -1 +364 568 -1 +365 568 -1 +366 568 -1 +367 568 -1 +368 568 -1 +2 569 1 +138 569 1 +209 569 -1 +219 569 1 +375 569 -1 +376 569 -1 +377 569 -1 +378 569 -1 +379 569 -1 +380 569 -1 +3 570 1 +138 570 1 +386 570 -1 +387 570 -1 +388 570 -1 +389 570 -1 +390 570 -1 +391 570 -1 +139 571 1 +191 571 1 +222 571 -1 +280 571 1 +281 571 1 +431 571 -1 +432 571 -1 +139 572 1 +192 572 1 +223 572 -1 +283 572 1 +284 572 1 +439 572 -1 +440 572 -1 +139 573 1 +286 573 1 +287 573 1 +1 574 1 +140 574 1 +183 574 1 +218 574 -1 +411 574 -1 +2 575 1 +140 575 1 +184 575 1 +219 575 -1 +414 575 -1 +3 576 1 +140 576 1 +416 576 -1 +141 577 1 +183 577 1 +200 577 -1 +234 577 1 +235 577 1 +236 577 1 +237 577 1 +315 577 -1 +2 578 1 +141 578 1 +184 578 1 +201 578 -1 +320 578 -1 +3 579 1 +141 579 1 +325 579 -1 +142 580 1 +181 580 1 +208 580 -1 +227 580 1 +368 580 -1 +142 581 1 +182 581 1 +209 581 -1 +230 581 1 +380 581 -1 +142 582 1 +233 582 1 +391 582 -1 +1 583 1 +143 583 1 +206 583 1 +208 583 -1 +364 583 -1 +365 583 -1 +366 583 -1 +367 583 -1 +368 583 -1 +143 584 1 +207 584 1 +209 584 -1 +353 584 1 +354 584 1 +376 584 -1 +377 584 -1 +378 584 -1 +379 584 -1 +380 584 -1 +143 585 1 +355 585 1 +356 585 1 +387 585 -1 +388 585 -1 +389 585 -1 +390 585 -1 +391 585 -1 +1 586 1 +144 586 1 +185 586 1 +216 586 -1 +407 586 -1 +2 587 1 +144 587 1 +186 587 1 +217 587 -1 +408 587 -1 +3 588 1 +144 588 1 +409 588 -1 +145 589 1 +204 589 1 +208 589 -1 +347 589 1 +145 590 1 +205 590 1 +209 590 -1 +349 590 1 +145 591 1 +351 591 1 +146 592 1 +189 592 1 +208 592 -1 +259 592 1 +260 592 1 +261 592 1 +262 592 1 +366 592 -1 +367 592 -1 +368 592 -1 +146 593 1 +190 593 1 +209 593 -1 +267 593 1 +268 593 1 +269 593 1 +270 593 1 +378 593 -1 +379 593 -1 +380 593 -1 +146 594 1 +275 594 1 +276 594 1 +277 594 1 +278 594 1 +389 594 -1 +390 594 -1 +391 594 -1 +1 595 1 +147 595 1 +202 595 1 +222 595 -1 +425 595 -1 +426 595 -1 +427 595 -1 +428 595 -1 +429 595 -1 +430 595 -1 +431 595 -1 +432 595 -1 +2 596 1 +147 596 1 +203 596 1 +223 596 -1 +433 596 -1 +434 596 -1 +435 596 -1 +436 596 -1 +437 596 -1 +438 596 -1 +439 596 -1 +440 596 -1 +3 597 1 +147 597 1 +441 597 -1 +442 597 -1 +148 598 1 +202 598 1 +220 598 -1 +332 598 1 +333 598 1 +334 598 1 +148 599 1 +203 599 1 +221 599 -1 +340 599 1 +341 599 1 +148 600 1 +345 600 1 +1 601 1 +149 601 1 +202 601 -1 +220 601 1 +329 601 -1 +330 601 -1 +331 601 -1 +332 601 -1 +333 601 -1 +334 601 -1 +2 602 1 +149 602 1 +203 602 -1 +221 602 1 +337 602 -1 +338 602 -1 +339 602 -1 +340 602 -1 +341 602 -1 +3 603 1 +149 603 1 +343 603 -1 +344 603 -1 +345 603 -1 +150 604 1 +202 604 1 +220 604 -1 +329 604 1 +330 604 1 +331 604 1 +332 604 1 +333 604 1 +334 604 1 +419 604 -1 +150 605 1 +203 605 1 +221 605 -1 +337 605 1 +338 605 1 +339 605 1 +340 605 1 +341 605 1 +422 605 -1 +150 606 1 +343 606 1 +344 606 1 +345 606 1 +424 606 -1 +151 607 1 +202 607 -1 +220 607 1 +332 607 -1 +333 607 -1 +334 607 -1 +419 607 1 +151 608 1 +203 608 -1 +221 608 1 +340 608 -1 +341 608 -1 +422 608 1 +151 609 1 +345 609 -1 +424 609 1 +152 610 1 +189 610 1 +220 610 -1 +255 610 1 +256 610 1 +257 610 1 +258 610 1 +259 610 1 +260 610 1 +261 610 1 +262 610 1 +417 610 -1 +418 610 -1 +419 610 -1 +152 611 1 +190 611 1 +221 611 -1 +263 611 1 +264 611 1 +265 611 1 +266 611 1 +267 611 1 +268 611 1 +269 611 1 +270 611 1 +420 611 -1 +421 611 -1 +422 611 -1 +152 612 1 +271 612 1 +272 612 1 +273 612 1 +274 612 1 +275 612 1 +276 612 1 +277 612 1 +278 612 1 +423 612 -1 +424 612 -1 +1 613 1 +153 613 1 +189 613 -1 +200 613 1 +256 613 -1 +257 613 -1 +258 613 -1 +259 613 -1 +260 613 -1 +261 613 -1 +262 613 -1 +2 614 1 +153 614 1 +190 614 -1 +201 614 1 +264 614 -1 +265 614 -1 +266 614 -1 +267 614 -1 +268 614 -1 +269 614 -1 +270 614 -1 +3 615 1 +153 615 1 +272 615 -1 +273 615 -1 +274 615 -1 +275 615 -1 +276 615 -1 +277 615 -1 +278 615 -1 +154 616 1 +191 616 -1 +208 616 1 +364 616 1 +365 616 1 +366 616 1 +367 616 1 +368 616 1 +154 617 1 +192 617 -1 +209 617 1 +376 617 1 +377 617 1 +378 617 1 +379 617 1 +380 617 1 +154 618 1 +387 618 1 +388 618 1 +389 618 1 +390 618 1 +391 618 1 +155 619 1 +191 619 -1 +208 619 1 +281 619 -1 +362 619 1 +363 619 1 +364 619 1 +365 619 1 +366 619 1 +367 619 1 +368 619 1 +155 620 1 +192 620 -1 +209 620 1 +284 620 -1 +375 620 1 +376 620 1 +377 620 1 +378 620 1 +379 620 1 +380 620 1 +155 621 1 +287 621 -1 +386 621 1 +387 621 1 +388 621 1 +389 621 1 +390 621 1 +391 621 1 +156 622 1 +183 622 -1 +208 622 1 +235 622 -1 +236 622 -1 +237 622 -1 +359 622 1 +360 622 1 +361 622 1 +362 622 1 +363 622 1 +364 622 1 +365 622 1 +366 622 1 +367 622 1 +368 622 1 +156 623 1 +184 623 -1 +209 623 1 +238 623 -1 +239 623 -1 +240 623 -1 +373 623 1 +374 623 1 +375 623 1 +376 623 1 +377 623 1 +378 623 1 +379 623 1 +380 623 1 +156 624 1 +241 624 -1 +242 624 -1 +385 624 1 +386 624 1 +387 624 1 +388 624 1 +389 624 1 +390 624 1 +391 624 1 +157 625 1 +183 625 -1 +208 625 1 +366 625 1 +367 625 1 +368 625 1 +157 626 1 +184 626 -1 +209 626 1 +378 626 1 +379 626 1 +380 626 1 +157 627 1 +389 627 1 +390 627 1 +391 627 1 +158 628 1 +187 628 -1 +208 628 1 +364 628 1 +365 628 1 +366 628 1 +367 628 1 +368 628 1 +158 629 1 +188 629 -1 +209 629 1 +376 629 1 +377 629 1 +378 629 1 +379 629 1 +380 629 1 +158 630 1 +387 630 1 +388 630 1 +389 630 1 +390 630 1 +391 630 1 +159 631 1 +185 631 1 +208 631 -1 +243 631 1 +365 631 -1 +366 631 -1 +367 631 -1 +368 631 -1 +159 632 1 +186 632 1 +209 632 -1 +244 632 1 +377 632 -1 +378 632 -1 +379 632 -1 +380 632 -1 +159 633 1 +245 633 1 +388 633 -1 +389 633 -1 +390 633 -1 +391 633 -1 +160 634 1 +181 634 -1 +208 634 1 +227 634 -1 +362 634 1 +363 634 1 +364 634 1 +365 634 1 +366 634 1 +367 634 1 +368 634 1 +160 635 1 +182 635 -1 +209 635 1 +230 635 -1 +375 635 1 +376 635 1 +377 635 1 +378 635 1 +379 635 1 +380 635 1 +160 636 1 +233 636 -1 +386 636 1 +387 636 1 +388 636 1 +389 636 1 +390 636 1 +391 636 1 +161 637 1 +181 637 -1 +208 637 1 +366 637 1 +367 637 1 +368 637 1 +161 638 1 +182 638 -1 +209 638 1 +378 638 1 +379 638 1 +380 638 1 +161 639 1 +389 639 1 +390 639 1 +391 639 1 +162 640 1 +185 640 -1 +208 640 1 +366 640 1 +367 640 1 +368 640 1 +162 641 1 +186 641 -1 +209 641 1 +378 641 1 +379 641 1 +380 641 1 +162 642 1 +389 642 1 +390 642 1 +391 642 1 +1 643 1 +163 643 1 +181 643 1 +208 643 -1 +359 643 -1 +360 643 -1 +361 643 -1 +362 643 -1 +363 643 -1 +364 643 -1 +365 643 -1 +366 643 -1 +367 643 -1 +368 643 -1 +2 644 1 +163 644 1 +182 644 1 +209 644 -1 +372 644 -1 +373 644 -1 +374 644 -1 +375 644 -1 +376 644 -1 +377 644 -1 +378 644 -1 +379 644 -1 +380 644 -1 +3 645 1 +163 645 1 +384 645 -1 +385 645 -1 +386 645 -1 +387 645 -1 +388 645 -1 +389 645 -1 +390 645 -1 +391 645 -1 +1 646 1 +164 646 1 +189 646 -1 +210 646 1 +257 646 -1 +258 646 -1 +259 646 -1 +260 646 -1 +261 646 -1 +262 646 -1 +2 647 1 +164 647 1 +190 647 -1 +211 647 1 +265 647 -1 +266 647 -1 +267 647 -1 +268 647 -1 +269 647 -1 +270 647 -1 +3 648 1 +164 648 1 +273 648 -1 +274 648 -1 +275 648 -1 +276 648 -1 +277 648 -1 +278 648 -1 +165 649 1 +189 649 1 +210 649 -1 +260 649 1 +261 649 1 +262 649 1 +165 650 1 +190 650 1 +211 650 -1 +268 650 1 +269 650 1 +270 650 1 +165 651 1 +276 651 1 +277 651 1 +278 651 1 +166 652 1 +190 652 -1 +224 652 1 +267 652 -1 +268 652 -1 +269 652 -1 +270 652 -1 +443 652 1 +166 653 1 +275 653 -1 +276 653 -1 +277 653 -1 +278 653 -1 +444 653 1 +2 654 1 +167 654 1 +190 654 -1 +224 654 1 +265 654 -1 +266 654 -1 +267 654 -1 +268 654 -1 +269 654 -1 +270 654 -1 +3 655 1 +167 655 1 +273 655 -1 +274 655 -1 +275 655 -1 +276 655 -1 +277 655 -1 +278 655 -1 +168 656 1 +189 656 -1 +222 656 1 +259 656 -1 +260 656 -1 +261 656 -1 +262 656 -1 +426 656 1 +427 656 1 +428 656 1 +429 656 1 +430 656 1 +431 656 1 +432 656 1 +168 657 1 +190 657 -1 +223 657 1 +267 657 -1 +268 657 -1 +269 657 -1 +270 657 -1 +434 657 1 +435 657 1 +436 657 1 +437 657 1 +438 657 1 +439 657 1 +440 657 1 +168 658 1 +275 658 -1 +276 658 -1 +277 658 -1 +278 658 -1 +441 658 1 +442 658 1 +169 659 1 +208 659 -1 +214 659 1 +368 659 -1 +403 659 1 +169 660 1 +209 660 -1 +215 660 1 +380 660 -1 +405 660 1 +169 661 1 +391 661 -1 +406 661 1 +170 662 1 +208 662 -1 +214 662 1 +365 662 -1 +366 662 -1 +367 662 -1 +368 662 -1 +402 662 1 +403 662 1 +170 663 1 +209 663 -1 +215 663 1 +377 663 -1 +378 663 -1 +379 663 -1 +380 663 -1 +404 663 1 +405 663 1 +3 664 1 +170 664 1 +388 664 -1 +389 664 -1 +390 664 -1 +391 664 -1 +171 665 1 +208 665 1 +214 665 -1 +364 665 1 +365 665 1 +366 665 1 +367 665 1 +368 665 1 +403 665 -1 +171 666 1 +209 666 1 +215 666 -1 +376 666 1 +377 666 1 +378 666 1 +379 666 1 +380 666 1 +405 666 -1 +171 667 1 +387 667 1 +388 667 1 +389 667 1 +390 667 1 +391 667 1 +406 667 -1 +172 668 1 +208 668 1 +214 668 -1 +361 668 1 +362 668 1 +363 668 1 +364 668 1 +365 668 1 +366 668 1 +367 668 1 +368 668 1 +402 668 -1 +403 668 -1 +172 669 1 +209 669 1 +215 669 -1 +375 669 1 +376 669 1 +377 669 1 +378 669 1 +379 669 1 +380 669 1 +404 669 -1 +405 669 -1 +3 670 -1 +172 670 1 +386 670 1 +387 670 1 +388 670 1 +389 670 1 +390 670 1 +391 670 1 +173 671 1 +183 671 1 +208 671 -1 +235 671 1 +236 671 1 +237 671 1 +365 671 -1 +366 671 -1 +367 671 -1 +368 671 -1 +173 672 1 +184 672 1 +209 672 -1 +238 672 1 +239 672 1 +240 672 1 +377 672 -1 +378 672 -1 +379 672 -1 +380 672 -1 +173 673 1 +241 673 1 +242 673 1 +388 673 -1 +389 673 -1 +390 673 -1 +391 673 -1 +174 674 1 +357 674 1 +358 674 1 +359 674 1 +360 674 1 +361 674 1 +362 674 1 +174 675 1 +370 675 1 +371 675 1 +372 675 1 +373 675 1 +374 675 1 +375 675 1 +174 676 1 +382 676 1 +383 676 1 +384 676 1 +385 676 1 +386 676 1 +175 677 1 +191 677 1 +208 677 -1 +279 677 1 +280 677 1 +281 677 1 +360 677 -1 +361 677 -1 +362 677 -1 +363 677 -1 +364 677 -1 +365 677 -1 +366 677 -1 +367 677 -1 +368 677 -1 +175 678 1 +192 678 1 +209 678 -1 +282 678 1 +283 678 1 +284 678 1 +374 678 -1 +375 678 -1 +376 678 -1 +377 678 -1 +378 678 -1 +379 678 -1 +380 678 -1 +175 679 1 +285 679 1 +286 679 1 +287 679 1 +386 679 -1 +387 679 -1 +388 679 -1 +389 679 -1 +390 679 -1 +391 679 -1 +176 680 1 +193 680 -1 +208 680 1 +289 680 -1 +290 680 -1 +291 680 -1 +292 680 -1 +358 680 1 +359 680 1 +360 680 1 +361 680 1 +362 680 1 +363 680 1 +364 680 1 +365 680 1 +366 680 1 +367 680 1 +368 680 1 +176 681 1 +194 681 -1 +209 681 1 +294 681 -1 +295 681 -1 +296 681 -1 +297 681 -1 +371 681 1 +372 681 1 +373 681 1 +374 681 1 +375 681 1 +376 681 1 +377 681 1 +378 681 1 +379 681 1 +380 681 1 +176 682 1 +298 682 -1 +299 682 -1 +300 682 -1 +301 682 -1 +383 682 1 +384 682 1 +385 682 1 +386 682 1 +387 682 1 +388 682 1 +389 682 1 +390 682 1 +391 682 1 +177 683 1 +189 683 1 +200 683 -1 +262 683 1 +177 684 1 +190 684 1 +201 684 -1 +270 684 1 +177 685 1 +278 685 1 +1 686 1 +178 686 1 +187 686 1 +208 686 -1 +357 686 -1 +358 686 -1 +359 686 -1 +360 686 -1 +361 686 -1 +362 686 -1 +363 686 -1 +364 686 -1 +365 686 -1 +366 686 -1 +367 686 -1 +368 686 -1 +2 687 1 +178 687 1 +188 687 1 +209 687 -1 +370 687 -1 +371 687 -1 +372 687 -1 +373 687 -1 +374 687 -1 +375 687 -1 +376 687 -1 +377 687 -1 +378 687 -1 +379 687 -1 +380 687 -1 +3 688 1 +178 688 1 +381 688 -1 +382 688 -1 +383 688 -1 +384 688 -1 +385 688 -1 +386 688 -1 +387 688 -1 +388 688 -1 +389 688 -1 +390 688 -1 +391 688 -1 +179 689 1 +187 689 -1 +208 689 1 +367 689 1 +368 689 1 +179 690 1 +188 690 -1 +209 690 1 +379 690 1 +380 690 1 +179 691 1 +390 691 1 +391 691 1 +180 692 1 +189 692 1 +210 692 -1 +255 692 1 +256 692 1 +257 692 1 +258 692 1 +259 692 1 +260 692 1 +261 692 1 +262 692 1 +393 692 -1 +180 693 1 +190 693 1 +211 693 -1 +263 693 1 +264 693 1 +265 693 1 +266 693 1 +267 693 1 +268 693 1 +269 693 1 +270 693 1 +394 693 -1 +180 694 1 +271 694 1 +272 694 1 +273 694 1 +274 694 1 +275 694 1 +276 694 1 +277 694 1 +278 694 1 +395 694 -1 +1 695 1 +225 695 -1 +226 695 -1 +227 695 -1 +2 696 1 +228 696 -1 +229 696 -1 +230 696 -1 +3 697 1 +231 697 -1 +232 697 -1 +233 697 -1 +1 698 1 +234 698 -1 +235 698 -1 +236 698 -1 +237 698 -1 +2 699 1 +238 699 -1 +239 699 -1 +240 699 -1 +3 700 1 +241 700 -1 +242 700 -1 +1 701 1 +243 701 -1 +2 702 1 +244 702 -1 +3 703 1 +245 703 -1 +1 704 1 +246 704 -1 +247 704 -1 +248 704 -1 +2 705 1 +249 705 -1 +250 705 -1 +251 705 -1 +3 706 1 +252 706 -1 +253 706 -1 +254 706 -1 +1 707 1 +255 707 -1 +256 707 -1 +257 707 -1 +258 707 -1 +259 707 -1 +260 707 -1 +261 707 -1 +262 707 -1 +2 708 1 +263 708 -1 +264 708 -1 +265 708 -1 +266 708 -1 +267 708 -1 +268 708 -1 +269 708 -1 +270 708 -1 +3 709 1 +271 709 -1 +272 709 -1 +273 709 -1 +274 709 -1 +275 709 -1 +276 709 -1 +277 709 -1 +278 709 -1 +1 710 1 +279 710 -1 +280 710 -1 +281 710 -1 +2 711 1 +282 711 -1 +283 711 -1 +284 711 -1 +3 712 1 +285 712 -1 +286 712 -1 +287 712 -1 +1 713 1 +288 713 -1 +289 713 -1 +290 713 -1 +291 713 -1 +292 713 -1 +2 714 1 +293 714 -1 +294 714 -1 +295 714 -1 +296 714 -1 +297 714 -1 +3 715 1 +298 715 -1 +299 715 -1 +300 715 -1 +301 715 -1 +1 716 1 +302 716 -1 +2 717 1 +303 717 -1 +1 718 1 +304 718 -1 +305 718 -1 +306 718 -1 +2 719 1 +307 719 -1 +308 719 -1 +309 719 -1 +3 720 1 +310 720 -1 +1 721 1 +311 721 -1 +312 721 -1 +313 721 -1 +314 721 -1 +315 721 -1 +2 722 1 +316 722 -1 +317 722 -1 +318 722 -1 +319 722 -1 +320 722 -1 +3 723 1 +321 723 -1 +322 723 -1 +323 723 -1 +324 723 -1 +325 723 -1 +1 724 1 +326 724 -1 +327 724 -1 +328 724 -1 +329 724 -1 +330 724 -1 +331 724 -1 +332 724 -1 +333 724 -1 +334 724 -1 +2 725 1 +335 725 -1 +336 725 -1 +337 725 -1 +338 725 -1 +339 725 -1 +340 725 -1 +341 725 -1 +3 726 1 +342 726 -1 +343 726 -1 +344 726 -1 +345 726 -1 +1 727 1 +346 727 -1 +347 727 -1 +2 728 1 +348 728 -1 +349 728 -1 +3 729 1 +350 729 -1 +351 729 -1 +1 730 1 +352 730 -1 +2 731 1 +353 731 -1 +354 731 -1 +3 732 1 +355 732 -1 +356 732 -1 +1 733 1 +357 733 -1 +358 733 -1 +359 733 -1 +360 733 -1 +361 733 -1 +362 733 -1 +363 733 -1 +364 733 -1 +365 733 -1 +366 733 -1 +367 733 -1 +368 733 -1 +2 734 1 +369 734 -1 +370 734 -1 +371 734 -1 +372 734 -1 +373 734 -1 +374 734 -1 +375 734 -1 +376 734 -1 +377 734 -1 +378 734 -1 +379 734 -1 +380 734 -1 +3 735 1 +381 735 -1 +382 735 -1 +383 735 -1 +384 735 -1 +385 735 -1 +386 735 -1 +387 735 -1 +388 735 -1 +389 735 -1 +390 735 -1 +391 735 -1 +1 736 1 +392 736 -1 +393 736 -1 +2 737 1 +394 737 -1 +3 738 1 +395 738 -1 +1 739 1 +396 739 -1 +397 739 -1 +398 739 -1 +2 740 1 +399 740 -1 +400 740 -1 +401 740 -1 +1 741 1 +402 741 -1 +403 741 -1 +2 742 1 +404 742 -1 +405 742 -1 +3 743 1 +406 743 -1 +1 744 1 +407 744 -1 +2 745 1 +408 745 -1 +3 746 1 +409 746 -1 +1 747 1 +410 747 -1 +411 747 -1 +2 748 1 +412 748 -1 +413 748 -1 +414 748 -1 +3 749 1 +415 749 -1 +416 749 -1 +1 750 1 +417 750 -1 +418 750 -1 +419 750 -1 +2 751 1 +420 751 -1 +421 751 -1 +422 751 -1 +3 752 1 +423 752 -1 +424 752 -1 +1 753 1 +425 753 -1 +426 753 -1 +427 753 -1 +428 753 -1 +429 753 -1 +430 753 -1 +431 753 -1 +432 753 -1 +2 754 1 +433 754 -1 +434 754 -1 +435 754 -1 +436 754 -1 +437 754 -1 +438 754 -1 +439 754 -1 +440 754 -1 +3 755 1 +441 755 -1 +442 755 -1 +2 756 1 +443 756 -1 +3 757 1 +444 757 -1 +1 758 38 +2 758 16 +3 758 19 +4 758 1 +5 758 1 +6 758 1 +7 758 1 +8 758 1 +9 758 1 +10 758 1 +11 758 1 +12 758 1 +13 758 1 +14 758 1 +15 758 1 +16 758 1 +17 758 1 +18 758 1 +19 758 1 +20 758 1 +21 758 1 +22 758 1 +23 758 1 +24 758 1 +25 758 1 +26 758 1 +27 758 1 +28 758 1 +29 758 1 +30 758 1 +31 758 1 +32 758 1 +33 758 1 +34 758 1 +35 758 1 +36 758 1 +37 758 1 +38 758 1 +39 758 1 +40 758 1 +41 758 1 +42 758 1 +43 758 1 +44 758 1 +45 758 1 +46 758 1 +47 758 1 +48 758 1 +49 758 1 +50 758 1 +51 758 1 +52 758 1 +53 758 1 +54 758 1 +55 758 1 +56 758 1 +57 758 1 +58 758 1 +59 758 1 +60 758 1 +61 758 1 +62 758 1 +63 758 1 +64 758 1 +65 758 1 +66 758 1 +67 758 1 +68 758 1 +69 758 1 +70 758 1 +71 758 1 +72 758 1 +73 758 1 +74 758 1 +75 758 1 +76 758 1 +77 758 1 +78 758 1 +79 758 1 +80 758 1 +81 758 1 +82 758 1 +83 758 1 +84 758 1 +85 758 1 +86 758 1 +87 758 1 +88 758 1 +89 758 1 +90 758 1 +91 758 1 +92 758 1 +93 758 1 +94 758 1 +95 758 1 +96 758 1 +97 758 1 +98 758 1 +99 758 1 +100 758 1 +101 758 1 +102 758 1 +103 758 1 +104 758 1 +105 758 1 +106 758 1 +107 758 1 +108 758 1 +109 758 1 +110 758 1 +111 758 1 +112 758 1 +113 758 1 +114 758 1 +115 758 1 +116 758 1 +117 758 1 +118 758 1 +119 758 1 +120 758 1 +121 758 1 +122 758 1 +123 758 1 +124 758 1 +125 758 1 +126 758 1 +127 758 1 +128 758 1 +129 758 1 +130 758 1 +131 758 1 +132 758 1 +133 758 1 +134 758 1 +135 758 1 +136 758 1 +137 758 1 +138 758 1 +139 758 1 +140 758 1 +141 758 1 +142 758 1 +143 758 1 +144 758 1 +145 758 1 +146 758 1 +147 758 1 +148 758 1 +149 758 1 +150 758 1 +151 758 1 +152 758 1 +153 758 1 +154 758 1 +155 758 1 +156 758 1 +157 758 1 +158 758 1 +159 758 1 +160 758 1 +161 758 1 +162 758 1 +163 758 1 +164 758 1 +165 758 1 +166 758 1 +167 758 1 +168 758 1 +169 758 1 +170 758 1 +171 758 1 +172 758 1 +173 758 1 +174 758 1 +175 758 1 +176 758 1 +177 758 1 +178 758 1 +179 758 1 +180 758 1 +183 758 1 +202 758 -1 +207 758 1 +209 758 -1 +234 758 1 +235 758 1 +236 758 1 +237 758 1 +263 758 1 +264 758 1 +265 758 1 +266 758 1 +267 758 1 +268 758 1 +269 758 1 +270 758 1 +300 758 1 +301 758 1 +331 758 -1 +332 758 -1 +334 758 1 +335 758 -1 +336 758 -1 +337 758 -1 +338 758 -1 +339 758 -1 +340 758 -1 +353 758 1 +354 758 1 +358 758 -1 +359 758 -1 +360 758 -1 +361 758 -1 +363 758 -1 +369 758 -1 +370 758 -1 +371 758 -1 +372 758 -1 +373 758 -1 +374 758 -1 +375 758 -1 +376 758 -1 +377 758 -1 +378 758 -1 +379 758 -1 +380 758 -1 +381 758 -1 +382 758 -1 +383 758 -1 +384 758 -1 +385 758 -1 +386 758 -1 +387 758 -1 +388 758 -1 +389 758 -1 +390 758 -1 +391 758 -1 +425 758 -2 +426 758 -2 +427 758 -2 +428 758 -2 +429 758 -2 +430 758 -2 diff --git a/test/netlib/degen2_bounds.mm b/test/netlib/degen2_bounds.mm new file mode 100644 index 000000000..d4fd6fb88 --- /dev/null +++ b/test/netlib/degen2_bounds.mm @@ -0,0 +1,760 @@ +%%MatrixMarket matrix coordinate real general +% Generated 28-Oct-2022 +757 2 757 +1 2 1000000000 +2 2 1000000000 +3 2 1000000000 +4 2 1000000000 +5 2 1000000000 +6 2 1000000000 +7 2 1000000000 +8 2 1000000000 +9 2 1000000000 +10 2 1000000000 +11 2 1000000000 +12 2 1000000000 +13 2 1000000000 +14 2 1000000000 +15 2 1000000000 +16 2 1000000000 +17 2 1000000000 +18 2 1000000000 +19 2 1000000000 +20 2 1000000000 +21 2 1000000000 +22 2 1000000000 +23 2 1000000000 +24 2 1000000000 +25 2 1000000000 +26 2 1000000000 +27 2 1000000000 +28 2 1000000000 +29 2 1000000000 +30 2 1000000000 +31 2 1000000000 +32 2 1000000000 +33 2 1000000000 +34 2 1000000000 +35 2 1000000000 +36 2 1000000000 +37 2 1000000000 +38 2 1000000000 +39 2 1000000000 +40 2 1000000000 +41 2 1000000000 +42 2 1000000000 +43 2 1000000000 +44 2 1000000000 +45 2 1000000000 +46 2 1000000000 +47 2 1000000000 +48 2 1000000000 +49 2 1000000000 +50 2 1000000000 +51 2 1000000000 +52 2 1000000000 +53 2 1000000000 +54 2 1000000000 +55 2 1000000000 +56 2 1000000000 +57 2 1000000000 +58 2 1000000000 +59 2 1000000000 +60 2 1000000000 +61 2 1000000000 +62 2 1000000000 +63 2 1000000000 +64 2 1000000000 +65 2 1000000000 +66 2 1000000000 +67 2 1000000000 +68 2 1000000000 +69 2 1000000000 +70 2 1000000000 +71 2 1000000000 +72 2 1000000000 +73 2 1000000000 +74 2 1000000000 +75 2 1000000000 +76 2 1000000000 +77 2 1000000000 +78 2 1000000000 +79 2 1000000000 +80 2 1000000000 +81 2 1000000000 +82 2 1000000000 +83 2 1000000000 +84 2 1000000000 +85 2 1000000000 +86 2 1000000000 +87 2 1000000000 +88 2 1000000000 +89 2 1000000000 +90 2 1000000000 +91 2 1000000000 +92 2 1000000000 +93 2 1000000000 +94 2 1000000000 +95 2 1000000000 +96 2 1000000000 +97 2 1000000000 +98 2 1000000000 +99 2 1000000000 +100 2 1000000000 +101 2 1000000000 +102 2 1000000000 +103 2 1000000000 +104 2 1000000000 +105 2 1000000000 +106 2 1000000000 +107 2 1000000000 +108 2 1000000000 +109 2 1000000000 +110 2 1000000000 +111 2 1000000000 +112 2 1000000000 +113 2 1000000000 +114 2 1000000000 +115 2 1000000000 +116 2 1000000000 +117 2 1000000000 +118 2 1000000000 +119 2 1000000000 +120 2 1000000000 +121 2 1000000000 +122 2 1000000000 +123 2 1000000000 +124 2 1000000000 +125 2 1000000000 +126 2 1000000000 +127 2 1000000000 +128 2 1000000000 +129 2 1000000000 +130 2 1000000000 +131 2 1000000000 +132 2 1000000000 +133 2 1000000000 +134 2 1000000000 +135 2 1000000000 +136 2 1000000000 +137 2 1000000000 +138 2 1000000000 +139 2 1000000000 +140 2 1000000000 +141 2 1000000000 +142 2 1000000000 +143 2 1000000000 +144 2 1000000000 +145 2 1000000000 +146 2 1000000000 +147 2 1000000000 +148 2 1000000000 +149 2 1000000000 +150 2 1000000000 +151 2 1000000000 +152 2 1000000000 +153 2 1000000000 +154 2 1000000000 +155 2 1000000000 +156 2 1000000000 +157 2 1000000000 +158 2 1000000000 +159 2 1000000000 +160 2 1000000000 +161 2 1000000000 +162 2 1000000000 +163 2 1000000000 +164 2 1000000000 +165 2 1000000000 +166 2 1000000000 +167 2 1000000000 +168 2 1000000000 +169 2 1000000000 +170 2 1000000000 +171 2 1000000000 +172 2 1000000000 +173 2 1000000000 +174 2 1000000000 +175 2 1000000000 +176 2 1000000000 +177 2 1000000000 +178 2 1000000000 +179 2 1000000000 +180 2 1000000000 +181 2 1000000000 +182 2 1000000000 +183 2 1000000000 +184 2 1000000000 +185 2 1000000000 +186 2 1000000000 +187 2 1000000000 +188 2 1000000000 +189 2 1000000000 +190 2 1000000000 +191 2 1000000000 +192 2 1000000000 +193 2 1000000000 +194 2 1000000000 +195 2 1000000000 +196 2 1000000000 +197 2 1000000000 +198 2 1000000000 +199 2 1000000000 +200 2 1000000000 +201 2 1000000000 +202 2 1000000000 +203 2 1000000000 +204 2 1000000000 +205 2 1000000000 +206 2 1000000000 +207 2 1000000000 +208 2 1000000000 +209 2 1000000000 +210 2 1000000000 +211 2 1000000000 +212 2 1000000000 +213 2 1000000000 +214 2 1000000000 +215 2 1000000000 +216 2 1000000000 +217 2 1000000000 +218 2 1000000000 +219 2 1000000000 +220 2 1000000000 +221 2 1000000000 +222 2 1000000000 +223 2 1000000000 +224 2 1000000000 +225 2 1000000000 +226 2 1000000000 +227 2 1000000000 +228 2 1000000000 +229 2 1000000000 +230 2 1000000000 +231 2 1000000000 +232 2 1000000000 +233 2 1000000000 +234 2 1000000000 +235 2 1000000000 +236 2 1000000000 +237 2 1000000000 +238 2 1000000000 +239 2 1000000000 +240 2 1000000000 +241 2 1000000000 +242 2 1000000000 +243 2 1000000000 +244 2 1000000000 +245 2 1000000000 +246 2 1000000000 +247 2 1000000000 +248 2 1000000000 +249 2 1000000000 +250 2 1000000000 +251 2 1000000000 +252 2 1000000000 +253 2 1000000000 +254 2 1000000000 +255 2 1000000000 +256 2 1000000000 +257 2 1000000000 +258 2 1000000000 +259 2 1000000000 +260 2 1000000000 +261 2 1000000000 +262 2 1000000000 +263 2 1000000000 +264 2 1000000000 +265 2 1000000000 +266 2 1000000000 +267 2 1000000000 +268 2 1000000000 +269 2 1000000000 +270 2 1000000000 +271 2 1000000000 +272 2 1000000000 +273 2 1000000000 +274 2 1000000000 +275 2 1000000000 +276 2 1000000000 +277 2 1000000000 +278 2 1000000000 +279 2 1000000000 +280 2 1000000000 +281 2 1000000000 +282 2 1000000000 +283 2 1000000000 +284 2 1000000000 +285 2 1000000000 +286 2 1000000000 +287 2 1000000000 +288 2 1000000000 +289 2 1000000000 +290 2 1000000000 +291 2 1000000000 +292 2 1000000000 +293 2 1000000000 +294 2 1000000000 +295 2 1000000000 +296 2 1000000000 +297 2 1000000000 +298 2 1000000000 +299 2 1000000000 +300 2 1000000000 +301 2 1000000000 +302 2 1000000000 +303 2 1000000000 +304 2 1000000000 +305 2 1000000000 +306 2 1000000000 +307 2 1000000000 +308 2 1000000000 +309 2 1000000000 +310 2 1000000000 +311 2 1000000000 +312 2 1000000000 +313 2 1000000000 +314 2 1000000000 +315 2 1000000000 +316 2 1000000000 +317 2 1000000000 +318 2 1000000000 +319 2 1000000000 +320 2 1000000000 +321 2 1000000000 +322 2 1000000000 +323 2 1000000000 +324 2 1000000000 +325 2 1000000000 +326 2 1000000000 +327 2 1000000000 +328 2 1000000000 +329 2 1000000000 +330 2 1000000000 +331 2 1000000000 +332 2 1000000000 +333 2 1000000000 +334 2 1000000000 +335 2 1000000000 +336 2 1000000000 +337 2 1000000000 +338 2 1000000000 +339 2 1000000000 +340 2 1000000000 +341 2 1000000000 +342 2 1000000000 +343 2 1000000000 +344 2 1000000000 +345 2 1000000000 +346 2 1000000000 +347 2 1000000000 +348 2 1000000000 +349 2 1000000000 +350 2 1000000000 +351 2 1000000000 +352 2 1000000000 +353 2 1000000000 +354 2 1000000000 +355 2 1000000000 +356 2 1000000000 +357 2 1000000000 +358 2 1000000000 +359 2 1000000000 +360 2 1000000000 +361 2 1000000000 +362 2 1000000000 +363 2 1000000000 +364 2 1000000000 +365 2 1000000000 +366 2 1000000000 +367 2 1000000000 +368 2 1000000000 +369 2 1000000000 +370 2 1000000000 +371 2 1000000000 +372 2 1000000000 +373 2 1000000000 +374 2 1000000000 +375 2 1000000000 +376 2 1000000000 +377 2 1000000000 +378 2 1000000000 +379 2 1000000000 +380 2 1000000000 +381 2 1000000000 +382 2 1000000000 +383 2 1000000000 +384 2 1000000000 +385 2 1000000000 +386 2 1000000000 +387 2 1000000000 +388 2 1000000000 +389 2 1000000000 +390 2 1000000000 +391 2 1000000000 +392 2 1000000000 +393 2 1000000000 +394 2 1000000000 +395 2 1000000000 +396 2 1000000000 +397 2 1000000000 +398 2 1000000000 +399 2 1000000000 +400 2 1000000000 +401 2 1000000000 +402 2 1000000000 +403 2 1000000000 +404 2 1000000000 +405 2 1000000000 +406 2 1000000000 +407 2 1000000000 +408 2 1000000000 +409 2 1000000000 +410 2 1000000000 +411 2 1000000000 +412 2 1000000000 +413 2 1000000000 +414 2 1000000000 +415 2 1000000000 +416 2 1000000000 +417 2 1000000000 +418 2 1000000000 +419 2 1000000000 +420 2 1000000000 +421 2 1000000000 +422 2 1000000000 +423 2 1000000000 +424 2 1000000000 +425 2 1000000000 +426 2 1000000000 +427 2 1000000000 +428 2 1000000000 +429 2 1000000000 +430 2 1000000000 +431 2 1000000000 +432 2 1000000000 +433 2 1000000000 +434 2 1000000000 +435 2 1000000000 +436 2 1000000000 +437 2 1000000000 +438 2 1000000000 +439 2 1000000000 +440 2 1000000000 +441 2 1000000000 +442 2 1000000000 +443 2 1000000000 +444 2 1000000000 +445 2 1000000000 +446 2 1000000000 +447 2 1000000000 +448 2 1000000000 +449 2 1000000000 +450 2 1000000000 +451 2 1000000000 +452 2 1000000000 +453 2 1000000000 +454 2 1000000000 +455 2 1000000000 +456 2 1000000000 +457 2 1000000000 +458 2 1000000000 +459 2 1000000000 +460 2 1000000000 +461 2 1000000000 +462 2 1000000000 +463 2 1000000000 +464 2 1000000000 +465 2 1000000000 +466 2 1000000000 +467 2 1000000000 +468 2 1000000000 +469 2 1000000000 +470 2 1000000000 +471 2 1000000000 +472 2 1000000000 +473 2 1000000000 +474 2 1000000000 +475 2 1000000000 +476 2 1000000000 +477 2 1000000000 +478 2 1000000000 +479 2 1000000000 +480 2 1000000000 +481 2 1000000000 +482 2 1000000000 +483 2 1000000000 +484 2 1000000000 +485 2 1000000000 +486 2 1000000000 +487 2 1000000000 +488 2 1000000000 +489 2 1000000000 +490 2 1000000000 +491 2 1000000000 +492 2 1000000000 +493 2 1000000000 +494 2 1000000000 +495 2 1000000000 +496 2 1000000000 +497 2 1000000000 +498 2 1000000000 +499 2 1000000000 +500 2 1000000000 +501 2 1000000000 +502 2 1000000000 +503 2 1000000000 +504 2 1000000000 +505 2 1000000000 +506 2 1000000000 +507 2 1000000000 +508 2 1000000000 +509 2 1000000000 +510 2 1000000000 +511 2 1000000000 +512 2 1000000000 +513 2 1000000000 +514 2 1000000000 +515 2 1000000000 +516 2 1000000000 +517 2 1000000000 +518 2 1000000000 +519 2 1000000000 +520 2 1000000000 +521 2 1000000000 +522 2 1000000000 +523 2 1000000000 +524 2 1000000000 +525 2 1000000000 +526 2 1000000000 +527 2 1000000000 +528 2 1000000000 +529 2 1000000000 +530 2 1000000000 +531 2 1000000000 +532 2 1000000000 +533 2 1000000000 +534 2 1000000000 +535 2 1000000000 +536 2 1000000000 +537 2 1000000000 +538 2 1000000000 +539 2 1000000000 +540 2 1000000000 +541 2 1000000000 +542 2 1000000000 +543 2 1000000000 +544 2 1000000000 +545 2 1000000000 +546 2 1000000000 +547 2 1000000000 +548 2 1000000000 +549 2 1000000000 +550 2 1000000000 +551 2 1000000000 +552 2 1000000000 +553 2 1000000000 +554 2 1000000000 +555 2 1000000000 +556 2 1000000000 +557 2 1000000000 +558 2 1000000000 +559 2 1000000000 +560 2 1000000000 +561 2 1000000000 +562 2 1000000000 +563 2 1000000000 +564 2 1000000000 +565 2 1000000000 +566 2 1000000000 +567 2 1000000000 +568 2 1000000000 +569 2 1000000000 +570 2 1000000000 +571 2 1000000000 +572 2 1000000000 +573 2 1000000000 +574 2 1000000000 +575 2 1000000000 +576 2 1000000000 +577 2 1000000000 +578 2 1000000000 +579 2 1000000000 +580 2 1000000000 +581 2 1000000000 +582 2 1000000000 +583 2 1000000000 +584 2 1000000000 +585 2 1000000000 +586 2 1000000000 +587 2 1000000000 +588 2 1000000000 +589 2 1000000000 +590 2 1000000000 +591 2 1000000000 +592 2 1000000000 +593 2 1000000000 +594 2 1000000000 +595 2 1000000000 +596 2 1000000000 +597 2 1000000000 +598 2 1000000000 +599 2 1000000000 +600 2 1000000000 +601 2 1000000000 +602 2 1000000000 +603 2 1000000000 +604 2 1000000000 +605 2 1000000000 +606 2 1000000000 +607 2 1000000000 +608 2 1000000000 +609 2 1000000000 +610 2 1000000000 +611 2 1000000000 +612 2 1000000000 +613 2 1000000000 +614 2 1000000000 +615 2 1000000000 +616 2 1000000000 +617 2 1000000000 +618 2 1000000000 +619 2 1000000000 +620 2 1000000000 +621 2 1000000000 +622 2 1000000000 +623 2 1000000000 +624 2 1000000000 +625 2 1000000000 +626 2 1000000000 +627 2 1000000000 +628 2 1000000000 +629 2 1000000000 +630 2 1000000000 +631 2 1000000000 +632 2 1000000000 +633 2 1000000000 +634 2 1000000000 +635 2 1000000000 +636 2 1000000000 +637 2 1000000000 +638 2 1000000000 +639 2 1000000000 +640 2 1000000000 +641 2 1000000000 +642 2 1000000000 +643 2 1000000000 +644 2 1000000000 +645 2 1000000000 +646 2 1000000000 +647 2 1000000000 +648 2 1000000000 +649 2 1000000000 +650 2 1000000000 +651 2 1000000000 +652 2 1000000000 +653 2 1000000000 +654 2 1000000000 +655 2 1000000000 +656 2 1000000000 +657 2 1000000000 +658 2 1000000000 +659 2 1000000000 +660 2 1000000000 +661 2 1000000000 +662 2 1000000000 +663 2 1000000000 +664 2 1000000000 +665 2 1000000000 +666 2 1000000000 +667 2 1000000000 +668 2 1000000000 +669 2 1000000000 +670 2 1000000000 +671 2 1000000000 +672 2 1000000000 +673 2 1000000000 +674 2 1000000000 +675 2 1000000000 +676 2 1000000000 +677 2 1000000000 +678 2 1000000000 +679 2 1000000000 +680 2 1000000000 +681 2 1000000000 +682 2 1000000000 +683 2 1000000000 +684 2 1000000000 +685 2 1000000000 +686 2 1000000000 +687 2 1000000000 +688 2 1000000000 +689 2 1000000000 +690 2 1000000000 +691 2 1000000000 +692 2 1000000000 +693 2 1000000000 +694 2 1000000000 +695 2 1000000000 +696 2 1000000000 +697 2 1000000000 +698 2 1000000000 +699 2 1000000000 +700 2 1000000000 +701 2 1000000000 +702 2 1000000000 +703 2 1000000000 +704 2 1000000000 +705 2 1000000000 +706 2 1000000000 +707 2 1000000000 +708 2 1000000000 +709 2 1000000000 +710 2 1000000000 +711 2 1000000000 +712 2 1000000000 +713 2 1000000000 +714 2 1000000000 +715 2 1000000000 +716 2 1000000000 +717 2 1000000000 +718 2 1000000000 +719 2 1000000000 +720 2 1000000000 +721 2 1000000000 +722 2 1000000000 +723 2 1000000000 +724 2 1000000000 +725 2 1000000000 +726 2 1000000000 +727 2 1000000000 +728 2 1000000000 +729 2 1000000000 +730 2 1000000000 +731 2 1000000000 +732 2 1000000000 +733 2 1000000000 +734 2 1000000000 +735 2 1000000000 +736 2 1000000000 +737 2 1000000000 +738 2 1000000000 +739 2 1000000000 +740 2 1000000000 +741 2 1000000000 +742 2 1000000000 +743 2 1000000000 +744 2 1000000000 +745 2 1000000000 +746 2 1000000000 +747 2 1000000000 +748 2 1000000000 +749 2 1000000000 +750 2 1000000000 +751 2 1000000000 +752 2 1000000000 +753 2 1000000000 +754 2 1000000000 +755 2 1000000000 +756 2 1000000000 +757 2 1000000000 diff --git a/test/ode_solvers_test.cpp b/test/ode_solvers_test.cpp index b8cfd9d6d..735afdef0 100644 --- a/test/ode_solvers_test.cpp +++ b/test/ode_solvers_test.cpp @@ -132,12 +132,12 @@ void check_norm_progress(Solver &solver, int num_steps, std::vector target, #else for (int i = 0; i < num_steps; i++) { solver.step(i, true); - solver.print_state(); + solver.print_state(std::cerr); } #endif NT norm = NT(0); for (unsigned int i = 0; i < solver.xs.size(); i++) { - norm += solver.xs[i].dot(solver.xs[i]); + norm += (solver.xs[i].cwiseProduct(solver.xs[i])).sum(); } norm = sqrt(norm); @@ -155,7 +155,9 @@ void check_norm_progress(Solver &solver, int num_steps, std::vector target, template void test_implicit_midpoint() { typedef Cartesian Kernel; typedef typename Kernel::Point Point; - typedef std::vector pts; + using MT = Eigen::Matrix; + using VT = Eigen::Matrix; + typedef std::vector pts; typedef GaussianFunctor::GradientFunctor grad; typedef GaussianFunctor::FunctionFunctor func; typedef GaussianFunctor::parameters func_params; @@ -172,13 +174,14 @@ template void test_implicit_midpoint() { Input input = Input(d, f, F); input.lb = -VT::Ones(d); input.ub = VT::Ones(d); - CrhmcProblem P = CrhmcProblem(input); + opts.EnableReordering=false; + opts.DynamicWeight = false; + CrhmcProblem P = CrhmcProblem(input,opts); d = P.dimension(); - Point x0 = Point(d); - Point v0 = Point::all_ones(d); + MT x0 = MT::Zero(d,1); + MT v0 = MT::Ones(d,1); pts q{x0, v0}; opts.solver_accuracy_threshold = 1e-2; - opts.DynamicWeight = false; ImplicitMidpointODESolver implicit_midpoint_solver = ImplicitMidpointODESolver(0, 0.01, q,