package scientific.stats.mcmc
import std.math.*
import std.collection.*
import std.io.*

// record Pair<T, U> {
//     let x: T
//     let y: U
//     public init(a: T, b: U) { 
//         x = a 
//         y = b 
//     }

//     public func first(): T { return x }
//     public func second(): U { return y } 

// }

// @Differentiable
// func f(x: Float64, y: Float64) : Float64 {
//     return x * x * y
// }

// @Adjoint [primal: f]
// func g(x: Float64, y: Float64): (Float64)*((Float64) -> Float64 * Float64) {
//     let x_squre = x * x
//     return (
//         x_squre * x,
//         { dy: Float64 =>
//             return (dy * x_squre * 2.0, dy * 2.0)
//         }
//     )
// }


// @Differentiable [except: [x]]
// public func normalPDF(x: Float64, mean: Float64, std: Float64): Float64 {
//   let temp = 1.0 / sqrt(2.0 * Float64.getPI()) * exp(-pow(x - mean, 2.0) / (2.0 * pow(std, 2.0)))
//   return temp
// }

// @Adjoint [primal: normalPDF]
// public func normalPDFAcc(x: Float64, mean: Float64, std: Float64): (Float64)*((Float64) -> Float64 * Float64) {
//   let temp = 1.0 / sqrt(2.0 * Float64.getPI()) * exp(-pow(x - mean, 2.0) / (2.0 * pow(std, 2.0)))
//   return (
//   temp,
//   { dy: Float64 =>
//     return (temp * (-(mean - x) / pow(std, 2.0)),  temp * (- 1.0 / std + pow(x - mean, 2.0) / pow(std, 3.0)))
//     }
//   )
// }


// class McmcDist {

//     var params: Tensor<Float64> = Tensor<Float64>([0.0, 1.0])
//     let params: Array<Float64> = Array<Float64>([0.2, 1.0])

//     open func density(x: Float64): Float64 {
//         return 0.0
//     }

//     open func density(x: Float64, params: Tensor<Float64>): Float64 {
//         return 0.0
//     }
    
// }

// func main() {
// public func testMCMC() {

//     // let product_grad = grad(normalPDF, (0.0, 3.0, 2.0))
//     // print(product_grad[0].toString() + "\n") 
//     // print(product_grad[1].toString() + "\n")

//     // let product_grad = grad(f, (2.0, 3.0))
//     // print(product_grad[0].toString() + "\n") 
//     // print(product_grad[1].toString() + "\n") 

//     // var a: Pair<String, Int64> = Pair<String, Int64>("hello", 0)
//     // println(a.first())
//     // println(a.second())
//     // let p: McmcDist = McmcDist()

//     // let param1: Array<Int64> = [1, 2]
//     // print("${param1[0]}")


//     //test io
//     let pathname: String = "./australian.txt"
//     var fs: FileStream = FileStream(pathname)

//     if (fs.openFile()) {

//         var toWrite: Array<UInt8> = Array<UInt8>(80, { i => 0 })
//         var res = fs.write(toWrite)
//         fs.flush()
//         println(res.toString())
//         fs.close()
//         println(fs.isClosed().toString())

//     }
//     if (fs.openFile()) {
//         var toRead: Array<UInt8> = Array<UInt8>(25, { i => 0 })
//         fs.read(toRead)
//         fs.flush()
//         var n = fs.seek(6, SeekOrigin.BeginPos)
//         println(n.toString())
//         fs.close()
//         println(toRead.toString())
//         println(fs.isClosed().toString())
//     }
//     fs.close()
//     return 0
// }