text:
module JqData

import JSON,HTTP
using DataFrames,CSV

export get_token,get_current_token,get_query_count,get_security_info
export get_all_securities,get_index_stocks,get_margincash_stocks,get_marginsec_stocks
export get_locked_shares,get_locked_shares,get_index_stocks,get_index_weights
export get_industries,get_industry,get_industry_stocks
export get_concepts,get_concepts
export get_trade_days,get_all_trade_days
export get_mtss,get_money_flow
export get_billboard_list,get_future_contracts
export get_dominant_future,get_fund_info,get_current_tick
export get_current_ticks,get_extras,get_price,get_price_period
export get_ticks,get_ticks_period,get_factor_values,run_query
export get_fundamentals,get_all_factors,get_pause_stocks,get_alpha101,get_alpha191
export get_fq_factor,get_current_price,get_call_auction

url="https://dataapi.joinquant.com/apis"

"""
    get_token(mob,pwd) - 获取用户凭证
调用其他获取数据接口之前，需要先调用本接口获取token。token被作为用户认证使用，当天有效

{
    "method": "get_token",
    "mob": "135xxxxxxx",
    "pwd": "xxxxxxxxxx",
}
返回 token:

5b6a9ba7b0f572bb6c287e280ed
token是调取数据唯一标识。token过期或者更改用户权限后，可以重新获取。重新获取token后，之前的token会失效。
"""
function get_token(mob,pwd)
    body=Dict("method"=>"get_token","mob"=>mob,"pwd"=>pwd)
    body=JSON.json(body)
    response=HTTP.post(url,"",body)
    String(response.body)
end
"""
    get_current_token(mob,pwd)- 获取用户当前可用凭证
当存在用户有效token时，直接返回原token，如果没有token或token失效则生成新token并返回

{
    "method": "get_current_token",
    "mob": "135xxxxxxx",
    "pwd": "xxxxxxxxxx",
}
返回 token:

5b6a9ba7b0f572bb6c287e280ed
"""
function get_current_token(mob,pwd)
    body=Dict("method"=>"get_current_token","mob"=>"mob","pwd"=>"pwd")
    body=JSON.json(body)
    response=HTTP.post(url,"",body)
    String(response.body)

end
"""
get_query_count(token) - 获取查询剩余条数
查询剩余条数

{
    "method": "get_query_count",
    "token":"5b6a9ba7b0f572bb6c287e280ed"
}
100000
"""
function get_query_count(token)

    body=Dict("method"=>"get_query_count","token"=>token)
    response=HTTP.post(url,"",JSON.json(body))
    parse(Int,String(response.body))
end
"""
get_security_info(token,code) - 获取单个标的信息
获取股票/基金/指数的信息

参数:

code: 证券代码
{
    "method": "get_security_info",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "502050.XSHG"
}
返回:

code: 标的代码
display_name: 中文名称
name: 缩写简称
start_date: 上市日期, [datetime.date] 类型
end_date: 退市日期， [datetime.date] 类型, 如果没有退市则为2200-01-01
type: 类型，stock(股票)，index(指数)，etf(ETF基金)，fja（分级A），fjb（分级B）
parent: 分级基金的母基金代码
code,display_name,name,start_date,end_date,type,parent
502050.XSHG,上证50B,SZ50B,2015-04-27,2200-01-01,fjb,502048.XSHG
"""
function get_security_info(token,code)
    body=Dict("method"=>"get_security_info","token"=>token,"code"=>code)
    dataframe(body)
end

function dataframe(body)

    body=JSON.json(body)
    res=HTTP.post(url,"",body)
    res=String(res.body)
    readtable(IOBuffer(res))
end
"""
get_price(token,code;unit="1d",count=10,end_date="",fq_ref_date="") - 获取指定时间周期的行情数据
获取各种时间周期的bar数据，bar的分割方式与主流股票软件相同， 同时还支持返回当前时刻所在 bar 的数据。get_price 与 get_bars 合并为一个函数

参数：

code: 证券代码
count: 大于0的整数，表示获取bar的条数，不能超过5000
unit: bar的时间单位, 支持如下周期：1m, 5m, 15m, 30m, 60m, 120m, 1d, 1w, 1M。其中m表示分钟，d表示天，w表示周，M表示月
end_date：查询的截止时间，默认是今天
fq_ref_date：复权基准日期，该参数为空时返回不复权数据
{
    "method": "get_price",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "600000.XSHG",
    "count": 10,
    "unit": "1d",
    "end_date": "2018-07-21",
    "fq_ref_date": "2018-07-21"
}
返回：

date: 日期
open: 开盘价
close: 收盘价
high: 最高价
low: 最低价
volume: 成交量
money: 成交额
当unit为1d时，包含以下返回值:
paused: 是否停牌，0 正常；1 停牌
high_limit: 涨停价
low_limit: 跌停价
avg: 当天均价
pre_close：前收价
当code为期货和期权时，包含以下返回值:
open_interest 持仓量
date,open,close,high,low,volume,money,paused,high_limit,low_limit,avg,pre_close
2018-07-09,9.27,9.50,9.53,9.27,22407527,212109327.00,0,10.20,8.34,9.47,9.27
2018-07-10,9.51,9.47,9.55,9.40,12534270,118668133.00,0,10.45,8.55,9.47,9.50
"""
function get_price(token,code;unit="1d",count=10,end_date="",fq_ref_date="")

    body=Dict(
        "method"=>"get_price",
        "token"=>token,
        "code"=>code,
        "unit"=>unit,
        "count"=>count,
        "end_date"=>end_date,
        "fq_ref_date"=>fq_ref_date
    )
    dataframe(body)
end
"""
    get_all_securities(token,code;date="")
"""
function get_all_securities(token,code;date="")

    body=Dict(
        "method"=>"get_all_securities",
        "token"=>token,
        "code"=>code,
        "date"=>date
    )
    dataframe(body)
end
"""
    get_index_stocks(token,code;date="")
获取一个指数给定日期在平台可交易的成分股列表

参数:

code: 指数代码
date: 查询日期
{
    "method": "get_index_stocks",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000300.XSHG",
    "date": "2019-01-09"
}
返回:

股票代码
000001.XSHE
000002.XSHE
"""
function get_index_stocks(token,code;date="")

    body=Dict(
        "method"=>"get_index_stocks",
        "token"=>token,
        "code"=>code,
        "date"=>date
    )
    dataframe(body)
end

"""
    get_margincash_stocks(token;date="") - 获取融资标的列表
参数:

date: 查询日期，默认为前一交易日
{
    "method": "get_margincash_stocks",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "date": "2018-07-02"
}
返回：

返回指定日期上交所、深交所披露的的可融资标的列表
000001.XSHE
000002.XSHE
"""
function get_margincash_stocks(token;date="")

    body=Dict(
        "method"=>"get_margincash_stocks",
        "token"=>token,
         "date"=>date
    )
    dataframe(body)
end

"""
get_marginsec_stocks(token;date="") - 获取融券标的列表
参数:

date: 查询日期，默认为前一交易日
{
    "method": "get_marginsec_stocks",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "date": "2018-08-02"
}
返回：

返回指定日期上交所、深交所披露的的可融券标的列表
000001.XSHE
000002.XSHE
"""
function get_marginsec_stocks(token;date="")

    body=Dict(
        "method"=>"get_marginsec_stocks",
        "token"=>token,
         "date"=>date
    )
    dataframe(body)
end

"""
get_locked_shares(token,code;date="",end_date="") - 获取限售解禁数据
获取指定日期区间内的限售解禁数据

参数：

code: 股票代码
date: 开始日期
end_date: 结束日期
{
    "method": "get_locked_shares",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "600000.XSHG",
    "date": "2010-09-29",
    "end_date": "2018-09-29"
}
返回：

day: 解禁日期
code: 股票代码
num: 解禁股数
rate1: 解禁股数/总股本
rate2: 解禁股数/总流通股本
day,code,num,rate1,rate2
2010-09-29,600000.XSHG,1175406872.0000,0.1024,0.1141
2015-10-14,600000.XSHG,3730694283.0000,0.2000,0.2500
"""
function get_locked_shares(token,code;date="",end_date="")

    body=Dict(
        "method"=>"get_locked_shares",
        "token"=>token,
        "code"=>code,
        "date"=>date,
        "end_date"=>end_date
    )
    dataframe(body)
end

"""
get_index_weights(token,code;date="") - 获取指数成份股权重（月度）
获取指数成份股给定日期的权重数据，每月更新一次

参数：

code: 代表指数的标准形式代码， 形式：指数代码.交易所代码，例如"000001.XSHG"。
date: 查询权重信息的日期，形式："%Y-%m-%d"，例如"2018-05-03"；
{
    "method": "get_index_weights",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000300.XSHG",
    "date": "2018-01-09"
}
返回：

code: 指数代码
display_name: 股票名称
date: 日期
weight: 权重
code,display_name,date,weight
000001.XSHE,平安银行,2018-01-09,0.9730
000002.XSHE,万科A,2018-01-09,1.2870
"""
function get_index_weights(token,code;date="")

    body=Dict(
        "method"=>"get_index_weights",
        "token"=>token,
        "code"=>code,
        "date"=>date
    )
    dataframe(body)
end

"""
get_industries(token,code) - 获取行业列表
按照行业分类获取行业列表

参数：

code：行业代码
sw_l1: 申万一级行业
sw_l2: 申万二级行业
sw_l3: 申万三级行业
jq_l1: 聚宽一级行业
jq_l2: 聚宽二级行业
zjw: 证监会行业
{
    "method": "get_industries",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "sw_l3"
}
返回：

index: 行业代码
name: 行业名称
start_date: 开始日期
index,name,start_date
850111,种子生产III,2014-02-21
850112,粮食种植III,2014-02-21
"""
function get_industries(token,code)

    body=Dict(
        "method"=>"get_industries",
        "token"=>token,
        "code"=>code,
    )
    dataframe(body)
end

"""
get_industry(token,code;date="") - 查询股票所属行业
查询股票所属行业

参数：

code：证券代码
date：查询的日期
{
    "method": "get_industry",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000011.XSHE",
    "date": "2018-12-01"
}
返回：

industry：一级行业代码
industry_code：二级行业代码
industry_name：行业名称
industry,industry_code,industry_name
jq_l1,HY011,房地产指数
jq_l2,HY509,房地产开发指数
sw_l1,801180,房地产I
"""
function get_industry(token,code;date="")

    body=Dict(
        "method"=>"get_industry",
        "token"=>token,
        "code"=>code,
        "date"=>date
    )
    dataframe(body)
end

"""
get_industry_stocks(token,code;date="") - 获取行业成份股
获取在给定日期一个行业的所有股票

参数：

code: 行业编码
date: 查询日期
{
    "method": "get_industry_stocks",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "HY007",
    "date": "2016-03-29"
}
返回：

返回股票代码的list
000001.XSHE
000002.XSHE
"""
function get_industry_stocks(token,code;date="")

    body=Dict(
        "method"=>"get_industry_stocks",
        "token"=>token,
        "code"=>code,
        "date"=>date
    )
    dataframe(body)
end

"""
get_concepts(token) - 获取概念列表
获取概念板块列表

{
    "method": "get_concepts"
    "token": "5b6a9ba7b0f572bb6c287e280ed",
}
返回：

code: 概念代码
name: 概念名称
start_date: 开始日期
code,name,start_date
GN001,参股金融,2013-12-31
GN028,智能电网,2013-12-31
"""

function get_concepts(token)

    body=Dict(
        "method"=>"get_concepts",
        "token"=>token,
    )
    dataframe(body)
end

"""
get_concept_stocks(token,code;date="") - 获取概念成份股
获取在给定日期一个概念板块的所有股票

参数：

code: 概念板块编码
date: 查询日期,
{
    "method": "get_concept_stocks",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "GN036",
    "date": "2016-12-19"
}
返回：

股票代码
000791.XSHE
000836.XSHE
"""
function get_concept_stocks(token,code;date="")

    body=Dict(
        "method"=>"get_concept_stocks",
        "token"=>token,
        "code"=>code,
        "date"=>date
    )
    dataframe(body)
end

"""
get_trade_days(token,date;end_date="") - 获取指定范围交易日
获取指定日期范围内的所有交易日

参数：

date: 开始日期
end_date: 结束日期
{
    "method": "get_trade_days",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "date": "2018-10-09",
    "end_date": "2018-11-18"
}
返回：

交易日日期
2018-10-09
2018-10-10
"""
function get_trade_days(token,date;end_date="")

    body=Dict(
        "method"=>"get_trade_days",
        "token"=>token,
        "date"=>date,
        "end_date"=>end_date
    )
    dataframe(body)
end

"""
get_all_trade_days(token) - 获取所有交易日
{
    "method": "get_all_trade_days"
    "token": "5b6a9ba7b0f572bb6c287e280ed",
}
2005-01-04
2005-01-05
"""
function get_all_trade_days(token)

    body=Dict(
        "method"=>"get_all_trade_days",
        "token"=>token,
    )
    dataframe(body)
end

"""
get_mtss(token,code,date;end_date="") - 获取融资融券信息
获取一只股票在一个时间段内的融资融券信息

参数：

code: 股票代码
date: 开始日期
end_date: 结束日期
{
    "method": "get_mtss",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE",
    "date": "2016-01-04",
    "end_date": "2016-04-01"
}
返回：

date: 日期
sec_code: 股票代码
fin_value: 融资余额(元）
fin_buy_value: 融资买入额（元）
fin_refund_value: 融资偿还额（元）
sec_value: 融券余量（股）
sec_sell_value: 融券卖出量（股）
sec_refund_value: 融券偿还量（股）
fin_sec_value: 融资融券余额（元）
date,sec_code,fin_value,fin_buy_value,fin_refund_value,sec_value,sec_sell_value,sec_refund_value,fin_sec_value
2016-01-04,000001.XSHE,3472611852,152129217,169414153,594640,184100,317900,3479349123
2016-01-05,000001.XSHE,3439316930,143615276,176910198,584540,20800,30900,3445980686
"""
function get_mtss(token,code,date;end_date="")

    body=Dict(
        "method"=>"get_mtss",
        "token"=>token,
        "code"=>code,
        "date"=>date,
        "end_date"=>end_date
    )
    dataframe(body)
end

"""
get_money_flow(token,code,date;end_date="") - 获取资金流信息
获取一只股票在一个时间段内的资金流向数据，仅包含股票数据，不可用于获取期货数据

参数：

code: 股票代码
date: 开始日期
end_date: 结束日期
{
    "method": "get_money_flow",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE",
    "date": "2016-02-01",
    "end_date": "2016-02-04"
}
返回：

date: 日期
sec_code: 股票代码
change_pct: 涨跌幅(%)
net_amount_main: 主力净额(万): 主力净额 = 超大单净额 + 大单净额
net_pct_main: 主力净占比(%): 主力净占比 = 主力净额 / 成交额
net_amount_xl: 超大单净额(万): 超大单：大于等于50万股或者100万元的成交单
net_pct_xl: 超大单净占比(%): 超大单净占比 = 超大单净额 / 成交额
net_amount_l: 大单净额(万): 大单：大于等于10万股或者20万元且小于50万股或者100万元的成交单
net_pct_l: 大单净占比(%): 大单净占比 = 大单净额 / 成交额
net_amount_m: 中单净额(万): 中单：大于等于2万股或者4万元且小于10万股或者20万元的成交单
net_pct_m: 中单净占比(%): 中单净占比 = 中单净额 / 成交额
net_amount_s: 小单净额(万): 小单：小于2万股或者4万元的成交单
net_pct_s: 小单净占比(%): 小单净占比 = 小单净额 / 成交额
date,sec_code,change_pct,net_amount_main,net_pct_main,net_amount_xl,net_pct_xl,net_amount_l,net_pct_l,net_amount_m,net_pct_m,net_amount_s,net_pct_s
2016-02-01,000001.XSHE,-2.00,-6940.54,-16.82,-5296.92,-12.84,-1643.63,-3.98,3782.95,9.17,3157.59,7.65
2016-02-02,000001.XSHE,1.53,1375.48,3.74,2235.87,6.09,-860.39,-2.34,-194.21,-0.53,-1181.27,-3.22
"""
function get_money_flow(token,code,date;end_date="")

    body=Dict(
        "method"=>"get_money_flow",
        "token"=>token,
        "code"=>code,
        "date"=>date,
        "end_date"=>end_date
    )
    dataframe(body)
end

"""
get_billboard_list(token,code,date;end_date="") - 获取龙虎榜数据
获取指定日期区间内的龙虎榜数据

参数：

code: 股票代码
date: 开始日期
end_date: 结束日期
{
    "method": "get_billboard_list",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE",
    "date": "2016-08-01",
    "end_date": "2018-11-29"
}
返回：

code: 股票代码
day: 日期
direction: ALL 表示『汇总』，SELL 表示『卖』，BUY 表示『买』
abnormal_code: 异常波动类型
abnormal_name: 异常波动名称
sales_depart_name: 营业部名称
rank: 0 表示汇总， 1~5 表示买一到买五， 6~10 表示卖一到卖五
buy_value: 买入金额
buy_rate: 买入金额占比(买入金额/市场总成交额)
sell_value: 卖出金额
sell_rate: 卖出金额占比(卖出金额/市场总成交额)
net_value: 净额(买入金额 - 卖出金额)
amount: 市场总成交额
code,day,direction,rank,abnormal_code,abnormal_name,sales_depart_name,buy_value,buy_rate,sell_value,sell_rate,total_value,net_value,amount
000001.XSHE,2017-07-11,ALL,0,106001,涨幅偏离值达7%的证券,,495288143.0000,0.1289,305812442.0000,0.0796,801100585.0000,189475701.0000,3842010171.2900
000001.XSHE,2017-07-11,BUY,1,106001,涨幅偏离值达7%的证券,中信证券股份有限公司上海古北路证券营业部,134111708
"""
function get_billboard_list(token,code,date;end_date="")

    body=Dict(
        "method"=>"get_billboard_list",
        "token"=>token,
        "code"=>code,
        "date"=>date,
        "end_date"=>end_date
    )
    dataframe(body)
end

"""
get_future_contracts(token,code;date="") - 获取期货可交易合约列表
获取某期货品种在指定日期下的可交易合约标的列表

参数：

code: 期货合约品种，如 AG (白银)
date: 指定日期
{
    "method": "get_future_contracts",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "AU",
    "date": "2017-01-05"
}
返回：

某一期货品种在指定日期下的可交易合约标的列表
AU1701.XSGE
AU1702.XSGE
"""
function get_future_contracts(token,code;date="")

    body=Dict(
        "method"=>"get_future_contracts",
        "token"=>token,
        "code"=>code,
        "date"=>date,

    )
    dataframe(body)
end

"""
get_dominant_future(token,code;date="") - 获取主力合约对应的标的
参数：

code: 期货合约品种，如 AG (白银)
date: 指定日期参数，获取历史上该日期的主力期货合约
{
    "method": "get_dominant_future",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "AU",
    "date": "2018-05-05"
}
返回：

主力合约对应的期货合约
AU1812.XSGE
"""
function get_dominant_future(token,code;date="")

    body=Dict(
        "method"=>"get_dominant_future",
        "token"=>token,
        "code"=>code,
        "date"=>date,

    )
    dataframe(body)
end

"""
get_fund_info(token,code;date="") - 基金基础信息数据接口
获取单个基金的基本信息

参数：

code: 基金代码
date: 查询日期， 默认日期是今天。
{
    "method": "get_fund_info",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "519223.OF",
    "date": "2018-12-01"
}
返回：

fund_name: 基金全称
fund_type: 基金类型
fund_establishment_day: 基金成立日
fund_manager: 基金管理人及基本信息
fund_management_fee: 基金管理费
fund_custodian_fee: 基金托管费
fund_status: 基金申购赎回状态
fund_size: 基金规模（季度）
fund_share: 基金份额（季度）
fund_asset_allocation_proportion: 基金资产配置比例（季度）
heavy_hold_stocks: 基金重仓股（季度）
heavy_hold_stocks_proportion: 基金重仓股占基金资产净值比例（季度）
heavy_hold_bond: 基金重仓债券（季度）
heavy_hold_bond_proportion: 基金重仓债券占基金资产净值比例（季度）
{
    "fund_name": "海富通欣荣灵活配置混合型证券投资基金C类",
    "fund_type": "混合型",
    "fund_establishment_day": "2016-09-22",
    "fund_manager": "海富通基金管理有限公司",
    "fund_management_fee": "",
    "fund_custodian_fee": "",
    "fund_status": "",
    "fund_size": "",
    "fund_share": 32345.96,
    "fund_asset_allocation_proportion": "",
    "heavy_hold_stocks": ["600519","601318","601398","000651","600887","600028","000338","600048","601939","000858"],
    "heavy_hold_stocks_proportion": 37.16,
    "heavy_hold_bond": ["111893625","018005","113014"],
    "heavy_hold_bond_proportion": 13.209999999999999
}
"""
function get_fund_info(token,code;date="")

    body=Dict(
        "method"=>"get_fund_info",
        "token"=>token,
        "code"=>code,
        "date"=>date
    )
    dataframe(body)
end

"""
get_current_tick(token,code) - 获取最新的 tick 数据
参数：需要付费

code: 标的代码， 支持股票、指数、基金、期货等。 不可以使用主力合约和指数合约代码。
{
    "method": "get_current_tick",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE"
}
返回：

time: 时间
current: 当前价
high: 截至到当前时刻的日内最高价
low: 截至到当前时刻的日内最低价
volume: 累计成交量
money: 累计成交额
position: 持仓量，期货使用
a1_v~a5_v: 五档卖量
a1_p~a5_p: 五档卖价
b1_v~b5_v: 五档买量
b1_p~b5_p: 五档买价
time,current,high,low,volume,money,position,a1_v,a2_v,a3_v,a4_v,a5_v,a1_p,a2_p,a3_p,a4_p,a5_p,b1_v,b2_v,b3_v,b4_v,b5_v,b1_p,b2_p,b3_p,b4_p,b5_p
20190129150003.000,11.0,11.07,10.77,82663110,904847854.07,,302833,195900,453000,437662,861700,1
"""
function get_current_tick(token,code)

    body=Dict(
        "method"=>"get_current_tick",
        "token"=>token,
        "code"=>code
    )
    dataframe(body)
end

"""
get_current_ticks(token,code) - 获取多标的最新的 tick 数据
参数：需要付费

code: 标的代码， 多个标的使用,分隔。每次请求的标的必须是相同类型。标的类型包括： 股票、指数、场内基金、期货、期权
{
    "method": "get_current_ticks",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE,000002.XSHE,000006.XSHE"
}
返回：

code: 标的代码
time: 时间
current: 当前价
high: 截至到当前时刻的日内最高价
low: 截至到当前时刻的日内最低价
volume: 累计成交量
money: 累计成交额
position: 持仓量，期货使用
a1_v~a5_v: 五档卖量
a1_p~a5_p: 五档卖价
b1_v~b5_v: 五档买量
b1_p~b5_p: 五档买价
code,time,current,high,low,volume,money,position,a1_v,a2_v,a3_v,a4_v,a5_v,a1_p,a2_p,a3_p,a4_p,a5_p,b1_v,b2_v,b3_v,b4_v,b5_v,b1_p,b2_p,b3_p,b4_p,b5_p
000001.XSHE,20190408113000.000,14.05,14.43,13.89,117052113,1666868688.81,,9200,600,9200,50641,71600,14.06,14.07,14.08,14.09,14.1,53900,21800,147100,94536,213900,14.05,14.04,14.03,14.02,14.01
000002.XSHE,20190408113000.000,31.58,32.8,31.54,42866139,1379238397.85,,700,9400,700,6700,1100,31.58
"""
function get_current_ticks(token,code)

    body=Dict(
        "method"=>"get_current_ticks",
        "token"=>token,
        "code"=>code,

    )
    dataframe(body)
end
"""
get_extras(token,code,date;end_date="") - 获取基金净值/期货结算价等
参数：

code: 证券代码
date: 开始日期
end_date: 结束日期
{
    "method": "get_extras",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE",
    "date": "2018-05-29",
    "end_date": "2018-07-06"
}
返回：

date: 日期
is_st: 是否是ST，是则返回 1，否则返回 0。股票使用
acc_net_value: 基金累计净值。基金使用
unit_net_value: 基金单位净值。基金使用
futures_sett_price: 期货结算价。期货使用
futures_positions: 期货持仓量。期货使用
adj_net_value: 场外基金的复权净值。场外基金使用
date,is_st
2018-05-29,0
2018-05-30,0
"""
function get_extras(token,code,date;end_date="")

    body=Dict(
        "method"=>"get_extras",
        "token"=>token,
        "code"=>code,
        "date"=>date,
        "end_date"=>end_date

    )
    dataframe(body)
end

"""
get_price_period(token,code,date;unit="1d",end_date="",fq_ref_date="")
    - 获取指定时间段的行情数据
指定开始时间date和结束时间end_date时间段，获取行情数据

参数：

code: 证券代码
unit: bar的时间单位, 支持如下周期：1m, 5m, 15m, 30m, 60m, 120m, 1d, 1w, 1M。其中m表示分钟，d表示天，w表示周，M表示月
date : 开始时间，不能为空，格式2018-07-03或2018-07-03 10:40:00，如果是2018-07-03则默认为2018-07-03 00:00:00
end_date：结束时间，不能为空，格式2018-07-03或2018-07-03 10:40:00，如果是2018-07-03则默认为2018-07-03 23:59:00
fq_ref_date：复权基准日期，该参数为空时返回不复权数据
注：当unit是1w或1M时，第一条数据是开始时间date所在的周或月的行情。当unit为分钟时，第一条数据是开始时间date所在的一个unit切片的行情。
最大获取1000个交易日数据

{
    "method": "get_price_period",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "600000.XSHG",
    "unit": "30m",
    "date": "2018-12-04 09:45:00",
    "end_date": "2018-12-04 10:40:00",
    "fq_ref_date": "2018-12-18"
}
返回：

date: 日期
open: 开盘价
close: 收盘价
high: 最高价
low: 最低价
volume: 成交量
money: 成交额
当unit为1d时，包含以下返回值:
paused: 是否停牌，0 正常；1 停牌
high_limit: 涨停价
low_limit: 跌停价
当code为期货和期权时，包含以下返回值:
open_interest 持仓量
date,open,close,high,low,volume,money
2018-12-04 10:00,11.00,11.03,11.07,10.97,4302800,47472956.00
2018-12-04 10:30,11.04,11.04,11.06,10.98,3047800,33599476.00
"""
function get_price_period(token,code,date;unit="1d",end_date="",fq_ref_date="")

    body=Dict(
        "method"=>"get_price_period",
        "token"=>token,
        "code"=>code,
        "unit"=>unit,
        "date"=>date,
        "end_date"=>end_date,
        "fq_ref_date"=>fq_ref_date
    )
    dataframe(body)
end

"""
get_ticks(token,code;count=15,end_date="") - 获取tick数据
股票部分， 支持 2010-01-01 至今的tick数据，提供买五卖五数据
期货部分， 支持 2010-01-01 至今的tick数据，提供买一卖一数据。 如果要获取主力合约的tick数据，可以先使用get_dominant_future获取主力合约对应的标的
期权部分，支持 2017-01-01 至今的tick数据，提供买五卖五数据

参数：需要付费

code: 证券代码
count: 取出指定时间区间内前多少条的tick数据，如不填count，则返回end_date一天内的全部tick
end_date: 结束日期，格式2018-07-03或2018-07-03 10:40:00
skip: 默认为true，过滤掉无成交变化的tick数据；
当skip=false时，返回的tick数据会保留从2019年6月25日以来无成交有盘口变化的tick数据。
由于期权成交频率低，所以建议请求期权数据时skip设为false
{
    "method": "get_ticks",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE",
    "count": 15,
    "end_date": "2018-07-03"
}
返回：

time: 时间
current: 当前价
high: 当日最高价
low: 当日最低价
volume: 累计成交量（手）
money: 累计成交额
position: 持仓量，期货使用
a1_v~a5_v: 五档卖量
a1_p~a5_p: 五档卖价
b1_v~b5_v: 五档买量
b1_p~b5_p: 五档买价
time,current,high,low,volume,money,a1_p,a1_v,a2_p,a2_v,a3_p,a3_v,a4_p,a4_v,a5_p,a5_v,b1_p,b1_v,b2_p,b2_v,b3_p,b3_v,b4_p,b4_v,b5_p,b5_v
2018-07-02 14:56:21,8.62,9.05,8.56,1280510.0,1128400132.0,8.62,5006.0,8.63,6549.0,8.64,417.0,8.65,466.0,8.66,816.0,8.61,1134.0,8.6,3960.0,8.59,2054.0,8.58,3171.0,8.57,1710.0
2018-07-02 14:56:24,8.62,9.05,8.56,1280663.0,1128531972.0,8.62,4934.0,8.63,6519.0,8.64,417.0,8.65,4
"""
function get_ticks(token,code;count=15,end_date="")

    body=Dict(
        "method"=>"get_ticks",
        "token"=>token,
        "code"=>code,
        "count"=>count,
        "end_date"=>end_date

    )
    dataframe(body)
end

"""
get_ticks_period(token,code,date;end_date="",skip=true)- 按时间段获取tick数据
股票部分， 支持 2010-01-01 至今的tick数据，提供买五卖五数据
期货部分， 支持 2010-01-01 至今的tick数据，提供买一卖一数据。 如果要获取主力合约的tick数据，可以先使用get_dominant_future获取主力合约对应的标的
期权部分，支持 2017-01-01 至今的tick数据，提供买五卖五数据

参数：需要付费

code: 证券代码
date: 开始时间，格式2018-07-03或2018-07-03 10:40:00
end_date: 结束时间，格式2018-07-03或2018-07-03 10:40:00
skip: 默认为true，过滤掉无成交变化的tick数据；
当skip=false时，返回的tick数据会保留从2019年6月25日以来无成交有盘口变化的tick数据。
注：
如果时间跨度太大、数据量太多则可能导致请求超时，所有请控制好data-end_date之间的间隔！

{
    "method": "get_ticks_period",
    "token":"5b6a9ba7b0f572bb6c287e280ed"
    "code": "CU1906.XSGE",
    "date": "2019-03-27 21:40:01",
    "end_date": "2019-03-28 09:40:04"
}
返回：

time: 时间
current: 当前价
high: 当日最高价
low: 当日最低价
volume: 累计成交量（手）
money: 累计成交额
position: 持仓量，期货使用
a1_v~a5_v: 五档卖量
a1_p~a5_p: 五档卖价
b1_v~b5_v: 五档买量
b1_p~b5_p: 五档买价
time,current,high,low,volume,money,position,a1_p,a1_v,b1_p,b1_v
2019-03-27 21:40:11,48480.0,48500.0,48430.0,5458.0,1322750300.0,128176.0,48480.0,8.0,48470.0,18.0
2019-03-27 21:40:11.500000,48480.0,48500.0,48430.0,5464.0,1324204700.0,128178.0,48490.0,39.0,484
"""
function get_ticks_period(token,code,date;end_date="",skip=true)

    body=Dict(
        "method"=>"get_ticks_period",
        "token"=>token,
        "code"=>code,
        "date"=>date,
        "end_date"=>end_date,
        "skip"=>skip
    )
    dataframe(body)
end

"""
get_factor_values(token,code,columns,date;end_date="") - 聚宽因子库数据
获取因子值的 API，点击查看因子列表

参数：需要付费

code: 单只股票代码
columns: 因子名称，因子名称，多个因子用逗号分隔
date: 开始日期
end_date: 结束日期
{
    "method": "get_factor_values",
    "token":"5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE",
    "date": "2019-01-20",
    "end_date":"2019-02-07",
    "columns":"net_profit_ratio,cfo_to_ev"
}
返回：

date：日期
查询因子值
注：

为保证数据的连续性，所有数据基于后复权计算
为了防止单次返回数据时间过长，尽量较少查询的因子数和时间段
如果第一次请求超时，尝试重试
date,cfo_to_ev,net_profit_ratio
2019-01-21,0.009278,0.217480
2019-01-22,0.009281,0.217480
"""
function get_factor_values(token,code,columns,date;end_date="")

    body=Dict(
        "method"=>"get_factor_values",
        "token"=>token,
        "code"=>code,
        "date"=>date,
        "end_date"=>end_date,
        "columns"=>columns
    )
    dataframe(body)
end

"""
run_query(token,table,columns,conditions,count) - 模拟JQDataSDK的run_query方法
run_query api 是模拟了JQDataSDK run_query方法获取财务、宏观、期权等数据
可查询的数据内容请查看JQData文档

以查询上市公司分红送股（除权除息）数据为例：

参数：

table: 要查询的数据库和表名，格式为 database + . + tablename 如finance.STK_XR_XD
columns: 所查字段，为空时则查询所有字段，多个字段中间用,分隔。如id,company_id，columns不能有空格等特殊字符
conditions: 查询条件，可以为空，格式为report_date#>=#2006-12-01&report_date#<=#2006-12-31，条件内部#号分隔，格式： column # 判断符 # value，多个条件使用&号分隔，表示and，conditions不能有空格等特殊字符
count: 查询条数，count为空时默认1条，最多查询1000条
{
    "method": "run_query",
    "token":"5b6a9ba7b0f572bb6c287e280ed",
    "table":"finance.STK_XR_XD",
    "columns":"company_id,company_name,code,report_date",
    "conditions":"report_date#=#2006-12-01",
    "count":10
}
返回：

返回的结果顺序为生成时间的顺序
company_id,company_name,code,report_date
420600103,福建省青山纸业股份有限公司,600103.XSHG,2006-12-01
430000506,中润资源投资股份有限公司,000506.XSHE,2006-12-01
注：run_query api 只是简单地模拟了python的sqlalchemy.orm.query.Query方法，不能支持复杂的搜索。想要更好查询体验，可以使用JQDataSDK。
"""
function run_query(token,table,columns,conditions,count)

    body=Dict(
        "method"=>"run_query",
        "token"=>token,
        "table"=>table,
        "columns"=>columns,
        "conditions"=>conditions,
        "count"=>count
    )
    dataframe(body)
end

"""
get_fundamentals(token,code,table,columns,date,count) - 获取基本财务数据
查询股票的市值数据、资产负债数据、现金流数据、利润数据、财务指标数据. 详情通过财务数据列表查看!

参数：

table: 要查询表名，可选项balance，income，cash_flow，indicator，valuation，bank_indicator，security_indicator，insurance_indicator
columns: 所查字段，为空时则查询所有字段，多个字段中间用,分隔。如id,company_id，columns不能有空格等特殊字符
code: 证券代码，多个标的使用,分隔
date: 查询日期2019-03-04或者年度2018或者季度2018q1 2018q2 2018q3 2018q4
count: 查询条数，最多查询1000条。不填count时按date查询
{
    "method": "get_fundamentals",
    "token":"5b6a9ba7b0f572bb6c287e280ed"
    "table":"valuation",
    "columns":"code,day,pb_ratio,ps_ratio,capitalization,circulating_cap",
    "code":"000001.XSHE,000002.XSHE",
    "date":"2016-12-04",
    "count": 4
}
返回：

返回的结果按日期顺序
code,day,pb_ratio,ps_ratio,capitalization,circulating_cap
000001.XSHE,2016-12-03,0.9198,1.5328,1717041.1250,1463118.0000
000001.XSHE,2016-12-04,0.9198,1.5328,1717041.1250,1463118.0000
000002.XSHE,2016-12-03,2.9081,1.2531,1103915.2500,970810.7500
000002.XSHE,2016-12-04,2.9081,1.2531,1103915.2500,970810.7500
"""
function get_fundamentals(token,code,table,columns,date,count)

    body=Dict(
        "method"=>"get_fundamentals",
        "token"=>token,
        "table"=>table,
        "columns"=>columns,
        "code"=>code,
        "date"=>date,
        "count"=>count
    )
    dataframe(body)
end

"""
get_all_factors(token) 获取聚宽因子库中所有因子的信息
获取聚宽因子库中所有因子的信息

{
    "method": "get_all_factors",
    "token":"5b6a9ba7b0f572bb6c287e280ed"
}
返回：

factor 因子代码
factor_intro 因子名称
category 因子分类
category_intro 分类名称
factor,factor_intro,category,category_intro
administration_expense_ttm,管理费用TTM,basics,基础科目及衍生类因子
asset_impairment_loss_ttm,资产减值损失TTM,basics,基础科目及衍生类因子
"""
function get_all_factors(token)

    body=Dict(
        "method"=>"get_all_factors",
        "token"=>token,
    )
    dataframe(body)
end

"""
get_pause_stocks(token)获取停牌股票列表
获取某日停牌股票列表

参数：

date 查询日期，date为空时默认为今天
{
    "method": "get_pause_stocks",
    "token":"5b6a9ba7b0f572bb6c287e280ed",
    "date": "2019-05-14"
}
返回：

股票代码列表
000029.XSHE
000333.XSHE
"""
function get_pause_stocks(token)

    body=Dict(
        "method"=>"get_pause_stocks",
        "token"=>token,
    )
    dataframe(body)
end

"""
get_alpha101(token,code,func_name;date="") 获取 Alpha 101 因子
因子来源： 根据 WorldQuant LLC 发表的论文 101 Formulaic Alphas 中给出的 101 个 Alphas 因子公式，我们将公式编写成了函数，方便大家使用。
需要付费
详细介绍： 函数计算公式、API 调用方法，输入输出值详情请见:数据 - Alpha 101.

参数：

code: 标的代码， 多个标的使用,分隔。建议每次请求的标的都是相同类型。支持最多1000个标的查询
func_name: 查询函数名称，如alpha_001，alpha_002等
date: 查询日期
{
    "method": "get_alpha101",
    "token":"5b6a9ba7b0f572bb6c287e280ed",
    "code":"000001.XSHE,000002.XSHE,000004.XSHE",
    "func_name":"alpha_001",
    "date":"2018-04-24"
}
返回：

股票代码
因子值
code,alpha_001
000001.XSHE,0.17
000002.XSHE,0.17
000004.XSHE,-0.17
"""
function get_alpha101(token,code,func_name;date="")

    body=Dict(
        "method"=>"get_alpha101",
        "token"=>token,
        "code"=>code,
        "func_name"=>func_name,
        "date"=>date
    )
    dataframe(body)
end

"""
get_alpha191(token,code,func_name;date="") 获取 Alpha 191 因子
因子来源： 根据国泰君安数量化专题研究报告 - 基于短周期价量特征的多因子选股体系给出了 191 个短周期交易型阿尔法因子。为了方便用户快速调用，我们将所有Alpha191因子基于股票的后复权价格做了完整的计算。用户只需要指定fq='post’即可获取全新计算的因子数据。
需要付费
详细介绍： 函数计算公式、API 调用方法，输入输出值详情请见:数据 - Alpha 191.

参数：

code: 标的代码， 多个标的使用,分隔。建议每次请求的标的都是相同类型。支持最多1000个标的查询
func_name: 查询函数名称，如alpha_001，alpha_002等
date: 查询日期
{
    "method": "get_alpha191",
    "token":"5b6a9ba7b0f572bb6c287e280ed",
    "code":"000001.XSHE,000002.XSHE,000004.XSHE",
    "func_name":"alpha_003",
    "date":"2018-04-24"
}
返回：

股票代码
因子值
code,alpha_003
000001.XSHE,0.55000000
000002.XSHE,0.27000000
000004.XSHE,-0.17000000
"""
function get_alpha191(token,code,func_name;date="")

    body=Dict(
        "method"=>"get_alpha191",
        "token"=>token,
        "code"=>code,
        "func_name"=>func_name,
        "date"=>date
    )
    dataframe(body)
end

"""
get_fq_factor(token,code,date;fq="pre",end_date="") 获取股票和基金复权因子
根据交易时间获取股票和基金复权因子值
参数：

code: 单只标的代码
fq: 复权选项 - pre 前复权； post后复权
date: 开始日期
end_date: 结束日期
{
    "method": "get_fq_factor",
    "token":"5b6a9ba7b0f572bb6c287e280ed",
    "code":"000001.XSHE",
    "fq":"pre",
    "date":"2019-06-17",
    "end_date":"2019-07-17"
}
返回：

date: 对应交易日
标的因子值
date,000001.XSHE
2019-06-25,0.989576
2019-06-26,1.000000
"""
function get_fq_factor(token,code,date;fq="pre",end_date="")

    body=Dict(
        "method"=>"get_fq_factor",
        "token"=>token,
        "code"=>code,
        "fq"=>fq,
        "end_date"=>end_date,
        "date"=>date
    )
    dataframe(body)
end

"""
get_current_price(token,code) 获取标的当前价
获取标的的当期价，等同于最新tick中的当前价
参数：

code: 标的代码， 多个标的使用,分隔。建议每次请求的标的都是相同类型。
{
    "method": "get_current_price",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE,600600.XSHG"
}
返回：

code: 标的代码
current: 当前价格
code,current
000001.XSHE,13.35
600600.XSHG,42.4
"""
function get_current_price(token,code)

    body=Dict(
        "method"=>"get_current_price",
        "token"=>token,
        "code"=>code,
    )
    dataframe(body)
end

"""
get_call_auction(token,code,date;end_date="") 获取集合竞价时的tick数据
获取指定时间区间内集合竞价时的tick数据
参数：无数据返回

code: 标的代码， 多个标的使用,分隔。支持最多100个标的查询。
date: 开始日期
end_date: 结束日期
{
    "method": "get_call_auction",
    "token": "5b6a9ba7b0f572bb6c287e280ed",
    "code": "000001.XSHE,000002.XSHE"
    "date":"2019-09-20",
    "end_date":"2019-09-23"
}
返回：

code: 标的代码
time 时间 datetime
current 当前价 float
volume 累计成交量（股）
money 累计成交额
a1_v~a5_v: 五档卖量
a1_p~a5_p: 五档卖价
b1_v~b5_v: 五档买量
b1_p~b5_p: 五档买价
code,time,current,volume,money,a1_v,a2_v,a3_v,a4_v,a5_v,a1_p,a2_p,a3_p,a4_p,a5_p,b1_v,b2_v,b3_v,b4_v,b5_v,b1_p,b2_p,b3_p,b4_p,b5_p
000001.XSHE,2019-09-20 09:25:03,14.9500,3917700,5856.9600,511751,55200,46700,471356,806000,14.9500,14.9600,14.9700,14.9800,14.9900,556400,229100,151400,179600,115500,14.9400,14.9300,14.9200,14.9100,14.9000
000002.XSHE,2019-09-20 09:25:03,26.8900,260700,701.0200,17280,16500,3700,1500,4700,26.8900,26.90
"""
function get_call_auction(token,code,date;end_date="")

    body=Dict(
        "method"=>"get_call_auction",
        "token"=>token,
        "code"=>code,
        "date"=>date,
        "end_date"=>end_date
    )
    dataframe(body)
end

end # module


text:
@testset "Sign flip" begin
    @test one(BFloat16sr) == -(-(one(BFloat16sr)))
    @test zero(BFloat16sr) == -(zero(BFloat16sr))
end

@testset "Integer promotion" begin
    f = BFloat16sr(1)
    @test 2f == BFloat16sr(2)
    @test 0f == BFloat16sr(0)
end

@testset "NaN and Inf" begin
    @test isnan(NaNB16sr)
    @test ~isfinite(NaNB16sr)
    @test ~isfinite(InfB16sr)

    N = 1000
    for i in 1:N
        @test InfB16sr == BFloat16_stochastic_round(Inf32)
        @test -InfB16sr == BFloat16_stochastic_round(-Inf32)
        @test isnan(BFloat16_stochastic_round(NaN32))
    end
end

@testset "No stochastic round to NaN" begin
    f1 = nextfloat(0f0)
    f2 = prevfloat(0f0)
    for i in 1:100
        @test isfinite(BFloat16_stochastic_round(f1))
        @test isfinite(BFloat16_stochastic_round(f2))
    end
end

@testset "Odd floats are never round away" begin
    N = 100_000

    f_odd = prevfloat(one(BFloat16sr))
    f_odd_f32 = Float32(f_odd)
    for _ = 1:N
        @test f_odd == BFloat16sr(f_odd_f32)
        @test f_odd == BFloat16_stochastic_round(f_odd_f32)
    end
end

@testset "Even floats are never round away" begin
    N = 100_000

    f_odd = prevfloat(prevfloat(one(BFloat16sr)))
    f_odd_f32 = Float32(f_odd)
    for _ = 1:N
        @test f_odd == BFloat16sr(f_odd_f32)
        @test f_odd == BFloat16_stochastic_round(f_odd_f32)
    end
end

@testset "Rounding" begin
    @test 1 == Int(round(BFloat16sr(1.2)))
    @test 1 == Int(floor(BFloat16sr(1.2)))
    @test 2 == Int(ceil(BFloat16sr(1.2)))

    @test -1 == Int(round(BFloat16sr(-1.2)))
    @test -2 == Int(floor(BFloat16sr(-1.2)))
    @test -1 == Int(ceil(BFloat16sr(-1.2)))
end

@testset "Nextfloat prevfloat" begin
    o = one(BFloat16sr)
    @test o == nextfloat(prevfloat(o))
    @test o == prevfloat(nextfloat(o))
end

@testset "Comparisons" begin
    @test BFloat16sr(1)   <  BFloat16sr(2)
    @test BFloat16sr(1f0) <  BFloat16sr(2f0)
    @test BFloat16sr(1.0) <  BFloat16sr(2.0)
    @test BFloat16sr(1)   <= BFloat16sr(2)
    @test BFloat16sr(1f0) <= BFloat16sr(2f0)
    @test BFloat16sr(1.0) <= BFloat16sr(2.0)
    @test BFloat16sr(2)   >  BFloat16sr(1)
    @test BFloat16sr(2f0) >  BFloat16sr(1f0)
    @test BFloat16sr(2)   >= BFloat16sr(1)
    @test BFloat16sr(2f0) >= BFloat16sr(1f0)
    @test BFloat16sr(2.0) >= BFloat16sr(1.0)
end

@testset "1.0 always to 1.0" begin
    for i = 1:10000
        @test 1.0f0 == Float32(BFloat16sr(1.0f0))
        @test 1.0f0 == Float32(BFloat16_stochastic_round(1.0f0))
    end
end

function test_chances_round_bf16(f32::Float32;N::Int=100_000)
    p = BFloat16_chance_roundup(f32)

    f16_round = BFloat16sr(f32)
    if Float32(f16_round) <= f32
        f16_rounddown = f16_round
        f16_roundup = nextfloat(f16_round)
    else
        f16_roundup = f16_round
        f16_rounddown = prevfloat(f16_round)
    end

    Ndown = 0
    Nup = 0
    for _ in 1:N
        f16 = BFloat16_stochastic_round(f32)
        if f16 == f16_rounddown
            Ndown += 1
        elseif f16 == f16_roundup
            Nup += 1
        end
    end

    return Ndown,Nup,N,p
end

@testset "Test for N(0,1)" begin
    for x in randn(Float32,10_000)
        Ndown,Nup,N,p = test_chances_round_bf16(x)
        @test Ndown + Nup == N
        @test isapprox(Ndown/N,1-p,atol=2e-2)
        @test isapprox(Nup/N,p,atol=2e-2)
    end
end

@testset "Test for U(0,1)" begin
    for x in rand(Float32,10_000)
        Ndown,Nup,N,p = test_chances_round_bf16(x)
        @test Ndown + Nup == N
        @test isapprox(Ndown/N,1-p,atol=2e-2)
        @test isapprox(Nup/N,p,atol=2e-2)
    end
end

@testset "Test for powers of two" begin
    for x in Float32[2,4,8,16,32,64,128,256]
        Ndown,Nup,N,p = test_chances_round_bf16(x)
        @test Ndown + Nup == N
        @test isapprox(Ndown/N,1-p,atol=2e-2)
        @test isapprox(Nup/N,p,atol=2e-2)
    end

    for x in -Float32[2,4,8,16,32,64,128,256]
        Ndown,Nup,N,p = test_chances_round_bf16(x)
        @test Ndown + Nup == N
        @test isapprox(Ndown/N,1-p,atol=2e-2)
        @test isapprox(Nup/N,p,atol=2e-2)
    end

    for x in Float32[1/2,1/4,1/8,1/16,1/32,1/64,1/128,1/256]
        Ndown,Nup,N,p = test_chances_round_bf16(x)
        @test Ndown + Nup == N
        @test isapprox(Ndown/N,1-p,atol=2e-2)
        @test isapprox(Nup/N,p,atol=2e-2)
    end

    for x in -Float32[1/2,1/4,1/8,1/16,1/32,1/64,1/128,1/256]
        Ndown,Nup,N,p = test_chances_round_bf16(x)
        @test Ndown + Nup == N
        @test isapprox(Ndown/N,1-p,atol=2e-2)
        @test isapprox(Nup/N,p,atol=2e-2)
    end
end

@testset "Test for subnormals" begin

    floatminBF16 = reinterpret(UInt32,Float32(floatmin(BFloat16sr)))
    minposBF16 = reinterpret(UInt32,Float32(nextfloat(zero(BFloat16sr))))

    N = 10_000
    subnormals = reinterpret.(Float32,rand(minposBF16:floatminBF16,N))
    for x in subnormals
        Ndown,Nup,N,p = test_chances_round_bf16(x)
        @test Ndown + Nup == N
        @test isapprox(Ndown/N,1-p,atol=2e-2)
        @test isapprox(Nup/N,p,atol=2e-2)
    end

    for x in -subnormals
        Ndown,Nup,N,p = test_chances_round_bf16(x)
        @test Ndown + Nup == N
        @test isapprox(Ndown/N,1-p,atol=2e-2)
        @test isapprox(Nup/N,p,atol=2e-2)
    end
end

ext: jl


text:
using Plots

t = 0:0.001:2pi
x = t.*cos.(t)
y = t.*sin.(t)

plot(x, y)
savefig("archimedean_spiral.png")


text:
# UnitCommitment.jl: Optimization Package for Security-Constrained Unit Commitment
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.

function set_warm_start!(model::JuMP.Model, solution::AbstractDict)::Nothing
    instance, T = model[:instance], model[:instance].time
    is_on = model[:is_on]
    for g in instance.units
        for t in 1:T
            JuMP.set_start_value(is_on[g.name, t], solution["Is on"][g.name][t])
            JuMP.set_start_value(
                switch_on[g.name, t],
                solution["Switch on"][g.name][t],
            )
            JuMP.set_start_value(
                switch_off[g.name, t],
                solution["Switch off"][g.name][t],
            )
        end
    end
    return
end


text:
using DiffEqOperators, Test

@testset "Auxiliary functions for GhostDerivativeOperator" begin
    # check length and size functions
    L = CenteredDifference(2, 2, 1., 10)
    Q = RobinBC((-1.2, .3, .5), (.2, .5, -30.5), 1.)
    A = L * Q

    @test ndims(A) == 2
    @test size(A) == (10, 10)
    @test size(A, 1) == 10
    @test length(A) == 100
end


text:
# Main entry point
function create_columns_from_iterabletable(itr; sel_cols=:all, na_representation=:datavalue, errorhandling=:error)
    in(errorhandling, (:error, :returnvalue)) || throw(ArgumentError("'$errorhandling' is not a valid argument for errorhandling."))
    in(na_representation, (:datavalue, :missing)) || throw(ArgumentError("'$na_representation' is not a valid argument for na_representation."))

    if TableTraits.isiterabletable(itr)===false
        if errorhandling==:error
            throw(ArgumentError("itr is not a table."))
        elseif errorhandling==:returnvalue
            return nothing
        end
    else

        array_factory = if na_representation==:datavalue
                (t,rows) -> begin
                    if t <: DataValue
                        return DataValueArray{eltype(t)}(rows)
                    else
                        return Array{t}(undef, rows)
                    end
                end
            elseif na_representation==:missing
                (t,rows) -> begin
                    if t <: DataValue
                        return Array{Union{eltype(t),Missing}}(undef, rows)
                    else
                        return Array{t}(undef, rows)
                    end
                end
            end

        itr2 = IteratorInterfaceExtensions.getiterator(itr)
        return _collect_columns(itr2, Base.IteratorSize(itr2), array_factory, sel_cols, errorhandling)
    end
end

function collect_empty_columns(itr::T, ::Base.EltypeUnknown, array_factory, sel_cols, errorhandling) where {T}
    S = Core.Compiler.return_type(first, Tuple{T})
    if S == Union{} || !(S <: NamedTuple)
        if errorhandling==:error
            throw(ArgumentError("itr is not a table."))
        elseif errorhandling==:returnvalue
            return nothing
        end
    end
    dest = getdest(S,0, array_factory, sel_cols)
    return collect(values(dest)), collect(keys(dest))
end

function collect_empty_columns(itr::T, ::Base.HasEltype, array_factory, sel_cols, errorhandling) where {T}
    if eltype(itr) <: NamedTuple
        dest = getdest(eltype(itr),0, array_factory, sel_cols)
        return collect(values(dest)), collect(keys(dest))
    else
        if errorhandling==:error
            throw(ArgumentError("itr is not a table."))
        elseif errorhandling==:returnvalue
            return nothing
        end
    end
end

function getdest(T, n, array_factory, sel_cols)
    if sel_cols==:all
        return NamedTuple{fieldnames(T)}(tuple((array_factory(fieldtype(T,i),n) for i in 1:length(fieldnames(T)))...))
    else
        return NamedTuple{fieldnames(T)}(tuple((i in sel_cols ? array_factory(fieldtype(T,i),n) : nothing for i in 1:length(fieldnames(T)))...))
    end
end

@generated function _setrow(dest::NamedTuple{NAMES,TYPES}, i, el::T) where {T,NAMES,TYPES}
    push_exprs = Expr(:block)
    for col_idx in 1:length(fieldnames(T))
        if fieldtype(TYPES, col_idx)!==Nothing
            if fieldtype(TYPES, col_idx) == Array{Any,1} && fieldtype(T, col_idx) == DataValue{Any}
                ex = :( dest[$col_idx][i] = get(el[$col_idx], missing) )
            else
                ex = :( dest[$col_idx][i] = el[$col_idx] )
            end
            push!(push_exprs.args, ex)
        end
    end

    return push_exprs
end

@generated function _pushrow(dest::NamedTuple{NAMES,TYPES}, el::T) where {T,NAMES,TYPES}
    push_exprs = Expr(:block)
    for col_idx in 1:length(fieldnames(T))
        if fieldtype(TYPES, col_idx)!==Nothing
            if fieldtype(TYPES, col_idx) == Array{Any,1} && fieldtype(T, col_idx) == DataValue{Any}
                ex = :( push!(dest[$col_idx], get(el[$col_idx], missing)) )
            else
                ex = :( push!(dest[$col_idx], el[$col_idx]) )
            end
            push!(push_exprs.args, ex)
        end
    end

    return push_exprs
end

function _collect_columns(itr, ::Union{Base.HasShape, Base.HasLength}, array_factory, sel_cols, errorhandling)
    y = iterate(itr)
    y===nothing && return collect_empty_columns(itr, Base.IteratorEltype(itr), array_factory, sel_cols, errorhandling)

    if !(typeof(y[1])<:NamedTuple)
        if errorhandling==:error
            throw(ArgumentError("itr is not a table."))
        elseif errorhandling==:returnvalue
            return nothing
        end
    end

    dest = getdest(typeof(y[1]), length(itr), array_factory, sel_cols)

    _setrow(dest,1,y[1])

    _collect_to_columns!(dest, itr, 2, y[2], sel_cols, errorhandling)
end

function _collect_to_columns!(dest::T, itr, offs, st, sel_cols, errorhandling) where {T<:NamedTuple}
    i = offs
    y = iterate(itr,st)
    while y!==nothing
        _setrow(dest,i,y[1])
        i += 1
        y = iterate(itr,y[2])
    end

    if sel_cols==:all
        return collect(values(dest)), collect(keys(dest))
    else
        names_to_use = tuple((fieldname(T,i) for i in sel_cols)...)
        r = NamedTuple{names_to_use}(dest)
        return collect(values(r)), collect(keys(r))
    end
end

function _collect_columns(itr, ::Base.SizeUnknown, array_factory, sel_cols, errorhandling)
    y = iterate(itr)
    y===nothing && return collect_empty_columns(itr, Base.IteratorEltype(itr), array_factory, sel_cols, errorhandling)

    if !(typeof(y[1])<:NamedTuple)
        if errorhandling==:error
            throw(ArgumentError("itr is not a table."))
        elseif errorhandling==:returnvalue
            return nothing
        end
    end

    dest = getdest(typeof(y[1]), 1, array_factory, sel_cols)

    _setrow(dest,1,y[1])

    _grow_to_columns!(dest, itr, y[2], sel_cols, errorhandling)
end

function _grow_to_columns!(dest::T, itr, st, sel_cols, errorhandling) where {T<:NamedTuple}
    y = iterate(itr, st)
    while y!==nothing
        _pushrow(dest, y[1])
        y = iterate(itr,y[2])
    end

    if sel_cols==:all
        return collect(values(dest)), collect(keys(dest))
    else
        names_to_use = tuple((fieldname(T,i) for i in sel_cols)...)
        r = NamedTuple{names_to_use}(dest)
        return collect(values(r)), collect(keys(r))
    end
end


text:
using Pkg
Pkg.activate(".")

using Negotiations

params = parameter_set_from_config("test/test-config.yaml")
include("test/create-db.jl")
db = load_database("test.sqlite")
model = setup_model(params, db)
rule = BoundedConfidence(bc = 2.0, inertia = 10.0)
simulate(model, rule, 2, db, batchname = "test")


text:
module ReservoirComputing

using Adapt
using CellularAutomata
using Distances
using Distributions
using GaussianProcesses
using LIBSVM
using LinearAlgebra
using MLJLinearModels
using NNlib
using Optim
using SparseArrays
using Statistics

export NLADefault, NLAT1, NLAT2, NLAT3
export StandardStates, ExtendedStates, PaddedStates, PaddedExtendedStates
export StandardRidge, LinearModel
export AbstractLayer, create_layer
export WeightedLayer, DenseLayer, SparseLayer, MinimumLayer, InformedLayer, NullLayer
export BernoulliSample, IrrationalSample
export GaussianProcess
export AbstractReservoir, create_reservoir
export RandSparseReservoir, PseudoSVDReservoir, DelayLineReservoir
export DelayLineBackwardReservoir, SimpleCycleReservoir, CycleJumpsReservoir, NullReservoir
export RNN, MRNN, GRU, GRUParams, FullyGated, Variant1, Variant2, Variant3, Minimal
export ESN, Default, Hybrid, train
export RECA, train
export RandomMapping, RandomMaps
export Generative, Predictive, OutputLayer

#define global types
abstract type AbstractReservoirComputer end
abstract type AbstractOutputLayer end
abstract type AbstractPrediction end
#training methods
abstract type AbstractLinearModel end
abstract type AbstractGaussianProcess end
abstract type AbstractSupportVector end
#should probably move some of these
abstract type AbstractVariation end
abstract type AbstractGRUVariant end

#general output layer struct
struct OutputLayer{T,I,S,L} <: AbstractOutputLayer
    training_method::T
    output_matrix::I
    out_size::S
    last_value::L
end

#prediction types
"""
    Generative(prediction_len)

This prediction methodology allows the models to produce an autonomous prediction, feeding the prediction into itself to generate the next step.
The only parameter needed is the number of steps for the prediction.
"""
struct Generative{T} <: AbstractPrediction
    prediction_len::T
end

struct Predictive{I,T} <: AbstractPrediction
    prediction_data::I
    prediction_len::T
end

"""
    Predictive(prediction_data)

Given a set of labels as ```prediction_data``` this method of prediction will return the correspinding labels in a standard Machine Learning fashion.
"""
function Predictive(prediction_data)
    prediction_len = size(prediction_data, 2)
    Predictive(prediction_data, prediction_len)
end

#general
include("states.jl")
include("predict.jl")

#general training
include("train/linear_regression.jl")
include("train/gaussian_regression.jl")
include("train/supportvector_regression.jl")

#esn
include("esn/esn_input_layers.jl")
include("esn/esn_reservoirs.jl")
include("esn/esn_reservoir_drivers.jl")
include("esn/echostatenetwork.jl")
include("esn/esn_predict.jl")

#reca
include("reca/reca.jl")
include("reca/reca_input_encodings.jl")

end #module

max_stars_repo_name: MartinuzziFrancesco/EchoStateNetwork

max_issues_repo_name: MartinuzziFrancesco/EchoStateNetwork

max_forks_repo_name: MartinuzziFrancesco/EchoStateNetwork


text:
### A Pluto.jl notebook ###
# v0.12.18

using Markdown
using InteractiveUtils

# ╔═╡ 92081fb8-5d90-11eb-2078-ddbf87421051
begin
	using ReinforcementLearning
	using Flux
	using Statistics
	using Plots
	using Distributions
end

# ╔═╡ 3254385c-5d90-11eb-2c99-07a3a40ae467
md"""
Again, we'll describe the car rental problem with a distributional model.
"""

# ╔═╡ a1a5176c-5d90-11eb-2ad6-2f108e1531e2
begin
	const PoissonUpperBound = 10
	const MaxCars= 20
	const MaxMoves = 5
	const CostPerMove = 2
	const CarRentalCartesianIndices = CartesianIndices((0:MaxCars,0:MaxCars))
	const CarRentalLinearIndices = LinearIndices((0:MaxCars,0:MaxCars))
	const Actions = -MaxMoves:MaxMoves
	const RequestDist_1 = Poisson(3)
	const RequestDist_2 = Poisson(4)
	const ReturnDist_1 = Poisson(3)
	const ReturnDist_2 = Poisson(2)

	decode_state(s::Int) = Tuple(CarRentalCartesianIndices[s])
	encode_state(s1::Int, s2::Int) = CarRentalLinearIndices[CartesianIndex(s1+1, s2+1)]
	decode_action(a::Int) = a - MaxMoves - 1
	encode_action(a::Int) = a + MaxMoves + 1

	function merge_prob(dist)
		merged = Dict()
		for (s′, r, p) in dist
			if haskey(merged, (s′, r))
				merged[(s′, r)] += p
			else
				merged[(s′, r)] = p
			end
		end
		[(r, false, s′) => p for ((s′, r), p) in merged]
	end

	function nextstep(state::Int, action::Int)
		(s1, s2), a = decode_state(state), decode_action(action)
		move = a > 0 ? min(a, s1) : max(a, -s2)
		reward = -CostPerMove*abs(move)
		s1′, s2′ = min(s1 - move, MaxCars), min(s2 + move, MaxCars)
		merge_prob(
			(
				encode_state(
					min(max(s1′-req_1, 0)+ret_1, MaxCars),
					min(max(s2′-req_2, 0)+ret_2, MaxCars)
					),
				reward + (min(s1′, req_1) + min(s2′, req_2)) * 10,
				(
					pdf(RequestDist_1, req_1) *
					pdf(RequestDist_2, req_2) *
					pdf(ReturnDist_1, ret_1) *
					pdf(ReturnDist_2, ret_2)
				)
			)
			for req_1 in 0:PoissonUpperBound,
				req_2 in 0:PoissonUpperBound,
				ret_1 in 0:PoissonUpperBound,
				ret_2 in 0:PoissonUpperBound
		)
	end

	struct CarRentalEnvModel <: AbstractEnvironmentModel
		dist
	end

	function CarRentalEnvModel()
		CarRentalEnvModel(
			Dict(
				(s,a) => nextstep(s,a)
				for s in 1:(MaxCars+1)^2 for a in 1:length(Actions)
			)
		)
	end

	(m::CarRentalEnvModel)(s, a) = m.dist[(s, a)]

	RLBase.state_space(m::CarRentalEnvModel) = Base.OneTo((MaxCars+1)^2)
	RLBase.action_space(m::CarRentalEnvModel) = Base.OneTo(length(Actions))
end

# ╔═╡ 20e3c8d6-5d92-11eb-1591-9911e62805bd
model = CarRentalEnvModel()

# ╔═╡ 0c099578-5d92-11eb-2a8b-2f4889026185
V = TabularVApproximator(n_state=length(state_space(model)), opt=Descent(1.0))

# ╔═╡ dda27350-5d94-11eb-1a82-c302513da719
p = TabularPolicy(;table=Dict(s=>1 for s in state_space(model)), n_action=length(action_space(model)))

# ╔═╡ 021f9b90-5d95-11eb-303a-ed2fb3de3d08
policy_iteration!(;V=V, π=p, model=model, γ=0.9, max_iter=300)

# ╔═╡ 8bbe08e6-5d98-11eb-0c02-4712c4659830
heatmap(0:MaxCars, 0:MaxCars, reshape([decode_action(p(x)) for x in state_space(model)], 1+MaxCars,1+MaxCars))

# ╔═╡ 91d90bf6-5d98-11eb-23a5-4dfc2839a707
heatmap(0:MaxCars, 0:MaxCars, reshape(V.table, 1+MaxCars,1+MaxCars))

# ╔═╡ Cell order:
# ╟─3254385c-5d90-11eb-2c99-07a3a40ae467
# ╠═92081fb8-5d90-11eb-2078-ddbf87421051
# ╠═a1a5176c-5d90-11eb-2ad6-2f108e1531e2
# ╠═20e3c8d6-5d92-11eb-1591-9911e62805bd
# ╠═0c099578-5d92-11eb-2a8b-2f4889026185
# ╠═dda27350-5d94-11eb-1a82-c302513da719
# ╠═021f9b90-5d95-11eb-303a-ed2fb3de3d08
# ╠═8bbe08e6-5d98-11eb-0c02-4712c4659830
# ╠═91d90bf6-5d98-11eb-23a5-4dfc2839a707


text:
using Documenter, DRIPs

# uncomment the following line to re-compile examples
# using Literate; include("compile_examples.jl");

makedocs(
    modules  = [DRIPs],
    format = Documenter.HTML(prettyurls = "--local" ∉ ARGS),
    sitename = "DRIPs.jl",
    pages    = [
         "Home" => "index.md",
         "Overview" => "overview.md",
         "Syntax" => "syntax.md",
         "Examples and Replications" => Any[
            "examples/ex1_pricing_nofeedback/ex1_pricing_pe_nofeedback.md",
            "examples/ex2_pricing_wfeedback/ex2_pricing_pe_with_feedback.md",
            "examples/ex3_mw2009/ex3_Mackowiak_Wiederholt_2009.md",
            "examples/ex4_sims2010/ex4_Sims_2010.md",
            "examples/ex5_mmw2018/ex5_Mackowiak_Matejka_Wiederholt_2018.md",
            "examples/ex6_ay2020/ex6_Afrouzi_Yang_2020.md",
            ]
         ]
    )

const devurl = "dev"

deploydocs(
    target = "build",
    repo   = "github.com/afrouzi/DRIPs.jl.git",
    branch = "gh-pages",
    deps   = nothing,
    make   = nothing,
    devbranch = "master",
    devurl = devurl,
    versions = ["v#.#", devurl => devurl],
    push_preview = false
)


text:
"""
    NodeRegistry

A registry to keep track of the node indeces already assigned. Used to speed up
hashing.
"""
mutable struct NodeRegistry
    latest_id::Int
end
"""
generate_next_id!

Generates the next, unassigned id and updates the internal state.
"""
function generate_next_id!(nr::NodeRegistry)
    nr.latest_id += 1
    return nr.latest_id
end
"""
    SearchNode

Describes a path along the graph. Containting states, action and cost.
"""
struct SearchNode{S, A}
    "The  state at the end of the path represented by this node"
    leaf_state::S
    "The  action at the end of the path represented by this node"
    leaf_action::Union{A, Nothing}
    "The cumulative cost for traversing the state trajectory represented by this node."
    cost::Float64
    "The parent node, if not a root node"
    parent::Union{SearchNode{S, A}, Nothing}
    "The depth of this node in the tree."
    depth::Int
    "A node registry that can generate unique identifiers"
    node_registry::NodeRegistry
    "The identifier of this node"
    id::Int
end
"""
    state_type

Returns the type of the state the search is run over.
"""
state_type(::SearchNode{S, A}) where {S, A} = S
"""
    action_type

Returns the type of the action the search is run over.
"""
action_type(::SearchNode{S, A}) where {S, A} = A
"""
    depth(n::SearchNode)

The depth of the search node in the tree.
"""
depth(n::SearchNode) = n.depth
"""
    Base.hash

Computes a fast hash for a search node.
"""
Base.hash(n::SearchNode, h::UInt) = n.id ⊻ h
"""
    Base.:==

Fast comparison for SearchNode based on id.
"""
==(n1::SearchNode, n2::SearchNode) = n1.id == n2.id
"""
    parent(n::SearchNode)

The parent node of the given search node. `nothing` if n is a root node.
"""
parent(n::SearchNode) = n.parent
"""
    cost(n::SearchNode)

Returns the cost for traversing the path described by the node.
"""
cost(n::SearchNode) = n.cost
"""
    leaf_state(n::SearchNode)

Returns the last state of the path described by the node.
"""
leaf_state(n::SearchNode) = n.leaf_state
"""
    leaf_action(n::SearchNode)

Returns the last action on the path described by this node.
"""
leaf_action(n::SearchNode) = n.leaf_action
"""
    action_sequence(n::SearchNode)

Returns the action sequence neccessary to traverse the path to the `leaf_state`
"""
function action_sequence(n::SearchNode)
    action_sequence = action_type(n)[]
    resize!(action_sequence, depth(n))

    current_node = n
    # traversing the path of the node in reverse order
    for i in reverse(1:depth(n))
        action_sequence[i] = leaf_action(current_node)
        current_node = parent(current_node)
    end
    # at the end of this path there must be a root node.
    # The parent of a root node is nothing!
    @assert isnothing(parent(current_node))

    return action_sequence::Vector{action_type(n)}
end
"""
    state_sequence(n::SearchNode)

Returns the sequence of states along the path represented by this node
"""
function state_sequence(n::SearchNode)
    state_sequence = state_type(n)[]
    resize!(state_sequence, depth(n))

    current_node = n
    # traversing the path of the node in reverse order
    for i in reverse(1:depth(n))
        state_sequence[i] = leaf_state(current_node)
        current_node = parent(current_node)
    end
    # at the end of this path there must be a root node.
    # The parent of a root node is nothing!
    @assert isnothing(parent(current_node))

    return state_sequence::Vector{state_type(n)}
end
"""
    expand(n::SearchNode)

Returns the child search nodes (set of next, longer pathes from this node)
"""
function expand(n::SearchNode, p::SearchProblem)
    # TODO: maybe resize in advance or sizehint!
    child_search_nodes = search_node_type(p)[]
    for (sp, a, c) in successors(p, leaf_state(n))
        np = SearchNode(sp, a, cost(n) + c, n, depth(n)+1, n.node_registry, generate_next_id!(n.node_registry))
        push!(child_search_nodes, np)
    end

    return child_search_nodes
end
"""
    root_node

Returns a SearchNode over the start_state of this problem
"""
function root_node(p::SearchProblem, root_cost::Float64=0.0)
    s = start_state(p)
    a = nothing
    c = root_cost
    parent = nothing
    depth = 0
    node_registry = NodeRegistry(0)
    id = generate_next_id!(node_registry)
    return search_node_type(p)(s, a, c, parent, depth, node_registry, id)
end


text:
"""
	GRclassic(b, M0)

The classic Gutenberg-Richter law can be expressed as an exponential distribution with
rate β and location `M0`:

```math
f(x; \\beta, M_{0}) = \\beta e^{-\\beta (x-M_{0})}, \\quad x ≥ M_{0}
```

`M0` is the minimum magnitude. β and the b-value `b` are linked by the following relation: ``\\beta = blog(10)``.

```julia
GRclassic(1.0, 0.5)  # distribution with a b-value of 1 and minimum magnitude of 0.5
bvalue(d)     #  get the b-value
rate(d)       #  get β
location(d)   #  get M0
params(d)     #  get the parameters (b, M0)
```

"""
struct GRclassic{T,S<:Real} <: ContinuousUnivariateDistribution
    b::T
    M0::S
    GRclassic(b::T, M0::S) where {T,S} = new{T,S}(b, M0)
end

bvalue(d::GRclassic) = d.b
avalue(d::GRclassic, N::Real, ΔM::Real) = log10(N) + d.b*( location(d)+ΔM/2 )

Distributions.rate(d::GRclassic) = d.b*log(10)
Distributions.location(d::GRclassic) = d.M0
Distributions.params(d::GRclassic) = (d.b, d.M0)

Distributions.mean(d::GRclassic) = 1/rate(d) + d.M0

#### Evaluation
Distributions.zval(d::GRclassic, x::Real) = (x .- d.M0) * rate(d)
Distributions.xval(d::GRclassic, z::Real) = (z * 1/rate(d)) + d.M0

Distributions.pdf(d::GRclassic, x::Real)    = x ≥ d.M0 ?  (rate(d) * exp(-rate(d) * (x-d.M0))) : zero(0.0)
Distributions.logpdf(d::GRclassic, x::Real) = x ≥ d.M0 ? log(rate(d)) - rate(d) * (x-d.M0) : -Inf

Distributions.cdf(d::GRclassic, x::Real)    = x ≥ d.M0 ? -expm1(-Distributions.zval(d, x)) : zero(0.0)
Distributions.logcdf(d::GRclassic, x::Real) = x ≥ d.M0 ? log( -expm1(-Distributions.zval(d, x)) ) : -Inf

Distributions.ccdf(d::GRclassic, x::Real)   = x ≥ d.M0 ?    exp(-Distributions.zval(d, x)) : zero(0.0)
Distributions.logccdf(d::GRclassic, x::Real) = x ≥ d.M0 ? -Distributions.zval(d, x) : -Inf

#### Sampling
Distributions.rand(rng::AbstractRNG, d::GRclassic) = Distributions.xval(d, randexp(rng))

"""
    fit_mle(D::Type{<:GRclassic}, mags, M0)

Use the maximum likelihood method to determine the `GRclassic` distribution fitting the
input data. The function calculates the b-value with the method of Aki-Utsu.

# Arguments
* `D`: distribution type (see [`GRclassic(b, M0)`](@ref)).
* `mags`: array storing magnitude values greater than or equal to the magnitude of completeness `M0`.
* `M0`: magnitude of completeness. See [Magnitude of completeness](@ref) for
    methods that can be used to estimate it.

The standard error affecting the b-value can be estimated with [`fit_stderr(D::Type{<:GRclassic}, mags)`](@ref)

# References
* Aki, 1965. Maximum Likelihood Estimate of b in the Formula logN=a-bM and its Confidence Limits.
  Belletin of the Earthquake Research Institute, 43, 237-239.
* Utsu 1966. A Statistical Significance Test of the Difference in b-value between Two Earthquake Groups.
  Journal of Physics of the Earth, 14, 37-40.
"""
function Distributions.fit_mle(::Type{<:GRclassic}, mags::AbstractArray{<:AbstractFloat}, M0::Real)

    μ = mean(mags)
    β = 1 / (μ - M0)

    return GRclassic(β/log(10), M0)
end

"""
    fit_binned(D::Type{<:GRclassic}, mags, M0, ΔM)

Determine the `GRclassic` distribution fitting the input data.
This function corresponds to the method of Tinti and Mulargia, which was designed
to properly estimate the b-value from binned magnitude values.

# Arguments
* `D`: distribution type (see [`GRclassic(b, M0)`](@ref)).
* `mags`: array storing binned magnitude values greater than or equal to the magnitude of completeness `M0`
* `M0`: magnitude of completeness. See [Magnitude of completeness](@ref) for methods that
   can be used to estimate it.
* `ΔM`: bin width used to group the magnitude values.`

The standard error affecting the b-value can be estimated with [`fit_stderrbinned(D::Type{<:GRclassic}, mags, ΔM)`](@ref)

# References
* Tinti and Mulargia, 1987. Confidence intervals of b values for grouped magnitudes.
  Bulletin of the Seismological Society of America, 77 (6), 2125–2134.
"""
function fit_binned(::Type{<:GRclassic}, mags::AbstractArray{<:AbstractFloat}, M0::Real, ΔM::Real)

    μ = mean(mags)

    z = (μ - M0)/ΔM - 0.5
    p = z/(z+1)
    β = -log(p) / ΔM

    return GRclassic(β/log(10), M0)

end

"""
    fit_stderr(D::Type{<:GRclassic}, mags)

Apply the method of Shi and Bolt to calculate the standard error affecting a b-value
determined with the method of Aki-Utsu [`fit_mle(D::Type{<:GRclassic}, mags, M0)`](@ref).

# Arguments
* `D`: distribution type (see [`GRclassic(b, M0)`](@ref)).
* `mags`: array storing magnitude values greater than or equal to the magnitude of completeness.

# References
* Shi and Bolt, 1982. The standard error of the magnitude-frequency b value.
  Bulletin of the Seismological Society of America, 72, 1677-1687.
"""
function fit_stderr(d::GRclassic, mags::AbstractVector{T}) where {T<:Real}

    μ = mean(mags)
    N = length(mags)

    σ = (sum((mags .- μ).^2)) / (N*(N-1))
    σ = 2.30 * sqrt(σ) * bvalue(d)^2

    return σ

end

"""
    fit_stdbinned(D::Type{<:GRclassic}, mags, ΔM)

Calculate the standard error affecting a b-value estimated with the
method of Tinti and Mulargia ([`fit_binned(D::Type{<:GRclassic}, mags, M0, ΔM)`](@ref)).

# Arguments
* `D`: distribution type (see [`GRclassic(b, M0)`](@ref)).
* `mags`: array storing magnitude values greater than or equal to the magnitude of completeness.
* `ΔM`: bin width used to group the magnitude values.`

# References
* Tinti and Mulargia, 1987. Confidence intervals of b values for grouped magnitudes.
  Bulletin of the Seismological Society of America, 77 (6), 2125–2134.
"""
function fit_stderrbinned(d::GRclassic, mags::AbstractVector{T}, ΔM::S) where {T,S<:Real}

    μ = mean(mags)
    N = length(mags)

    z = (μ - (d.M0))/ΔM - 0.5
    p = z/(z+1)
    σ = (1-p)/(log(10)*ΔM*sqrt(N*p))

    return σ

end


text:
using DataStructures

"""
Testcase type.
"""
struct Testcase
    name :: String
    "Remembered creation order, used for test execution."
    func
    "Testcase parameters"
    parameters :: Array{Fixture, 1}
    """
    All leaf global dependencies of parameters
    (that is, the global fixtures in the dependency tree
    that are not parametrized themselves).
    """
    dependencies :: OrderedSet{AbstractGlobalFixture}
    "Testcase tags"
    tags :: Set{Symbol}
    """
    If `true`, this testcase will be executed in the same process
    for all combinations of the fixture values.
    """
    single_process :: Bool

    """
        Testcase(func, params...; tags=[])

    Define a testcase.

    `func` is a testcase function.
    The number of function parameters must be equal to the number
    of parametrizing fixtures given in `params`.
    This function will be called with all combinations of values
    of fixtures from `params`.

    `params` are either fixtures, iterables or pairs of two iterables
    used to parametrize the function.
    In the latter case, the first iterable will be used to produce the values,
    and the second one to produce the corresponding labels (for logging).

    `tags` is an array of `Symbol`s.
    Testcases can be filtered in or out by tags,
    see [run options](@ref run_options_manual) for details.

    Returns a [`Testcase`](@ref) object.
    """
    function Testcase(
            func, name::String, params...;
            tags::Array{Symbol, 1}=Symbol[], single_process::Bool=false)

        params = collect(map(normalize_fixture, params))
        deps = union(map(dependencies, params)..., global_fixtures(params))
        new(name, func, params, deps, Set(tags), single_process)
    end
end

parameters(tc::Testcase) = tc.parameters

dependencies(tc::Testcase) = tc.dependencies

tags(tc::Testcase) = tc.tags

struct TestGroup
    name :: String
    func
    single_process :: Bool

    function TestGroup(func, name; single_process::Bool=false)
        new(name, func, single_process)
    end
end

function register_testobj(obj)
    if !haskey(task_local_storage(), TESTCASE_ACCUM_ID)
        task_local_storage(TESTCASE_ACCUM_ID, Any[])
    end
    push!(task_local_storage(TESTCASE_ACCUM_ID), obj)
end

function collect_testobjs(func)
    task_local_storage(TESTCASE_ACCUM_ID, Any[]) do
        func()
        task_local_storage(TESTCASE_ACCUM_ID)
    end
end

function get_testcases(group::TestGroup)
    collect_testobjs() do
        Base.invokelatest(group.func)
    end
end


text:
module Query

using NullableArrays
using Requires
using NamedTuples
using DataStructures
import FunctionWrappers: FunctionWrapper

import Base.start
import Base.next
import Base.done
import Base.collect
import Base.length
import Base.eltype
import Base.join

export @from, Grouping, null

include("operators.jl")

include("enumerable/enumerable.jl")
include("enumerable/enumerable_groupby.jl")
include("enumerable/enumerable_join.jl")
include("enumerable/enumerable_groupjoin.jl")
include("enumerable/enumerable_orderby.jl")
include("enumerable/enumerable_select.jl")
include("enumerable/enumerable_where.jl")
include("enumerable/enumerable_selectmany.jl")

include("queryable/queryable.jl")
include("queryable/queryable_select.jl")
include("queryable/queryable_where.jl")

include("query_translation.jl")

include("sources/source_array.jl")
include("sources/source_iterable.jl")
include("sources/source_dataframe.jl")
include("sources/source_sqlite.jl")
include("sources/source_typedtable.jl")
include("sources/source_datastream.jl")
include("sources/source_ndsparsedata.jl")

include("sinks/sink_array.jl")
include("sinks/sink_dataframe.jl")
include("sinks/sink_csvfile.jl")

macro from(range::Expr, body::Expr)
	if range.head!=:call || range.args[1]!=:in
		error()
	end

	if body.head!=:block
		error()
	end

	body.args = filter(i->i.head!=:line,body.args)

	insert!(body.args,1,:( @from $(range.args[2]) in $(range.args[3]) ))

	translate_query(body)

	return body.args[1]
end

macro where_internal(source, f)
	q = Expr(:quote, f)
    :(where($(esc(source)), $(esc(f)), $(esc(q))))
end

macro select_internal(source, f)
	q = Expr(:quote, f)
    :(select($(esc(source)), $(esc(f)), $(esc(q))))
end

macro orderby_internal(source, f)
	q = Expr(:quote, f)
    :(orderby($(esc(source)), $(esc(f)), $(esc(q))))
end

macro orderby_descending_internal(source, f)
	q = Expr(:quote, f)
    :(orderby_descending($(esc(source)), $(esc(f)), $(esc(q))))
end

macro thenby_internal(source, f)
	q = Expr(:quote, f)
    :(thenby($(esc(source)), $(esc(f)), $(esc(q))))
end

macro thenby_descending_internal(source, f)
	q = Expr(:quote, f)
    :(thenby_descending($(esc(source)), $(esc(f)), $(esc(q))))
end

macro join_internal(outer, inner, outerKeySelector, innerKeySelector, resultSelector)
	q_outerKeySelector = Expr(:quote, outerKeySelector)
	q_innerKeySelector = Expr(:quote, innerKeySelector)
	q_resultSelector = Expr(:quote, resultSelector)

	:(join($(esc(outer)), $(esc(inner)), $(esc(outerKeySelector)), $(esc(q_outerKeySelector)), $(esc(innerKeySelector)),$(esc(q_innerKeySelector)), $(esc(resultSelector)),$(esc(q_resultSelector))))
end

macro group_join_internal(outer, inner, outerKeySelector, innerKeySelector, resultSelector)
	q_outerKeySelector = Expr(:quote, outerKeySelector)
	q_innerKeySelector = Expr(:quote, innerKeySelector)
	q_resultSelector = Expr(:quote, resultSelector)

	:(group_join($(esc(outer)), $(esc(inner)), $(esc(outerKeySelector)), $(esc(q_outerKeySelector)), $(esc(innerKeySelector)),$(esc(q_innerKeySelector)), $(esc(resultSelector)),$(esc(q_resultSelector))))
end

macro select_many_internal(source,collectionSelector,resultSelector)
	q_collectionSelector = Expr(:quote, collectionSelector)
	q_resultSelector = Expr(:quote, resultSelector)

	:(select_many($(esc(source)), $(esc(collectionSelector)), $(esc(q_collectionSelector)), $(esc(resultSelector)), $(esc(q_resultSelector))))
end

macro group_by_internal(source,elementSelector,resultSelector)
	q_elementSelector = Expr(:quote, elementSelector)
	q_resultSelector = Expr(:quote, resultSelector)

	:(group_by($(esc(source)), $(esc(elementSelector)), $(esc(q_elementSelector)), $(esc(resultSelector)), $(esc(q_resultSelector))))
end

macro group_by_internal_simple(source,elementSelector)
	q_elementSelector = Expr(:quote, elementSelector)

	:(group_by($(esc(source)), $(esc(elementSelector)), $(esc(q_elementSelector))))
end

end # module


text:
mutable struct Variant
    index::UInt64 # 1-based
    offset::UInt64
    record_type::UInt8
    length::UInt64
end

struct Header{VTT,VLT,ACT,PRFT}
    # magic number (first two bytes): 0x6c 0x1b.
    storage_mode::UInt # third byte. restrict to 0x10 for now.
    n_variants::UInt # 4th-7th byte.
    n_samples::UInt # 8th-11th byte.
    bits_per_variant_type::UInt # bits 0-3 of 12th byte
    bytes_per_record_length::UInt # bits 0-3 of 12th byte
    bytes_per_allele_count::UInt # bits 4-5 of 12th byte, restrict to 0 for now (no multiallelic variants allowed).
    bytes_per_sample_id::UInt # determined by n_samples (1 if < 2 ^ 8, etc.)
    provisional_reference::UInt # bits 6-7 of 12th byte.
    n_blocks::UInt # number of blocks of 2^16 variants. Int(ceil(n_variants / 2 ^ 16)).
    variant_block_offsets::Vector{UInt} # record starting points of #0, #65536, ... length of (8 * n_blocks) bytes.
    # The following appear in blocks of 2^16 variants.
    variant_types::VTT # Union{ScatteredBitsVector, ScatteredVector}
    variant_lengths::VLT # ScatteredVector
    allele_counts::ACT # Union{ScatteredVector, Nothing}
    provisional_reference_flags::PRFT # Union{ScatteredBitsVector, Nothing}
    most_recent_non_ld::Dict{UInt, Variant}
end

struct Pgen{ST}
    io::IOStream
    data::Union{Nothing, Vector{UInt8}}
    header::Header
    variant_record_cache::Union{Nothing, Vector{UInt8}} # used only with no_mmap
    genotypes_prev::Vector{UInt8} # for LD-compressed genotypes
    genotypes_cache::Vector{UInt8} # 0x00, 0x01, or 0x02. Byte-aligned for performance.
    genotypes_raw_cache::Vector{UInt8}
    dosage_cache::Vector{Float32} # Dosage values are represented by 16-bit numbers, Float32 is enough.
    difflist_cache::Vector{ST} # length-64 vector for 64 Sample IDs.
    difflist_cache_incr::Vector{UInt32}
end

"""
    Pgen(filename; no_mmap)

Creates an instance of `Pgen` from `filename`. `no_mmap` chooses whether to use `Mmap`.
"""
function Pgen(filename::String; no_mmap::Bool=false)
    io = open(filename)
    if !no_mmap
        data = mmap(io)
    else
        data = nothing
    end
    header = Header(io)
    ST = bytes_to_UInt[header.bytes_per_sample_id]
    if !no_mmap
        variant_record_cache = nothing
    else
        variant_record_cache = Vector{UInt8}(undef, maximum(header.variant_lengths))
    end
    genotypes_prev = Vector{UInt8}(undef, header.n_samples)
    genotypes_cache = Vector{UInt8}(undef, header.n_samples)
    genotypes_raw_cache = Vector{UInt8}(undef, (header.n_samples + 3) >> 2)
    dosage_cache = Vector{Float32}(undef, header.n_samples)
    difflist_cache = Vector{ST}(undef, 64)
    difflist_cache_incr = Vector{UInt32}(undef, 64)
    difflist_cache_incr[1] = 0
    Pgen{ST}(io, data, header, variant_record_cache, genotypes_prev, genotypes_cache,
    genotypes_raw_cache,
    dosage_cache, difflist_cache, difflist_cache_incr)
end

@inline n_variants(p::Pgen) = p.header.n_variants
@inline n_samples(p::Pgen) = p.header.n_samples


text:
# Experimental threads example. WIP!

using CmdStan
using Statistics
using Distributions

ProjDir = @__DIR__
cd(ProjDir) #do

bernoullimodel = "
data {
  int<lower=1> N;
  int<lower=0,upper=1> y[N];
}
parameters {
  real<lower=0,upper=1> theta;
}
model {
  theta ~ beta(1,1);
  y ~ bernoulli(theta);
}
";

#isdir(ProjDir * "/tmp") && rm(ProjDir * "/tmp", recursive=true)
tmpdir = ProjDir * "/tmp"

p1 = 24 # p1 is the number of models to fit

n = 100;
p = range(0, stop=1, length=p1)
observeddata = [Dict("N" => n, "y" => Int.(rand(Bernoulli(p[i]), n))) for i in 1:p1]

sm = [Stanmodel(name="bernoulli_m$i", model=bernoullimodel;
  output_format=:namedtuple, tmpdir=tmpdir) for i in 1:p1]

println("\nThreads loop\n")

estimates = Vector(undef, p1)
Threads.@threads for i in 1:p1
    rc, samples, cnames = stan(sm[i], observeddata[i]; summary=false);
    if rc == 0
      estimates[i] = [mean(reshape(samples.theta, 4000)), std(reshape(samples.theta, 4000))]
    end
end

estimates |> display

#end


text:
"""
    AbstractIntrospectedStruct

Default supertype for introspected structs.
"""
abstract type AbstractIntrospectedStruct end
StructTypes.StructType(::Type{<:AbstractIntrospectedStruct}) = StructTypes.Struct()

function Base.show(io::IO, ::MIME"text/plain", obj::T) where {T <: AbstractIntrospectedStruct}
    nonnull_fields = Symbol[]
    for field in fieldnames(T)
        !isnothing(getproperty(obj, field)) && push!(nonnull_fields, field)
    end
    display_text = split(string(typeof(obj)),'#')[3]
    if length(nonnull_fields) == 0
        display_text *= "\n  All fields are nothing"
    else
        longest = maximum(length.(string.(nonnull_fields)))
        for field in nonnull_fields
            display_text *= "\n  "
            display_text *= lpad(field, longest)
            display_text *= " : $(getproperty(obj, field))"
        end
    end
    print(io, display_text)
end

"""
    create_struct_AST(struct_name::Symbol, parent_type, fields, mutable=true)

Returns an `Expr` which can be evaluated to create a struct. The struct
has fields and types specifed by the key value pairs of `fields`, with all types
being a union of `Nothing` and the type supplied. If the `parent_type` method is used
the struct is given the supplied parent type. Mutability can be controlled with
the `mutable` kwarg.
"""
function create_struct_AST(struct_name::Symbol, parent_type, fields; mutable=true)
    e = Expr(:struct, mutable)
    push!(e.args,Expr(:<:))
    push!(e.args[2].args, struct_name)
    push!(e.args[2].args, parent_type)
    push!(e.args, Expr(:block))
    for (name, type) in fields
        push!(e.args[3].args, :($name::Union{Nothing, $type}))
    end
    return e
end

"""
    build_name_to_type(client,
                       object_name;
                       objects_being_introspected=String[],
                       allowed_level=2,
                       custom_scalar_types=GQL_DEFAULT_SCALAR_TO_JULIA_TYPE,
                       kwargs...)

Builds a dictionary of field name to Julia type for the given object.
"""
function build_name_to_type(client,
                            object_name;
                            objects_being_introspected=String[],
                            allowed_level=2,
                            scalar_types=GQL_DEFAULT_SCALAR_TO_JULIA_TYPE,
                            kwargs...)

    fields_dict = client.type_to_fields_map[object_name]

    name_to_type = Dict{Symbol, Type}()
    for (key, val) in fields_dict
        type = getjuliatype(val; scalar_types)
        if !(type <: GraphQLType) && !(type <: Vector{<:GraphQLType})
            # Simple types, just add to dictionary
            push!(name_to_type, Symbol(key) => type)
        elseif getroottype(val) in objects_being_introspected
            @warn "Cannot introspect field $key on type $object_name due to recursion of object $(getroottype(val))"
            continue
        elseif allowed_level <= 1
            @warn "Cannot introspect field $key on type $object_name due to allowed_level kwarg"
            continue
        else
            introspected_type = _instrospect_object(
                client,
                getroottype(val);
                objects_being_introspected,
                allowed_level=allowed_level-1,
                scalar_types=scalar_types,
                kwargs...
            )
            if type <: GraphQLType
                push!(name_to_type, Symbol(key) => introspected_type)
            elseif type <: Vector{<:GraphQLType}
                push!(name_to_type, Symbol(key) => Vector{introspected_type})
            end
        end
    end
    return name_to_type
end

"""
    _instrospect_object(client,
                        object_name;
                        objects_being_introspected=String[],
                        parent_map=Dict{String, Type}(),
                        mutable=true,
                        allowed_level=2,
                        scalar_types=GQL_DEFAULT_SCALAR_TO_JULIA_TYPE)

Create a new type from instrospection of the object specified by `object_name`. The name of the
tupe is calculated by `gen_sym(string(object_name))`

This is an internal method that is called recursively.

See also: [`introspect_object`](@ref).
"""
function _instrospect_object(client,
                             object_name;
                             objects_being_introspected=String[],
                             parent_map=Dict{String, Type}(),
                             mutable=true,
                             allowed_level=2,
                             scalar_types=GQL_DEFAULT_SCALAR_TO_JULIA_TYPE)

    # If this object has already been introspected, return type
    haskey(client.introspected_types, object_name) && return client.introspected_types[object_name]

    # Build a dictionary of field names to types whilst keeping track of what objects are currently being intropsected
    push!(objects_being_introspected, object_name)
    name_to_type = build_name_to_type(
        client,
        object_name;
        objects_being_introspected,
        allowed_level,
        parent_map,
        mutable,
        scalar_types,
    )
    deleteat!(objects_being_introspected, findfirst(obj -> obj==object_name, objects_being_introspected))

    # Create struct from dictionary
    name = gensym(string(object_name)) # gensym creates a unique name, string needed in case of substring
    super_type = get(parent_map, object_name, AbstractIntrospectedStruct)
    eval(create_struct_AST(name, super_type, name_to_type; mutable))

    # Add to objects introspected in this pass
    push!(client.introspected_types, object_name => eval(name)) # eval so type goes in dict
    return eval(name)
end

"""
    introspect_object([client::Client],
                      object_name;
                      force=false,
                      reset_all=false,
                      parent_type=nothing,
                      parent_map=Dict{String, Type}(),
                      mutable=true,
                      allowed_level=2,
                      custom_scalar_types=Dict{String, DataType}())

Introspects an object and creates a Julia type.

Due to the recursion that is possible with GraphQL schemas, this introspection
can be difficult. Please read this docstring carefully.

# Parent Type

All introspected type, by default, will be given the parent type `AbstractIntrospectedStruct`.
The parent type of the top level object being introspected can be set by `parent_type`, and
the parent types of any object being introspected can be set using the `parent_map` dictionary.
If `object_type` is a key in `parent_map` and `parent_type` is not `nothing`, the value of
`parent_type` will take precedence.

# StructTypes

`AbstractIntrospectedStruct` has a defined `StructType` of `Struct` for JSON serialisation.
You can define `StructType`s for the concrete type that is introspected by doing

```
StructTypes.StructType(::Type{GraphQLClient.get_introspected_object(object_name)}) = StructTypes.Struct()
```

# Recursion

Recursion is handled by two methods:

1. Providing the `allowed_level` kwarg to control how deep introspection goes.
2. Maintaining a list of objects that are currently being introspected. No object can be instrospected
    twice and a type cannot be used in a type definition until it has been defined itself. Therefore
    if this situation occurs, the fields that need to use the not-yet-defined type are ignored.
    This means the order in which objects are intropsected can have an impact on the final structs.

For example consider the following objects

```
Country:
 - name: String
 - leader: Person

Person:
 - name: String
 - countryOfBirth: Country
```

If we introspected `Country` first, the `Person` object would not contain the `countryOfBirth` field,
as it is impossible to set the type of that field to `Country` before it is defined itself. If we
introspected `Person` first, the `Country` boject would not contain the `leader` field for the same
reason.

# Keyword Arguments
- `force=false`: if `false`, the introspection will use already introspected types for objects
    if they exist. If `true`, any previously introspected types will be overwritten if they
    are introspected whilst introspecting `object_name`. Use with caution, as other types
    may rely on types that are then overwritten.
- `reset_all`: delete all introspected types to start from a clean sheet.
- `parent_type=nothing`: the parent type to give to the new introspected struct. See
    comment above.
- `parent_map=Dict{String, Type}()`: dictionary to maps
    object names to desired parent types. If `parent_type` is supplied, this value
    will take precedence over the entry in `parent_map` for `object_name`.
- `mutable=true`: boolean to set the mutability of top level and all lower level types.
- `allowed_level=2`: how many levels of introspection are allowed. For example, if this
    is `1` then only top level fields that are objects will be in the introspected type.
- `custom_scalar_types`: dictionary of custom GraphQL scalar type to Julia type. This kwarg enables
    custom scalar types to be introspected to the correct type.
"""
introspect_object(object_name; kwargs...) = introspect_object(global_graphql_client(), object_name; kwargs...)
function introspect_object(client::Client,
                           object_name;
                           force=false,
                           reset_all=false,
                           parent_type=nothing,
                           parent_map=Dict{String, Type}(),
                           mutable=true,
                           allowed_level=2,
                           custom_scalar_types=Dict{String, DataType}())

    if reset_all
        empty!(client.introspected_types)
    elseif force
        perviously_introspected_types = deepcopy(client.introspected_types)
        empty!(client.introspected_types)
    end

    if !haskey(parent_map, object_name)
        parent_map[object_name] = isnothing(parent_type) ? AbstractIntrospectedStruct : parent_type
    elseif haskey(parent_map, object_name) && !isnothing(parent_type)
        @warn "Parent type for $object_name supplied in both parent_map and parent_type kwargs. \n parent_type value ($(parent_type)) will be used."
        parent_map[object_name] = parent_type
    end

    scalar_types = merge(GQL_DEFAULT_SCALAR_TO_JULIA_TYPE, custom_scalar_types)

    _instrospect_object(client, object_name; parent_map, mutable, allowed_level, scalar_types)

    # Update client
    if force
        # Ensure any newly introspected types get precedence
        client.introspected_types = merge(perviously_introspected_types, client.introspected_types)
    end

    return client.introspected_types[object_name]
end

"""
    get_introspected_type([client::Client], object_name::String)

Return the introspected `Type` for an object.
"""
get_introspected_type(object_name::String) = get_introspected_type(global_graphql_client(), object_name)
get_introspected_type(client::Client, object_name::String) = client.introspected_types[object_name]

"""
    list_all_introspected_objects([client::Client])

Return a `Vector` of the objects which have been introspected.
"""
list_all_introspected_objects() = list_all_introspected_objects(global_graphql_client())
list_all_introspected_objects(client::Client) = collect(keys(client.introspected_types))

"""
    initialise_introspected_struct([client::Client], name::String)
    initialise_introspected_struct([client::Client], name::SubString)
    initialise_introspected_struct(T::Type)

Initialise an introspected struct with all fields set to nothing. If name of
type supplied as string, this get the `Type` from `client.introspected_types`.
"""
initialise_introspected_struct(name::AbstractString) = initialise_introspected_struct(global_graphql_client(), name)
initialise_introspected_struct(client::Client, name::String) = initialise_introspected_struct(client.introspected_types[name])
initialise_introspected_struct(client::Client, name::SubString) = initialise_introspected_struct(client, string(name))
function initialise_introspected_struct(T::Type)
    n_fields = length(fieldnames(T))
    return T((nothing for i in 1:n_fields)...)
end

"""
    create_introspected_struct([client::Client], object_name::AbstractString, fields::AbstractDict)

Creates a struct for the object specified and populates its fields with
the keys and values of `fields`.

# Examples
```julia
julia> GraphQLClient.create_introspected_struct("ResultObject",Dict(:resultId=>"MyResult", :Score => 1.0))
ResultObject
  Score : 1.0
      resultId : MyResult
```
"""
create_introspected_struct(object_name::AbstractString, fields::AbstractDict) = create_introspected_struct(global_graphql_client(), object_name, fields)
function create_introspected_struct(client::Client, object_name::AbstractString, fields::AbstractDict)
    struct_instance = initialise_introspected_struct(client, object_name)
    !ismutable(struct_instance) && throw(GraphQLClientException("create_introspected_struct only works for mutable types"))
    for (key, val) in fields
        setproperty!(struct_instance, Symbol(key), val)
    end
    return struct_instance
end


text:
function run(recommender::Type{T}) where {T<:Recommender}
    m = [NaN 3 NaN 1 2 1 NaN 4
         1 2 NaN NaN 3 2 NaN 3
         NaN 2 3 3 NaN 5 NaN 1]
    data = DataAccessor(m)

    recommender = recommender(data, 2)
    build!(recommender, learning_rate=15e-4, max_iter=100)

    # top-4 recommended item set should be same as CF/SVD-based recommender
    rec = recommend(recommender, 1, 4, [i for i in 1:8])
    @test Set([item for (item, score) in rec]) == Set([2, 5, 6, 8])
end

function test_mf()
    println("-- Testing MF-based (aliased) recommender")
    run(MF)
end

function test_matrix_factorization()
    println("-- Testing Matrix Factorization-based recommender")
    run(MatrixFactorization)
end

function test_mf_with_random_init()
    println("-- Testing MF-based recommender with randomly initialized params")
    m = [NaN 3 NaN 1 2 1 NaN 4
         1 2 NaN NaN 3 2 NaN 3
         NaN 2 3 3 NaN 5 NaN 1]
    data = DataAccessor(m)

    recommender = MF(data, 2)
    build!(recommender, random_init=true)

    rec = recommend(recommender, 1, 4, [i for i in 1:8])
    @test size(rec, 1) == 4  # top-4 recos
end

test_mf()
test_matrix_factorization()
test_mf_with_random_init()


text:
#=
Doubly linked list
=#

using SimpleDataStructures

sll = SimpleLinkedList{Int}()
push!(sll, 1)
push!(sll, 2)
push!(sll, 3)
first(sll)
last(sll)

sll[9]

insert!(sll, 3, 10)
insert!(sll, 4, 100)
collect(sll)
deleteat!(sll, 3)
deleteat!(sll, 3)
pop!(sll)
popfirst!(sll)
collect(sll)


text:
@deprecate predict(mm::LinearModel, newx::AbstractMatrix, interval::Symbol, level::Real = 0.95) predict(mm, newx; interval=interval, level=level)

@deprecate confint(obj::LinearModel, level::Real) confint(obj, level=level)
@deprecate confint(obj::AbstractGLM, level::Real) confint(obj, level=level)


text:
function central_diff(Qbase, Qcon, cellxmax, cellymax, mu, lambda,
                        vecAx, vecAy, specific_heat_ratio, volume, Rd, nval)

    E_vis_hat = zeros(cellxmax+1,   cellymax, nval)
    F_vis_hat = zeros(  cellxmax, cellymax+1, nval)

    for i in 2:cellxmax+1 -1
        for j in 2:cellymax -1

            rho_av = 0.5*(Qbase[i,j,1] + Qbase[i-1,j,1])
            u_av   = 0.5*(Qbase[i,j,2] + Qbase[i-1,j,2])
            v_av   = 0.5*(Qbase[i,j,3] + Qbase[i-1,j,3])
            T_av   = Qbase[i,j,4]/(Qbase[i,j,1]*Rd) - Qbase[i-1,j,4]/(Qbase[i-1,j,1]*Rd)

            mu_av     = 0.5*(mu[i-1,j] + mu[i,j])
            lambda_av = (0.5*(1/lambda[i-1,j] + 1/lambda[i,j]))^(-1)

            volume_av = 0.5*(volume[i,j] + volume[i-1,j])

            dudxi = Qbase[i,j,2] - Qbase[i-1,j,2]
            dvdxi = Qbase[i,j,3] - Qbase[i-1,j,3]
            dTdxi = Qbase[i,j,4]/(Qbase[i,j,1]*Rd) - Qbase[i-1,j,4]/(Qbase[i-1,j,1]*Rd)

            dudeta = 0.25 * (Qbase[i,j+1,2] - Qbase[i,j-1,2] + Qbase[i-1,j+1,2] - Qbase[i-1,j-1,2])
            dvdeta = 0.25 * (Qbase[i,j+1,3] - Qbase[i,j-1,3] + Qbase[i-1,j+1,3] - Qbase[i-1,j-1,3])
            dTdeta = 0.25* (Qbase[i,j+1,4]/(Qbase[i,j+1,1]*Rd) - Qbase[i,j-1,4]/(Qbase[i,j-1,1]*Rd) +
                            Qbase[i-1,j+1,4]/(Qbase[i-1,j+1,1]*Rd) -  Qbase[i-1,j-1,4]/(Qbase[i-1,j-1,1]*Rd))

            vecAy_xav    = 0.25*( vecAy[i,j,1] + vecAy[i,j+1,1] + vecAy[i-1,j,1] + vecAy[i-1,j+1,1] )
            vecAy_yav    = 0.25*( vecAy[i,j,2] + vecAy[i,j+1,2] + vecAy[i-1,j,2] + vecAy[i-1,j+1,2] )

            tau_xx = 2/3*mu_av*(2*( vecAx[i,j,1] * dudxi + vecAy_xav * dudeta )
                    - (vecAx[i,j,2]*dvdxi + vecAy_yav*dvdeta ))

            tau_yy = 2/3*mu_av*(( vecAx[i,j,1]*dudxi -vecAy_xav*dudeta )
                    + 2*(vecAx[i,j,2]*dvdxi + vecAy_yav*dvdeta ))

            tau_xy = mu_av*(
                    + (vecAx[i,j,2]*dudxi + vecAy_yav*dudeta )
                    + ( vecAx[i,j,1]*dvdxi + vecAy_xav*dvdeta ) )

            dTdx = vecAx[i,j,1]*dTdxi + vecAy_xav*dTdeta
            dTdy = vecAx[i,j,2]*dTdxi + vecAy_yav*dTdeta

            betax = u_av*tau_xx + v_av*tau_xy + lambda_av * dTdx
            betay = u_av*tau_xy + v_av*tau_yy + lambda_av * dTdy

            E_vis_hat[i,j,1] = 0.0
            E_vis_hat[i,j,2] = (vecAx[i,j,1]*tau_xx + vecAx[i,j,2]*tau_xy) / volume_av
            E_vis_hat[i,j,3] = (vecAx[i,j,1]*tau_xy + vecAx[i,j,2]*tau_yy) / volume_av
            E_vis_hat[i,j,4] = (vecAx[i,j,1]*betax + vecAx[i,j,2]*betay)   / volume_av
        end
    end

    for i in 2:cellxmax -1
        for j in 2:cellymax+1 -1

            rho_av = 0.5*(Qbase[i,j,1] + Qbase[i,j-1,1])
            u_av = 0.5*(Qbase[i,j,2] + Qbase[i,j-1,2])
            v_av = 0.5*(Qbase[i,j,3] + Qbase[i,j-1,3])
            T_av   = Qbase[i,j,4]/(Qbase[i,j,1]*Rd) - Qbase[i,j-1,4]/(Qbase[i,j-1,1]*Rd)

            mu_av     = 0.5*(mu[i,j-1] + mu[i,j])
            lambda_av = (0.5*(1/lambda[i,j-1] + 1/lambda[i,j]))^(-1)

            volume_av = 0.5*(volume[i,j] + volume[i,j-1])

            dudxi = 0.25 * (Qbase[i+1,j,2] - Qbase[i-1,j,2] + Qbase[i+1,j-1,2] - Qbase[i-1,j-1,2])
            dvdxi = 0.25 * (Qbase[i+1,j,3] - Qbase[i-1,j,3] + Qbase[i+1,j-1,3] - Qbase[i-1,j-1,3])
            dTdxi = 0.25 * (Qbase[i+1,j,4]/(Qbase[i+1,j,1]*Rd) - Qbase[i-1,j,4]/(Qbase[i-1,j,1]*Rd) +
                            Qbase[i+1,j-1,4]/(Qbase[i+1,j-1,1]*Rd) - Qbase[i-1,j-1,4]/(Qbase[i-1,j-1,1]*Rd))

            dudeta = Qbase[i,j,2] - Qbase[i,j-1,2]
            dvdeta = Qbase[i,j,3] - Qbase[i,j-1,3]
            dTdeta = (Qbase[i,j,4]/(Qbase[i,j,1]*Rd) - Qbase[i,j-1,4]/(Qbase[i,j-1,1]*Rd))

            vecAx_xav    = 0.25*( vecAx[i,j,1] + vecAx[i+1,j,1] + vecAx[i,j-1,1] + vecAx[i+1,j-1,1] )
            vecAx_yav    = 0.25*( vecAx[i,j,2] + vecAx[i+1,j,2] + vecAx[i,j-1,2] + vecAx[i+1,j-1,2] )

            tau_xx = 2/3*mu_av*(2*( vecAx_xav * dudxi + vecAy[i,j,1] * dudeta )
                    - (vecAx_yav*dvdxi + vecAy[i,j,2]*dvdeta ))

            tau_yy = 2/3*mu_av*(( vecAx_xav*dudxi -vecAy[i,j,1]*dudeta )
                    + 2*(vecAx_yav*dvdxi + vecAy[i,j,2]*dvdeta ))

            tau_xy = mu_av*(
                    + (vecAx_yav*dudxi + vecAy[i,j,2]*dudeta )
                    + ( vecAx_xav*dvdxi + vecAy[i,j,1]*dvdeta ) )

            dTdx = vecAx_xav*dTdxi + vecAy[i,j,1]*dTdeta
            dTdy = vecAx_yav*dTdxi + vecAy[i,j,2]*dTdeta

            betax = u_av*tau_xx + v_av*tau_xy + lambda_av * dTdx
            betay = u_av*tau_xy + v_av*tau_yy + lambda_av * dTdy

            F_vis_hat[i,j,1] = 0.0
            F_vis_hat[i,j,2] = (vecAy[i,j,1]*tau_xx + vecAy[i,j,2]*tau_xy) / volume_av
            F_vis_hat[i,j,3] = (vecAy[i,j,1]*tau_xy + vecAy[i,j,2]*tau_yy) / volume_av
            F_vis_hat[i,j,4] = (vecAy[i,j,1]*betax + vecAy[i,j,2]*betay)   / volume_av
        end
    end
    return E_vis_hat, F_vis_hat
end

max_stars_repo_name: hide-dog/test

max_issues_repo_name: hide-dog/test

max_forks_repo_name: hide-dog/test


text:
include("..\\src\\generate_decompositions.jl")

data_path = "..\\data\\OPF_instances"
instances = ["case1354pegase.m"]
algo = "cholesky" #OR "MD" or "cholesky_real"
repo_name = "test_kmax2"
FUSION = "YES"
fusion_type = "our_merging_heuristic"
kmax=2
size_max_IPmerging = 0
nb_times = 0

write_file_decompositions(data_path, instances, algo, repo_name, FUSION, fusion_type, size_max_IPmerging, nb_times, kmax)

max_stars_repo_name: JulieSliwak/CliqueMerging

max_issues_repo_name: JulieSliwak/CliqueMerging

max_forks_repo_name: JulieSliwak/CliqueMerging


text:
module WignerFamilies

using HalfIntegers
using OffsetArrays

export WignerSymbolVector
export WignerF, get_wigner_array
export wigner3j_f, wigner3j_f!
export rasch_yu_index

abstract type AbstractWigner{T, Ti} end
abstract type AbstractWignerF{T, Ti} <: AbstractWigner{T, Ti} end
# abstract type AbstractWignerH{T, Ti} <: AbstractWigner{T, Ti} end  # TODO: 6j

include("wignersymbolvector.jl")
include("rasch_yu.jl")
include("wigner3j_f.jl")

end


text:
# Profiler control

export
    @profile, @cuprofile

@enum(CUoutput_mode, CSV            = 0x00,
                     KEY_VALUE_PAIR = 0x01)

"""
    @profile ex

Run expressions while activating the CUDA profiler.

Note that this API is used to programmatically control the profiling granularity by allowing
profiling to be done only on selective pieces of code. It does not perform any profiling on
itself, you need external tools for that.
"""
macro profile(ex)
    quote
        Profile.start()
        local ret = $(esc(ex))
        Profile.stop()
        ret
    end
end

module Profile

using CUDAdrv
import CUDAdrv: @apicall

"""
    start()

Enables profile collection by the active profiling tool for the current context. If
profiling is already enabled, then this call has no effect.
"""
start() = @apicall(:cuProfilerStart, (Ptr{Cvoid},), C_NULL)

"""
    stop()

Disables profile collection by the active profiling tool for the current context. If
profiling is already disabled, then this call has no effect.
"""
stop() = @apicall(:cuProfilerStop, (Ptr{Cvoid},), C_NULL)

end


text:
module ShercliffTest

using Gridap
using Test

using GridapMHD: shercliff
using GridapMHD: analytical_shercliff_u
using GridapMHD: analytical_shercliff_j
using GridapMHD: compute_u_j_errors

# Problem setting
ρ = 1.0
ν = 1.0
σ = 1.0

U0 = 10.0
B0 = 10.0
L = 1.0

Re = U0 * L / ν
Ha = B0 * L * sqrt(σ/(ρ*ν))
K = Ha / (1-0.825*Ha^(-1/2)-Ha^(-1))
∂p∂z = -Re * K / L^3

f_u = VectorValue(0.0,0.0, -∂p∂z) * L/U0^2

xh, trian, dΩ = shercliff(nx=5,ny=5,Re=Re,Ha=Ha,f_u=f_u)

uh, ph, jh, φh = xh
divj = (∇⋅jh)

# Scale unknowns
uh = uh * U0
jh = jh * σ * B0 * U0

# Analyical solutions
side_wall_semilength = 1.0
hartmann_wall_semilength = 1.0
number_fourier_sumands = 10
wall_thickness = 1.0
wall_conductivity = 0.0
K = Ha / (1-0.825*Ha^(-1/2)-Ha^(-1))
∂p∂z = -Re * K / L^3
u0(x) = analytical_shercliff_u(side_wall_semilength, hartmann_wall_semilength,
  wall_thickness, wall_conductivity, σ, ν*ρ, ∂p∂z, Ha, number_fourier_sumands, x)

j0(x) = analytical_shercliff_j(side_wall_semilength, hartmann_wall_semilength,
  wall_thickness, wall_conductivity, σ, ν*ρ, ∂p∂z, Ha, number_fourier_sumands, x)

eu_l2, ej_l2 = compute_u_j_errors(uh, jh, u0, j0, dΩ)
e_divj = sqrt(sum(∫(divj*divj)* dΩ))

@test eu_l2 < 0.3
@test ej_l2 < 5
@test e_divj < 1e-12

end #module


text:
@system Diffusion begin
    Dw: diffusion_coeff_for_water_vapor_in_air_at_20 => 24.2 ~ preserve(u"mm^2/s", parameter)
    Dc: diffusion_coeff_for_co2_in_air_at_20 => 14.7 ~ preserve(u"mm^2/s", parameter)
    Dh: diffusion_coeff_for_heat_in_air_at_20 => 21.5 ~ preserve(u"mm^2/s", parameter)
    Dm: diffusion_coeff_for_momentum_in_air_at_20 => 15.1 ~ preserve(u"mm^2/s", parameter)
end