text:
BithumbSecretAPIKey
BTCDepositAddress 1HkdMBE3i3etnLz76icGT8iufATbvNDniX
BCHDepositAddress
ETHDepositAddress 0x4c8ebf59092ed387c9c284f5834c86aca9688d3e
XRPDepositAddress rsG1sNifXJxGS2nDQ9zHyoe1S5APrtwpjV DestinationTag 1000837387
DASHDepositAddress XnAZVy1C6nNarpJnBCxfzM7edgd2p4D5PZ
LTCDepositAddress LMwSwcBSYcbbzjdPpib9gNem1wHmLrrFVV
ETCDepositAddress 0x43f60ea748af75d20a2b7e9bcdfe3d7e969de415

BitsoSecretAPIKey
BTCDepositAddress 3GU2pbeeKZZ3KCLTjzLdLsfjMss5BrE6sB
BCHDepositAddress
ETHDepositAddress 0x9205e8e2ac93928028471b96ff3bb2524f22b18f
XRPDepositAddress rHZaDC6tsGN2JWGeXhjKL6664RNCq5hu4B DestinationTag 72314142
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

PoloniexSecretAPIKey 755ccffbf1091005b9b7a75d146ae1b29eb56c7f0cdb492efa2742beba19df5baf7b996d531d4a9f93118829197a264535eb3aa865bea3571edb717b9ebbd352
PoloniexAPIKey XZ7T1T2T-M0J1ZP38-TKQ8X4T0-YBAY29AQ
BTCDepositAddress 1JwSYf8iKP9G6QZUyyqMCLbqq2KwUjdNvc
BCHDepositAddress 15bYSNgL7seLNpJC2Yw5b5aHiu17iVdS39
ETHDepositAddress 0xf8b65914af478fa354f6d46788080e0a04b299ae
# Requires .5 ETH to create
XRPDepositAddress rh6MZQwGgGgiEqF9PhVhRpDuGP6bwacuWD DestinationTag
# Requires 20 XRP as reserve
DASHDepositAddress Xop2J6q8wzw2Rx1jHVxHRNH2PJ24fkeceP
LTCDepositAddress LeVqnqyYQm4Shb4L96ZLpeByDBVXn2ZYAZ
ETCDepositAddress 0x59e8f2ca251f946c2581c25030dec859d457dfdd
# Requires 1 ETC as min deposit

API: https://www.okcoin.com/html/okcoin_com_etc_api.html
OKCoinSecretAPIKey C0E96ED5F7CBA8CBDB9B27B1C67B724E
OKCoinAPIKey 1fd239b7-f26f-4b8d-9052-ae8323045f0b
BTCDepositAddress 3MFrP8ZTFN95v9XwrLUrKLSSrN6vLmoQtL
# One block confirmation
BCHDepositAddress LeieW3umpMEW3z5fV2Zrogbs9i6WLmZKqm
ETHDepositAddress 0xdad0487a2e32bf305fbc77bd675235edabe227d4
# 30 blocks confirmation for ETH deposit arrival
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress 0x3c15a510b913b5cb535b738df923a328611a3be5

BitShares Password P5HybrYHxAtLnikJRrz2APJ92fRZGrVjUm2bKZrzmEoLVxuboiCT
BitSharesSecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

SecretAPIKey
BTCDepositAddress
BCHDepositAddress
ETHDepositAddress
XRPDepositAddress  DestinationTag
DASHDepositAddress
LTCDepositAddress
ETCDepositAddress

max_stars_repo_path: Dojo/C++ Programming Practices and Principles - Stroustrup/exchanges.jl

max_stars_repo_name: miguelraz/PathToPerformance

max_issues_repo_name: miguelraz/PathToPerformance

max_forks_repo_name: miguelraz/PathToPerformance


text:
function processresults!(moduletracker::ModuleTracker, μ, clonalmutations, rng::AbstractRNG;
    fixedmu=false)

    mutationlist = get_mutationlist(moduletracker)
    expandedmutationids =
        get_expandedmutationids(μ, mutationlist, clonalmutations, rng, fixedmu=fixedmu)
    expandmutations!(moduletracker, expandedmutationids, clonalmutations)

    return moduletracker
end

function processresults!(populationtracker::Array{ModuleTracker, 1}, μ, clonalmutations,
    rng::AbstractRNG; fixedmu=false)

    mutationlist = get_mutationlist(populationtracker)
    expandedmutationids =
        get_expandedmutationids(μ, mutationlist, clonalmutations, rng, fixedmu=fixedmu)

    for moduletracker in populationtracker
        expandmutations!(moduletracker, expandedmutationids, clonalmutations)
    end
    return populationtracker
end

function expandmutations!(moduletracker, expandedmutationids, clonalmutations)

    if length(expandedmutationids) > 0
        for cell in moduletracker.cells
            cell.mutations = expandmutations(expandedmutationids, cell.mutations)
            if clonalmutations > 0
                prepend!(cell.mutations, 1:clonalmutations)
            end
        end
    elseif clonalmutations > 0
        for cell in moduletracker.cells
            cell.mutations = collect(1:clonalmutations)
        end
    end
    #get list of mutations in each subclone
    if length(expandedmutationids) > 0
        for subclone in moduletracker.subclones
            subclone.mutations = expandmutations(expandedmutationids, subclone.mutations)
        end
    end
    return moduletracker
end

function expandmutations(expandedmutationids, originalmutations)
    return reduce(
        vcat,
        filter(!isempty, map(x -> expandedmutationids[x], originalmutations)),
        init=Int64[]
    )
end

function get_mutationlist(populationtracker::Array{ModuleTracker, 1})
    #get list of all mutations assigned to each cell
    mutationlist = [mutation
        for moduletracker in populationtracker
            for cell in moduletracker.cells
                for mutation in cell.mutations
    ]
    return sort(unique(mutationlist))
end

function get_mutationlist(moduletracker::ModuleTracker)
    #get list of all mutations assigned to each cell
    mutationlist = [mutation
        for cell in moduletracker.cells
            for mutation in cell.mutations
    ]
    return unique(mutationlist)
end

function get_expandedmutationids(μ, mutationlist, clonalmutations, rng; fixedmu=false)
    if fixedmu
        mutationsN = fill(μ, length(mutationlist))
    else
        mutationsN = rand(rng, Poisson(μ), length(mutationlist))
    end
    expandedmutationids = Dict{Int64, Vector{Int64}}()
    i = clonalmutations + 1
    for (mutkey, N) in zip(mutationlist, mutationsN)
        push!(expandedmutationids, mutkey=>collect(i:i+N-1))
        i += N
    end
    return expandedmutationids
end

function remove_undetectable!(moduletracker::ModuleTracker, clonefreq, clonefreqp, numclones, detectableclones)
    #if there are clones outside the detectable range remove them from the data
    if sum(detectableclones) < numclones
        numclones = sum(detectableclones)
        clonefreq = clonefreq[detectableclones]
        clonefreqp = clonefreqp[detectableclones]
        moduletracker.subclones = moduletracker.subclones[detectableclones]
        pushfirst!(detectableclones, true)
        moduletracker.clonesize = moduletracker.clonesize[detectableclones]
        detectableclones = detectableclones[1:length(br)]
    end
    return moduletracker, clonefreq, clonefreqp, numclones
end

function calculateclonefreq!(clonefreq, subclonalmutations, subclones)
    for i in length(subclones):-1:2
        if subclones[i].parenttype > 1
            clonefreq[subclones[i].parenttype-1] += clonefreq[i]
            subclonalmutations[i] -= subclonalmutations[subclones[i].parenttype-1]
        end
    end
    if (sum(clonefreq.>1.0) > 0)
        error("There is a clone with frequency greater than 1, this should be impossible
                ($(clonesize)), $(parenttype), $(clonefreq)")
    end
    return clonefreq, subclonalmutations
  end

ext: jl


text:
import Statistics
import YAML
import JLD2
import DICOM
import DICOMTools
import MRIRelax

function main()
	directory = ""
	local full_dcmdict
	for specfile in ARGS
		# Get specs and DICOMs
		specs = YAML.load_file(specfile)

		# Load DICOMs
		multiseries = let
			if length(directory) == 0 || directory != tmp
				directory = expanduser(specs["directory"])
				full_dcmdict = DICOMTools.load_dcms(directory, DICOMTools.read_uid)
			end

			# Filter DICOMs by uid and fully load matches
			dcmdict = DICOMTools.filter(
				dcms -> dcms[1][DICOM.tag"SeriesInstanceUID"] in specs["uids"],
				full_dcmdict
			)
			DICOMTools.load_dcms!(dcmdict)

			# Extract DICOMs from dictionary
			[series.dcms for series in values(dcmdict)]
		end

		# Get tag and fitfunc
		if specs["type"] == "Inversion Recovery"
			tagname = DICOM.tag"InversionTime"
			tags = DICOMTools.get_tag(multiseries, tagname; outtype=Float64)
			# Note: Get tags here because some applications might use other (non-numeric, multiple) tags
			fitfunc = (Tinv, signal, Δsignal) -> begin
				let	T1_0::Float64 = specs["T1_0"],
					Minv_0::Float64 = specs["Minv_0"],
					M0_0::Float64 = specs["M0_0"]
					MRIRelax.fit_inversion_recovery(Tinv, signal, Δsignal, T1_0, Minv_0, M0_0)
				end
			end
			num_params = 6
			names = ["T1", "ΔT1", "Minv", "ΔMinv", "M0", "ΔM0"]
		elseif specs["type"] == "Transverse Relaxation"
			tagname = DICOM.tag"EchoTime"
			tags = DICOMTools.get_tag(multiseries, tagname; outtype=Float64)
			fitfunc = MRIRelax.fit_transverse_relax
			num_params = 4
			names = ["T2", "ΔM0", "ΔM0"]
		end

		# Get signals and tags from DICOMs
		signal = DICOMTools.merge_multiseries(multiseries; data_type=Float64)

		# Get background
		background = ntuple(
			i -> specs["background_lower"][i]:specs["background_upper"][i],
			3
		)

		# Perform the fitting
		maps, Δsignal = fit2dcm(fitfunc, num_params, signal, tags, background)

		# Write the results
		JLD2.jldsave(
			splitext(specfile)[1] * ".jld2";
			maps,
			names,
			coordinates=tags,
			coordinatename=tagname,
			signal,
			Δsignal
		)
	end
end

function fit2dcm(
	fitfunc::Function,
	num_params::Integer,
	signal::AbstractArray{<: Real, 4},
	tags::AbstractVector,
	background::NTuple{3, UnitRange{Int64}}
)

	# Get noise estimation for each signal(coordinate or tag)
	Δsignal = Statistics.std(view(signal, :, background...); dims=2:4)
	Δsignal = dropdims(Δsignal; dims=(2, 3, 4))

	# Construct array for fitting results
	maps = [
		Array{Float64, 3}(undef, size(signal)[2:4]...)
		for _ in 1:num_params
	]

	# Iterate over voxels
	Threads.@threads for I in CartesianIndices(size(signal)[2:4])
		tid = Threads.threadid()
		returned = fitfunc(tags, signal[:, I], Δsignal)
		for (tag_idx, value) in enumerate(returned)
			maps[tag_idx][I] = value
		end
	end

	return maps, Δsignal
end

main()


text:
#Diagonal shocktube
function setup_tubexy(self::data2d)

    @assert hyd.x[1] == hyd.y[1]
    @assert hyd.x[end] == hyd.y[end]
    @assert hyd.nx == hyd.ny

    rho1 = 1.0
    rho2 = 0.125
    press1 = 1.0
    press2 = 0.14

    self.rho[:,:] = rho1
    self.press[:,:] = press1
    self.eps[:,:] = press1/rho1/(gamma - 1.0)

    for i = 1:self.ny
        for j = 1:i
                self.rho[i, j] = rho2
                self.press[i, j] = press2
                self.eps[i, j] = press2/rho2/(gamma - 1.0)
            end
        end

    return self
end

#Blast wave
function setup_blast(self::data2d)

    rho1 = 1.0
    press1 = 0.1
    press2 = 10.0

    self.rho[:,:] = rho1*ones(self.ny, self.nx)
    self.press[:,:] = press1*ones(self.ny, self.nx)
    self.eps[:,:] = press1./rho1./(gamma - 1.0)*ones(self.ny,self.nx)
    self.velx[:,:] = zeros(self.ny, self.nx)
    self.vely[:,:] = zeros(self.ny, self.nx)

    midx = Int(self.nx/2)
    midy = Int(self.ny/2)

    #circle=[1,3,4,4,5,5]
    #circle=[2,4,5,6,6,6,7,7]
    #circle=[3,5,6,7,8,9,9,10,10,10]
		size=7
    #N = length(circle)
    #for j = 0:N-1
    #    yy = j
    #    xx = circle[N-j]
#
#        self.press[midy+yy, midx-xx:midx+xx] .= press2
#        self.eps[midy+yy, midx-xx:midx+xx] .= press2./rho1./(gamma - 1.0)
#        self.press[midy-yy, midx-xx:midx+xx] .= press2
#        self.eps[midy-yy, midx-xx:midx+xx] .= press2./rho1./(gamma - 1.0)
 #   end
 		for i = 1:self.nx, j = 1:self.ny
			sqrdistance = (i-midx)^2 + (j-midy)^2
			if sqrdistance <= size^2
				self.press[i,j] = press2
				self.eps[i,j] = press2/rho1/(gamma-1.0)
			end
		end

    return self
end

#Two colliding spheres
function setup_collision(self::data2d)

    rho1 = 0.01
    rho2 = 10.0
    press1 = 0.01
    vel2 = 2.0

    self.rho[:,:] = rho1*ones(self.ny, self.nx)
    self.press[:,:] = press1*ones(self.ny, self.nx)
    self.eps[:,:] = press1./rho1./(gamma - 1.0)
    self.velx[:,:] = zeros(self.ny, self.nx)
    self.vely[:,:] = zeros(self.ny, self.nx)

    #first ball
    midx = int(self.nx/2)
    midy = int(0.25self.ny)

    #circle=[1,3,4,4,5,5]
    #circle=[2,4,5,6,6,6,7,7]
    circle=[3,5,6,7,8,9,9,10,10,10]
    N = length(circle)
    for j = 0:N-1
        yy = j
        xx = circle[N-j]

        self.rho[midy+yy, midx-xx:midx+xx] = rho2
        self.rho[midy-yy, midx-xx:midx+xx] = rho2

        self.vely[midy+yy, midx-xx:midx+xx] = vel2
        self.vely[midy-yy, midx-xx:midx+xx] = vel2

    end

    #second ball
    midx = int(self.nx/2)
    midy = int(0.75self.ny)
    #circle=[1,3,4,4,5,5]
    #circle=[2,4,5,6,6,6,7,7]
    circle=[3,5,6,7,8,9,9,10,10,10]
    N = length(circle)
    for j = 0:N-1
        yy = j
        xx = circle[N-j]

        self.rho[midy+yy, midx-xx:midx+xx] = rho2
        self.rho[midy-yy, midx-xx:midx+xx] = rho2

        self.vely[midy+yy, midx-xx:midx+xx] = -vel2
        self.vely[midy-yy, midx-xx:midx+xx] = -vel2
    end

    return self
end

#Free falling spheres
function setup_fall(self::data2d)

    rho1 = 1.0
    rho2 = 2.0
    press1 = 2.5
    press2 = 1.25

    self.rho[:,:] = rho1*ones(self.ny, self.nx)
    self.press[:,:] = press1*ones(self.ny, self.nx)
    self.eps[:,:] = press1./rho1./(gamma - 1.0)
    self.velx[:,:] = zeros(self.ny, self.nx)
    self.vely[:,:] = zeros(self.ny, self.nx)

    #first ball
    midx = int(self.nx/2)
    midy = int(0.8self.ny)

    #circle=[1,3,4,4,5,5]
    #circle=[2,4,5,6,6,6,7,7]
    circle=[3,5,6,7,8,9,9,10,10,10]
    N = length(circle)
    for j = 0:N-1
        yy = j
        xx = circle[N-j]

        self.rho[midy+yy, midx-xx:midx+xx] = rho2
        self.rho[midy-yy, midx-xx:midx+xx] = rho2

        self.press[midy+yy, midx-xx:midx+xx] = press2
        self.press[midy-yy, midx-xx:midx+xx] = press2
    end

    return self
end

#Taylor instability initial data
function setup_taylor(self::data2d)
    rchange = int(0.8self.ny)

    grav = 0.005
    rho1 = 2.0
    rho2 = 1.0
    press1 = 0.01

    self.rho[1:(rchange-1), :] = rho2*ones(rchange-1, self.nx)
    self.rho[rchange:(self.ny), :] = rho1*ones((self.ny-rchange)+1, self.nx)

    self.press[:,:] = press1*ones(self.ny, self.nx)
    self.eps[:,:] = press1./rho1./(gamma - 1.0)

    self.velx[:,:] = zeros(self.ny, self.nx)
    self.vely[:,:] = zeros(self.ny, self.nx)

    offs = 35
    offsy= 30
    dx = self.x[self.nx-offs-1] - self.x[offs]

    function siny(j)
        sin(pi*(self.y[j]-self.y[rchange-offsy])/(self.y[rchange+offsy]-self.y[rchange-offsy]))
    end

#    for j = rchange:self.ny

    #for j = (rchange-offsy):(rchange+offsy)
    for j = (rchange):(rchange+offsy)

        self.vely[j, offs:(self.nx-offs-1)] = Float64[-0.01siny(j)*sin(pi*(self.x[n]-self.x[offs])/dx) for n = offs:(self.nx-offs-1)]
#        self.vely[j, offs:(self.nx-offs-1)] = Float64[-10.0sin(pi*(self.x[n]-self.x[offs])/dx) for n = offs:(self.nx-offs-1)]
    end

    for j = 1:self.ny
        self.press[j,:] = 2.5 - self.rho[j,20]*grav*self.y[j]
    end

    return self
end

#Taylor instability initial data according to Athena code
function setup_taylor2(self::data2d)
    rchange = Int(0.5self.ny)

    A = 0.01
    grav = 0.005
    rho1 = 2.0
    rho2 = 1.0

    self.rho[1:(rchange-1), :] = rho2*ones(rchange-1, self.nx)
    self.rho[rchange:(self.ny), :] = rho1*ones((self.ny-rchange)+1, self.nx)

    self.press = zeros(self.ny, self.nx)

    self.velx[:,:] = zeros(self.ny, self.nx)
    self.vely[:,:] = zeros(self.ny, self.nx)

    Lx = abs(self.x[self.nx - self.g] - self.x[self.g+1])
    Ly = abs(self.y[self.ny - self.g] - self.y[self.g+1])

    for j = (self.g+1):(self.ny - self.g), i = (self.g+1):(self.nx - self.g)
        self.vely[j,i] = A*((1.0+cos(2pi*self.x[i]/Lx)*(1.0+cos(2pi*self.y[j]/Ly))))
    end

    #set pressure to hydrostatic equiblibrium
    for j = (self.g+1):(self.ny-self.g)
        self.press[j,:] = 2.5 - self.rho[j,20]*grav
    end
    self.eps[:,:] = self.press[:,:] ./ self.rho[:,:] ./ (gamma - 1.0)

    return self
end

#Kelvin-Helmholtz -instability
function setup_kh(self::data2d)

    A = 0.01
    rho1 = 1.0
    rho2 = 2.0
    vel = 0.5

    for j = 1:self.ny, i = 1:self.nx
        if abs(self.y[j]) >= 0.25
            self.rho[j, i] = rho1
            self.velx[j,i] = vel
        else
            self.rho[j, i] = rho2
            self.velx[j,i] = -vel
        end
    end

    Lx = 0.5*abs(self.x[self.nx - self.g] - self.x[self.g+1])
    Ly = 0.5*abs(self.y[self.ny - self.g] - self.y[self.g+1])

    for j = (self.g+1):(self.ny - self.g), i = (self.g+1):(self.nx - self.g)
        #self.velx[j,i] += A*((1.0+cos(2pi*self.x[i]/Lx)*(1.0+cos(2pi*self.y[j]/Ly))))
        self.vely[j,i] += A*((1.0+sin(2pi*self.x[i]/Lx)*(1.0+sin(2pi*self.y[j]/Ly))))
    end

    self.press = ones(self.ny, self.nx)*2.5
    self.vely[:,:] = zeros(self.ny, self.nx)
    self.eps[:,:] = self.press[:,:] ./ self.rho[:,:] ./ (gamma - 1.0)

    return self
end

max_stars_repo_name: gzahl/hydro

max_issues_repo_name: gzahl/hydro

max_forks_repo_name: gzahl/hydro


text:
import Pkg; Pkg.add(Pkg.PackageSpec(url="https://github.com/JuliaComputing/JuliaAcademyData.jl"))
using JuliaAcademyData; activate("Parallel_Computing")

# # Fast (serial) programming with Julia
#
# Yes, this is a parallel computing course — but to write efficient parallel
# programs we first must learn how to write fast serial Julia code. This is
# a rapid primer in high performance (serial) programming.
#
# I _highly_ recommend reviewing the [Performance Tips](https://docs.julialang.org/en/v1.1/manual/performance-tips/)
# in the manual. This is only going to briefly introduce some of the main concepts.

#-

# ## Measure, measure, measure.
#
# It is very easy to experiment in Julia; you can rapidly try many options and
# see what is the fastest.

#-

# Use the [BenchmarkTools](https://github.com/JuliaCI/BenchmarkTools.jl) package:

using BenchmarkTools

"""
    findclosest(data, point)

A simple example that returns the element in `data` that is closest to `point`
"""
function findclosest(data, point)
    _, index =  findmin(abs.(data .- point))
    return data[index]
end
data = rand(5000)
findclosest(data, 0.5)

#-

@time findclosest(data, 0.5)

#-

@benchmark findclosest($data, $0.5)

# ### Profile!

using Profile

Profile.clear()
@profile for _ in 1:100000; findclosest(data, 0.5); end

Profile.print(maxdepth=11)

# ### Iterate!
#
# Before we had:
# ```julia
# function findclosest(data, point)
#     _, index =  findmin(abs.(data .- point))
#     return data[index]
# end
# ```
#
# Let's come up with a new definition that can combine the two operations:

function findclosest2(data, point)
    bestval = first(data)
    bestdist = abs(bestval - point)
    for elt in data
        dist = abs(elt - point)
        if dist < bestdist
            bestval = elt
            bestdist = dist
        end
    end
    return bestval
end

## And do a spot-check to make sure we did the optimization correctly:
findclosest2(data, 0.5) == findclosest(data, .5)

#-

@benchmark findclosest2($data, $0.5)

# ## A quick word on macros
#
# Macros are those funny things starting with `@`. They can reinterpret what
# you write and do something different — essentially introducing a new keyword.
#
# For example, the `@assert` macro simply takes an expression and throws an
# exception if it returns `false`.

@assert 2+2 == 4

# It does this by literally re-writing what you wrote. You can see it in action
# with `@macroexpand`

@macroexpand @assert 2+2 == 4

# Each macro can define its own special syntax, and this is used extensively for
# code introspection, serial performance improvements, and — perhaps most
# importantly — parallelization perimitives!

#-

# ## How is Julia fast?
#
# By understanding the basics of how Julia _can_ be fast, you can get a better
# sense for how to write fast Julia code.
#
# Perhaps most importantly, Julia can reason about types. Recall: this is the definition of `findclosest2`:
#
# ```julia
# function findclosest2(data, point)
#     bestval = first(data)
#     bestdist = abs(bestval - point)
#     for elt in data
#         dist = abs(elt - point)
#         if dist < bestdist
#             bestval = elt
#             bestdist = dist
#         end
#     end
#     return bestval
# end
# ```

@code_typed optimize=false findclosest2(data, 0.5)

#-

typeof(data)

#-

newdata = Real[data...]
typeof(newdata)

#-

@code_typed optimize=false findclosest2(newdata, 0.5)

#-

@benchmark findclosest2(newdata, 0.5)

#-

@code_warntype findclosest2(newdata, 0.5)

# ### Type stability
#
# A function is called type-stable if Julia is able to infer what the output
# type will be based purely on the types of the inputs.
#
# Things that thwart type stability:
# * Running things in global scope: create functions instead!
# * Non-concretely typed containers
# * Structs with abstractly-typed fields
# * Non-constant globals (they might change!)
# * Functions that change what they return based on the _values_:

#-

# #### More on macros
#
# Each and every macro can define its own syntax. The `@benchmark` macro uses `$` in a special way.
# The goal behind `@benchmark` is to evaluate the performance of a code snippet
# as though it were written in a function. Use `$` to flag what will be an argument
# or local variable in the function. Forgetting to use `$`s may result in faster
# or slower timings than real-world performance.

x = 0.5 # non-constant global
@btime sin(x)
@btime sin($x)

#-

@btime sin(0.5) # constant literal!
@btime sin($0.5)

# ### Specializations
#
# Julia's reasoning about types is particularly important since it generates
# specialized machine code specifically for the given arguments.

@code_llvm 1 + 2

# This applies just the same to any functions we write — even the more complicated ones:

@code_llvm findclosest2(Float32[2.2,3.4,4.5],Float32(3.2))

# This applies just the same to any functions we write — even the more complicated ones:

remove_comments(s) = join(filter(x->!startswith(x, ";"), split(s, "\n")), "\n")
sprint(code_llvm, findclosest2, Tuple{Vector{Float32}, Int}) |> remove_comments |> print

# ## Modern hardware effects
#
# There are lots of little performance quirks in modern computers; I'll just
# cover two interesting ones here:

@benchmark findclosest2($data, $0.5)

#-

sorteddata = sort(data)
@benchmark findclosest2($sorteddata, $0.5)

# Unfortunately, this isn't demonstrable on a hardened cloud platform... because
# it's a huge security risk!
#
# * https://meltdownattack.com
# * https://discourse.julialang.org/t/psa-microbenchmarks-remember-branch-history/17436

idxs = sortperm(data)
sortedview = @view data[idxs]
@benchmark findclosest2($sortedview, $0.5)

# ### Memory latencies
#
# | System Event                   | Actual Latency | Scaled Latency |
# | ------------------------------ | -------------- | -------------- |
# | One CPU cycle                  |     0.4 ns     |     1 s        |
# | Level 1 cache access           |     0.9 ns     |     2 s        |
# | Level 2 cache access           |     2.8 ns     |     7 s        |
# | Level 3 cache access           |      28 ns     |     1 min      |
# | Main memory access (DDR DIMM)  |    ~100 ns     |     4 min      |
# | Intel Optane memory access     |     <10 μs     |     7 hrs      |
# | NVMe SSD I/O                   |     ~25 μs     |    17 hrs      |
# | SSD I/O                        |  50–150 μs     | 1.5–4 days     |
# | Rotational disk I/O            |    1–10 ms     |   1–9 months   |
# | Internet call: SF to NYC       |      65 ms     |     5 years    |
# | Internet call: SF to Hong Kong |     141 ms     |    11 years    |
#
#  (from https://www.prowesscorp.com/computer-latency-at-a-human-scale/)

#-

# # Key Takeaways
#
# * Measure, measure, measure!
# * Get familiar with the [Performance Tips](https://docs.julialang.org/en/v1/manual/performance-tips/)
# * Don't be scared of `@code_typed`/`@code_warntype` and `@code_llvm`

max_stars_repo_name: fercarozzi/JuliaAcademyMaterials

max_issues_repo_name: fercarozzi/JuliaAcademyMaterials

max_forks_repo_name: fercarozzi/JuliaAcademyMaterials


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder

name = "z3"
version = v"4.8.10"

# Collection of sources required to complete build
sources = [
    GitSource("https://github.com/Z3Prover/z3.git", "517d907567f4283ad8b48ff9c2a3f6dce838569e"),
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir/z3/

mkdir z3-build && cd z3-build
cmake -DCMAKE_INSTALL_PREFIX=${prefix} \
    -DCMAKE_FIND_ROOT_PATH="${prefix}" \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TARGET_TOOLCHAIN} \
    -DZ3_BUILD_JULIA_BINDINGS=True \
    ..
make -j${nproc}
make install
install_license ${WORKSPACE}/srcdir/z3/LICENSE.txt
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms_libcxxwrap = [
    Platform("armv7l", "linux"; libc="glibc"),
    Platform("x86_64", "linux"; libc="glibc"),
    Platform("x86_64", "macos"),
    Platform("x86_64", "windows")
]

platforms = filter(x->!(x in platforms_libcxxwrap), supported_platforms())

platforms_libcxxwrap = expand_cxxstring_abis(platforms_libcxxwrap)
platforms = expand_cxxstring_abis(platforms)

# The products that we will ensure are always built
products_libcxxwrap = [
    LibraryProduct("libz3", :libz3),
    LibraryProduct("libz3jl", :libz3jl),
    ExecutableProduct("z3", :z3)
]

products = [
    LibraryProduct("libz3", :libz3),
    ExecutableProduct("z3", :z3)
]

# Dependencies that must be installed before this package can be built
dependencies = Dependency[
    Dependency("libcxxwrap_julia_jll")
]

# Build the tarballs, and possibly a `build.jl` as well.
non_reg_ARGS = filter(arg -> arg != "--register", ARGS)

include("../../fancy_toys.jl")

if any(should_build_platform.(triplet.(platforms_libcxxwrap)))
    build_tarballs(non_reg_ARGS, name, version, sources, script, platforms_libcxxwrap, products_libcxxwrap, dependencies; preferred_gcc_version=v"8")
end
if any(should_build_platform.(triplet.(platforms)))
    build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; preferred_gcc_version=v"8")
end


text:
using YaoPlots
include("plot_compose.jl")
include("planar_maps.jl")

function YaoPlots.plot(q::Tait; backend = :planar, kwargs...)
    backend === :compose && return plot_compose(q; kwargs...)
    backend === :planar && return plot_planar(q; kwargs...)
end

function YaoPlots.plot(g::PlanarMultigraph; backend = :planar, kwargs...)
    backend === :planar && return plot_planar(g; kwargs...)
end


text:
export recLinear,∂recLinear

function recLinear(rᵢ)
  rₒ=max(rᵢ,0.)
end
function ∂recLinear(rᵢ)
  rₒ=1-2*sign(rᵢ)
end


text:
# # [Prepare Greenberger–Horne–Zeilinger state with Quantum Circuit](@id example-ghz)

# First, you have to use this package in Julia.

using Yao

# Now, we just define the circuit according to the circuit image below:
# ![ghz](assets/ghz4.png)

circuit = chain(
    4,
    put(1=>X),
    repeat(H, 2:4),
    control(2, 1=>X),
    control(4, 3=>X),
    control(3, 1=>X),
    control(4, 3=>X),
    repeat(H, 1:4),
)

# Let me explain what happens here.

# ## Put single qubit gate X to location 1
# we have an `X` gate applied to the first qubit.
# We need to tell `Yao` to put this gate on the first qubit by

put(4, 1=>X)

# We use Julia's `Pair` to denote the gate and its location in the circuit,
# for two-qubit gate, you could also use a tuple of locations:

put(4, (1, 2)=>swap(2, 1, 2))

# But, wait, why there's no `4` in the definition above? This is because
# all the functions in `Yao` that requires to input the number of qubits as its
# first arguement could be lazy (curried), and let other constructors to infer the total
# number of qubits later, e.g

put(1=>X)

# which will return a lambda that ask for a single arguement `n`.

put(1=>X)(4)

# ## Apply the same gate on different locations

# next we should put Hadmard gates on all locations except the 1st qubits.

# We provide `repeat` to apply the same block repeatly, repeat can take an
# iterator of desired locations, and like `put`, we can also leave the total number
# of qubits there.

repeat(H, 2:4)

# ## Define control gates

# In Yao, we could define controlled gates by feeding a gate to `control`

control(4, 2, 1=>X)

# Like many others, you could leave the number of total qubits there, and infer it
# later.

control(2, 1=>X)

# ## Composite each part together

# This will create a `ControlBlock`, the concept of block in Yao basically
# just means quantum operators, since the quantum circuit itself is a quantum operator,
# we could create a quantum circuit by composite each part of.

# Here, we use `chain` to chain each part together, a chain of quantum operators
# means to apply each operators one by one in the chain. This will create a `ChainBlock`.

circuit = chain(
    4,
    put(1=>X),
    repeat(H, 2:4),
    control(2, 1=>X),
    control(4, 3=>X),
    control(3, 1=>X),
    control(4, 3=>X),
    repeat(H, 1:4),
)

# You can check the type of it with `typeof`

typeof(circuit)

# ## Construct GHZ state from 00...00

# For simulation, we provide a builtin register type called `ArrayReg`,
# we will use the simulated register in this example.

# First, let's create ``|00⋯00⟩``, you can create it with `zero_state`

zero_state(4)

# Or we also provide bit string literals to create arbitrary eigen state

ArrayReg(bit"0000")

# They will both create a register with Julia's builtin `Array` as storage.

# ## Feed Registers to Circuits

# Circuits can be applied to registers with `apply!`

apply!(zero_state(4), circuit)

# or you can use pipe operator `|>`, when you want to chain several operations
# together, here we measure the state right after the circuit for `1000` times

results = zero_state(4) |> circuit |> r->measure(r, nshots=1000)

using StatsBase, Plots

hist = fit(Histogram, Int.(results), 0:16)
bar(hist.edges[1] .- 0.5, hist.weights, legend=:none)

# GHZ state will collapse to ``|0000⟩`` or ``|1111⟩``.

max_stars_repo_name: logankilpatrick/tutorials

max_issues_repo_name: logankilpatrick/tutorials

max_forks_repo_name: logankilpatrick/tutorials


text:
"""
Wrapper around Iterators.Flatten to provide total length.
"""
struct FlattenIteratorWrapper{T}
    element_type::Type{T}
    iter::Iterators.Flatten
    length::Int
end

function FlattenIteratorWrapper(element_type::Type{T}, vals) where {T}
    len = isempty(vals) ? 0 : sum((length(x) for x in vals))
    return FlattenIteratorWrapper(T, Iterators.Flatten(vals), len)
end

Base.iterate(iter::FlattenIteratorWrapper) = Base.iterate(iter.iter)
Base.iterate(iter::FlattenIteratorWrapper, state) = Base.iterate(iter.iter, state)
Base.eltype(iter::FlattenIteratorWrapper) = iter.element_type

function Base.length(iter::FlattenIteratorWrapper)
    return iter.length
end


text:
# maps:
map(x -> x * 10, [1, 2, 3]) #> [10, 20, 30]
cubes = map(x-> Base.power_by_squaring(x, 3), collect(1:5)) #> [1, 8, 27, 64, 125]
map(*, [1, 2, 3], [4, 5, 6]) #> [4, 10, 18]

# do block:
map( x -> begin
            if x == 0 return 0
            elseif iseven(x) return 2
            elseif isodd(x) return 1
            end
          end,
    collect(-3:3)) #> [1,2,1,0,1,2,1]

map(collect(-3:3)) do x
    if x == 0 return 0
    elseif iseven(x) return 2
    elseif isodd(x) return 1
    end
end #> [1,2,1,0,1,2,1]

# filter:
filter( n -> iseven(n), collect(1:10) )#> [2, 4, 6, 8, 10]
filter( n -> n % 2 == 0, collect(1:10) )#> [2, 4, 6, 8, 10]

# comprehensions:
arr0 = [n for n in 1:1000] #> [1,2,...,1000]
# better write it as arr0 = [1:1000]
arr = Float64[x^2 for x in 1:4] #> [1.0,4.0,9.0,16.0]
cubes = [x^3 for x in collect(1:5)] #> [1, 8, 27, 64, 125]
mat1 = [x + y for x in 1:2, y in 1:3] #> creates a 2 x 3 Array{Int64,2}:
# 2  3  4
# 3  4  5
table10 = [x*y for x=1:10, y=1:10] #>
#=
#1   2   3   4   5   6   7   8   9   10
#2   4   6   8  10  12  14  16  18   20
#3   6   9  12  15  18  21  24  27   30
#4   8  12  16  20  24  28  32  36   40
#5  10  15  20  25  30  35  40  45   50
#6  12  18  24  30  36  42  48  54   60
#7  14  21  28  35  42  49  56  63   70
#8  16  24  32  40  48  56  64  72   80
#9  18  27  36  45  54  63  72  81   90
#10  20  30  40  50  60  70  80  90  100
=#

arrany = Any[i * 2 for i in 1:5] #> [2,4,6,8,10]
[ sqrt(exp(i))-j for i = 1:8, j = 1:8]
# 8x8 Array{Float64,2}:
#   0.648721  -0.351279  -1.35128   …  -4.35128  -5.35128   -6.35128
#   1.71828    0.718282  -0.281718     -3.28172  -4.28172   -5.28172
#   3.48169    2.48169    1.48169      -1.51831  -2.51831   -3.51831
#   6.38906    5.38906    4.38906       1.38906   0.389056  -0.610944
#  11.1825    10.1825     9.18249       6.18249   5.18249    4.18249
#  19.0855    18.0855    17.0855    …  14.0855   13.0855    12.0855
#  32.1155    31.1155    30.1155       27.1155   26.1155    25.1155
#  53.5982    52.5982    51.5982       48.5982   47.5982    46.5982